Previous 15994 Revisions Next

r14540 Sunday 19th February, 2012 at 23:05:23 UTC by R. Belmont
Initial submit of Apollo workstation driver and related peripheral chips; not compiled or hooked in yet. [Hans Ostermeyer, R. Belmont]
[src/mess/drivers]apollo.c*
[src/mess/includes]apollo.h*
[src/mess/layout]apollo.lay* apollo_15i.lay* apollo_dsp.lay*
[src/mess/machine]3c505.c* 3c505.h* apollo.c* apollo_dbg.c* apollo_eth.c* apollo_kbd.c* apollo_kbd.h* apollo_net.c* omti8621.c* omti8621.h* sc499.c* sc499.h*
[src/mess/video]apollo.c*

src/mess/machine/omti8621.h
r0r14540
1/*
2 * omti8621.h - SMS OMTI 8621 disk controller
3 *
4 *  Created on: August 30, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#pragma once
13
14#ifndef OMTI8621_H_
15#define OMTI8621_H_
16
17#include "emu.h"
18
19/***************************************************************************
20 TYPE DEFINITIONS
21 ***************************************************************************/
22
23typedef void (*omti8621_set_irq)(const running_machine*, int);
24
25typedef struct _omti8621_config omti8621_config;
26struct _omti8621_config {
27   omti8621_set_irq set_irq;
28};
29
30/***************************************************************************
31 DEVICE CONFIGURATION MACROS
32 ***************************************************************************/
33
34#define MCFG_OMTI8621_ADD(_tag, _config) \
35   MCFG_FRAGMENT_ADD( omti_disk ) \
36   MCFG_DEVICE_ADD(_tag, OMTI8621, 0) \
37   MCFG_DEVICE_CONFIG(_config)
38
39/***************************************************************************
40 FUNCTION PROTOTYPES
41 ***************************************************************************/
42
43READ16_DEVICE_HANDLER( omti8621_r );
44WRITE16_DEVICE_HANDLER( omti8621_w );
45
46void omti8621_set_verbose(int on_off);
47
48// get sector diskaddr of logical unit lun into data_buffer
49UINT32 omti8621_get_sector(device_t *device, INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun);
50
51/* ----- device interface ----- */
52
53DECLARE_LEGACY_DEVICE(OMTI8621, omti8621);
54MACHINE_CONFIG_EXTERN( omti_disk );
55
56//###############################################################NEWNEW
57
58#endif /* OMTI8621_H_ */
src/mess/machine/apollo_kbd.c
r0r14540
1/*
2 * apollo_kbd.c - Apollo keyboard and mouse emulation
3 *
4 *  Created on: Dec 27, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
11 *
12 */
13
14#define VERBOSE 0
15
16#include "machine/apollo_kbd.h"
17#include "sound/beep.h"
18
19#include <unistd.h>
20#include <fcntl.h>
21#include <errno.h>
22
23#if defined(__linux__)
24// on linux we may attach a real Apollo keyboard at /dev/ttyS0
25#include <termios.h>
26#include <sys/ioctl.h>
27#define KBD_TTY_NAME "/dev/ttyS0"
28#endif
29
30#define LOG(x)   { logerror ("%s apollo_kbd: ", m_device->cpu_context()); logerror x; logerror ("\n"); }
31#define LOG1(x)   { if (VERBOSE > 0) LOG(x)}
32#define LOG2(x)   { if (VERBOSE > 1) LOG(x)}
33
34#define MAP_APOLLO_KEYS 1
35
36//**************************************************************************
37//  DEVICE DEFINITIONS
38//**************************************************************************
39
40//const device_type APOLLO_KBD = apollo_kbd_device_config::static_alloc_device_config;
41
42//**************************************************************************
43//  CONSTANTS
44//**************************************************************************
45
46#define KBD_MODE_0_COMPATIBILITY 0
47#define KBD_MODE_1_KEYSTATE 1
48#define KBD_MODE_2_RELATIVE_CURSOR_CONTROL 2
49#define KBD_MODE_3_ABSOLUTE_CURSOR_CONTROL 3
50
51#define CODE_TABLE_DOWN_CODE 0
52#define CODE_TABLE_UP_CODE 1
53#define CODE_TABLE_UNSHIFTED_CODE 2
54#define CODE_TABLE_SHIFTED_CODE 3
55#define CODE_TABLE_CONTROL_CODE 4
56#define CODE_TABLE_CAPS_LOCK_CODE 5
57#define CODE_TABLE_UP_TRANS_CODE 6
58#define CODE_TABLE_AUTO_REPEAT_CODE 7
59#define CODE_TABLE_ENTRY_SIZE 8
60
61#define NOP 0
62#define No  0
63#define Yes 1
64
65/***************************************************************************
66    IMPLEMENTATION
67***************************************************************************/
68
69// device type definition
70const device_type APOLLO_KBD = &device_creator<apollo_kbd_device>;
71
72//-------------------------------------------------
73// apollo_kbd_device - constructor
74//-------------------------------------------------
75
76apollo_kbd_device::apollo_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
77    : device_t(mconfig, APOLLO_KBD, "Apollo Keyboard", tag, owner, clock)
78{
79   memset(static_cast<apollo_kbd_interface *>(this), 0, sizeof(apollo_kbd_interface));
80}
81
82//-------------------------------------------------
83//  static_set_interface - set the interface struct
84//-------------------------------------------------
85
86void apollo_kbd_device::static_set_interface(device_t &device, const apollo_kbd_interface &interface)
87{
88   apollo_kbd_device &kbd = downcast<apollo_kbd_device &>(device);
89
90   static_cast<apollo_kbd_interface &>(kbd) = interface;
91}
92
93//-------------------------------------------------
94//  device_start - device-specific startup
95//-------------------------------------------------
96
97void apollo_kbd_device::device_start()
98{
99   m_device = this;
100   LOG1(("start apollo_kbd"));
101
102   m_beeper.start(this);
103   m_mouse.start(this);
104   m_tx_fifo.start(this);
105   m_keyboard_tty.start(this);
106
107   m_timer = machine().scheduler().timer_alloc(FUNC(static_poll_callback), this);
108}
109
110//-------------------------------------------------
111//  device_reset - device-specific reset
112//-------------------------------------------------
113
114void apollo_kbd_device::device_reset()
115{
116   LOG1(("reset apollo_kbd"));
117
118   m_beeper.reset();
119   m_mouse.reset();
120   m_tx_fifo.reset();
121   m_keyboard_tty.reset();
122
123   // init keyboard
124   m_loopback_mode = 1;
125   m_mode = KBD_MODE_0_COMPATIBILITY;
126   m_delay = 500;
127   m_repeat = 33;
128   m_last_pressed = 0;
129   memset(m_keytime, 0, sizeof(m_keytime));
130   memset(m_keyon, 0, sizeof(m_keyon));
131
132   // start timer
133   m_timer->adjust( attotime::zero, 0, attotime::from_msec(5)); // every 5ms
134}
135
136/***************************************************************************
137 cpu_context - return a string describing the current CPU context
138 ***************************************************************************/
139
140const char *apollo_kbd_device::cpu_context()
141{
142   static char statebuf[64]; /* string buffer containing state description */
143
144   device_t *cpu = machine().firstcpu;
145   osd_ticks_t t = osd_ticks();
146   int s = t / osd_ticks_per_second();
147   int ms = (t % osd_ticks_per_second()) / 1000;
148
149   /* if we have an executing CPU, output data */
150   if (cpu != NULL)
151   {
152      sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
153            cpu_get_previouspc(cpu), tag());
154   }
155   else
156   {
157      sprintf(statebuf, "%d.%03d", s, ms);
158   }
159   return statebuf;
160}
161
162//**************************************************************************
163//  Beeper
164//**************************************************************************
165
166apollo_kbd_device::beeper::beeper() :
167   m_device(NULL),
168   m_beeper(NULL),
169   m_timer(NULL)
170{
171}
172
173void apollo_kbd_device::beeper::start(apollo_kbd_device *device)
174{
175   m_device = device;
176   LOG2(("start apollo_kbd::beeper"));
177   m_beeper = m_device->machine().device("beep");
178   m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_beeper_callback), this);
179}
180
181void apollo_kbd_device::beeper::reset()
182{
183   LOG2(("reset apollo_kbd::beeper"));
184   on();
185}
186
187void apollo_kbd_device::beeper::off()
188{
189   beep_set_state(m_beeper, 0);
190}
191
192void apollo_kbd_device::beeper::on()
193{
194   if (keyboard_has_beeper())
195   {
196      beep_set_frequency(m_beeper, 1000);
197      beep_set_state(m_beeper, 1);
198      m_timer->adjust( attotime::from_msec(10), 0, attotime::zero);
199   }
200}
201
202int apollo_kbd_device::beeper::keyboard_has_beeper()
203{
204   return m_device->apollo_kbd_has_beeper ?
205         (m_device->apollo_kbd_has_beeper)(m_device, 0) : 0;
206}
207
208void apollo_kbd_device::beeper::beeper_callback()
209{
210   off();
211}
212
213TIMER_CALLBACK( apollo_kbd_device::beeper::static_beeper_callback )
214{
215   reinterpret_cast<beeper *> (ptr)->beeper_callback();
216}
217
218//**************************************************************************
219//  Mouse
220//**************************************************************************
221
222apollo_kbd_device::mouse::mouse() :
223   m_device(NULL)
224{
225}
226
227void apollo_kbd_device::mouse::start(apollo_kbd_device *device)
228{
229   m_device = device;
230   LOG2(("start apollo_kbd::mouse"));
231}
232
233void apollo_kbd_device::mouse::reset()
234{
235   LOG2(("reset apollo_kbd::mouse"));
236
237   m_last_b = -1;
238   m_last_x = 0;
239   m_last_y = 0;
240   m_tx_pending = 0;
241}
242
243void apollo_kbd_device::mouse::read_mouse()
244{
245   if (m_tx_pending > 0)
246   {
247      m_tx_pending -= 5;
248   }
249   else
250   {
251      int b = input_port_read(m_device->machine(), "mouse1");
252      int x = input_port_read(m_device->machine(), "mouse2");
253      int y = input_port_read(m_device->machine(), "mouse3");
254
255      if (m_last_b < 0)
256      {
257         m_last_b = b;
258         m_last_x = x;
259         m_last_y = y;
260      }
261      else if (b != m_last_b || x != m_last_x || y != m_last_y)
262      {
263         int dx = x - m_last_x;
264         int dy = y - m_last_y;
265         UINT8 mouse_data[4];
266         int mouse_data_size;
267
268         LOG2(("read_mouse: b=%02x x=%04x y=%04x dx=%d dy=%d", b, x, y, dx, dy));
269
270         if (m_device->m_mode == KBD_MODE_0_COMPATIBILITY)
271         {
272            mouse_data[0] = 0xdf;
273            mouse_data[1] = 0xf0 ^ b;
274            mouse_data[2] = dx;
275            mouse_data[3] = -dy;
276            mouse_data_size = 4;
277         }
278         else
279         {
280            if (m_device->m_mode != KBD_MODE_2_RELATIVE_CURSOR_CONTROL)
281            {
282               m_device->set_mode(KBD_MODE_2_RELATIVE_CURSOR_CONTROL);
283            }
284
285            mouse_data[0] = 0xf0 ^ b;
286            mouse_data[1] = dx;
287            mouse_data[2] = -dy;
288            mouse_data_size = 3;
289         }
290
291         if (m_device->m_tx_fifo.putdata(mouse_data, mouse_data_size))
292         {
293            // mouse data submitted; update current mouse state
294            m_last_b = b;
295            m_last_x = x;
296            m_last_y = y;
297         }
298         m_tx_pending = 100; // mouse data packet will take 50 ms
299      }
300   }
301}
302
303//**************************************************************************
304//  tx fifo
305//**************************************************************************
306
307apollo_kbd_device::tx_fifo::tx_fifo() :
308   m_device(NULL),
309   m_timer(NULL)
310{
311}
312
313void apollo_kbd_device::tx_fifo::start(apollo_kbd_device *device)
314{
315   m_device = device;
316   LOG2(("start apollo_kbd::tx_fifo"));
317   m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_callback), this);
318}
319
320void apollo_kbd_device::tx_fifo::reset()
321{
322   LOG2(("reset apollo_kbd::tx_fifo"));
323
324   memset(fifo, 0, sizeof(fifo));
325   m_read_ptr = 0;
326   m_write_ptr = 0;
327   m_char_count = 0;
328   m_tx_pending = 0;
329   m_baud_rate = 1200;
330
331   // reset timer
332   m_timer->adjust(attotime::never, 0);
333}
334
335UINT8 apollo_kbd_device::tx_fifo::getchar()
336{
337   UINT8 data;
338
339   if (m_char_count == 0)
340   {
341      LOG(("apollo_kbd FIFO underflow"));
342      data = 0x0;
343   }
344   else
345   {
346      data = fifo[m_read_ptr++];
347      if (m_read_ptr == TX_FIFO_SIZE)
348      {
349         m_read_ptr = 0;
350      }
351      m_char_count--;
352   }
353   return data;
354}
355
356void apollo_kbd_device::tx_fifo::putchar(UINT8 data)
357{
358   if (m_char_count >= TX_FIFO_SIZE)
359   {
360      LOG(("apollo_kbd FIFO overflow"));
361   }
362   else
363   {
364      fifo[m_write_ptr++] = data;
365      if (m_write_ptr == TX_FIFO_SIZE)
366      {
367         m_write_ptr = 0;
368      }
369      m_char_count++;
370      if ( m_tx_pending == 0)
371      {
372         flush();
373      }
374   }
375}
376
377int apollo_kbd_device::tx_fifo::putdata(const UINT8 *data, int data_length)
378{
379   if (m_char_count + data_length >= TX_FIFO_SIZE-5)
380   {
381      // tx fifo is full
382      return 0;
383   }
384   else
385   {
386      while (data_length-- > 0) {
387         putchar(*data++);
388      }
389      return 1;
390   }
391}
392
393void apollo_kbd_device::tx_fifo::flush()
394{
395   if (m_char_count > 0)
396   {
397      m_tx_pending = 1;
398
399      if (m_device->apollo_kbd_putchar)
400         (m_device->apollo_kbd_putchar)(m_device, 0, getchar());
401      // 11 = one start, 8 data, one parity (even), one stop bit
402      m_timer->adjust(attotime::from_hz(m_baud_rate / 11), 0);
403   }
404   else
405   {
406      m_tx_pending = 0;
407//      m_timer->adjust(attotime::never, 0);
408   }
409}
410
411void apollo_kbd_device::tx_fifo::timer_callback()
412{
413   flush();
414}
415
416TIMER_CALLBACK( apollo_kbd_device::tx_fifo::static_timer_callback )
417{
418   reinterpret_cast<apollo_kbd_device::tx_fifo *> (ptr)->timer_callback();
419}
420
421//**************************************************************************
422//  Real Apollo keyboard connected at the keyboard tty (i.e. /dev/ttyS0)
423//**************************************************************************
424
425apollo_kbd_device::keyboard_tty::keyboard_tty() :
426   m_device(NULL),
427    m_tty_name(NULL),
428    m_tty_fd(-1),
429    m_connected(0)
430{
431}
432
433void apollo_kbd_device::keyboard_tty::start(apollo_kbd_device *device)
434{
435   m_device = device;
436   LOG2(("start apollo_kbd::keyboard_tty"));
437#if defined(KBD_TTY_NAME)
438   m_tty_name = KBD_TTY_NAME;
439#endif
440}
441
442void apollo_kbd_device::keyboard_tty::reset()
443{
444   LOG2(("reset apollo_kbd::keyboard_tty"));
445
446   m_connected = 0;
447
448#if defined(KBD_TTY_NAME)
449    /* Open the tty line */
450   m_tty_fd = open(m_tty_name, 2);
451   if (m_tty_fd < 0)
452   {
453      LOG1(("failed to open %s", m_tty_name));
454   }
455   else
456   {
457      int serial;
458      struct termios tty_mode;
459
460      // set nonblocking mode
461      fcntl(m_tty_fd, F_SETFL, fcntl(m_tty_fd, F_GETFL) | O_NONBLOCK);
462
463      tcgetattr(m_tty_fd, &tty_mode);
464      tty_mode.c_iflag = INPCK;
465      tty_mode.c_oflag = 0;
466      tty_mode.c_cflag = B1200 | CS8 | CREAD | HUPCL | PARENB | CLOCAL;
467      tty_mode.c_lflag = 0;
468      tty_mode.c_cc[VTIME] = 0;
469      tty_mode.c_cc[VMIN] = 1;
470      tcsetattr(m_tty_fd, TCSANOW, &tty_mode);
471
472      ioctl(m_tty_fd, TIOCMGET, &serial);
473
474      if ((serial & TIOCM_RTS) && !(serial & TIOCM_CTS))
475      {
476         // Apollo keyboard not connected
477         close(m_tty_fd);
478         m_tty_fd = -1;
479         m_connected = 0;
480      }
481      else
482      {
483         LOG1(("opened %s with RTS=%d CTS=%d", m_tty_name,
484            serial & TIOCM_RTS ? 1 : 0, serial & TIOCM_CTS ? 1 : 0 ));
485      }
486   }
487#endif
488}
489
490int apollo_kbd_device::keyboard_tty::isConnected()
491{
492   return m_connected;
493}
494
495int apollo_kbd_device::keyboard_tty::getchar()
496{
497   UINT8 data;
498   if (m_tty_fd < 0 || read(m_tty_fd, &data, 1) != 1) {
499      return -1;
500   } else {
501      LOG2(("keyboard_tty::getchar <---- %02x", data))
502      m_connected = 1;
503      return data;
504   }
505}
506
507void apollo_kbd_device::keyboard_tty::putchar(UINT8 data)
508{
509   if (isConnected() && m_tty_fd >= 0 ) {
510      while (write(m_tty_fd, &data, 1) != 1) {
511         LOG(("keyboard_tty::putchar data=%02x errno=%d", data, errno ));
512      }
513      LOG2(("keyboard_tty::putchar -> %02x", data));
514   }
515}
516
517/*-------------------------------------------------
518 keyboard_is_german - check for german keyboard
519 -------------------------------------------------*/
520
521int apollo_kbd_device::keyboard_is_german()
522{
523   return apollo_kbd_is_german ?
524         (*apollo_kbd_is_german)(this, 0) : 0;
525}
526
527/*-------------------------------------------------
528 putchar - put keyboard char to sio
529 -------------------------------------------------*/
530
531void apollo_kbd_device::set_mode(UINT16 mode)
532{
533   putchar(0xff);
534   putchar(mode);
535   m_mode = mode;
536}
537
538/*-------------------------------------------------
539 putchar - put keyboard char to sio
540 -------------------------------------------------*/
541
542void apollo_kbd_device::putchar(const UINT8 data)
543{
544   LOG1(("putchar(%d) -> %02x", m_mode, data));
545   m_tx_fifo.putchar(data);
546}
547
548/*-------------------------------------------------
549 putdata - put keyboard data to sio
550 -------------------------------------------------*/
551
552void apollo_kbd_device::putdata(const UINT8 *data, int data_length)
553{
554   // send data only if no real Apollo keyboard has been connected
555   if (!m_keyboard_tty.isConnected())
556   {
557      if (m_mode > KBD_MODE_1_KEYSTATE)
558      {
559         set_mode(KBD_MODE_1_KEYSTATE);
560      }
561      m_tx_fifo.putdata(data, data_length);
562   }
563}
564
565/*-------------------------------------------------
566 putstring - put keyboard string to sio
567 -------------------------------------------------*/
568
569void apollo_kbd_device::putstring(const char *data)
570{
571   putdata((UINT8 *) data, strlen(data));
572}
573
574/*-------------------------------------------------
575 apollo_kbd_getchar - get char from sio line
576 -------------------------------------------------*/
577
578void apollo_kbd_getchar(device_t *device, UINT8 data)
579{
580   downcast<apollo_kbd_device *> (device)->getchar(data);
581}
582
583void apollo_kbd_device::getchar(UINT8 data)
584{
585   static const UINT8 ff1116_data[] = { 0x00, 0xff, 0x00 };
586
587   LOG1(("getchar <- %02x", data));
588
589   if (m_keyboard_tty.isConnected())
590   {
591      m_keyboard_tty.putchar(data);
592   }
593
594   if (data == 0xff)
595   {
596      m_rx_message = data;
597      putdata(&data, 1);
598      m_loopback_mode = 1;
599   }
600   else if (data == 0x00)
601   {
602      if (m_loopback_mode)
603      {
604         set_mode(KBD_MODE_0_COMPATIBILITY);
605         m_loopback_mode = 0;
606      }
607   }
608   else
609   {
610      m_rx_message = m_rx_message << 8 | data;
611
612      switch (m_rx_message)
613      {
614      case 0xff00:
615         putdata(&data, 1);
616         m_mode = KBD_MODE_0_COMPATIBILITY;
617         m_loopback_mode = 0;
618         m_rx_message = 0;
619      case 0xff01:
620         putdata(&data, 1);
621         m_mode = KBD_MODE_1_KEYSTATE;
622         m_rx_message = 0;
623         break;
624      case 0xff11:
625         putdata(&data, 1);
626         break;
627      case 0xff1116:
628         putdata(ff1116_data, sizeof(ff1116_data));
629         m_loopback_mode = 0;
630         m_rx_message = 0;
631         break;
632      case 0xff1117:
633         m_rx_message = 0;
634         break;
635      case 0xff12:
636         putdata(&data, 1);
637         break;
638      case 0xff1221: // receive ID message
639         m_loopback_mode = 0;
640         putdata(&data, 1);
641         if (keyboard_is_german())
642         {
643            putstring("3-A\r2-0\rSD-03863-MS\r");
644         }
645         else
646         {
647            putstring("3-@\r2-0\rSD-03863-MS\r");
648         }
649
650         if (m_mode == KBD_MODE_0_COMPATIBILITY)
651         {
652            set_mode(KBD_MODE_0_COMPATIBILITY);
653         }
654         else
655         {
656            set_mode(KBD_MODE_1_KEYSTATE);
657         }
658         m_rx_message = 0;
659         break;
660      case 0xff2181: // beeper on (for 300 ms)
661         putdata(&data, 1);
662         m_rx_message = 0;
663         m_beeper.on();
664         break;
665      case 0xff2182: // beeper off
666         putdata(&data, 1);
667         m_rx_message = 0;
668         m_beeper.off();
669         break;
670      default:
671         if (m_loopback_mode && data != 0)
672         {
673            putdata(&data, 1);
674         }
675         break;
676      }
677   }
678}
679
680int apollo_kbd_device::push_scancode(UINT8 code, UINT8 repeat)
681{
682   int n_chars = 0;
683   UINT16 key_code = 0;
684   UINT8 caps = BIT(input_port_read(machine(), "keyboard4"),0);
685   UINT8 shift = BIT(input_port_read(machine(), "keyboard4"),1) | BIT(input_port_read(machine(), "keyboard4"),5);
686   UINT8 ctrl = BIT(input_port_read(machine(), "keyboard4"),2);
687   UINT8 numlock = BIT(input_port_read(machine(), "keyboard4"),6);
688   UINT16 index;
689
690   if (keyboard_is_german())
691   {
692      // map special keys for German keyboard
693      switch (code)
694      {
695      case 0x00: code = 0x68; break; // _
696      case 0x0e: code = 0x6b; break; // #
697      case 0x29: code = 0x69; break; // <>
698      case 0x42: code = 0x6f; break; // NP-
699      case 0x46: code = 0x6e; break; // NP+
700      case 0x4e: code = 0x73; break; // NP ENTER
701      }
702   }
703
704#if MAP_APOLLO_KEYS
705   if (numlock)
706   {
707      // don't map function keys to Apollo left keypad
708      switch (code)
709      {
710      case 0x52: code = 0x75; break; // F1
711      case 0x53: code = 0x76; break; // F2
712      case 0x54: code = 0x77; break; // F3
713      case 0x55: code = 0x78; break; // F4
714      case 0x56: code = 0x79; break; // F5
715      case 0x57: code = 0x7a; break; // F6
716      case 0x58: code = 0x7b; break; // F7
717      case 0x59: code = 0x7c; break; // F8
718      case 0x5a: code = 0x7d; break; // F9
719      case 0x5b: code = 0x74; break; // F0 = F10
720      }
721   }
722#endif
723
724   index = (code & 0x7f) * CODE_TABLE_ENTRY_SIZE;
725   if (m_mode == KBD_MODE_0_COMPATIBILITY)
726   {
727      if (code & 0x80)
728      {
729         // skip up code in ASCII mode
730      }
731      else if (repeat > 0
732            && m_code_table[index + CODE_TABLE_AUTO_REPEAT_CODE] != Yes)
733      {
734         // skip repeat in ASCII mode
735      }
736      else if (ctrl)
737      {
738         key_code = m_code_table[index + CODE_TABLE_CONTROL_CODE];
739      }
740      else if (shift)
741      {
742         key_code = m_code_table[index + CODE_TABLE_SHIFTED_CODE];
743      }
744      else if (caps)
745      {
746         key_code = m_code_table[index + CODE_TABLE_CAPS_LOCK_CODE];
747      }
748      else
749      {
750         key_code = m_code_table[index + CODE_TABLE_UNSHIFTED_CODE];
751      }
752   }
753   else
754   {
755      if (repeat > 0)
756      {
757         if (repeat == 1)
758         {
759            // auto repeat (but only for first scanned key)
760            key_code = 0x7f;
761         }
762      }
763      else if (code & 0x80)
764      {
765         key_code = m_code_table[index + CODE_TABLE_UP_CODE];
766      }
767      else
768      {
769         key_code = m_code_table[index + CODE_TABLE_DOWN_CODE];
770      }
771   }
772
773   if (key_code != 0)
774   {
775      LOG2(("scan_code = 0x%02x key_code = 0x%04x",code, key_code));
776      if (m_mode > KBD_MODE_1_KEYSTATE)
777      {
778         set_mode(KBD_MODE_1_KEYSTATE);
779      }
780
781      if (key_code & 0xff00)
782      {
783         putchar(key_code >> 8);
784         n_chars++;
785      }
786      putchar(key_code & 0xff);
787      n_chars++;
788   }
789   return n_chars;
790}
791
792void apollo_kbd_device::scan_keyboard()
793{
794   int x;
795   int repeat = 0;
796
797   static const char * const keynames[] = { "keyboard1", "keyboard2", "keyboard3", "keyboard4" };
798
799   for (x = 0; x < 0x80; x++)
800   {
801      if (!(input_port_read(machine(), keynames[x / 32]) & (1 << (x % 32))))
802      {
803         // no key pressed
804         if (m_keyon[x] != 0)
805         {
806            // a key has been released
807            push_scancode(0x80 + x, 0);
808            m_keytime[x] = 0;
809            m_keyon[x] = 0;
810            m_last_pressed = 0;
811            LOG2(("released key 0x%02x at time %d",x, m_keytime[x]));
812         }
813      }
814      else if (m_keyon[x] == 0)
815      {
816         // a key has been pressed
817         if (push_scancode(x, 0) > 0)
818         {
819            m_keytime[x] = m_mode == KBD_MODE_0_COMPATIBILITY ? m_delay : m_repeat;
820            m_keyon[x] = 1;
821            m_last_pressed = x;
822            LOG2(("pushed key 0x%02x at time %d",x, m_keytime[x]));
823         }
824      }
825      else if (m_last_pressed == x)
826      {
827         // a key is being held; adjust delay/repeat timers
828         m_keytime[x] -= 5;
829         if (m_keytime[x] <= 0)
830         {
831            push_scancode(x, ++repeat);
832            m_keytime[x] = m_repeat;
833         }
834         LOG2(("holding key 0x%02x at time %d",x, m_keytime[x]));
835      }
836   }
837}
838
839void apollo_kbd_device::poll_callback()
840{
841   int data;
842   while ((data = m_keyboard_tty.getchar()) >= 0)
843   {
844      putchar(data);
845   }
846   scan_keyboard();
847
848   // Note: we omit extra traffic while keyboard is in Compatibitlit mode
849   if (m_device->m_mode != KBD_MODE_0_COMPATIBILITY)
850   {
851      m_mouse.read_mouse();
852   }
853}
854
855TIMER_CALLBACK( apollo_kbd_device::static_poll_callback )
856{
857   reinterpret_cast<apollo_kbd_device *> (ptr)->poll_callback();
858}
859
860UINT16 apollo_kbd_device::m_code_table[] = {
861
862        /* Key   | Keycap      | Down | Up  |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto  */
863        /* Number| Legend      | Code | Code|Code     | Code  | Code  |Code     | Code   |Repeat*/
864
865      /* B14     ~ ' / ESC   */ 0x24, 0xA4, 0x60,     0x7E,   0x1E,   0x60,     NOP,     No,
866        /* B1      ESC         */ 0x17, 0x97, 0x1B,     0x1B,   NOP,    0x1B,     NOP,     No,
867        /* B2      ! 1         */ 0x18, 0x98, 0x31,     0x21,   NOP,    0x31,     NOP,     No,
868        /* B3      @ 2         */ 0x19, 0x99, 0x32,     0x40,   NOP,    0x32,     NOP,     No,
869        /* B4      # 3         */ 0x1A, 0x9A, 0x33,     0x23,   NOP,    0x33,     NOP,     No,
870        /* B5      $ 4         */ 0x1B, 0x9B, 0x34,     0x24,   NOP,    0x34,     NOP,     No,
871        /* B6      % 5         */ 0x1C, 0x9C, 0x35,     0x25,   NOP,    0x35,     NOP,     No,
872        /* B7      ^ 6         */ 0x1D, 0x9D, 0x36,     0x5E,   NOP,    0x36,     NOP,     No,
873        /* B8      & 7         */ 0x1E, 0x9E, 0x37,     0x26,   NOP,    0x37,     NOP,     No,
874        /* B9      * 8         */ 0x1F, 0x9F, 0x38,     0x2A,   NOP,    0x38,     NOP,     No,
875        /* B10     ( 9         */ 0x20, 0xA0, 0x39,     0x28,   NOP,    0x39,     NOP,     No,
876        /* B11     ) 0         */ 0x21, 0xA1, 0x30,     0x29,   NOP,    0x30,     NOP,     No,
877        /* B12     _ -         */ 0x22, 0xA2, 0x2D,     0x5F,   NOP,    0x2D,     NOP,     Yes,
878        /* B13     + =         */ 0x23, 0xA3, 0x3D,     0x2B,   NOP,    0x3D,     NOP,     Yes,
879        /* B14     ~ ' / BS    */ 0x24, 0xA4, 0x60,     0x7E,   0x1E,   0x60,     NOP,     No,
880        /* B15     BACKSPACE   */ 0x25, 0xA5, 0xDE,     0xDE,   NOP,    0xDE,     NOP,     Yes,
881
882        /* C1      TAB         */ 0x2C, 0xAC, 0xCA,     0xDA,   0xFA,   0xCA,     NOP,     No,
883        /* C2      Q           */ 0x2D, 0xAD, 0x71,     0x51,   0x11,   0x51,     NOP,     No,
884        /* C3      W           */ 0x2E, 0xAE, 0x77,     0x57,   0x17,   0x57,     NOP,     No,
885        /* C4      E           */ 0x2F, 0xAF, 0x65,     0x45,   0x05,   0x45,     NOP,     No,
886        /* C5      R           */ 0x30, 0xB0, 0x72,     0x52,   0x12,   0x52,     NOP,     No,
887        /* C6      T           */ 0x31, 0xB1, 0x74,     0x54,   0x14,   0x54,     NOP,     No,
888        /* C7      V           */ 0x32, 0xB2, 0x79,     0x59,   0x19,   0x59,     NOP,     No,
889        /* C8      U           */ 0x33, 0xB3, 0x75,     0x55,   0x15,   0x55,     NOP,     No,
890        /* C9      I           */ 0x34, 0xB4, 0x69,     0x49,   0x09,   0x49,     NOP,     No,
891        /* C10     O           */ 0x35, 0xB5, 0x6F,     0x4F,   0x0F,   0x4F,     NOP,     No,
892        /* C11     P           */ 0x36, 0xB6, 0x70,     0x50,   0x10,   0x50,     NOP,     No,
893        /* C12     { [ / Ü     */ 0x37, 0xB7, 0x7B,     0x5B,   0x1B,   0x7B,     NOP,     No,
894        /* C13     } ] / Ö     */ 0x38, 0xB8, 0x7D,     0x5D,   0x1D,   0x7D,     NOP,     No,
895        /* D13     RETURN      */ 0x52, 0xD2, 0xCB,     0xDB,   NOP,    0xCB,     NOP,     No,
896
897        /* D2      A           */ 0x46, 0xC6, 0x61,     0x41,   0x01,   0x41,     NOP,     No,
898        /* D3      S           */ 0x47, 0xC7, 0x73,     0x53,   0x13,   0x53,     NOP,     No,
899        /* D4      D           */ 0x48, 0xC8, 0x64,     0x44,   0x04,   0x44,     NOP,     No,
900        /* D5      F           */ 0x49, 0xC9, 0x66,     0x46,   0x06,   0x46,     NOP,     No,
901        /* D6      G           */ 0x4A, 0xCA, 0x67,     0x47,   0x07,   0x47,     NOP,     No,
902        /* D7      H           */ 0x4B, 0xCB, 0x68,     0x48,   0x08,   0x48,     NOP,     No,
903        /* D8      J           */ 0x4C, 0xCC, 0x6A,     0x4A,   0x0A,   0x4A,     NOP,     No,
904        /* D9      K           */ 0x4D, 0xCD, 0x6B,     0x4B,   0x0B,   0x4B,     NOP,     No,
905        /* D10     L           */ 0x4E, 0xCE, 0x6C,     0x4C,   0x0C,   0x4C,     NOP,     No,
906        /* D11     : ;         */ 0x4F, 0xCF, 0x3B,     0x3A,   0xFB,   0x3B,     NOP,     No,
907        /* D12     " ' / Ä     */ 0x50, 0xD0, 0x27,     0x22,   0xF8,   0x27,     NOP,     No,
908        /* D14     ! \         */ 0x53, 0xD3, 0xC8,     0xC9,   NOP,    0xC8,     NOP,     No,
909
910        /* E2      Z           */ 0x60, 0xE0, 0x7A,     0x5A,   0x1A,   0x5A,     NOP,     No,
911        /* E3      X           */ 0x61, 0xE1, 0x78,     0x58,   0x18,   0x58,     NOP,     No,
912        /* E4      C           */ 0x62, 0xE2, 0x63,     0x43,   0x03,   0x43,     NOP,     No,
913        /* E5      V           */ 0x63, 0xE3, 0x76,     0x56,   0x16,   0x56,     NOP,     No,
914        /* E6      8           */ 0x64, 0xE4, 0x62,     0x42,   0x02,   0x42,     NOP,     No,
915        /* E7      N           */ 0x65, 0xE5, 0x6E,     0x4E,   0x0E,   0x4E,     NOP,     No,
916        /* E8      M           */ 0x66, 0xE6, 0x6D,     0x4D,   0x0D,   0x4D,     NOP,     No,
917        /* E9      < ,         */ 0x67, 0xE7, 0x2C,     0x3C,   NOP,    0x2C,     NOP,     No,
918        /* E10     > .         */ 0x68, 0xE8, 0x2E,     0x3E,   NOP,    0x2E,     NOP,     Yes,
919        /* E11     ? /         */ 0x69, 0xE9, 0xCC,     0xDC,   0xFC,   0xCC,     NOP,     No,
920
921//      /* B14     ~ '         */ 0x24, 0xA4, 0x60,     0x7E,   0x1E,   0x60,     NOP,     No,
922        /*         _           */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
923        /* F1      (space bar) */ 0x76, 0xF6, 0x20,     0x20,   0x20,   0x20,     NOP,     Yes,
924        /* LC0     Home        */ 0x27, 0xA7, 0x84,     0x94,   0x84,   0x84,     0xA4,    No,
925#if !MAP_APOLLO_KEYS
926        /* C14     DELETE      */ 0x3A, 0xBA, 0x7F,     0x7F,   NOP,    0x7F,     NOP,     Yes,
927#else
928        /* E13     POP         */ 0x6C, 0xEC, 0x80,     0x90,   0x80,   0x80,     0xA0,    No,
929#endif
930        /* LF0     Roll Up     */ 0x72, 0xF2, 0x8D,     0x9D,   0x8D,   0x8D,     0xAD,    No,
931        /* LF2     Roll Down   */ 0x74, 0xF4, 0x8F,     0x9F,   0x8F,   0x8F,     0xAF,    No,
932        /* LC2     End         */ 0x29, 0xA9, 0x86,     0x96,   0x86,   0x86,     0xA6,    No,
933        /* LE0     Cursor left */ 0x59, 0xD9, 0x8A,     0x9A,   0x9A,   0x9A,     0xAA,    Yes,
934        /* LD1     Cursor Up   */ 0x41, 0xC1, 0x88,     0x98,   0x88,   0x88,     0xA8,    Yes,
935        /* LE2     Cursor right*/ 0x5B, 0xDB, 0x8C,     0x9C,   0x8C,   0xBE,     0xAC,    Yes,
936        /* LF1     Cursor down */ 0x73, 0xF3, 0x8E,     0x9E,   0x8E,   0x8E,     0xAE,    Yes,
937
938#if !MAP_APOLLO_KEYS
939        /*         Numpad CLR  */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
940        /*         Numpad /    */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
941        /*         Numpad *    */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
942        /* RD4     -           */ 0x58, 0xD8, 0xFE2D,   0xFE5F, NOP,    0xFE2D,   NOP,     No,
943        /* RC1     7           */ 0x3C, 0xBC, 0xFE37,   0xFE26, NOP,    0xFE37,   NOP,     No,
944        /* RC2     8           */ 0x3D, 0xBD, 0xFE38,   0xFE2A, NOP,    0xFE38,   NOP,     No,
945        /* RC3     9           */ 0x3E, 0xBE, 0xFE39,   0xFE28, NOP,    0xFE39,   NOP,     No,
946        /* RC4     +           */ 0x3F, 0xBF, 0xFE2B,   0xFE3D, NOP,    0xFE2B,   NOP,     No,
947        /* RD1     4           */ 0x55, 0xD5, 0xFE34,   0xFE24, NOP,    0xFE34,   NOP,     No,
948        /* RD2     5           */ 0x56, 0xD6, 0xFE35,   0xFE25, NOP,    0xFE35,   NOP,     No,
949        /* RD3     6           */ 0x57, 0xD7, 0xFE36,   0xFE5E, NOP,    0xFE36,   NOP,     No,
950        /*         Numpad =    */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
951        /* RE1     1           */ 0x6E, 0xEE, 0xFE31,   0xFE21, NOP,    0xFE31,   NOP,     No,
952        /* RE2     2           */ 0x6F, 0xEF, 0xFE32,   0xFE40, NOP,    0xFE32,   NOP,     No,
953        /* RE3     3           */ 0x70, 0xF0, 0xFE33,   0xFE23, NOP,    0xFE33,   NOP,     No,
954        /* RF3     ENTER       */ 0x7C, 0xFC, 0xFECB,   0xFEDB, NOP,    0xFECB,   NOP,     No,
955        /* RF1     0           */ 0x79, 0xF9, 0xFE30,   0xFE29, NOP,    0xFE30,   NOP,     No,
956        /*         Numpad ,    */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
957        /* RF2     .           */ 0x7B, 0xFB, 0xFE2E,   0xFE2E, NOP,    0xFE2E,   NOP,     No,
958        /* A0      F0          */ 0x04, 0x84, 0x1C,     0x5C,   0x7C,   0x1C,     0xBC,    No,
959        /* A1      F1          */ 0x05, 0x85, 0xC0,     0xD0,   0xF0,   0xC0,     0xE0,    No,
960        /* A2      F2          */ 0x06, 0x86, 0xC1,     0x01,   0xF1,   0xC1,     0xE1,    No,
961        /* A3      F3          */ 0x07, 0x87, 0xC2,     0x02,   0xF2,   0xC2,     0xE2,    No,
962        /* A4      F4          */ 0x08, 0x88, 0xC3,     0x03,   0xF3,   0xC3,     0xE3,    No,
963        /* A5      F5          */ 0x09, 0x89, 0xC4,     0x04,   0xF4,   0xC4,     0xE4,    No,
964        /* A6      F6          */ 0x0A, 0x8A, 0xC5,     0x05,   0xF5,   0xC5,     0xE5,    No,
965        /* A7      F7          */ 0x0B, 0x8B, 0xC6,     0x06,   0xF6,   0xC6,     0xE6,    No,
966        /* A8      F8          */ 0x0C, 0x8C, 0xC7,     0x07,   0xF7,   0xC7,     0xE7,    No,
967        /* A9      F9          */ 0x0D, 0x8D, 0x1F,     0x2F,   0x3F,   0x1F,     0xBD,    No,
968#else
969        /* E13     POP         */ 0x6C, 0xEC, 0x80,     0x90,   0x80,   0x80,     0xA0,    No,
970        /* LDO     [<-]        */ 0x40, 0xC0, 0x87,     0x97,   0x87,   0x87,     0xA7,    No,
971        /* LD2     [->]        */ 0x42, 0xC2, 0x89,     0x99,   0x89,   0x89,     0xA9,    No,
972        /* RD4     Numpad -    */ 0x58, 0xD8, 0xFE2D,   0xFE5F, NOP,    0xFE2D,   NOP,     No,
973        /* LC0   7 Home        */ 0x27, 0xA7, 0x84,     0x94,   0x84,   0x84,     0xA4,    No,
974        /* LD1   8 Cursor Up   */ 0x41, 0xC1, 0x88,     0x98,   0x88,   0x88,     0xA8,    Yes,
975        /* LF0   9 Roll Up     */ 0x72, 0xF2, 0x8D,     0x9D,   0x8D,   0x8D,     0xAD,    No,
976        /* RC4     Numpad +    */ 0x3F, 0xBF, 0xFE2B,   0xFE3D, NOP,    0xFE2B,   NOP,     No,
977        /* LE0   4 Cursor left */ 0x59, 0xD9, 0x8A,     0x9A,   0x9A,   0x9A,     0xAA,    Yes,
978        /* LE1     NEXT WINDOW */ 0x5A, 0xDA, 0x8B,     0x9B,   0x8B,   0x8B,     0xAB,    No,
979        /* LE2   6 Cursor right*/ 0x5B, 0xDB, 0x8C,     0x9C,   0x8C,   0xBE,     0xAC,    Yes,
980        /*         Numpad =    */ 0x7C, 0xFC, 0xFEC8,   0xFED8, NOP,    0xFECB,   NOP,     No,
981        /* LC2   1 End         */ 0x29, 0xA9, 0x86,     0x96,   0x86,   0x86,     0xA6,    No,
982        /* LF1   2 Cursor down */ 0x73, 0xF3, 0x8E,     0x9E,   0x8E,   0x8E,     0xAE,    Yes,
983        /* LF2   3 Roll Down   */ 0x74, 0xF4, 0x8F,     0x9F,   0x8F,   0x8F,     0xAF,    No,
984        /* RF3     ENTER       */ 0x7C, 0xFC, 0xFECB,   0xFEDB, NOP,    0xFECB,   NOP,     No,
985        /* LE1     NEXT WINDOW */ 0x5A, 0xDA, 0x8B,     0x9B,   0x8B,   0x8B,     0xAB,    No,
986        /*         Numpad ,    */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
987        /* E13     POP         */ 0x6C, 0xEC, 0x80,     0x90,   0x80,   0x80,     0xA0,    No,
988
989        /* LC1  F1/SHELL/CMD   */ 0x28, 0xA8, 0x85,     0x95,   0x85,   0x85,     0xA5,    No,
990        /* LB0  F2/CUT/COPY    */ 0x13, 0x93, 0xB0,     0xB4,   0xB0,   0xB0,     0xB8,    No,
991        /* LB1  F3/UNDO/PASTE  */ 0x14, 0x94, 0xB1,     0xB5,   0xB1,   0xB1,     0xB9,    No,
992        /* LB2  F4/MOVE/GROW   */ 0x15, 0x95, 0xB2,     0xB6,   0xB2,   0xB2,     0xBA,    No,
993
994        /* LAO  F5/INS/MARK    */ 0x01, 0x81, 0x81,     0x91,   0x81,   0x81,     0xA1,    No,
995        /* LA1  F6/LINE DEL    */ 0x02, 0x82, 0x82,     0x92,   0x82,   0x82,     0xA2,    No,
996        /* LA2  F7/CHAR DEL    */ 0x03, 0x83, 0x83,     0x93,   0x83,   0x83,     0xA3,    Yes,
997        /* RA0  F8/AGAIN       */ 0x0E, 0x8E, 0xCD,     0xE9,   0xCD,   0xCD,     0xED,    No,
998
999        /* RA1  F9/READ        */ 0x0F, 0x8F, 0xCE,     0xEA,   0xCE,   0xCE,     0xEE,    No,
1000        /* RA2 F10/SAVE/EDIT   */ 0x10, 0x90, 0xCF,     0xEB,   0xCF,   0xCF,     0xEF,    No,
1001#endif
1002        /* RA3 F11/ABORT/EXIT  */ 0x11, 0x91, 0xDD,     0xEC,   0xD0,   0xD0,     0xFD,    No,
1003        /* RA4 F12/HELP/HOLD   */ 0x12, 0x92, 0xB3,     0xB7,   0xB3,   0xB3,     0xBB,    No,
1004
1005        /* LE1     NEXT WINDOW */ 0x5A, 0xDA, 0x8B,     0x9B,   0x8B,   0x8B,     0xAB,    No,
1006        /* LE1     NEXT WINDOW */ 0x5A, 0xDA, 0x8B,     0x9B,   0x8B,   0x8B,     0xAB,    No,
1007
1008        /* D1      CAPS LOCK   */ NOP,  NOP,  NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1009        /* E1      SHIFT       */ 0x5E, 0xDE, NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1010        /* DO      CTRL        */ 0x43, 0xC3, NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1011// FIXME: ALT swapped!
1012        /* ??      ALT_R       */ 0x77, 0xF7, 0xfe00,   NOP,    NOP,    NOP,      0xfe01,  No,
1013        /* ??      ALT_L       */ 0x75, 0xF5, 0xfe02,   NOP,    NOP,    NOP,      0xfe03,  No,
1014        /* E12     SHIFT       */ 0x6A, 0xEA, NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1015// not yet used:
1016      /* E0      REPEAT      */ 0x5D, 0xDD, NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1017      /*        CAPS LOCK LED*/ 0x7E, 0xFE, NOP,      NOP,    NOP,    NOP,      NOP,     NOP,
1018// german kbd:
1019        /* 0x68 B1_DE   _      */ 0x17, 0x97, 0x60,     0x7E,   0x1E,   0x60,     NOP,     No,
1020        /* 0x69 E1a_DE  <>     */ 0x5F, 0xDF, 0xBE,     0xBE,   NOP,    0xBE,     NOP,     No,
1021        /* 0x6a B14_DE  ESC    */ 0x16, 0x96, 0x1B,     0x1B,   NOP,    0x1B,     NOP,     No,
1022        /* 0x6b D14_DE  # \    */ 0x51, 0xD1, 0xC8,     0xC9,   NOP,    0xC8,     NOP,     No,
1023
1024        /* 0x6c NPG     NP (   */ 0x3F, 0xBF, 0xFE28,   0xFE0E, NOP,    0xFE28,   NOP,     No,
1025        /* 0x6d NPF     NP )   */ 0x58, 0xD8, 0xFE29,   0xFE0F, NOP,    0xFE29,   NOP,     No,
1026        /* 0x6e NPD     NP +   */ 0x3B, 0xBB, 0xFE2B,   0xFE26, NOP,    0xFE2B,   NOP,     No,
1027        /* 0x6f NPC     NP -   */ 0x54, 0xD4, 0xFE2D,   0xFE7E, NOP,    0xFE2D,   NOP,     No,
1028        /* 0x70 NPB     NP *   */ 0x6D, 0xED, 0xFE2A,   0xFE21, NOP,    0xFE2A,   NOP,     No,
1029        /* 0x71 NPA     NP /   */ 0x78, 0xF8, 0xFECC,   0xFEC8, NOP,    0xFECC,   NOP,     No,
1030        /* 0x72 NPP     NP .   */ 0x7B, 0xFB, 0xFE2E,   0xFE2C, NOP,    0xFE2E,   NOP,     No,
1031        /* 0x73 NPE     ENTER  */ 0x7C, 0xFC, 0xFECB,   0xFE3D, NOP,    0xFECB,   NOP,     No,
1032
1033        /* 0x74 A0      F0     */ 0x04, 0x84, 0x1C,     0x5C,   0x7C,   0x1C,     0xBC,    No,
1034        /* 0x75 A1      F1     */ 0x05, 0x85, 0xC0,     0xD0,   0xF0,   0xC0,     0xE0,    No,
1035        /* 0x76 A2      F2     */ 0x06, 0x86, 0xC1,     0x01,   0xF1,   0xC1,     0xE1,    No,
1036        /* 0x77 A3      F3     */ 0x07, 0x87, 0xC2,     0x02,   0xF2,   0xC2,     0xE2,    No,
1037        /* 0x78 A4      F4     */ 0x08, 0x88, 0xC3,     0x03,   0xF3,   0xC3,     0xE3,    No,
1038        /* 0x79 A5      F5     */ 0x09, 0x89, 0xC4,     0x04,   0xF4,   0xC4,     0xE4,    No,
1039        /* 0x7a A6      F6     */ 0x0A, 0x8A, 0xC5,     0x05,   0xF5,   0xC5,     0xE5,    No,
1040        /* 0x7b A7      F7     */ 0x0B, 0x8B, 0xC6,     0x06,   0xF6,   0xC6,     0xE6,    No,
1041        /* 0x7c A8      F8     */ 0x0C, 0x8C, 0xC7,     0x07,   0xF7,   0xC7,     0xE7,    No,
1042        /* 0x7d A9      F9     */ 0x0D, 0x8D, 0x1F,     0x2F,   0x3F,   0x1F,     0xBD,    No,
1043
1044        /* Key   | Keycap      | Down | Up  |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto  */
1045        /* Number| Legend      | Code | Code|Code     | Code  | Code  |Code     | Code   |Repeat*/
1046};
1047
1048INPUT_PORTS_START( apollo_kbd )
1049
1050   PORT_START( "keyboard1" )
1051   PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* ESC */
1052   PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) /* ESC */
1053   PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1 ! */
1054   PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) /* 2 " */
1055   PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3 # */
1056   PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4 $ */
1057   PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5 % */
1058   PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("6 &") PORT_CODE(KEYCODE_6) /* 6 & */
1059   PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("7 \'") PORT_CODE(KEYCODE_7) /* 7 ' */
1060   PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("8 (") PORT_CODE(KEYCODE_8) /* 8 ( */
1061   PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("9 )") PORT_CODE(KEYCODE_9) /* 9 ) */
1062   PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("0") PORT_CODE(KEYCODE_0) /* 0 */
1063   PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* - _ */
1064   PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* = + */
1065   PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("@ ^") PORT_CODE(KEYCODE_BACKSLASH2) /* ~ ` */
1066   PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_CODE(KEYCODE_BACKSPACE) /* Backspace */
1067   PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_CODE(KEYCODE_TAB) /* Tab */
1068   PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q */
1069   PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W */
1070   PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E */
1071   PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R */
1072   PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T */
1073   PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y */
1074   PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U */
1075   PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I */
1076   PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O */
1077   PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P */
1078   PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [ { */
1079   PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ] } */
1080   PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_CODE(KEYCODE_ENTER) /* Return */
1081   PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A */
1082   PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S */
1083
1084   PORT_START( "keyboard2" )
1085   PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D */
1086   PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F */
1087   PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G */
1088   PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H */
1089   PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J */
1090   PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K */
1091   PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L */
1092   PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) /* ; + */
1093   PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME(": *") PORT_CODE(KEYCODE_QUOTE) /* : * */
1094   PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \\ | */
1095   PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z */
1096   PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X */
1097   PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C */
1098   PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V */
1099   PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B */
1100   PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N */
1101   PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M */
1102   PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* , < */
1103   PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* . > */
1104   PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* / ? */
1105//??
1106   PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* Underscore (shifted only?) */
1107   PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Space")  PORT_CODE(KEYCODE_SPACE) /* Space */
1108   PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Home")  PORT_CODE(KEYCODE_HOME) /* Home */
1109   PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Delete")  PORT_CODE(KEYCODE_DEL) /* Del */
1110   PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Roll Up")  PORT_CODE(KEYCODE_PGUP) /* Roll Up */
1111   PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Roll Down")  PORT_CODE(KEYCODE_PGDN) /* Roll Down */
1112   PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("End")  PORT_CODE(KEYCODE_END) /* End */
1113   PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Cursor Left")  PORT_CODE(KEYCODE_LEFT) /* Left */
1114   PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Cursor Up")  PORT_CODE(KEYCODE_UP) /* Up */
1115   PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Cursor Right")  PORT_CODE(KEYCODE_RIGHT) /* Right */
1116   PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Cursor Down")  PORT_CODE(KEYCODE_DOWN) /* Down */
1117//   PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad CLR")  PORT_CODE(KEYCODE_NUMLOCK) /* CLR */
1118   PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("MENU")  PORT_CODE(KEYCODE_MENU) /* Menu = POP */
1119
1120   PORT_START( "keyboard3" )
1121   PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad /")  PORT_CODE(KEYCODE_SLASH_PAD) /* / (numpad) */
1122   PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad *")  PORT_CODE(KEYCODE_ASTERISK) /* * (numpad) */
1123   PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad -")  PORT_CODE(KEYCODE_MINUS_PAD) /* - (numpad) */
1124   PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 7")  PORT_CODE(KEYCODE_7_PAD) /* 7 (numpad) */
1125   PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 8")  PORT_CODE(KEYCODE_8_PAD) /* 8 (numpad) */
1126   PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 9")  PORT_CODE(KEYCODE_9_PAD) /* 9 (numpad) */
1127   PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad +")  PORT_CODE(KEYCODE_PLUS_PAD) /* + (numpad) */
1128   PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 4")  PORT_CODE(KEYCODE_4_PAD) /* 4 (numpad) */
1129   PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 5")  PORT_CODE(KEYCODE_5_PAD) /* 5 (numpad) */
1130   PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 6")  PORT_CODE(KEYCODE_6_PAD) /* 6 (numpad) */
1131   PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad =") /* = (numpad) */
1132   PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 1")  PORT_CODE(KEYCODE_1_PAD) /* 1 (numpad) */
1133   PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 2")  PORT_CODE(KEYCODE_2_PAD) /* 2 (numpad) */
1134   PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 3")  PORT_CODE(KEYCODE_3_PAD) /* 3 (numpad) */
1135   PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad Enter")  PORT_CODE(KEYCODE_ENTER_PAD) /* Enter (numpad) */
1136   PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad 0")  PORT_CODE(KEYCODE_0_PAD) /* 0 (numpad) */
1137   PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad ,") /* , (numpad) */
1138   PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Numpad .")  PORT_CODE(KEYCODE_DEL_PAD) /* 2 (numpad) */
1139
1140   PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F1")  PORT_CODE(KEYCODE_F1) /* F1 */
1141   PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F2")  PORT_CODE(KEYCODE_F2) /* F2 */
1142   PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F3")  PORT_CODE(KEYCODE_F3) /* F3 */
1143   PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F4")  PORT_CODE(KEYCODE_F4) /* F4 */
1144   PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F5")  PORT_CODE(KEYCODE_F5) /* F5 */
1145   PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F6")  PORT_CODE(KEYCODE_F6) /* F6 */
1146   PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F7")  PORT_CODE(KEYCODE_F7) /* F7 */
1147   PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F8")  PORT_CODE(KEYCODE_F8) /* F8 */
1148   PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F9")  PORT_CODE(KEYCODE_F9) /* F9 */
1149   PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10 */
1150   PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F11") PORT_CODE(KEYCODE_F11) /* F11 */
1151   PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("F12") PORT_CODE(KEYCODE_F12) /* F12 */
1152   PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Insert") PORT_CODE(KEYCODE_INSERT) /* Insert */
1153//   PORT_BIT( 0x80000000, 0x0000, IPT_UNUSED )
1154   PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("WIN_R")  PORT_CODE(KEYCODE_RWIN) /* Windows Right = Next Window */
1155
1156   PORT_START( "keyboard4" )
1157
1158   PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Caps")  PORT_CODE(KEYCODE_CAPSLOCK) /* Caps lock */
1159   PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Shift")  PORT_CODE(KEYCODE_LSHIFT) /* Shift */
1160   PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Ctrl")  PORT_CODE(KEYCODE_LCONTROL)  PORT_CODE(KEYCODE_RCONTROL) /* Ctrl */
1161   PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("ALT_L")  PORT_CODE(KEYCODE_LALT) /* ALT */
1162   PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("ALT_R")  PORT_CODE(KEYCODE_RALT) /* ALT GR */
1163   PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Shift")  PORT_CODE(KEYCODE_RSHIFT) /* Shift */
1164   PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD )  PORT_NAME("Num Lock")  PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock */
1165
1166   PORT_START("mouse1")  // mouse buttons
1167   PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1)
1168   PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON3)
1169   PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Center mouse button") PORT_CODE(MOUSECODE_BUTTON2)
1170
1171   PORT_START("mouse2")  // X-axis
1172   PORT_BIT( 0xfff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
1173
1174   PORT_START("mouse3")  // Y-axis
1175   PORT_BIT( 0xfff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
1176
1177INPUT_PORTS_END
src/mess/machine/apollo_kbd.h
r0r14540
1/*
2 * apollo_kbd.h
3 *
4 *  Created on: Dec 27, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#pragma once
13
14#ifndef __APOLLO_KBD_H__
15#define __APOLLO_KBD_H__
16
17#include "emu.h"
18
19#define TX_FIFO_SIZE 128
20
21//**************************************************************************
22//  DEVICE CONFIGURATION MACROS
23//**************************************************************************
24
25#define MCFG_APOLLO_KBD_ADD(_tag, _interface) \
26   MCFG_DEVICE_ADD(_tag, APOLLO_KBD, 0) \
27   apollo_kbd_device::static_set_interface(*device, _interface);
28
29INPUT_PORTS_EXTERN(apollo_kbd);
30
31//**************************************************************************
32// Keyboard READ/WRITE
33//**************************************************************************
34
35void apollo_kbd_getchar(device_t *device, UINT8 data);
36
37//**************************************************************************
38//  TYPE DEFINITIONS
39//**************************************************************************
40
41// ======================> apollo_kbd_interface
42
43struct apollo_kbd_interface
44{
45   write8_device_func apollo_kbd_putchar;
46   read8_device_func apollo_kbd_has_beeper;
47   read8_device_func apollo_kbd_is_german;
48};
49
50#define APOLLO_KBD_INTERFACE(name) const struct apollo_kbd_interface (name)
51
52// ======================> apollo_kbd_device
53
54class apollo_kbd_device :   public device_t, public apollo_kbd_interface
55{
56public:
57   // construction/destruction
58   apollo_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
59
60   // static configuration helpers
61   static void static_set_interface(device_t &device, const apollo_kbd_interface &interface);
62
63   void getchar(UINT8 data);
64
65private:
66   // device-level overrides
67   virtual void device_start();
68   virtual void device_reset();
69
70   const char *cpu_context() ;
71
72   int keyboard_is_german();
73
74   void set_mode(UINT16 mode);
75   void putchar(const UINT8 data);
76   void putdata(const UINT8 *data, int data_length);
77   void putstring(const char *data);
78
79   int push_scancode( UINT8 code, UINT8 repeat);
80   void scan_keyboard();
81   void poll_callback();
82   static TIMER_CALLBACK( static_poll_callback );
83
84   // the keyboard beeper
85   class beeper
86   {
87   public:
88      beeper();
89      void start(apollo_kbd_device *device);
90      void reset();
91      void off();
92      void on();
93   private:
94      int keyboard_has_beeper();
95      void beeper_callback();
96      static TIMER_CALLBACK( static_beeper_callback );
97
98      apollo_kbd_device *m_device; // pointer back to our device
99      device_t *m_beeper; // the keyboard beeper device
100      emu_timer * m_timer; // timer to clock data in
101   };
102
103   // the keyboard mouse
104   class mouse
105   {
106   public:
107      mouse();
108      void start(apollo_kbd_device *device);
109      void reset();
110      void read_mouse();
111   private:
112      apollo_kbd_device *m_device; // pointer back to our device
113
114      int m_last_b;  // previous mouse button values
115      int m_last_x;  // previous mouse x-axis value
116      int m_last_y;  // previous mouse y-axis value
117      int m_tx_pending;  // mouse data packet is pending
118   };
119
120    /* Transmitter fifo */
121   class tx_fifo
122   {
123   public:
124      tx_fifo();
125      void start(apollo_kbd_device *device);
126      void reset();
127      UINT8 getchar();
128      void putchar(UINT8 data);
129      int putdata(const UINT8 *data, int data_length);
130      void flush();
131
132   private:
133      void timer_callback();
134      static TIMER_CALLBACK( static_timer_callback );
135
136      apollo_kbd_device *m_device; // pointer back to our device
137
138      UINT16 m_baud_rate;
139
140      UINT16 fifo[TX_FIFO_SIZE];
141      UINT16 m_read_ptr;
142      UINT16 m_write_ptr;
143      UINT16 m_char_count;
144      UINT16 m_tx_pending;
145      emu_timer *m_timer;
146   };
147
148   // the keyboard tty
149   class keyboard_tty
150   {
151   public:
152      keyboard_tty();
153      void start(apollo_kbd_device *device);
154      void reset();
155      int isConnected();
156      int getchar();
157      void putchar(UINT8 data);
158   private:
159      apollo_kbd_device *m_device; // pointer back to our device
160      const char *m_tty_name;
161      int m_tty_fd; /* File descriptor of keyboard tty */
162      int m_connected;
163   };
164
165//   const apollo_kbd_interface &m_config;
166
167   beeper   m_beeper;
168   mouse   m_mouse;
169    tx_fifo m_tx_fifo;
170    keyboard_tty  m_keyboard_tty;
171
172   apollo_kbd_device *m_device; // pointer to myself (nasty: used for cpu_context)
173
174   /* Receiver */
175   UINT32 m_rx_message;
176   UINT16 m_loopback_mode;
177
178   emu_timer* m_timer;
179   UINT16 m_mode;
180   UINT16 m_delay;         // key press delay after initial press
181   UINT16 m_repeat;        // key press repeat rate
182   UINT16 m_last_pressed;  // last key pressed, for repeat key handling
183   int m_keytime[0x80];    // time until next key press (1 ms)
184   UINT8 m_keyon[0x80];    // is 1 if key is pressed
185
186   static UINT16 m_code_table[];
187};
188
189// device type definition
190extern const device_type APOLLO_KBD;
191
192#endif
src/mess/machine/apollo.c
r0r14540
1/*
2 * apollo.c - Apollo DS3500 CPU Board
3 *
4 *  Created on: Jan 20, 2011
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 * Contains:
11 * - apollo_config.c - APOLLO DS3500 configuration
12 * - apollo_csr.c - APOLLO DS3500 CPU Control and Status registers
13 * - apollo_dma.c - APOLLO DS3500 DMA controllers
14 * - apollo_pic.c - APOLLO DS3500 PIC8259 controllers
15 * - apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840
16 * - apollo_rtc.c - APOLLO DS3500 RTC MC146818
17 * - apollo_sio.c - APOLLO DS3500 SIO
18 * - apollo_sio2.c - APOLLO DS3500 SIO2
19 * - apollo_fdc.c - APOLLO DS3500 Floppy disk controller
20 *
21 * see also:
22 * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
23 * - http://www.freescale.com/files/32bit/doc/inactive/MC68681UM.pdf
24 *
25 */
26
27#include "includes/apollo.h"
28#include "machine/apollo_kbd.h"
29#include "machine/omti8621.h"
30#include "machine/sc499.h"
31#include "machine/3c505.h"
32
33#include "machine/6840ptm.h"
34#include "machine/68681.h"
35#include "machine/8237dma.h"
36#include "machine/mc146818.h"
37#include "machine/pic8259.h"
38
39#include "machine/pc_fdc.h"
40#include "formats/basicdsk.h"
41
42#include "cpu/m68000/m68000.h"
43//#include "cpu/m68000/m68kcpu.h"
44
45#include "emuopts.h"
46
47#include <fcntl.h>
48#include <unistd.h>
49
50#define APOLLO_IRQ_VECTOR 0xa0
51#define APOLLO_IRQ_PTM 0
52#define APOLLO_IRQ_SIO1 1
53#define APOLLO_IRQ_PIC_SLAVE 3
54#define APOLLO_IRQ_CTAPE 5
55#define APOLLO_IRQ_FDC 6
56#define APOLLO_IRQ_RTC 8 // DN3000 only
57#define APOLLO_IRQ_SIO2 8 // DN3500
58#define APOLLO_IRQ_ETH2 9
59#define APOLLO_IRQ_ETH1 10
60#define APOLLO_IRQ_DIAG 13
61#define APOLLO_IRQ_WIN1 14
62
63#define APOLLO_DMA_ETH1 6
64#define APOLLO_DMA_ETH2 3
65
66//##########################################################################
67// machine/apollo_config.c - APOLLO DS3500 configuration
68//##########################################################################
69
70#undef VERBOSE
71#define VERBOSE 0
72
73static UINT16 config = 0;
74
75/***************************************************************************
76 apollo_config - check configuration setting
77 ***************************************************************************/
78
79int apollo_config(int mask)
80{
81   return config & mask ? 1 : 0;
82}
83
84/***************************************************************************
85 Input Ports
86 ***************************************************************************/
87
88INPUT_PORTS_START( apollo_config )
89   PORT_START( "apollo_config" )
90      PORT_CONFNAME(APOLLO_CONF_SERVICE_MODE, 0x00, "Normal/Service" )
91      PORT_CONFSETTING(0x00, "Service" )
92      PORT_CONFSETTING(APOLLO_CONF_SERVICE_MODE, "Normal " )
93
94      PORT_CONFNAME(APOLLO_CONF_GERMAN_KBD, 0x00, "German Keyboard")
95      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
96      PORT_CONFSETTING(APOLLO_CONF_GERMAN_KBD, DEF_STR ( On ) )
97
98      PORT_CONFNAME(APOLLO_CONF_DATE_1990, 0x00, "20 Years Ago ...")
99      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
100      PORT_CONFSETTING(APOLLO_CONF_DATE_1990, DEF_STR ( On ) )
101
102      PORT_CONFNAME(APOLLO_CONF_NODE_ID, 0x00, "Node ID from Disk")
103      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
104      PORT_CONFSETTING(APOLLO_CONF_NODE_ID, DEF_STR ( On ) )
105
106      PORT_CONFNAME(APOLLO_CONF_IDLE_SLEEP, 0x00, "Idle Sleep")
107      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
108      PORT_CONFSETTING(APOLLO_CONF_IDLE_SLEEP, DEF_STR ( On ) )
109
110      PORT_CONFNAME(APOLLO_CONF_TRAP_TRACE, 0x00, "Trap Trace")
111      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
112      PORT_CONFSETTING(APOLLO_CONF_TRAP_TRACE, DEF_STR ( On ) )
113
114      PORT_CONFNAME(APOLLO_CONF_FPU_TRACE, 0x00, "FPU Trace")
115      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
116      PORT_CONFSETTING(APOLLO_CONF_FPU_TRACE, DEF_STR ( On ) )
117
118      PORT_CONFNAME(APOLLO_CONF_DISK_TRACE, 0x00, "Disk Trace")
119      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
120      PORT_CONFSETTING(APOLLO_CONF_DISK_TRACE, DEF_STR ( On ) )
121
122      PORT_CONFNAME(APOLLO_CONF_NET_TRACE, 0x00, "Network Trace")
123      PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
124      PORT_CONFSETTING(APOLLO_CONF_NET_TRACE, DEF_STR ( On ) )
125INPUT_PORTS_END
126
127/*-------------------------------------------------
128 device start callback
129 -------------------------------------------------*/
130
131static DEVICE_START(apollo_config)
132{
133   DLOG1(("start apollo_config"));
134}
135
136/*-------------------------------------------------
137 device reset callback
138 -------------------------------------------------*/
139
140static DEVICE_RESET(apollo_config)
141{
142   DLOG1(("reset apollo_config"));
143   // load configuration
144   config = input_port_read(device->machine(), "apollo_config");
145}
146
147/*-------------------------------------------------
148 device get info callback
149 -------------------------------------------------*/
150
151static DEVICE_GET_INFO(apollo_config)
152{
153   switch (state)
154   {
155      /* --- the following bits of info are returned as pointers to data or functions --- */
156      case DEVINFO_FCT_START:               info->start = DEVICE_START_NAME(apollo_config); break;
157      case DEVINFO_FCT_RESET:               info->reset = DEVICE_RESET_NAME(apollo_config);break;
158
159      /* --- the following bits of info are returned as NULL-terminated strings --- */
160      case DEVINFO_STR_NAME:               strcpy(info->s, "Apollo Configuration");break;
161      case DEVINFO_STR_FAMILY:            strcpy(info->s, "Configuration");      break;
162      case DEVINFO_STR_VERSION:            strcpy(info->s, "1.0");               break;
163      case DEVINFO_STR_SOURCE_FILE:         strcpy(info->s, __FILE__);            break;
164      case DEVINFO_STR_CREDITS:            strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
165   }
166}
167
168static DECLARE_LEGACY_DEVICE(APOLLO_CONF, apollo_config);
169
170DEFINE_LEGACY_DEVICE(APOLLO_CONF, apollo_config);
171
172//##########################################################################
173// machine/apollo_csr.c - APOLLO DS3500 CPU Control and Status registers
174//##########################################################################
175
176#undef VERBOSE
177#define VERBOSE 0
178
179#define CPU_CONTROL_REGISTER_ADDRESS 0x010100
180
181static UINT16 cpu_status_register = APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_SERVICE;
182static UINT16 cpu_control_register = 0x0000;
183
184/*-------------------------------------------------
185  apollo_csr_get/set_servicemode
186 -------------------------------------------------*/
187
188static int apollo_csr_get_servicemode()
189{
190
191   return cpu_status_register & APOLLO_CSR_SR_SERVICE ? 0 : 1;
192}
193
194static void apollo_csr_set_servicemode(int mode)
195{
196   apollo_csr_set_status_register(1, mode ? APOLLO_CSR_SR_SERVICE : 0);
197}
198
199UINT16 apollo_csr_get_control_register(void)
200{
201   return cpu_control_register;
202}
203
204UINT16 apollo_csr_get_status_register(void)
205{
206   return cpu_status_register;
207}
208
209void apollo_csr_set_status_register(UINT16 mask, UINT16 data)
210{
211   UINT16 new_value = (cpu_status_register & ~mask) | (data & mask);
212
213   if (new_value != cpu_status_register)
214   {
215      cpu_status_register = new_value;
216      LOG1(("#### setting CPU Status Register with data=%04x & %04x to %04x", data, mask, cpu_status_register));
217   }
218}
219
220/*-------------------------------------------------
221 DN3000/DN3500 CPU Status Register at 0x8000/0x10000
222 -------------------------------------------------*/
223
224WRITE16_HANDLER( apollo_csr_status_register_w ) {
225   // To clear bus timeouts or parity conditions from status register,
226   // write to the status register. This register is readonly.
227   // in DN3500 bit 15 is always set (undocumented !?)
228   cpu_status_register &= (APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_FP_TRAP | APOLLO_CSR_SR_SERVICE);
229   SLOG1(("writing CPU Status Register at offset %X = %04x & %04x (%04x)", offset, data, mem_mask, cpu_status_register));
230}
231
232READ16_HANDLER( apollo_csr_status_register_r ) {
233   SLOG2(("reading CPU Status Register at offset %X = %04x & %04x", offset, cpu_status_register, mem_mask));
234   return cpu_status_register & mem_mask;
235}
236
237/*-------------------------------------------------
238 DN3000/DN3500 CPU Control Register at 0x8100/0x10100
239 -------------------------------------------------*/
240
241WRITE16_HANDLER( apollo_csr_control_register_w )
242{
243   int leds;
244
245   if ((mem_mask & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
246   {
247      // FPU Trap enable not involved
248   }
249   else if (((data ^ cpu_control_register) & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
250   {
251      // FPU Trap enable remains unchanged
252   }
253   else if ((data & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
254   {
255      // enable FPU (i.e. FPU opcodes in CPU)
256//      apollo_set_cpu_has_fpu(&space->device(), 1);
257   }
258   else
259   {
260      // disable FPU (i.e. FPU opcodes in CPU)
261//      apollo_set_cpu_has_fpu(&space->device(), 0);
262
263      if (!apollo_is_dn3000())
264      {
265         // hack: set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test
266         // APOLLO_CSR_SR_FP_TRAP in status register should be set by next fmove instruction
267         // cpu_status_register |= APOLLO_CSR_SR_FP_TRAP;
268      }
269   }
270
271   cpu_control_register = (cpu_control_register & ~mem_mask) | (data & mem_mask);
272
273   output_set_value("internal_led_1", (cpu_control_register >> 15) & 1);
274   output_set_value("internal_led_2", (cpu_control_register >> 14) & 1);
275   output_set_value("internal_led_3", (cpu_control_register >> 13) & 1);
276   output_set_value("internal_led_4", (cpu_control_register >> 12) & 1);
277   output_set_value("external_led_a", (cpu_control_register >> 11) & 1);
278   output_set_value("external_led_b", (cpu_control_register >> 10) & 1);
279   output_set_value("external_led_c", (cpu_control_register >> 9) & 1);
280   output_set_value("external_led_d", (cpu_control_register >> 8) & 1);
281
282   leds = ((cpu_control_register >> 8) & 0xff) ^ 0xff;
283
284   SLOG1(("writing CPU Control Register at offset %X = %04x & %04x (%04x - %d%d%d%d %d%d%d%d)",
285               offset, data, mem_mask, cpu_control_register,
286               (leds >> 3) & 1,(leds >> 2) & 1, (leds >> 1) & 1, (leds >> 0) & 1,
287               (leds >> 7) & 1,(leds >> 6) & 1, (leds >> 5) & 1, (leds >> 4) & 1 ));
288
289   if (data & APOLLO_CSR_CR_RESET_DEVICES)
290   {
291      // FIXME: reset all devices (but not SIO lines!)
292   }
293}
294
295READ16_HANDLER( apollo_csr_control_register_r )
296{
297   SLOG1(("reading CPU Control Register at offset %X = %04x & %04x", offset, cpu_control_register, mem_mask));
298   return cpu_control_register & mem_mask;
299}
300
301//##########################################################################
302// machine/apollo_dma.c - APOLLO DS3500 DMA
303//##########################################################################
304
305#undef VERBOSE
306#define VERBOSE 0
307
308static UINT16 address_translation_map[0x400];
309
310static UINT16 dma_page_register[16] =
311   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
312
313static const UINT8 channel2page_register[8] = { 7, 3, 1, 2, 0, 11, 9, 10};
314
315static UINT8 dn3000_dma_channel1 = 1; // 1 = memory/ctape, 2 = floppy dma channel
316static UINT8 dn3000_dma_channel2 = 5; // 5 = memory dma channel
317
318INLINE device_t *get_device_dma8237_1(device_t *device) {
319   return device->machine().driver_data<apollo_state>()->dma8237_1;
320}
321
322INLINE device_t *get_device_dma8237_2(device_t *device) {
323   return device->machine().driver_data<apollo_state>()->dma8237_2;
324}
325
326static void apollo_dma_fdc_drq(device_t *device, int state) {
327   DLOG2(("apollo_dma_fdc_drq: state=%x", state));
328   i8237_dreq2_w(get_device_dma8237_1(device), state);
329}
330
331static void apollo_dma_ctape_drq(device_t *device, int state) {
332   DLOG1(("apollo_dma_ctape_drq: state=%x", state));
333   i8237_dreq1_w(get_device_dma8237_1(device), state);
334}
335
336/*-------------------------------------------------
337 DN3000/DN3500 DMA Controller 1 at 0x9000/0x10c00
338 -------------------------------------------------*/
339
340WRITE8_HANDLER(apollo_dma_1_w ) {
341   SLOG1(("apollo_dma_1_w: writing DMA Controller 1 at offset %02x = %02x", offset, data));
342   i8237_w(get_device_dma8237_1(&space->device()), offset, data);
343}
344
345READ8_HANDLER( apollo_dma_1_r ) {
346   UINT8 data = i8237_r(get_device_dma8237_1(&space->device()), offset);
347   SLOG1(("apollo_dma_1_r: reading DMA Controller 1 at offset %02x = %02x", offset, data));
348   return data;
349}
350
351/*-------------------------------------------------
352 DN3000/DN3500 DMA Controller 2 at 0x9100/0x10d00
353 -------------------------------------------------*/
354
355WRITE8_HANDLER(apollo_dma_2_w ) {
356   SLOG1(("apollo_dma_2_w: writing DMA Controller 2 at offset %02x = %02x", offset/2, data));
357   i8237_w(get_device_dma8237_2(&space->device()), offset / 2, data);
358}
359
360READ8_HANDLER( apollo_dma_2_r ) {
361   UINT8 data = i8237_r(get_device_dma8237_2(&space->device()), offset / 2);
362   SLOG1(("apollo_dma_2_r: reading DMA Controller 2 at offset %02x = %02x", offset/2, data));
363   return data;
364}
365
366/***************************************************************************
367 DN3000 DMA Page Register at 0x9200
368 ***************************************************************************/
369
370WRITE8_HANDLER(apollo_dma_page_register_w ) {
371   dma_page_register[offset & 0x0f] = data;
372   SLOG1(("writing DMA Page Register at offset %02x = %02x", offset,  data));
373}
374
375READ8_HANDLER( apollo_dma_page_register_r ) {
376   UINT8 data = dma_page_register[offset & 0x0f];
377   SLOG1(("reading DMA Page Register at offset %02x = %02x", offset, data));
378   return data;
379}
380
381/*-------------------------------------------------
382 DN3500 Address Translation Map at 0x017000
383 -------------------------------------------------*/
384
385WRITE16_HANDLER(apollo_address_translation_map_w ) {
386   address_translation_map[offset & 0x3ff] = data;
387   SLOG2(("writing Address Translation Map at offset %02x = %04x", offset, data));
388}
389
390READ16_HANDLER( apollo_address_translation_map_r ) {
391   UINT16 data = address_translation_map[offset & 0x3ff];
392   SLOG2(("reading Address Translation Map at offset %02x = %04x", offset, data));
393   return data;
394}
395
396static READ8_HANDLER( apollo_dma_read_byte ) {
397   UINT8 data;
398   offs_t page_offset;
399
400   if (apollo_is_dn3000()) {
401      page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16;
402   } else {
403      // FIXME: address_translation_map[0x200] ?
404      page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00;
405      offset &= 0x3ff;
406   }
407
408   data = space->read_byte(page_offset + offset);
409
410   if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff)
411   {
412      SLOG1(("dma read byte at offset %x+%03x = %02x", page_offset, offset, data));
413   }
414
415   return data;
416}
417
418static WRITE8_HANDLER( apollo_dma_write_byte ) {
419   offs_t page_offset;
420   if (apollo_is_dn3000()) {
421      page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16;
422   } else {
423      // FIXME: address_translation_map[0x200] ?
424      page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00;
425      offset &= 0x3ff;
426   }
427    // FIXME: MSB not available, writing only LSB
428   space->write_byte(page_offset + offset, data);
429
430   if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff)
431   {
432      SLOG1(("dma write byte at offset %x+%03x = %02x", page_offset, offset , data));
433   }
434}
435
436static READ8_HANDLER( apollo_dma_read_word ) {
437   UINT16 data;
438   offs_t page_offset;
439
440   if (apollo_is_dn3000()) {
441      page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16;
442      page_offset &= 0xfffe0000;
443      offset <<= 1;
444   } else {
445      // FIXME: address_translation_map[0x200] ?
446      page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) << 10) & 0x7FFFFC00;
447      offset = (offset << 1) & 0x3ff;
448   }
449
450   data = space->read_byte(page_offset + offset);
451
452   SLOG1(("dma read word at offset %x+%03x = %04x", page_offset, offset , data));
453    // FIXME: MSB will get lost
454   return data;
455}
456
457static WRITE8_HANDLER( apollo_dma_write_word ) {
458   offs_t page_offset;
459
460   SLOG1(("dma write word at offset %x = %02x", offset, data));
461
462   if (apollo_is_dn3000()) {
463      page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16;
464      page_offset &= 0xfffe0000;
465      offset <<= 1;
466   } else {
467      // FIXME: address_translation_map[0x200] ?
468      page_offset
469            = (((offs_t) address_translation_map[0x200 + (offset >> 9)])
470                  << 10) & 0x7FFFFC00;
471      offset = (offset << 1) & 0x3ff;
472   }
473
474   space->write_byte(page_offset + offset, data);
475   SLOG1(("dma write word at offset %x+%03x = %02x", page_offset, offset, data));
476}
477
478static READ8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_r ) {
479
480   UINT8 data = sc499_dack_r(&device->machine());
481   DLOG2(("dma ctape dack read %02x",data));
482
483   // hack for DN3000: select appropriate DMA channel No.
484   dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel
485
486   return data;
487}
488
489static WRITE8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_w ) {
490   DLOG2(("dma ctape dack write %02x", data));
491   sc499_dack_w(&device->machine(), data);
492
493   // hack for DN3000: select appropriate DMA channel No.
494   // Note: too late for this byte, but next bytes will be ok
495   dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel
496}
497
498static READ8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_r ) {
499   UINT8 data = pc_fdc_dack_r(device->machine());
500   //   DLOG2(("dma fdc dack read %02x",data));
501
502   // hack for DN3000: select appropriate DMA channel No.
503   dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel
504
505   return data;
506}
507
508static WRITE8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_w ) {
509   // DLOG2(("dma fdc dack write %02x", data));
510   pc_fdc_dack_w(device->machine(), data);
511
512   // hack for DN3000: select appropriate DMA channel No.
513   // Note: too late for this byte, but next bytes will be ok
514   dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel
515}
516
517static READ8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_r ) {
518   UINT8 data = 0xff; // omti8621_dack_r(device->machine);
519   DLOG1(("dma wdc dack read %02x (not used, not emulated!)",data));
520   return data;
521}
522
523static WRITE8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_w ) {
524   DLOG1(("dma wdc dack write %02x (not used, not emulated!)", data));
525//   omti8621_dack_w(device->machine, data);
526}
527
528static WRITE_LINE_DEVICE_HANDLER( apollo_dma8237_out_eop ) {
529   DLOG1(("dma out eop state %02x", state));
530   pc_fdc_set_tc_state(device->machine(), state ? 0 : 1);
531   sc499_set_tc_state(&device->machine(), state);
532}
533
534static WRITE_LINE_DEVICE_HANDLER( apollo_dma_1_hrq_changed ) {
535   // DLOG2(("dma 1 hrq changed state %02x", state));
536   i8237_dreq0_w(get_device_dma8237_2(device), state);
537
538   /* Assert HLDA */
539   i8237_hlda_w(device, state);
540
541   // cascade mode?
542   // i8237_hlda_w(get_device_dma8237_2(device), state);
543}
544
545static WRITE_LINE_DEVICE_HANDLER( apollo_dma_2_hrq_changed ) {
546   // DLOG2(("dma 2 hrq changed state %02x", state));
547   cputag_set_input_line(device->machine(), MAINCPU, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
548
549   /* Assert HLDA */
550   i8237_hlda_w(device, state);
551}
552
553static I8237_INTERFACE( apollo_dma8237_1_config )
554{
555   DEVCB_LINE(apollo_dma_1_hrq_changed),
556   DEVCB_LINE(apollo_dma8237_out_eop),
557   DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_read_byte),
558   DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_write_byte),
559   {   DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_r), DEVCB_HANDLER(apollo_dma8237_fdc_dack_r), DEVCB_NULL},
560   {   DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_w), DEVCB_HANDLER(apollo_dma8237_fdc_dack_w), DEVCB_NULL},
561   {   DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL}
562};
563
564static I8237_INTERFACE( apollo_dma8237_2_config )
565{
566   DEVCB_LINE(apollo_dma_2_hrq_changed),
567   DEVCB_NULL,
568   DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_read_word),
569   DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_write_word),
570   {   DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_r)},
571   {   DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_w)},
572   {   DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL}
573};
574
575//##########################################################################
576// machine/apollo_pic.c - APOLLO DS3500 PIC 8259 controllers
577//##########################################################################
578
579#undef VERBOSE
580#define VERBOSE 0
581
582INLINE device_t *get_pic8259_master(device_t *device) {
583   return device->machine().driver_data<apollo_state>()->pic8259_master;
584}
585
586INLINE device_t *get_pic8259_slave(device_t *device) {
587   return device->machine().driver_data<apollo_state>()->pic8259_slave;
588}
589
590/*-------------------------------------------------
591 Interrupt Controller 8259 PIC #1 at 0x9400/0x11000
592 -------------------------------------------------*/
593
594WRITE8_DEVICE_HANDLER(apollo_pic8259_master_w ) {
595   DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data));
596   pic8259_w(device, offset, data);
597}
598
599READ8_DEVICE_HANDLER( apollo_pic8259_master_r ) {
600   UINT8 data = pic8259_r(device, offset);
601   DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data));
602   return data;
603}
604
605/*-------------------------------------------------
606 Interrupt Controller 8259 PIC #2 at 0x9500/0x11100
607 -------------------------------------------------*/
608
609WRITE8_DEVICE_HANDLER(apollo_pic8259_slave_w ) {
610   DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data));
611   pic8259_w(device, offset, data);
612}
613
614READ8_DEVICE_HANDLER( apollo_pic8259_slave_r ) {
615   UINT8 data = pic8259_r(device, offset);
616   DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data));
617   return data;
618}
619
620static void apollo_pic_set_irq_line(device_t *device, int irq, int state) {
621   // don't log PTM interrupts
622   if (irq != APOLLO_IRQ_PTM) {
623      DLOG1(("apollo_pic_set_irq_line: irq=%d state=%d", irq, state));
624   }
625
626   switch (irq) {
627   case 0: pic8259_ir0_w(get_pic8259_master(device), state); break;
628   case 1: pic8259_ir1_w(get_pic8259_master(device), state); break;
629   case 2: pic8259_ir2_w(get_pic8259_master(device), state); break;
630   case 3: pic8259_ir3_w(get_pic8259_master(device), state); break;
631   case 4: pic8259_ir4_w(get_pic8259_master(device), state); break;
632   case 5: pic8259_ir5_w(get_pic8259_master(device), state); break;
633   case 6: pic8259_ir6_w(get_pic8259_master(device), state); break;
634   case 7: pic8259_ir7_w(get_pic8259_master(device), state); break;
635
636   case 8: pic8259_ir0_w(get_pic8259_slave(device), state); break;
637   case 9: pic8259_ir1_w(get_pic8259_slave(device), state); break;
638   case 10: pic8259_ir2_w(get_pic8259_slave(device), state); break;
639   case 11: pic8259_ir3_w(get_pic8259_slave(device), state); break;
640   case 12: pic8259_ir4_w(get_pic8259_slave(device), state); break;
641   case 13: pic8259_ir5_w(get_pic8259_slave(device), state); break;
642   case 14: pic8259_ir6_w(get_pic8259_slave(device), state); break;
643   case 15: pic8259_ir7_w(get_pic8259_slave(device), state); break;
644   }
645}
646
647IRQ_CALLBACK(apollo_pic_acknowledge) {
648   UINT32 vector = pic8259_acknowledge(get_pic8259_master(device));
649   if ((vector & 0x0f) == APOLLO_IRQ_PIC_SLAVE) {
650      vector = pic8259_acknowledge(get_pic8259_slave(device));
651   }
652
653   // don't log ptm interrupts
654   if (vector != APOLLO_IRQ_VECTOR+APOLLO_IRQ_PTM) {
655      DLOG1(("apollo_pic_acknowledge: irq=%d vector=%x", vector & 0x0f, vector));
656   }
657
658   if (apollo_is_dn3000()) {
659      apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, 0);
660   } else {
661      // clear bit Interrupt Pending in Cache Status Register
662      apollo_set_cache_status_register(0x10, 0x00);
663   }
664   return vector;
665}
666
667/*************************************************************
668 * pic8259 configuration
669 *************************************************************/
670
671static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_master_set_int_line ) {
672   static int interrupt_line = -1;
673   if (state != interrupt_line) {
674      DLOG1(("apollo_pic8259_master_set_int_line: %x", state));
675   }
676   interrupt_line = state;
677
678   if (apollo_is_dn3000()) {
679      apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING,
680            state ? APOLLO_CSR_SR_INTERRUPT_PENDING : 0);
681   } else {
682      // set bit Interrupt Pending in Cache Status Register
683      apollo_set_cache_status_register(0x10, state ? 0x10 : 0x00);
684   }
685
686   cputag_set_input_line_and_vector(device->machine(), MAINCPU, M68K_IRQ_6,state ? ASSERT_LINE : CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR);
687}
688
689static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_slave_set_int_line ) {
690   static int interrupt_line = -1;
691   if (state != interrupt_line) {
692      DLOG1(("apollo_pic8259_slave_set_int_line: %x", state));
693      interrupt_line = state;
694      apollo_pic_set_irq_line(device, 3, state);
695   }
696}
697
698static const struct pic8259_interface apollo_pic8259_master_config = {
699      DEVCB_LINE(apollo_pic8259_master_set_int_line) };
700
701static const struct pic8259_interface apollo_pic8259_slave_config = {
702      DEVCB_LINE(apollo_pic8259_slave_set_int_line) };
703
704//##########################################################################
705// machine/apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840
706//##########################################################################
707
708#undef VERBOSE
709#define VERBOSE 0
710
711static emu_timer* ptm_timer;
712static UINT32 ptm_counter = 0;
713
714static TIMER_CALLBACK(apollo_ptm_timer_callback)
715{
716   ptm6840_device *device = downcast<ptm6840_device *>((device_t *) ptr);
717
718   ptm_counter++;
719   device->set_c1( 1);
720   device->set_c1( 0);
721   device->set_c2(ptm_counter & 1);
722
723   if ((ptm_counter & 1) == 0)
724   {
725      device->set_c3((ptm_counter >> 1) & 1);
726   }
727
728   if (ptm_counter % 250000 == 0)
729   {
730      DLOG2(("apollo_ptm_timer_callback: %d", ptm_counter / 250000));
731   }
732}
733
734static WRITE_LINE_DEVICE_HANDLER( apollo_ptm_irq_function ) {
735   DLOG1(("apollo_ptm_irq_function: state=%d", state ));
736
737//   ptm6840_device *ptm = device->machine().device<ptm6840_device>(APOLLO_PTM_TAG);
738
739   apollo_pic_set_irq_line(device, APOLLO_IRQ_PTM, state);
740}
741
742//   Timer 1's input is a 250-kHz (4-microsecond period) signal.
743//   Timer 2's input is a 125-kHz (8-microsecond period) signal.
744//   Timer 3's input is a 62.5-kHz (16-microsecond period) signal.
745//   The Timer 3 input may be prescaled to make the effective input signal have a 128-microsecond period.
746
747static const ptm6840_interface apollo_ptm_config = {
748      0,
749      { 250000, 125000, 62500 },
750      { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
751      DEVCB_LINE(apollo_ptm_irq_function)
752};
753
754static DEVICE_START( apollo_ptm )
755{
756   DLOG1(("start apollo_ptm"));
757   // allocate and start ptm timer
758   ptm_timer = device->machine().scheduler().timer_alloc(FUNC(apollo_ptm_timer_callback), device);
759   ptm_timer->adjust( attotime::zero, 0, attotime::from_usec(4));
760}
761
762static DEVICE_RESET( apollo_ptm )
763{
764   DLOG1(("reset apollo_ptm"));
765   device->reset();
766}
767
768READ8_DEVICE_HANDLER(apollo_ptm_r) {
769   UINT8 data =downcast<ptm6840_device *>((device_t *) device)->read(offset / 2);
770
771   // prevent excessive logging
772   static UINT8 previous = 255;
773   if (offset / 2 != 1 || data != previous) {
774      DLOG1(("apollo_ptm_read reg %x returned %02x", offset/2, data ));
775      if (offset / 2 == 1) {
776         previous = data;
777      }
778   }
779   return data;
780}
781
782WRITE8_DEVICE_HANDLER(apollo_ptm_w) {
783   DLOG1(("apollo_ptm_write reg %x with %02x", offset/2, data ));
784   downcast<ptm6840_device *>((device_t *) device)->write(offset / 2, data);
785}
786
787//##########################################################################
788// machine/apollo_rtc.c - APOLLO DS3500 RTC MC146818
789//##########################################################################
790
791#undef VERBOSE
792#define VERBOSE 0
793
794/***************************************************************************
795 DN3000/DN3500 Realtime Calendar MC146818 at 0x8900/0x10900
796 ***************************************************************************/
797
798static DEVICE_RESET( apollo_rtc ) {
799   address_space *space = device->machine().device(MAINCPU)->memory().space(AS_PROGRAM);
800   UINT8 year = apollo_rtc_r(space, 9);
801
802   // change year according to configuration settings
803   if (year < 20 && apollo_config(APOLLO_CONF_DATE_1990))
804   {
805      year+=80;
806      apollo_rtc_w(space, 9, year);
807   }
808   else if (year >= 80 && !apollo_config(APOLLO_CONF_DATE_1990))
809   {
810      year -=80;
811      apollo_rtc_w(space, 9, year);
812   }
813
814   SLOG1(("reset apollo_rtc year=%d", year));
815}
816
817WRITE8_HANDLER( apollo_rtc_w )
818{
819   mc146818_device *rtc = space->machine().device<mc146818_device> (APOLLO_RTC_TAG);
820   rtc->write(*space, 0, offset);
821   rtc->write(*space, 1, data);
822   if (offset >= 0x0b && offset <= 0x0c)
823   {
824      SLOG2(("writing MC146818 at offset %02x = %02x", offset, data));
825   }
826}
827
828READ8_HANDLER( apollo_rtc_r )
829{
830   UINT8 data;
831   mc146818_device *rtc = space->machine().device<mc146818_device> (APOLLO_RTC_TAG);
832   rtc->write(*space, 0, offset);
833   data = rtc->read(*space, 1);
834   if (offset >= 0x0b && offset <= 0x0c)
835   {
836      SLOG2(("reading MC146818 at offset %02x = %02x", offset, data));
837   }
838   return data;
839}
840
841static TIMER_CALLBACK( apollo_rtc_timer )
842{
843   address_space *space = machine.device(MAINCPU)->memory().space(AS_PROGRAM);
844
845   // FIXME: reading register 0x0c will clear all interrupt flags
846   if ((apollo_rtc_r(space, 0x0c) & 0x80))
847   {
848      SLOG2(("apollo_rtc_timer - set_irq_line %d", APOLLO_IRQ_RTC));
849      apollo_pic_set_irq_line(&space->device(), APOLLO_IRQ_RTC, 1);
850   }
851}
852
853//##########################################################################
854// machine/apollo_sio.c - APOLLO DS3500 SIO
855//##########################################################################
856
857#undef VERBOSE
858#define VERBOSE 0
859
860#define SIO_SLEEP_DELAY_TIME 30000 // ms
861
862static int isInitialized = 0;
863static int input_from_stdin = 0;
864
865static UINT8 sio_input_data = 0xff;
866static UINT8 sio_output_data = 0xff;
867
868static emu_timer *kbd_timer;
869static int sleep_time = 0;
870
871static int sio_irq_line = 0;
872
873static UINT8 sio_csrb = 0;
874
875/*-------------------------------------------------
876 sio_sleep - sleep to reduce the CPU usage
877 -------------------------------------------------*/
878
879// we reduce the CPU usage, if SRB is being polled for input
880// but only as long as the transmitter is empty and ready
881// and the initial delay time has passed w/o IO
882
883static void sio_sleep(int delay) {
884   if (!apollo_config(APOLLO_CONF_IDLE_SLEEP)) {
885      // nothing to do; sleeping is not enabled
886   } else if (delay <= 0) {
887      //reset the sleep delay time
888      if (sleep_time > 0) {
889         LOG2(("sio_sleep: sleeping stopped"))
890         sleep_time = 0;
891      }
892   } else if (sleep_time < delay) {
893      // sleep delay pending (i.e. don't sleep)
894      sleep_time++;
895   } else {
896      if (sleep_time == delay) {
897         LOG2(("sio_sleep: sleeping started after %d ms",sleep_time));
898         sleep_time++;
899      }
900      // Note: ticks_per_second/100 will sleep for 6 ms (= 4-10 ms)
901      osd_sleep(osd_ticks_per_second() / 50);
902   }
903}
904
905/*-------------------------------------------------
906 apollo_sio_rx_data - get character from keyboard/stdin
907 -------------------------------------------------*/
908
909void apollo_sio_rx_data(device_t* device, int ch, UINT8 data) {
910   // omit logging for channel 1
911   if (ch == 0) {
912      DLOG1(("apollo_sio_rx_data ch=%d <- data=%02x", ch, data ));
913   }
914
915   if (ch == 1 && !isInitialized && data == '\r' && apollo_csr_get_servicemode()) {
916      // force baudrate recognition
917      data = 0xff;
918      isInitialized = 1;
919   }
920
921   duart68681_rx_data(device, ch, data);
922}
923
924/*-------------------------------------------------
925 apollo_sio_tx_data - put character to display/stdout
926 -------------------------------------------------*/
927
928static void apollo_sio_tx_data(device_t *device, int channel, UINT8 data) {
929   if (channel == 0) {
930      DLOG1(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data ));
931      device_t *keyboard = device->machine().device( APOLLO_KBD_TAG );
932      if (keyboard != NULL) {
933         apollo_kbd_getchar(keyboard, data);
934      }
935   } else if (channel == 1) {
936      DLOG2(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data ));
937
938      if (data != '\r') {
939         // output data to stdout
940         putchar(data);
941         fflush(stdout);
942
943         if (apollo_is_dsp3x00()) {
944            // output data to terminal emulator
945            apollo_terminal_write(data);
946         }
947      }
948   }
949}
950
951/*-------------------------------------------------
952 sio configuration
953 -------------------------------------------------*/
954
955static void sio_irq_handler(device_t *device, UINT8 vector) {
956   DLOG2(("sio_irq_handler: vector=%02x", vector ));
957   apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 1);
958   sio_irq_line = 1;
959}
960
961static UINT8 sio_input(device_t *device) {
962   // necessary for DN3000?
963   // sio_input_data = sio_input_data ? 0 : 0x0f;
964   DLOG2(("reading 2681 input: %02x", sio_input_data ));
965   return sio_input_data;
966}
967
968static void sio_output(device_t *device, UINT8 data) {
969   DLOG1(("writing 2681 output: %02x", data ));
970
971   if ((data & 0x80) != (sio_output_data & 0x80)) {
972      apollo_pic_set_irq_line(device, APOLLO_IRQ_DIAG, (data & 0x80) ? 1 : 0);
973      sio_output_data = data;
974   }
975}
976
977const duart68681_config apollo_sio_config = {
978      sio_irq_handler,
979      apollo_sio_tx_data,
980      sio_input,
981      sio_output
982};
983
984/*-------------------------------------------------
985 DN3000/DS3500 SIO at 0x8400/0x10400
986 -------------------------------------------------*/
987
988READ8_DEVICE_HANDLER(apollo_sio_r) {
989   static int last_read8_offset[2] = { -1, -1 };
990   static int last_read8_value[2] = { -1, -1 };
991
992   static const char * const duart68681_reg_read_names[0x10] = { "MRA", "SRA",
993         "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB",
994         "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter",
995         "Stop Counter" };
996
997   int data = duart68681_r(device, offset / 2);
998
999   if (sio_irq_line) {
1000      apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0);
1001      sio_irq_line = 0;
1002   }
1003
1004   switch (offset / 2) {
1005   case 0x0b: /* RHRB */
1006      if (data == 0x0d && sio_csrb == 0x77) {
1007         // special for MD command SK (Select keyboard) with baudrate set to 2000
1008         data = 0xff;
1009      }
1010      break;
1011   }
1012
1013   // omit logging if sio is being polled from the boot rom
1014   if ((offset != last_read8_offset[1] || data != last_read8_value[1])
1015         && (offset != last_read8_offset[0] || data != last_read8_value[0])) {
1016      last_read8_offset[0] = last_read8_offset[1];
1017      last_read8_value[0] = last_read8_value[1];
1018      last_read8_offset[1] = offset;
1019      last_read8_value[1] = data;
1020      DLOG2(("reading 2681 reg %x (%s) returned %02x",
1021            offset, duart68681_reg_read_names[offset/2], data ));
1022   }
1023
1024   return data;
1025}
1026
1027WRITE8_DEVICE_HANDLER(apollo_sio_w)
1028{
1029   static const char * const duart68681_reg_write_names[0x10] = { "MRA",
1030         "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB",
1031         "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" };
1032
1033   if (sio_irq_line) {
1034      apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0);
1035      sio_irq_line = 0;
1036   }
1037
1038   // don't log THRB
1039   if (offset != 0x17) {
1040      DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data ));
1041   }
1042
1043   switch (offset / 2) {
1044   case 0x09: /* CSRB */
1045      // remember CSRB to handle MD command SK on DSP3x00
1046      sio_csrb = data;
1047      break;
1048   case 0x0b: /* THRB */
1049      // stop sleeping
1050      sio_sleep(0);
1051      break;
1052   case 0x0d: /* OPCR */
1053      if ((data & 0x0c) == 0x04) {
1054         // Unhandled OPCR value; used for RAM refresh circuit
1055         // ignore value; omit error message
1056         data &= ~0x0c;
1057      }
1058      break;
1059   }
1060   duart68681_w(device, offset / 2, data);
1061}
1062
1063/*-------------------------------------------------
1064 kbd tty timer callback
1065 -------------------------------------------------*/
1066
1067static TIMER_CALLBACK(kbd_timer_callback)
1068{
1069
1070#if defined(__linux__)
1071   device_t *device = (device_t *) ptr;
1072   UINT8 data;
1073
1074#define SRA 0x01
1075#define SRB 0x09
1076
1077   if (!(duart68681_r(device, SRB) & 0x02))
1078   {
1079      // Channel B FIFO not yet full (STATUS_FIFO_FULL)
1080      if (read(STDIN_FILENO, &data, 1) == 1)
1081      {
1082         apollo_sio_rx_data(device, 1, data == '\n' ? '\r' : data);
1083         input_from_stdin = 1;
1084         // stop sleeping to reduce CPU usage
1085         sio_sleep(0);
1086      }
1087      else if (input_from_stdin && (duart68681_r(device, SRB) & 0x0c) == 0x0c)
1088      {
1089         // we reduce the CPU usage, if SRB is being polled for input
1090         // but only as long as the transmitter is empty and ready
1091         // and the initial delay time has has passed
1092         sio_sleep(SIO_SLEEP_DELAY_TIME);
1093      }
1094   }
1095#endif
1096
1097   // The counter/timer on the SIO chip is used for the refresh count.
1098   // This is set up in the timer mode to   produce a square wave output on output OP3.
1099   // The period of the output is 15 microseconds.
1100
1101   // toggle memory refresh counter
1102   sio_input_data ^= 0x01;
1103}
1104
1105/*-------------------------------------------------
1106 device start callback
1107 -------------------------------------------------*/
1108
1109static DEVICE_START(apollo_sio)
1110{
1111   kbd_timer = device->machine().scheduler().timer_alloc(FUNC(kbd_timer_callback), device);
1112}
1113
1114/*-------------------------------------------------
1115 device reset callback
1116 -------------------------------------------------*/
1117
1118static DEVICE_RESET(apollo_sio)
1119{
1120   DLOG1(("reset apollo_sio"));
1121
1122   isInitialized = 0;
1123   input_from_stdin = 0;
1124   sleep_time = 0;
1125   sio_input_data = apollo_get_ram_config_byte();
1126   sio_output_data = 0xff;
1127
1128#if defined(__linux__)
1129   // FIXME: unavailable in mingw
1130   // set stdin to nonblocking to allow polling in sio_poll_rxb
1131   fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
1132#endif
1133
1134   // start the keyboard timer
1135   kbd_timer->adjust( attotime::zero, 0, attotime::from_msec(1));
1136}
1137
1138//##########################################################################
1139// machine/apollo_sio2.c - APOLLO DS3500 SIO2
1140//##########################################################################
1141
1142#undef VERBOSE
1143#define VERBOSE 0
1144
1145/*-------------------------------------------------
1146 sio2 configuration (DN3500 only)
1147 -------------------------------------------------*/
1148
1149static void sio2_irq_handler(device_t *device, UINT8 vector)
1150{
1151   DLOG1(("sio2_irq_handler: vector=%02x", vector ));
1152   apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 1);
1153}
1154
1155static void sio2_tx_data(device_t *device, int channel, UINT8 data)
1156{
1157   DLOG1(("apollo_sio2_tx_data ch=%d -> data=%02x", channel, data ));
1158}
1159
1160static UINT8 sio2_input(device_t *device)
1161{
1162   UINT8 data = 0x00;
1163   DLOG1(("reading 2681 input: %02x", data ));
1164   return data;
1165}
1166
1167static void sio2_output(device_t *device, UINT8 data)
1168{
1169   DLOG1(("writing 2681 output: %02x", data ));
1170}
1171
1172const duart68681_config apollo_sio2_config = {
1173      sio2_irq_handler,
1174      sio2_tx_data,
1175      sio2_input,
1176      sio2_output
1177};
1178
1179/*-------------------------------------------------
1180 DN3500 SIO2 at 0x10500
1181 -------------------------------------------------*/
1182
1183READ8_DEVICE_HANDLER(apollo_sio2_r)
1184{
1185   static const char * const duart68681_reg_read_names[0x10] = { "MRA", "SRA",
1186         "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB",
1187         "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter",
1188         "Stop Counter" };
1189
1190   apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0);
1191
1192   int data = duart68681_r(device, offset / 2);
1193
1194   DLOG2(("reading 2681 reg %x (%s) returned %02x",
1195            offset, duart68681_reg_read_names[offset/2], data ));
1196   return data;
1197}
1198
1199WRITE8_DEVICE_HANDLER(apollo_sio2_w)
1200{
1201   static const char * const duart68681_reg_write_names[0x10] = { "MRA",
1202         "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB",
1203         "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" };
1204
1205   DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data ));
1206
1207   apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0);
1208
1209   switch (offset / 2) {
1210   case 0x04: /* ACR */
1211      if (data == 0x80) {
1212         // FIXME: unhandled ACR value
1213         // data = 0xe0;
1214      }
1215      break;
1216   }
1217
1218   duart68681_w(device, offset / 2, data);
1219}
1220
1221/*-------------------------------------------------
1222 device start callback
1223 -------------------------------------------------*/
1224
1225static DEVICE_START(apollo_sio2)
1226{
1227   DLOG1(("start apollo_sio2"));
1228}
1229
1230/*-------------------------------------------------
1231 device reset callback
1232 -------------------------------------------------*/
1233
1234static DEVICE_RESET(apollo_sio2)
1235{
1236   DLOG1(("reset apollo_sio2"));
1237}
1238
1239//##########################################################################
1240// machine/apollo_fdc.c - APOLLO DS3500 Floppy disk controller
1241//##########################################################################
1242
1243#undef VERBOSE
1244#define VERBOSE 0
1245
1246static device_t *apollo_fdc_device = NULL;
1247
1248static LEGACY_FLOPPY_OPTIONS_START( apollo )
1249      LEGACY_FLOPPY_OPTION( img2d, "afd", "Apollo floppy disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
1250      HEADS([2])
1251      TRACKS([77])
1252      SECTORS([8])
1253      SECTOR_LENGTH([1024])
1254      FIRST_SECTOR_ID([1]))
1255      LEGACY_FLOPPY_OPTIONS_END0
1256
1257static const floppy_interface apollo_fdc_floppy_config = { //
1258      DEVCB_NULL, //
1259      DEVCB_NULL, //
1260      DEVCB_NULL, //
1261      DEVCB_NULL, //
1262      DEVCB_NULL, //
1263      FLOPPY_STANDARD_5_25_DSHD, //
1264      LEGACY_FLOPPY_OPTIONS_NAME(apollo), //
1265      NULL, //
1266      NULL //
1267};
1268
1269/*************************************
1270 *  Floppy Disk Controller
1271 *************************************/
1272
1273static void apollo_fdc_interrupt(running_machine &machine, int state) {
1274   apollo_pic_set_irq_line( machine.firstcpu, APOLLO_IRQ_FDC, state);
1275}
1276
1277static void apollo_fdc_dma_drq(running_machine &machine, int state) {
1278   apollo_dma_fdc_drq(machine.firstcpu, state);
1279}
1280
1281static device_t *apollo_fdc_get_image(running_machine &machine,
1282      int floppy_index) {
1283   return floppy_get_device(machine, 0);
1284}
1285
1286static device_t * apollo_fdc_get_device(running_machine &machine) {
1287   return apollo_fdc_device;
1288}
1289
1290static const struct pc_fdc_interface apollo_fdc_interface = {
1291      apollo_fdc_interrupt, //
1292      apollo_fdc_dma_drq, //
1293      apollo_fdc_get_image, //
1294      apollo_fdc_get_device //
1295};
1296
1297/*-------------------------------------------------
1298 FDC upd765 at 0x5f800 - 0x5f807
1299 -------------------------------------------------*/
1300
1301static DEVICE_START( apollo_fdc ) {
1302   DLOG1(("device_start_apollo_fdc"));
1303   apollo_fdc_device = device;
1304   pc_fdc_init(device->machine(), &apollo_fdc_interface);
1305
1306   // hack to make upd765.c work again for apollo with MESS version >= 0.142u6
1307   // 2011-07-23 Hans Ostermyer
1308//   extern void upd765_hack_for_apollo();
1309//   upd765_hack_for_apollo();
1310}
1311
1312WRITE8_HANDLER(apollo_fdc_w ) {
1313   SLOG1(("writing FDC upd765 at offset %X = %02x", offset, data));
1314   pc_fdc_w(space, offset, data);
1315}
1316
1317READ8_HANDLER( apollo_fdc_r ) {
1318   UINT8 data = pc_fdc_r(space, offset);
1319   SLOG1(("reading FDC upd765 at offset %X = %02x", offset, data));
1320   return data;
1321}
1322
1323/***************************************************************************
1324 DN3500 3c505 DEVICE Configuration
1325 ***************************************************************************/
1326
1327static void apollo_3c505_set_irq(device_t *device, int state) {
1328   // DLOG2(("apollo_3c505_interrupt: state=%x", state ));
1329   apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_ETH1, state);
1330}
1331
1332static int apollo_3c505_tx_data(device_t *device,
1333      const UINT8 tx_data_buffer[], int tx_data_length) {
1334
1335   // transmit all transmitted packets to the apollo_netserver
1336   apollo_netserver_receive(device, tx_data_buffer, tx_data_length);
1337
1338   // transmit all transmitted packets to the host ethernet (ignore any errors)
1339   return apollo_eth_transmit(device, tx_data_buffer, tx_data_length);
1340}
1341
1342static int apollo_3c505_setfilter(device_t *device, int node_id)
1343{
1344   return apollo_eth_setfilter(device, node_id);
1345}
1346
1347static int apollo_3c505_rx_data(device_t *device,
1348      const UINT8 rx_data_buffer[], int rx_data_length) {
1349
1350   // transmit all received packets to the threecom3c505 receiver
1351   return threecom3c505_receive(device, rx_data_buffer, rx_data_length);
1352}
1353
1354static void apollo_3c505_tx_init(device_t *device) {
1355
1356   apollo_eth_init(device, apollo_3c505_rx_data);
1357
1358   // setup to receive all packets from the apollo_netserver
1359   apollo_netserver_init(device->machine().options().media_path(), apollo_3c505_rx_data);
1360}
1361
1362static THREECOM3C505_INTERFACE(apollo_3c505_config) = {
1363   apollo_3c505_set_irq,
1364   apollo_3c505_tx_init,
1365   apollo_3c505_tx_data,
1366   apollo_3c505_setfilter
1367};
1368
1369/***************************************************************************
1370 DN3500 OMTI 8621 DEVICE Configuration
1371 ***************************************************************************/
1372
1373static void apollo_wdc_set_irq(const running_machine *machine, int state) {
1374//   FIXME:
1375//   MLOG2(("apollo_wdc_set_irq: state=%x", state ));
1376   apollo_pic_set_irq_line(machine->firstcpu, APOLLO_IRQ_WIN1, state);
1377}
1378
1379static const omti8621_config apollo_wdc_config = {
1380      apollo_wdc_set_irq
1381};
1382
1383/***************************************************************************
1384 DN3500 Cartridge Tape DEVICE Configuration
1385 ***************************************************************************/
1386
1387static void apollo_ctape_set_irq(const device_t *device, int state) {
1388   DLOG2(("apollo_ctape_set_irq: state=%x", state ));
1389   apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_CTAPE, state);
1390}
1391
1392
1393static void apollo_ctape_dma_drq(const device_t *device, int state) {
1394   DLOG2(("apollo_ctape_dma_drq: state=%x", state ));
1395   apollo_dma_ctape_drq(device->machine().firstcpu, state);
1396}
1397
1398static const sc499_interface apollo_ctape_config = {
1399   apollo_ctape_set_irq,
1400   apollo_ctape_dma_drq,
1401};
1402
1403//##########################################################################
1404// machine/apollo.c - APOLLO DS3500 CPU Board
1405//##########################################################################
1406
1407#undef VERBOSE
1408#define VERBOSE 0
1409
1410MACHINE_CONFIG_FRAGMENT( apollo )
1411   // configuration MUST be reset first !
1412   MCFG_DEVICE_ADD(APOLLO_CONF_TAG, APOLLO_CONF, 0)
1413
1414   MCFG_I8237_ADD( APOLLO_DMA1_TAG, XTAL_14_31818MHz/3, apollo_dma8237_1_config )
1415   MCFG_I8237_ADD( APOLLO_DMA2_TAG, XTAL_14_31818MHz/3, apollo_dma8237_2_config )
1416   MCFG_PIC8259_ADD( APOLLO_PIC1_TAG, apollo_pic8259_master_config )
1417   MCFG_PIC8259_ADD( APOLLO_PIC2_TAG, apollo_pic8259_slave_config )
1418   MCFG_PTM6840_ADD(APOLLO_PTM_TAG, apollo_ptm_config)
1419   MCFG_MC146818_ADD( APOLLO_RTC_TAG, MC146818_UTC )
1420    MCFG_DUART68681_ADD( APOLLO_SIO_TAG, XTAL_3_6864MHz, apollo_sio_config )
1421    MCFG_DUART68681_ADD( APOLLO_SIO2_TAG, XTAL_3_6864MHz, apollo_sio2_config )
1422
1423   MCFG_UPD765A_ADD(APOLLO_FDC_TAG, pc_fdc_upd765_connected_1_drive_interface)
1424#ifdef MCFG_FLOPPY_DRIVE_ADD
1425   MCFG_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config)
1426#else
1427   MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config)
1428#endif
1429   MCFG_OMTI8621_ADD(APOLLO_WDC_TAG, apollo_wdc_config)
1430   MCFG_SC499_ADD(APOLLO_CTAPE_TAG, apollo_ctape_config)
1431   MCFG_THREECOM3C505_ADD(APOLLO_ETH_TAG, apollo_3c505_config)
1432MACHINE_CONFIG_END
1433
1434DRIVER_INIT( apollo )
1435{
1436   MLOG1(("driver_init_apollo"));
1437}
1438
1439MACHINE_START( apollo )
1440{
1441   MLOG1(("machine_start_apollo"));
1442
1443   device_start_apollo_fdc (machine.device(APOLLO_FDC_TAG));
1444   device_start_apollo_ptm (machine.device(APOLLO_PTM_TAG) );
1445   device_start_apollo_sio(machine.device(APOLLO_SIO_TAG));
1446   device_start_apollo_sio2(machine.device(APOLLO_SIO2_TAG));
1447
1448   if (apollo_is_dn3000())
1449   {
1450      MLOG1(("faking mc146818 interrupts (DN3000 only)"));
1451      // fake mc146818 interrupts (DN3000 only)
1452      machine.scheduler().timer_pulse(attotime::from_hz(2), FUNC(apollo_rtc_timer));
1453   }
1454}
1455
1456MACHINE_RESET( apollo )
1457{
1458   apollo_state *st = machine.driver_data<apollo_state>();
1459   MLOG1(("machine_reset_apollo"));
1460
1461   st->dma8237_1 = machine.device(APOLLO_DMA1_TAG);
1462   st->dma8237_2 = machine.device(APOLLO_DMA2_TAG);
1463   st->pic8259_master = machine.device(APOLLO_PIC1_TAG);
1464   st->pic8259_slave = machine.device(APOLLO_PIC2_TAG);
1465
1466   // set configuration
1467   apollo_csr_set_servicemode(apollo_config(APOLLO_CONF_SERVICE_MODE));
1468
1469   device_reset_apollo_ptm(machine.device(APOLLO_PTM_TAG));
1470   device_reset_apollo_rtc(machine.device(APOLLO_RTC_TAG));
1471   device_reset_apollo_sio(machine.device(APOLLO_SIO_TAG));
1472   device_reset_apollo_sio2(machine.device(APOLLO_SIO2_TAG));
1473}
src/mess/machine/3c505.c
r0r14540
1/*
2 * 3c505.c - 3COM 3C505 ethernet controller (for Apollo DN3x00)
3 *
4 *  Created on: August 27, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also:
11 *  - http://lxr.free-electrons.com/source/drivers/net/3c505.h
12 *  - http://lxr.free-electrons.com/source/drivers/net/3c505.c
13 *  - http://stason.org/TULARC/pc/network-cards/O/OLIVETTI-Ethernet-NPU-9144-3C505.html
14 *  - http://www.bitsavers.org/pdf/3Com/3C500_Mar83.pdf
15 */
16
17#include "machine/3c505.h"
18
19#define VERBOSE 0
20
21static int verbose = VERBOSE;
22
23#define LOG(x)   { logerror ("%s: ", m_device->cpu_context()); logerror x; logerror ("\n"); }
24#define LOG1(x)   { if (verbose > 0) LOG(x)}
25#define LOG2(x)   { if (verbose > 1) LOG(x)}
26
27#define  MAINCPU "maincpu"
28
29//**************************************************************************
30//  DEVICE DEFINITIONS
31//**************************************************************************
32
33//const device_type THREECOM3C505 = threecom3c505_device_config::static_alloc_device_config;
34
35//**************************************************************************
36//  CONSTANTS
37//**************************************************************************
38
39// Apollo microcode version
40#define APOLLO_MC_VERSION_SR10_2 0x0302
41#define APOLLO_MC_VERSION_SR10_4 0x0303
42
43#define PORT_DATA_FIFO_SIZE 20
44
45/*
46 * I/O register offsets
47 */
48#define PORT_COMMAND    0x00    /* read/write, 8-bit */
49#define PORT_STATUS     0x02    /* read only, 8-bit */
50#define PORT_AUXDMA     0x02    /* write only, 8-bit */
51#define PORT_DATA       0x04    /* read/write, 16-bit */
52#define PORT_CONTROL    0x06    /* read/write, 8-bit */
53
54#define ELP_IO_EXTENT   0x10    /* size of used IO registers */
55
56/*
57 * host control registers bits
58 */
59#define ATTN    0x80    /* attention */
60#define FLSH    0x40    /* flush data register */
61#define DMAE    0x20    /* DMA enable */
62#define DIR_    0x10    /* direction */
63#define TCEN    0x08    /* terminal count interrupt enable */
64#define CMDE    0x04    /* command register interrupt enable */
65#define HSF2    0x02    /* host status flag 2 */
66#define HSF1    0x01    /* host status flag 1 */
67
68/*
69 * combinations of HSF flags used for PCB transmission
70 */
71#define HSF_PCB_ACK     HSF1
72#define HSF_PCB_NAK     HSF2
73#define HSF_PCB_END     (HSF2|HSF1)
74#define HSF_PCB_MASK    (HSF2|HSF1)
75
76/*
77 * host status register bits
78 */
79#define HRDY    0x80    /* data register ready */
80#define HCRE    0x40    /* command register empty */
81#define ACRF    0x20    /* adapter command register full */
82/* #define DIR_  0x10    direction - same as in control register */
83#define DONE    0x08    /* DMA done */
84#define ASF3    0x04    /* adapter status flag 3 */
85#define ASF2    0x02    /* adapter status flag 2 */
86#define ASF1    0x01    /* adapter status flag 1 */
87
88/*
89 * combinations of ASF flags used for PCB reception
90 */
91#define ASF_PCB_ACK     ASF1
92#define ASF_PCB_NAK     ASF2
93#define ASF_PCB_END     (ASF2|ASF1)
94#define ASF_PCB_MASK    (ASF3|ASF2|ASF1)
95
96/*
97 * host aux DMA register bits
98 */
99#define DMA_BRST        0x01    /* DMA burst */
100
101/*
102 * maximum amount of data allowed in a PCB
103 */
104#define MAX_PCB_DATA    62
105
106#define CMD_RESPONSE_OFFSET 0x30
107enum
108{
109   /* host PCB commands */
110   CMD_CONFIGURE_ADAPTER_MEMORY = 0x01,
111   CMD_CONFIGURE_82586 = 0x02,
112   CMD_STATION_ADDRESS = 0x03,
113   CMD_DMA_DOWNLOAD = 0x04,
114   CMD_DMA_UPLOAD = 0x05,
115   CMD_PIO_DOWNLOAD = 0x06,
116   CMD_PIO_UPLOAD = 0x07,
117   CMD_RECEIVE_PACKET = 0x08,
118   CMD_TRANSMIT_PACKET = 0x09,
119   CMD_NETWORK_STATISTICS = 0x0a,
120   CMD_LOAD_MULTICAST_LIST = 0x0b,
121   CMD_CLEAR_PROGRAM = 0x0c,
122   CMD_DOWNLOAD_PROGRAM = 0x0d,
123   CMD_EXECUTE_PROGRAM = 0x0e,
124   CMD_SELF_TEST = 0x0f,
125   CMD_SET_STATION_ADDRESS = 0x10,
126   CMD_ADAPTER_INFO = 0x11,
127
128   CMD_MC_17 = 0x17,
129   CMD_TRANSMIT_PACKET_18 = 0x18,
130   CMD_MC_F8 =0xf8,
131   CMD_MC_F9 =0xf9,
132   CMD_MC_FA =0xfa,
133
134   /*adapter PCB commands */
135   CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31,
136   CMD_CONFIGURE_82586_RESPONSE = 0x32,
137   CMD_ADDRESS_RESPONSE = 0x33,
138   CMD_DOWNLOAD_DATA_REQUEST = 0x34,
139   CMD_UPLOAD_DATA_REQUEST = 0x35,
140   CMD_RECEIVE_PACKET_COMPLETE = 0x38,
141   CMD_TRANSMIT_PACKET_COMPLETE = 0x39,
142   CMD_NETWORK_STATISTICS_RESPONSE = 0x3a,
143   CMD_LOAD_MULTICAST_RESPONSE = 0x3b,
144   CMD_CLEAR_PROGRAM_RESPONSE = 0x3c,
145   CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d,
146   CMD_EXECUTE_PROGRAM_RESPONSE = 0x3e,
147   CMD_SELF_TEST_RESPONSE = 0x3f,
148   CMD_SET_ADDRESS_RESPONSE = 0x40,
149   CMD_ADAPTER_INFO_RESPONSE = 0x41,
150
151   CMD_MC_17_COMPLETE = 0x47,
152   CMD_TRANSMIT_PACKET_18_COMPLETE = 0x48,
153
154   CMD_MC_E1_RESPONSE = 0xe1,
155   CMD_MC_E2_RESPONSE = 0xe2
156};
157
158/* These defines for 'configure' */
159#define RECV_STATION    0x00
160#define RECV_BROAD      0x01
161#define RECV_MULTI      0x02
162#define RECV_PROMISC    0x04
163#define NO_LOOPBACK     0x00
164#define INT_LOOPBACK    0x08
165#define EXT_LOOPBACK    0x10
166
167// FIXME:
168// #define lsb_first(a) (((a & 255) << 8) | ((a >>8) & 255))
169#define lsb_first(a) (a)
170
171/***************************************************************************
172    IMPLEMENTATION
173***************************************************************************/
174
175// device type definition
176const device_type THREECOM3C505 = &device_creator<threecom3c505_device>;
177
178//-------------------------------------------------
179// sc499_device - constructor
180//-------------------------------------------------
181
182threecom3c505_device::threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
183    : device_t(mconfig, THREECOM3C505, "Threecom 3C505", tag, owner, clock)
184{
185   memset(static_cast<threecom3c505_interface *>(this), 0, sizeof(threecom3c505_interface));
186}
187
188//-------------------------------------------------
189//  static_set_interface - set the interface struct
190//-------------------------------------------------
191
192void threecom3c505_device::static_set_interface(device_t &device, const threecom3c505_interface &interface)
193{
194   threecom3c505_device &threecom3c505 = downcast<threecom3c505_device &>(device);
195   static_cast<threecom3c505_interface &>(threecom3c505) = interface;
196}
197
198//-------------------------------------------------
199//  device_start - device-specific startup
200//-------------------------------------------------
201
202void threecom3c505_device::device_start()
203{
204   m_device = this;
205   LOG1(("start 3COM 3C505"));
206
207    m_rx_fifo.start(this, RX_FIFO_SIZE, ETH_BUFFER_SIZE);
208    m_rx_data_buffer.start(this, ETH_BUFFER_SIZE);
209    m_tx_data_buffer.start(this, ETH_BUFFER_SIZE);
210    m_program_buffer.start(this, PGM_BUFFER_SIZE);
211
212   if (tx_init != NULL)
213   {
214      (*tx_init)(this);
215   }
216
217   m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_set_interrupt), this);
218}
219
220//-------------------------------------------------
221//  device_reset - device-specific reset
222//-------------------------------------------------
223
224void threecom3c505_device::device_reset()
225{
226   LOG1(("reset 3COM 3C505"));
227
228   m_rx_fifo.reset();
229   m_rx_data_buffer.reset();
230   m_tx_data_buffer.reset();
231   m_program_buffer.reset();
232
233   memset(m_reg, 0, sizeof(m_reg));
234   m_status = HCRE;
235   m_control = 0;
236   m_command_index = 0;
237   m_command_pending = 0;
238   m_rx_data_index = 0;
239   m_rx_pending = 0;
240   m_tx_data_length = 0;
241   m_response_length = 0;
242   m_response_index = 0;
243   m_microcode_running = 0;
244   m_microcode_version = 0;
245   m_i82586_config = 0;
246   memset(m_station_address, 0 , sizeof(m_station_address));
247   memset(m_multicast_list, 0 , sizeof(m_multicast_list));
248   set_filter_list();
249}
250
251/***************************************************************************
252 cpu_context - return a string describing the current CPU context
253 ***************************************************************************/
254
255const char *threecom3c505_device::cpu_context()
256{
257   static char statebuf[64]; /* string buffer containing state description */
258
259   device_t *cpu = machine().device(MAINCPU);
260   osd_ticks_t t = osd_ticks();
261   int s = t / osd_ticks_per_second();
262   int ms = (t % osd_ticks_per_second()) / 1000;
263
264   /* if we have an executing CPU, output data */
265   if (cpu != NULL)
266   {
267      sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
268            cpu_get_previouspc(cpu), tag());
269   }
270   else
271   {
272      sprintf(statebuf, "%d.%03d", s, ms);
273   }
274   return statebuf;
275}
276
277//**************************************************************************
278//  data_buffer
279//**************************************************************************
280
281threecom3c505_device::data_buffer::data_buffer() :
282   m_device(NULL),
283   m_size(0L),
284   m_data(NULL)
285{
286}
287
288void threecom3c505_device::data_buffer::start(threecom3c505_device *device, INT32 size)
289{
290   m_device = device;
291   LOG2(("start threecom3c505_device::data_buffer with size %0x", size));
292   m_size = size;
293   m_data = auto_alloc_array(device->machine(), UINT8, size);
294}
295
296void threecom3c505_device::data_buffer::reset()
297{
298   LOG2(("reset threecom3c505_device::data_buffer"));
299   m_length = 0;
300}
301
302void threecom3c505_device::data_buffer::copy(data_buffer *db) const
303{
304   db->m_size = m_size;
305   db->m_length = m_length;
306   memcpy(db->m_data, m_data, m_size);
307}
308
309int threecom3c505_device::data_buffer::append(UINT8 data)
310{
311   if (m_length >= m_size)
312   {
313      return 0;
314   }
315   else
316   {
317      m_data[m_length++] = data;
318      return 1;
319   }
320}
321
322void threecom3c505_device::data_buffer::log(const char * title) const
323{
324   if (verbose > 0)
325   {
326      int i;
327      logerror("%s: %s (length=%02x)", m_device->cpu_context(),   title, m_length);
328      for (i = 0; i < m_length; i++)
329      {
330         logerror(" %02x", m_data[i]);
331         if (i >= 1023)
332         {
333            logerror(" ...");
334            break;
335         }
336      }
337      logerror("\n");
338   }
339}
340
341//**************************************************************************
342//  data_buffer fifo
343//**************************************************************************
344
345threecom3c505_device::data_buffer_fifo::data_buffer_fifo() :
346   m_device(NULL),
347   m_size(0)
348{
349}
350
351void threecom3c505_device::data_buffer_fifo::start(
352      threecom3c505_device *device, INT32 size, INT32 db_size)
353{
354   m_device = device;
355   LOG2(("start threecom3c505_device::data_buffer_fifo"));
356
357   int i;
358   // FIXME: fifo size is hardcoded
359   m_size = RX_FIFO_SIZE; // size;
360   for (i = 0; i < m_size; i++)
361   {
362      m_db[i] = new data_buffer();
363      m_db[i]->start(device, db_size);
364   }
365}
366
367void threecom3c505_device::data_buffer_fifo::reset()
368{
369   LOG2(("reset threecom3c505_device::data_buffer_fifo"));
370   m_get_index = m_put_index = 0;
371   m_count = 0;
372}
373
374int threecom3c505_device::data_buffer_fifo::put(const UINT8 data[], const int length)
375{
376   UINT16 next_index = (m_put_index + 1) % m_size;
377
378   LOG2(("threecom3c505_device::data_buffer_fifo::put %d", m_count));
379
380   if (next_index == m_get_index)
381   {
382      // overflow, fifo full
383      return 0;
384   }
385   else
386   {
387      memcpy(m_db[m_put_index]->m_data, data, length);
388      m_db[m_put_index]->m_length = length;
389      m_put_index = next_index;
390      m_count++;
391      return 1;
392   }
393}
394
395int threecom3c505_device::data_buffer_fifo::get(data_buffer *db)
396{
397   LOG2(("threecom3c505_device::data_buffer_fifo::get %d", m_count));
398
399   if (m_get_index == m_put_index)
400   {
401      // fifo empty
402      return 0;
403   }
404   else
405   {
406      m_db[m_get_index]->copy(db);
407      m_get_index = (m_get_index + 1) % m_size;
408      m_count--;
409      return 1;
410   }
411}
412
413/*-------------------------------------------------
414 set_filter_list - set the ethernet packet filter list
415 -------------------------------------------------*/
416
417void threecom3c505_device::set_filter_list()
418{
419   memset(m_filter_list, 0 , sizeof(m_filter_list));
420   memcpy(m_filter_list, m_station_address,  ETHERNET_ADDR_SIZE);
421   memset(m_filter_list+ETHERNET_ADDR_SIZE,0xff, ETHERNET_ADDR_SIZE);
422   memcpy(m_filter_list+ETHERNET_ADDR_SIZE*2, m_multicast_list, sizeof(m_multicast_list));
423
424   if (setfilter != NULL)
425   {
426      int node_id = (((m_station_address[3] << 8) + m_station_address[4]) << 8) + m_station_address[5];
427      LOG1(("set_filter_list node_id=%x",node_id));
428      (*setfilter)(this, node_id);
429   }
430
431}
432
433/*-------------------------------------------------
434 set_interrupt - set the IRQ state
435 -------------------------------------------------*/
436
437void threecom3c505_device::set_interrupt(enum line_state state)
438{
439   if (state != irq_state)
440   {
441      LOG1(("set_interrupt(%d)",state));
442      if (set_irq != NULL)
443      {
444         (*set_irq)(this, state);
445      }
446      irq_state = state;
447
448      // FIXME: hack?
449      if ( m_command_buffer[0] == CMD_EXECUTE_PROGRAM && state == 1)
450      {
451         m_status |= ASF_PCB_END;
452      }
453   }
454}
455
456TIMER_CALLBACK( threecom3c505_device::static_set_interrupt )
457{
458   reinterpret_cast<threecom3c505_device *> (ptr)->set_interrupt(ASSERT_LINE);
459}
460
461// -------------------------------------
462
463void threecom3c505_device::log_command()
464{
465   if (verbose > 0)
466   {
467      int i;
468      logerror("%s: Command ", cpu_context());
469      switch (m_command_buffer[0])
470      {
471      case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01
472         logerror("CMD_CONFIGURE_ADAPTER_MEMORY");
473         break;
474      case CMD_CONFIGURE_82586: // 0x02
475         logerror("CMD_CONFIGURE_82586");
476         break;
477      case CMD_RECEIVE_PACKET: // 0x08
478         logerror("CMD_RECEIVE_PACKET");
479         break;
480      case CMD_TRANSMIT_PACKET: // 0x09
481         logerror("CMD_TRANSMIT_PACKET");
482         break;
483      case CMD_NETWORK_STATISTICS: // 0x0a
484         logerror("CMD_NETWORK_STATISTICS");
485         break;
486      case CMD_LOAD_MULTICAST_LIST: // 0x0b,
487         logerror("CMD_LOAD_MULTICAST_LIST");
488         break;
489      case CMD_CLEAR_PROGRAM: // 0x0c
490         logerror("!!! Unexpected CMD_CLEAR_PROGRAM");
491         break;
492      case CMD_DOWNLOAD_PROGRAM: // 0x0d
493         logerror("CMD_DOWNLOAD_PROGRAM");
494         break;
495      case CMD_EXECUTE_PROGRAM: // 0x0e
496         logerror("CMD_EXECUTE_PROGRAM");
497         break;
498      case CMD_SET_STATION_ADDRESS: // 0x10
499         logerror("CMD_SET_STATION_ADDRESS");
500         break;
501      case CMD_ADAPTER_INFO: // 0x11
502         logerror("CMD_ADAPTER_INFO");
503         break;
504      case CMD_MC_17: // 0x17
505         logerror("CMD_MC_17");
506         break;
507      case CMD_TRANSMIT_PACKET_18: // 0x18
508         logerror("CMD_TRANSMIT_PACKET_18");
509         break;
510
511      case CMD_MC_F8: // 0xf8
512         logerror("CMD_MC_F8");
513         break;
514      case CMD_MC_F9: // 0xf9
515         logerror("CMD_MC_F9");
516         break;
517      case CMD_MC_FA: // 0xfa
518         logerror("CMD_MC_FA");
519         break;
520
521      default:
522         logerror("!!! Unexpected Command !!!");
523      }
524
525      switch (m_command_buffer[0])
526      {
527      case CMD_MC_F9: // 0xf9
528//         logerror(" (%02x, length=00)", m_command_buffer[0]);
529         break;
530
531      default:
532         logerror(" (%02x, length=%02x)", m_command_buffer[0],
533               m_command_buffer[1]);
534         for (i = 2; i < m_command_index; i++)
535         {
536            logerror(" %02x", m_command_buffer[i]);
537         }
538         break;
539      }
540      logerror("\n");
541   }
542}
543
544void threecom3c505_device::log_response()
545{
546   if (verbose > 0)
547   {
548      int i;
549      logerror("%s: Response ", cpu_context());
550      switch (m_response.command)
551      {
552      case CMD_CONFIGURE_ADAPTER_RESPONSE: // 0x31
553         logerror("CMD_CONFIGURE_ADAPTER_RESPONSE");
554         break;
555      case CMD_CONFIGURE_82586_RESPONSE: // 0x32
556         logerror("CMD_CONFIGURE_82586_RESPONSE");
557         break;
558      case CMD_RECEIVE_PACKET_COMPLETE: // 0x38
559         logerror("CMD_RECEIVE_PACKET_COMPLETE");
560         break;
561      case CMD_TRANSMIT_PACKET_COMPLETE: // 0x39
562         logerror("CMD_TRANSMIT_PACKET_COMPLETE");
563         break;
564      case CMD_NETWORK_STATISTICS_RESPONSE: // 0x3a
565         logerror("CMD_NETWORK_STATISTICS_RESPONSE");
566         break;
567      case CMD_LOAD_MULTICAST_RESPONSE: // 0x3b
568         logerror("CMD_LOAD_MULTICAST_RESPONSE");
569         break;
570      case CMD_DOWNLOAD_PROGRAM_RESPONSE: // 0x3d
571         logerror("CMD_DOWNLOAD_PROGRAM_RESPONSE");
572         break;
573      case CMD_EXECUTE_PROGRAM_RESPONSE: // 0x3e
574         logerror("CMD_EXECUTE_PROGRAM_RESPONSE");
575         break;
576      case CMD_SET_ADDRESS_RESPONSE: // 0x40
577         logerror("CMD_SET_ADDRESS_RESPONSE");
578         break;
579      case CMD_ADAPTER_INFO_RESPONSE: // 0x41
580         logerror("CMD_ADAPTER_INFO_RESPONSE");
581         break;
582      case CMD_MC_17_COMPLETE: // 0x47
583         logerror("CMD_MC_17_COMPLETE");
584         break;
585      case CMD_TRANSMIT_PACKET_18_COMPLETE: // 0x48
586         logerror("CMD_TRANSMIT_PACKET_18_COMPLETE");
587         break;
588      case CMD_MC_E1_RESPONSE: // 0xe1
589         logerror("CMD_MC_E1_RESPONSE");
590         break;
591      case CMD_MC_E2_RESPONSE: // 0xe2
592         logerror("CMD_MC_E2_RESPONSE");
593         break;
594      default:
595         logerror("!!! Unexpected Response !!!");
596      }
597      logerror(" (%02x, length=%02x)", m_response.command, m_response.length);
598      for (i = 0; i < m_response.length; i++)
599      {
600         logerror(" %02x", m_response.data.raw[i]);
601      }
602      logerror("\n");
603   }
604}
605
606void threecom3c505_device::do_receive_command()
607{
608   LOG2(("do_receive_command - data_length=%x rx_pending=%d",
609               m_rx_data_buffer.get_length(), m_rx_pending));
610#if 0
611   if (m_microcode_running && m_microcode_version == APOLLO_MC_VERSION_SR10_4)
612   {
613      m_response.command = CMD_MC_E1_RESPONSE;
614      m_response.length = 0;
615      m_response_length = 0;
616      m_response_index = 0;
617
618      m_rx_pending++;
619   }
620   else
621#endif
622
623   {
624      m_response.command = CMD_RECEIVE_PACKET_COMPLETE; // 0x38
625      m_response.length = 16;
626      m_response.data.rcv_resp.buf_ofs = 0;
627      m_response.data.rcv_resp.buf_seg = 0;
628      m_response.data.rcv_resp.buf_len = m_rx_data_buffer.get_length();
629      m_response.data.rcv_resp.pkt_len = m_rx_data_buffer.get_length(); // (?)
630      m_response.data.rcv_resp.timeout = 0; // successful completion
631      m_response.data.rcv_resp.status = m_rx_data_buffer.get_length() > 0 ? 0 : 0xffff;
632      m_response.data.rcv_resp.timetag = 0L; // TODO
633
634      m_response_length = m_response.length + 2;
635      m_response_index = 0;
636   }
637
638   m_status |= ACRF; /* adapter command register full */
639
640   if (m_control & CMDE)
641   {
642      LOG2(("do_receive_command - set_interrupt(%d)", ASSERT_LINE));
643      // set_interrupt(ASSERT_LINE);
644
645      // interrupt later
646      m_timer->adjust( attotime::from_usec(10));
647   }
648}
649
650void threecom3c505_device::set_command_pending(int onoff)
651{
652   m_command_pending = onoff;
653   LOG1(("set_command_pending %d m_rx_pending=%d m_rx_data_buffer.get_length()=%x%s", m_command_pending, m_rx_pending, m_rx_data_buffer.get_length(), onoff ? "" :"\n"));
654
655   if (!m_command_pending)
656   {
657      // clear previous command byte
658      m_command_buffer[0] = 0;
659
660      if (m_rx_pending > 0 && m_rx_data_buffer.get_length() > 0)
661      {
662         m_rx_pending--;
663         m_command_pending = 1;
664
665         LOG1(("set_command_pending %d m_rx_pending=%d", m_command_pending, m_rx_pending));
666
667         do_receive_command();
668      }
669   }
670}
671
672/***************************************************************************
673 do_command
674 ***************************************************************************/
675
676void threecom3c505_device::do_command()
677{
678   // default to successful completion
679   m_response.command = m_command_buffer[0] + CMD_RESPONSE_OFFSET;
680   m_response.length = 1;
681   m_response.data.failed = 0; // successful completion
682
683   switch (m_command_buffer[0])
684   {
685   case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01
686      m_i82586_config = m_program_buffer.get_word(1);
687      break;
688
689//   case CMD_MC_F8:
690   case CMD_RECEIVE_PACKET: // 0x08
691      if (m_rx_data_buffer.get_length() == 0 && !m_rx_fifo.get(&m_rx_data_buffer))
692      {
693         m_rx_pending++;
694         set_command_pending(0);
695      }
696      else
697      {
698         do_receive_command();
699      }
700      return;
701      // break;
702
703//      case CMD_MC_F8:
704      case CMD_MC_F9:
705//      case CMD_MC_FA:
706      // FIXME:
707      m_response.command = CMD_TRANSMIT_PACKET_COMPLETE;
708//      break;
709
710   case CMD_TRANSMIT_PACKET: // 0x09
711   case CMD_TRANSMIT_PACKET_18: // 0x18
712      m_response.length = 8;
713      m_response.data.xmit_resp.buf_ofs = 0;
714      m_response.data.xmit_resp.buf_seg = 0;
715      m_response.data.xmit_resp.c_stat = 0; // successful completion
716      m_response.data.xmit_resp.status = 0;
717      break;
718
719   case CMD_EXECUTE_PROGRAM: // 0x0e
720      m_response.length = 0;
721      m_microcode_running = 1;
722      m_microcode_version = m_program_buffer.get_word(1);
723      break;
724
725   case CMD_NETWORK_STATISTICS: // 0x0a
726      m_response.length = sizeof(struct Netstat);
727      // FIXME: replace test data; must be LSB first!
728      m_response.data.netstat.tot_recv = 1;
729      m_response.data.netstat.tot_xmit = 2;
730      m_response.data.netstat.err_CRC = 3;
731      m_response.data.netstat.err_align = 4;
732      m_response.data.netstat.err_res = 5;
733      m_response.data.netstat.err_ovrrun = 6;
734      break;
735
736   case CMD_ADAPTER_INFO: // 0x11
737      m_response.length = sizeof(struct Info);
738      // FIXME: replace test data; must be LSB first!
739      m_response.data.info.minor_vers = 1;
740      m_response.data.info.major_vers = 2;
741      m_response.data.info.ROM_cksum = lsb_first(3);
742      m_response.data.info.RAM_sz = lsb_first(4);
743      m_response.data.info.free_ofs = lsb_first(5);
744      m_response.data.info.free_seg = lsb_first(6);
745      break;
746
747   case CMD_LOAD_MULTICAST_LIST:// 0x0b
748      if (m_command_buffer[1] > sizeof(m_multicast_list) ||
749            (m_command_buffer[1] % ETHERNET_ADDR_SIZE) != 0)
750      {
751         LOG(("CMD_LOAD_MULTICAST_LIST - !!! unexpected data size %d !!!", m_command_buffer[1]));
752      }
753      else
754      {
755         memset(m_multicast_list, 0 , sizeof(m_multicast_list));
756         memcpy(m_multicast_list, m_command_buffer+2 , m_command_buffer[1]-2);
757         set_filter_list();
758      }
759      break;
760
761   case CMD_SET_STATION_ADDRESS: // 0x10
762      if (m_command_buffer[1] != sizeof(m_station_address))
763      {
764         LOG(("CMD_SET_STATION_ADDRESS - !!! unexpected data size %d !!!", m_command_buffer[1]));
765         memset(m_station_address, 0 , sizeof(m_station_address));
766      }
767      else
768      {
769         memcpy(m_station_address, m_command_buffer+2 , m_command_buffer[1]);
770      }
771      set_filter_list();
772      break;
773
774   case CMD_CONFIGURE_82586: // 0x02
775   case CMD_DOWNLOAD_PROGRAM: // 0x0d
776   case CMD_MC_17: // 0x17
777   default:
778      break;
779   }
780
781   m_response_index = 0;
782   m_response_length = m_response.length + 2;
783   m_status |= ACRF; /* adapter command register full */
784
785   if (m_control & CMDE)
786   {
787      switch (m_command_buffer[0])
788      {
789      case CMD_NETWORK_STATISTICS: // 0x0a
790      case CMD_DOWNLOAD_PROGRAM: // 0xd
791      case CMD_EXECUTE_PROGRAM: // 0x0e
792      case CMD_ADAPTER_INFO: // 0x11
793         // interrupt later
794         m_timer->adjust( attotime::from_msec(10));
795         break;
796
797      default:
798         // interrupt at once
799         set_interrupt(ASSERT_LINE);
800         break;
801      }
802   }
803}
804
805/***************************************************************************
806 ethernet_packet_is_for_me - check if ethernet address is for me
807 ***************************************************************************/
808
809int threecom3c505_device::ethernet_packet_is_for_me(const UINT8 mac_address[])
810{
811   // tcpdump -i eth0 -q ether host 08:00:1e:01:ae:a5 or ether broadcast or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01
812   // wireshark filter: eth.addr eq 08:00:1e:01:ae:a5 or eth.dst eq ff:ff:ff:ff:ff:ff or eth.dst eq 09:00:1e:00:00:00 or eth.dst eq 09:00:1e:00:00:01
813
814   int i;
815   for (i = 0; i + ETHERNET_ADDR_SIZE < sizeof(m_filter_list); i += ETHERNET_ADDR_SIZE)
816   {
817      if (memcmp(mac_address, m_filter_list + i, ETHERNET_ADDR_SIZE) == 0)
818      {
819         return 1;
820      }
821   }
822   return  0;
823}
824
825/***************************************************************************
826 threecom3c505_receive - receive and process an ethernet packet
827 ***************************************************************************/
828
829int threecom3c505_device::threecom3c505_receive(const UINT8 data[], int length)
830{
831   if (length < ETHERNET_ADDR_SIZE || !ethernet_packet_is_for_me(data))
832   {
833      // skip packet
834      return 0;
835   }
836//   else if (m_command_pending && m_command_buffer[0] == CMD_MC_F9)
837//   {
838//      LOG(("threecom3c505_receive: data_length=%x !!!! skipped data while CMD_MC_F9 is pending!", length));
839//      return 0;
840//   }
841   else if (!m_rx_fifo.put(data, length))
842   {
843      // fifo overrun
844      LOG1(("threecom3c505_receive: data_length=%x !!! RX FIFO OVERRUN !!!", length));
845      return 0;
846   }
847   else
848   {
849      LOG1(("threecom3c505_receive: data_length=%x m_rx_pending=%d", length, m_rx_pending));
850
851      if (m_rx_data_buffer.get_length() == 0)
852      {
853         m_rx_fifo.get(&m_rx_data_buffer);
854      }
855
856//      if (m_command_pending && m_command_buffer[0] == CMD_MC_F9)
857//      {
858//         verbose = 2;
859//      }
860
861      if (!m_command_pending && m_rx_pending > 0
862            && m_rx_data_buffer.get_length() > 0)
863      {
864         m_rx_pending--;
865         set_command_pending(1);
866         do_receive_command();
867      }
868
869//      guessing!
870//      else if (m_control & CMDE)
871//      {
872//         m_status |= ACRF; /* adapter command register full */
873//
874//         LOG(("threecom3c505_receive - set_interrupt(%d)",ASSERT_LINE));
875//         set_interrupt(ASSERT_LINE);
876//      }
877
878      return 1;
879   }
880}
881
882void threecom3c505_device::write_command_port( UINT8 data)
883{
884   LOG2(("writing 3C505 command port %02x - m_status=%02x m_control=%02x m_command_index=%02x", data, m_status, m_control, m_command_index));
885
886   if ((m_control & HSF_PCB_MASK) != HSF_PCB_END)
887   {
888      m_command_buffer[m_command_index++] = data;
889      m_status |= HCRE; /* command register empty */
890
891      if (m_command_index == 1)
892      {
893         switch (data)
894         {
895         case 0:
896            // spurious data; set command register empty
897            m_command_index = 0;
898            m_status |= HCRE;
899//            verbose = 2;
900            break;
901
902         case CMD_MC_F9:
903//         case CMD_MC_FA:
904            // read data length from data port (not from command port)
905            m_tx_data_buffer.reset();
906            m_status |= HRDY; /* data register ready */
907            set_command_pending(1);
908            break;
909
910         default:
911            set_command_pending(1);
912            break;
913         }
914      }
915   }
916   else
917   {
918      m_status &= ~ASF_PCB_MASK;
919      m_status |= (data == m_command_index) ? ASF_PCB_END : ASF_PCB_NAK;
920
921      log_command();
922
923      switch (m_command_buffer[0])
924      {
925      case CMD_TRANSMIT_PACKET_18:
926         // read transmit data into m_tx_data_buffer
927         m_tx_data_buffer.reset();
928         m_tx_data_length = m_command_buffer[2] + (m_command_buffer[3] << 8);
929         m_status |= HRDY; /* data register ready */
930         break;
931
932      case CMD_TRANSMIT_PACKET:
933         // read transmit data into m_tx_data_buffer
934         m_tx_data_buffer.reset();
935         m_tx_data_length = m_command_buffer[6] + (m_command_buffer[7] << 8);
936         m_status |= HRDY; /* data register ready */
937         break;
938
939      case CMD_DOWNLOAD_PROGRAM:
940         // read program data into m_program_buffer
941         m_program_buffer.reset();
942         m_program_length = m_command_buffer[2] + (m_command_buffer[3] << 8);
943         m_status |= HRDY; /* data register ready */
944         break;
945
946      default:
947         do_command();
948         break;
949      }
950   }
951}
952
953UINT8 threecom3c505_device::read_command_port()
954{
955   UINT8 data;
956   if (m_response_index == 0)
957   {
958//      set_command_pending(1);
959      data = m_response.command;
960   }
961   else if (m_response_index == 1)
962   {
963      data = m_response.length;
964   }
965   else if (m_response_index < m_response_length)
966   {
967      data = m_response.data.raw[m_response_index - 2];
968   }
969   else if (m_response_index == m_response_length)
970   {
971      data = m_response.length + 2;
972   }
973   else if (m_response_index == m_response_length+1 /*&& m_microcode_running*/)
974   {
975      // FIXME: special for SR10.4 microcode, content doesn't matter?
976      data = 0; // ?
977      m_response_index++;
978
979      m_status &= ~ACRF; /* adapter command register no longer full */
980
981      LOG2(("FIXME: reading 3C505 Command Register at offset %02x with index %02x = %02x",
982            PORT_COMMAND, m_response_index, data));
983   }
984   else
985   {
986      // should never happen
987      data = 0; // 0xff;
988      LOG(("UNEXPECTED: reading 3C505 Command Register at offset %02x = %02x", PORT_COMMAND, data));
989   }
990
991   if (m_response_index <= m_response_length + 1)
992   {
993      if (++m_response_index == m_response_length)
994      {
995         m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_END;
996      }
997      else if (m_response_index == m_response_length + 1)
998      {
999         // FIXME:
1000         if (!(m_status & DIR_))
1001         {
1002            m_status &= ~HRDY; /* data register no longer ready */
1003         }
1004
1005         log_response();
1006
1007         switch (m_response.command)
1008         {
1009         case CMD_MC_E1_RESPONSE:
1010            m_status |= HRDY; /* data register ready */
1011            // prepend data length
1012            m_rx_data_index = -2;
1013            break;
1014
1015         case CMD_RECEIVE_PACKET_COMPLETE:
1016            m_status |= HRDY; /* data register ready */
1017            m_rx_data_index = 0;
1018            break;
1019
1020         case CMD_TRANSMIT_PACKET_COMPLETE:
1021         case CMD_TRANSMIT_PACKET_18_COMPLETE:
1022            if (tx_data != NULL && //
1023               (*tx_data)(this, m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length()) == 0)
1024            {
1025               // FIXME: failed to transmit the ethernet packet
1026               LOG(("read_command_port(): failed to transmit ethernet packet"));
1027            }
1028
1029            m_tx_data_buffer.reset();
1030            set_command_pending(0);
1031            break;
1032
1033         case CMD_DOWNLOAD_PROGRAM_RESPONSE:
1034            m_program_buffer.reset();
1035            set_command_pending(0);
1036            break;
1037
1038         default:
1039            set_command_pending(0);
1040            break;
1041         }
1042      }
1043   }
1044   return data;
1045}
1046
1047void threecom3c505_device::write_data_port( UINT8 data)
1048{
1049   if (m_control & FLSH)
1050   {
1051      // flush input data
1052   }
1053   else if ((m_status & HRDY) == 0)
1054   {
1055      // this will happen in ether.dex Test 20/1
1056      LOG(("write_data_port: failed to write tx data (data register not ready), data length=%x status=%x",
1057                  m_tx_data_buffer.get_length(), m_status));
1058   }
1059
1060#if 0
1061   else if (m_command_buffer[0] == CMD_MC_F8)
1062   {
1063      // FIXME: what does it do?
1064      LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data=%02x", m_command_buffer[0], data));
1065   }
1066#endif
1067
1068   else if (m_command_buffer[0] == CMD_MC_F9)
1069   {
1070      switch (m_command_index) {
1071      case 1:
1072         m_command_buffer[m_command_index++] = data;
1073         break;
1074      case 2:
1075         m_command_buffer[m_command_index++] = data;
1076         m_tx_data_length = m_command_buffer[1] + (m_command_buffer[2] << 8);
1077         log_command();
1078         break;
1079      default:
1080         if (!m_tx_data_buffer.append(data))
1081         {
1082            LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x",
1083                        m_tx_data_buffer.get_length()));
1084         }
1085         if (m_tx_data_buffer.get_length() == m_tx_data_length)
1086         {
1087            // CMD_TRANSMIT_PACKET_COMPLETE
1088#if 0
1089            if (m_command_buffer[0] == CMD_MC_F8)
1090            {
1091               // FIXME: what does it do?
1092               LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data length=%x", m_command_buffer[0], m_tx_data_length));
1093            }
1094#endif
1095            m_tx_data_buffer.log("Tx Data");
1096            do_command();
1097         }
1098         break;
1099      }
1100   }
1101   else if (m_command_buffer[0] == CMD_TRANSMIT_PACKET ||
1102         m_command_buffer[0] == CMD_TRANSMIT_PACKET_18)
1103   {
1104      if (!m_tx_data_buffer.append(data))
1105      {
1106         LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x",
1107                     m_tx_data_buffer.get_length()));
1108      }
1109
1110      if (m_tx_data_buffer.get_length() == m_tx_data_length)
1111      {
1112         // CMD_TRANSMIT_PACKET_COMPLETE
1113         m_tx_data_buffer.log("Tx Data");
1114         do_command();
1115      }
1116   }
1117   else if (m_command_buffer[0] == CMD_DOWNLOAD_PROGRAM)
1118   {
1119      if (!m_program_buffer.append(data))
1120      {
1121         LOG(("write_data_port: failed to write program data (buffer size exceeded), data length=%x",
1122                     m_program_buffer.get_length()));
1123      }
1124
1125      if (m_program_buffer.get_length() == m_program_length)
1126      {
1127         m_program_buffer.log("Program Data");
1128         do_command();
1129      }
1130   }
1131   else if (m_tx_data_buffer.get_length() < PORT_DATA_FIFO_SIZE)
1132   {
1133      // write to data fifo
1134      if (!m_tx_data_buffer.append(data))
1135      {
1136         LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x",
1137                     m_tx_data_buffer.get_length()));
1138      }
1139   }
1140   else
1141   {
1142      LOG(("write_data_port: !!! UNEXPECTED !!! command=%x data=%02x", m_command_buffer[0], data));
1143   }
1144
1145   if (m_tx_data_buffer.get_length() >= PORT_DATA_FIFO_SIZE
1146         && m_tx_data_buffer.get_length() >= m_tx_data_length)
1147   {
1148      m_status &= ~HRDY; /* data register not ready */
1149      if (m_tx_data_buffer.get_length() > PORT_DATA_FIFO_SIZE
1150            && m_tx_data_buffer.get_length() > m_tx_data_length)
1151      {
1152         LOG(("write_data_port: port_data tx fifo exhausted, data length=%x status=%x",
1153                     m_tx_data_buffer.get_length(), m_status));
1154      }
1155   }
1156}
1157
1158UINT8 threecom3c505_device::read_data_port(){
1159   UINT8 data;
1160   UINT16 data_length = m_rx_data_buffer.get_length();
1161   // DomainOS will read  words (i.e. even number of bytes); must handle packets with odd byte length
1162   UINT16 even_data_length = (data_length+1) & ~1;
1163
1164   if (m_rx_data_index < even_data_length)
1165   {
1166      // eventually prepend data length (for CMD_MC_E1_RESPONSE)
1167      data = m_rx_data_index == -2 ? (data_length & 0xff) : //
1168            m_rx_data_index == -1 ? (data_length << 8) : //
1169            m_rx_data_buffer.get(m_rx_data_index);
1170
1171      m_rx_data_index++;
1172
1173      if (m_rx_data_index == even_data_length)
1174      {
1175         m_status &= ~HRDY; /* data register no longer ready */
1176         m_rx_data_buffer.log("Rx Data");
1177         m_rx_data_buffer.reset();
1178         set_command_pending(0);
1179      }
1180   }
1181
1182#if 0
1183   else if (m_rx_data_index == data_length && (data_length & 1))
1184   {
1185      // data length is odd, pad with 0 to next even size
1186      data = 0;
1187      m_rx_data_index++;
1188      LOG(("!!!: padding 3C505 Rx Data with odd data length %2x with value %02x", data_length, data));
1189   }
1190#endif
1191
1192   else
1193   {
1194      // FIXME: should never happen
1195      data = 0xff;
1196      m_status &= ~HRDY; /* data register no longer ready */
1197      set_command_pending(0);
1198      LOG(("UNEXPECTED: reading 3C505 data Register as %02x (data_length=%02x)", data, data_length));
1199   }
1200   return data;
1201}
1202
1203void threecom3c505_device::write_control_port( UINT8 data)
1204{
1205   // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x3C4BAD48) verbose = 3;
1206   // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x010464DC) verbose = 3;
1207
1208   if (verbose <= 2 && (data & (DMAE | TCEN /*| CMDE*/)) != 0)
1209   {
1210      // dma or interrupts enabled
1211      LOG1(("writing 3C505 Control Register at offset %02x = %02x", PORT_CONTROL, data));
1212   }
1213
1214   m_status = (m_status & ~DIR_) | (data & DIR_);
1215
1216   switch (data & HSF_PCB_MASK)
1217   {
1218   case HSF_PCB_ACK: // HSF1
1219      break;
1220   case HSF_PCB_NAK: // HSF2
1221      if (m_microcode_running)
1222      {
1223         m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK;
1224      }
1225      break;
1226   case HSF_PCB_END: // (HSF2|HSF1)
1227      m_status &= ~(ATTN | DMAE | ASF_PCB_MASK);
1228      if (m_microcode_running)
1229      {
1230         m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK;
1231      }
1232      break;
1233   default: // 0
1234      m_command_index = 0;
1235      m_status |= HCRE; /* command register empty */
1236
1237      if (data == 0x00)
1238      {
1239         // hardware reset
1240         m_status |= HRDY; /* data register ready */
1241         // flush data register (reset tx data fifo)
1242         m_tx_data_length = 0;
1243         // FIXME: Don't do this (but why?)
1244         // m_tx_data_buffer.reset();
1245      }
1246      else if (data == DIR_)
1247      {
1248         // why?? dex ether 20 expects HRDY
1249         // m_status &= ~HRDY; /* data register not ready */
1250         m_status |= HRDY; /* data register ready */
1251      }
1252      else if (data & FLSH)
1253      {
1254         if (data & DIR_)
1255         {
1256            m_status &= ~HRDY; /* data register not ready */
1257         }
1258         else
1259         {
1260            // flush data register (reset tx data fifo)
1261//            m_tx_data_length = 0;
1262            m_tx_data_buffer.reset();
1263            m_status |= HRDY; /* data register ready */
1264         }
1265      }
1266      break;
1267   }
1268
1269   if ((m_control & (ATTN | FLSH)) == (ATTN | FLSH) && (data & (ATTN | FLSH)) == 0)
1270   {
1271      m_status |= ASF_PCB_END;
1272   }
1273
1274   m_control = data;
1275}
1276
1277UINT8 threecom3c505_device::read_status_port()
1278{
1279   UINT8 data = m_status;
1280   m_status &= ~ASF_PCB_MASK;
1281
1282   switch (data & ASF_PCB_MASK) {
1283   case ASF_PCB_END:
1284      m_status |= ASF_PCB_ACK;
1285      break;
1286   }
1287   return data;
1288}
1289
1290void threecom3c505_device::write_port(offs_t offset, UINT8 data)
1291{
1292   m_reg[offset & 0x0f] = data;
1293   LOG2(("writing 3C505 Register at offset %02x = %02x", offset, data));
1294
1295   switch (offset)
1296   {
1297   case PORT_COMMAND: /* 0x00 read/write, 8-bit */
1298      write_command_port(data);
1299      break;
1300   case PORT_AUXDMA: /* 0x02 write only, 8-bit */
1301      break;
1302   case PORT_DATA: /* 0x04 read/write, 16-bit */
1303   case PORT_DATA + 1: /* 0x04 read/write, 16-bit */
1304      write_data_port(data);
1305      break;
1306   case PORT_CONTROL: /* 0x06 read/write, 8-bit */
1307      write_control_port(data);
1308      break;
1309   default:
1310      break;
1311   }
1312}
1313
1314//READ8_DEVICE_HANDLER( threecom3c505_r )
1315UINT8 threecom3c505_device::read_port(offs_t offset)
1316{
1317   // data to omit excessive logging
1318   static UINT8 last_data = 0xff;
1319   static UINT32 last_pc = 0;
1320
1321   UINT8 data = m_reg[offset & 0x0f];
1322   switch (offset)
1323   {
1324   case PORT_COMMAND: /* 0x00 read/write, 8-bit */
1325      data = read_command_port();
1326      break;
1327   case PORT_STATUS: /* 0x02 read only, 8-bit */
1328      data=read_status_port();
1329
1330      set_interrupt(CLEAR_LINE);
1331
1332      // omit excessive logging
1333      if (data == last_data)
1334      {
1335         UINT32 pc = cpu_get_previouspc(machine().device(MAINCPU));
1336         if (pc == last_pc) {
1337            return data;
1338         }
1339         last_pc = pc;
1340      }
1341      last_data = data;
1342
1343      break;
1344   case PORT_DATA: /* 0x04 read/write, 16-bit */
1345   case PORT_DATA + 1: /* 0x04 read/write, 16-bit */
1346      data = read_data_port();
1347      break;
1348   case PORT_CONTROL: /* 0x06 read/write, 8-bit */
1349      // just return current value
1350      break;
1351   default:
1352      break;
1353   }
1354
1355   LOG2(("reading 3C505 Register at offset %02x = %02x", offset, data));
1356   return data;
1357}
1358
1359//**************************************************************************
1360//  GLOBAL STUBS
1361//**************************************************************************
1362
1363READ8_DEVICE_HANDLER( threecom3c505_r )
1364{
1365   return downcast<threecom3c505_device *> (device)->read_port(offset);
1366}
1367
1368WRITE8_DEVICE_HANDLER( threecom3c505_w )
1369{
1370   downcast<threecom3c505_device *> (device)->write_port(offset, data);
1371}
1372
1373int threecom3c505_receive(device_t *device, const UINT8 data[], int length)
1374{
1375   return downcast<threecom3c505_device *> (device)->threecom3c505_receive(data,length);
1376}
1377
1378void threecom3c505_set_verbose(int on_off)
1379{
1380   verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
1381}
src/mess/machine/3c505.h
r0r14540
1/*
2 * threecom3c505.h - 3COM 3C505 ethernet controller
3 *
4 *  Created on: August 27, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#pragma once
13
14#ifndef THREECOM3C505_H_
15#define THREECOM3C505_H_
16
17#include "emu.h"
18
19#define CMD_BUFFER_SIZE 100
20#define ETH_BUFFER_SIZE 2048
21#define PGM_BUFFER_SIZE 0x2000
22
23#define   ETHERNET_ADDR_SIZE 6                 /* size of ethernet addr */
24
25#define RX_FIFO_SIZE 32
26
27/***************************************************************************
28 FUNCTION PROTOTYPES
29 ***************************************************************************/
30
31READ8_DEVICE_HANDLER( threecom3c505_r );
32WRITE8_DEVICE_HANDLER( threecom3c505_w );
33
34int threecom3c505_receive(device_t *device, const UINT8 *data, int length);
35
36void threecom3c505_set_verbose(int on_off);
37
38//**************************************************************************
39//  DEVICE CONFIGURATION MACROS
40//**************************************************************************
41
42#define MCFG_THREECOM3C505_ADD(_tag, _interface) \
43   MCFG_DEVICE_ADD(_tag, THREECOM3C505, 0) \
44   threecom3c505_device::static_set_interface(*device, _interface);
45
46//**************************************************************************
47//  TYPE DEFINITIONS
48//**************************************************************************
49
50typedef void (*threecom3c505_set_irq)(device_t *, int);
51typedef void (*threecom3c505_tx_init)(device_t *);
52typedef int (*threecom3c505_tx_data)(device_t *, const UINT8 *, int);
53typedef int (*threecom3c505_setfilter)(device_t *, int);
54
55struct threecom3c505_interface
56{
57   threecom3c505_set_irq set_irq;
58   threecom3c505_tx_init tx_init;
59   threecom3c505_tx_data tx_data;
60   threecom3c505_setfilter setfilter;
61};
62
63#define THREECOM3C505_INTERFACE(name) const struct threecom3c505_interface (name)
64
65// ======================> PCB data structure
66
67struct Memconf
68{
69   UINT16 cmd_q, rcv_q, mcast, frame, rcv_b, progs;
70};
71
72struct Rcv_pkt
73{
74   UINT16 buf_ofs, buf_seg, buf_len, timeout;
75};
76
77struct Xmit_pkt
78{
79   UINT16 buf_ofs, buf_seg, pkt_len;
80};
81
82struct Rcv_resp
83{
84   UINT16 buf_ofs, buf_seg, buf_len, pkt_len, timeout, status;
85   UINT32 timetag;
86};
87
88struct Xmit_resp
89{
90   UINT16 buf_ofs, buf_seg, c_stat, status;
91};
92
93struct Netstat
94{
95   UINT32 tot_recv, tot_xmit;
96   UINT16 err_CRC, err_align, err_res, err_ovrrun;
97};
98
99struct Selftest
100{
101   UINT16 error;
102   union
103   {
104      UINT16 ROM_cksum;
105      struct
106      {
107         UINT16 ofs, seg;
108      } RAM;
109      UINT16 i82586;
110   } failure;
111};
112
113struct Info
114{
115   UINT8 minor_vers, major_vers;
116   UINT16 ROM_cksum, RAM_sz, free_ofs, free_seg;
117};
118
119struct Memdump
120{
121   UINT16 size, off, seg;
122};
123
124/*
125 Primary Command Block. The most important data structure. All communication
126 between the host and the adapter is done with these. (Except for the actual
127 Ethernet data, which has different packaging.)
128 */
129typedef struct
130{
131   UINT8 command;
132   UINT8 length;
133   union
134   {
135      struct Memconf memconf;
136      UINT16 configure;
137      struct Rcv_pkt rcv_pkt;
138      struct Xmit_pkt xmit_pkt;
139      UINT8 multicast[10][6];
140      UINT8 eth_addr[6];
141      UINT8 failed;
142      struct Rcv_resp rcv_resp;
143      struct Xmit_resp xmit_resp;
144      struct Netstat netstat;
145      struct Selftest selftest;
146      struct Info info;
147      struct Memdump memdump;
148      UINT8 raw[62];
149   } data;
150} pcb_struct;
151
152// ======================> threecom3c505_device
153
154class threecom3c505_device:  public device_t, public threecom3c505_interface
155{
156public:
157   // construction/destruction
158   threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
159
160   // static configuration helpers
161   static void static_set_interface(device_t &device, const threecom3c505_interface &interface);
162
163   int threecom3c505_receive(const UINT8 data[], int length);
164   // device register I/O
165   UINT8 read_port(offs_t offset);
166   void write_port(offs_t offset, UINT8 data);
167
168private:
169   // device-level overrides
170   virtual void device_start();
171   virtual void device_reset();
172
173   const char *cpu_context();
174
175   class data_buffer_fifo;
176
177    /* data buffer */
178   class data_buffer
179   {
180      friend class data_buffer_fifo;
181
182   public:
183      data_buffer();
184      void start(threecom3c505_device *device, INT32 size);
185      void reset();
186      int append(UINT8 data);
187      UINT8 get(int i) { return m_data[i]; };
188      UINT16 get_word(int i) { return (m_data[i*2+1] << 8) + m_data[i*2]; };
189      int is_empty() {return  m_length == 0; };
190      int is_full() {return  m_length >= m_size; };
191      UINT16 get_length() { return m_length; };
192      UINT16 get_size() { return m_size; };
193      UINT8 *get_data() { return m_data; };
194      void copy(data_buffer *db) const;
195      void log(const char *title) const;
196
197   private:
198      threecom3c505_device *m_device; // pointer back to our device
199      UINT16 m_length;
200      UINT16 m_size;
201      UINT8 *m_data;
202   };
203
204    /* data_buffer fifo (used to buffer the received data) */
205   class data_buffer_fifo
206   {
207   public:
208      data_buffer_fifo();
209      void start(threecom3c505_device *device, INT32 size, INT32 db_size);
210      void reset();
211      int put(const UINT8 data[], const int length);
212      int get(data_buffer *db);
213   private:
214      threecom3c505_device *m_device; // pointer back to our device
215      UINT16 m_size;
216      UINT16 m_count;
217      UINT16 m_get_index;
218      UINT16 m_put_index;
219      data_buffer *m_db[RX_FIFO_SIZE];
220   };
221
222   void set_filter_list();
223   void set_interrupt(enum line_state state);
224   static TIMER_CALLBACK( static_set_interrupt );
225
226   void log_command();
227   void log_response();
228   void log_tx_data();
229   void log_rx_data();
230
231   void do_receive_command();
232   void set_command_pending(int onoff);
233   void do_command();
234
235   int ethernet_packet_is_for_me(const UINT8 mac_address[]);
236
237   void write_command_port( UINT8 data);
238   UINT8 read_command_port();
239   void write_data_port( UINT8 data);
240   UINT8 read_data_port();
241   void write_control_port( UINT8 data);
242   UINT8 read_status_port();
243
244    // pointer to myself (nasty: used for cpu_context)
245   threecom3c505_device *m_device;
246
247   UINT8 m_reg[16];
248
249   UINT8 m_status;
250   UINT8 m_control;
251
252   UINT8 m_command_buffer[CMD_BUFFER_SIZE];
253   int m_command_index;
254   int m_command_pending;
255
256   data_buffer_fifo m_rx_fifo;
257
258   data_buffer m_rx_data_buffer; // the ethernet receive buffer
259   int m_rx_data_index;
260   int m_rx_pending;
261
262   data_buffer m_tx_data_buffer; // the ethernet transmit buffer
263   int m_tx_data_length;
264
265   data_buffer m_program_buffer; // the program data buffer
266   int m_program_length;
267
268   pcb_struct m_response;
269   int m_response_length;
270   int m_response_index;
271
272   UINT16 m_microcode_version;
273   UINT16 m_microcode_running;
274
275   UINT16 m_i82586_config;
276
277   UINT8 m_station_address[ETHERNET_ADDR_SIZE];
278   UINT8 m_multicast_list[ETHERNET_ADDR_SIZE*2];
279   UINT8 m_filter_list[ETHERNET_ADDR_SIZE*4];
280
281   enum line_state irq_state;
282
283   emu_timer * m_timer; // timer to delay interrupts
284};
285
286// device type definition
287extern const device_type THREECOM3C505;
288
289#endif /* THREECOM3C505_H_ */
src/mess/machine/sc499.c
r0r14540
1/*
2 * sc499.c - ARCHIVE SC-499 cartridge tape controller (for Apollo DN3x00)
3 *_DeviceClass
4 *  Created on: April 17, 2011
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also:
11 *  - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf
12 *  - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
13 *  - http://www.bitsavers.org/pdf/archive/20271-001_scorpPrDesc_Mar84.pdf
14 *  - http://www.bitsavers.org/pdf/archive/SidewinderProdDescr.pdf
15 *
16 */
17
18#include "machine/sc499.h"
19
20#define VERBOSE 0
21
22static int verbose = VERBOSE;
23
24#define LOG(x)   { logerror ("%s: ", cpu_context()); logerror x; logerror ("\n"); }
25#define LOG1(x)   { if (verbose > 0) LOG(x)}
26#define LOG2(x)   { if (verbose > 1) LOG(x)}
27#define LOG3(x)   { if (verbose > 2) LOG(x)}
28
29#define  MAINCPU "maincpu"
30
31//**************************************************************************
32//  DEVICE DEFINITIONS
33//**************************************************************************
34
35//const device_type SC499 = sc499_device_config::static_alloc_device_config;
36
37sc499_device *sc499_device::m_device;
38
39//**************************************************************************
40//  CONSTANTS
41//**************************************************************************
42
43// I/O register offsets
44
45#define SC499_PORT_DATA       0x00    // read data (status data)
46#define SC499_PORT_COMMAND    0x00    // write command
47#define SC499_PORT_STATUS     0x01    // read status
48#define SC499_PORT_CONTROL    0x01    // write control
49#define SC499_PORT_DMAGO      0x02    // write only, Start DMA
50#define SC499_PORT_RSTDMA     0x03    // write only, Reset DMA
51
52// Tape Status Byte 0 (LSB)
53
54#define SC499_ST0     0x8000    // 0=> Status byte 0
55#define SC499_ST0_NOC 0x4000    // 1=> Cartridge not in place
56#define SC499_ST0_USD 0x2000    // 1=> Unselected drive
57#define SC499_ST0_WP  0x1000    // 1=> Write protected cartridge
58#define SC499_ST0_EOM 0x0800    // 1=> End of media (EOM)
59#define SC499_ST0_UDE 0x0400    // 1=> Unrecoverable data error
60#define SC499_ST0_BNL 0x0200    // 1=> Bad block not located
61#define SC499_ST0_FM  0x0100    // 1=> Filemark detected
62#define SC499_ST0_MASK 0x7f00
63
64// Tape Status Byte 1 (MSB)
65
66#define SC499_ST1     0x0080    // 1=> Status byte 1
67#define SC499_ST1_ILL 0x0040    // 1=> Illegal command
68#define SC499_ST1_NOD 0x0020    // 1=> No data detected
69#define SC499_ST1_MGN 0x0010    // 1=> Marginal block detected
70#define SC499_ST1_BOM 0x0008    // 1=> Beginning of media (BOM)
71#define SC499_ST1_BPE 0x0004    // 1=> Reserved for bus parity error
72#define SC499_ST1_ERM 0x0002    // 1=> Reserved for end of recorded media
73#define SC499_ST1_POR 0x0001    // 1=> Power on/reset occurred
74#define SC499_ST1_MASK 0x007f
75
76#define SC499_ST_CLEAR_ALL      ~(SC499_ST0_NOC | SC499_ST0_USD | SC499_ST0_WP | SC499_ST0_EOM |  SC499_ST1_BOM)
77#define SC499_ST_READ_ERROR      (SC499_ST0_UDE | SC499_ST0_BNL |  SC499_ST1_NOD)
78
79// Tape Status word
80
81//dc.w $EFFF,$C000 // 3a No cartridge
82//dc.w $FFFF,$F000 // 39 No drive
83//dc.w $FFFF,$8800 // 38 End of media
84//dc.w $EFFF,$8488 // 37 Write abort
85//dc.w $EFFF,$8400 // 36 Read error, bad blk xfer
86//dc.w $EFFF,$8600 // 35 Read error, filler blk xfer
87//dc.w $EFFF,$86A0 // 34 Read error, no data
88//dc.w $EFFF,$8EA0 // 33 Read error, no data and EOM
89//dc.w $EFE9,$86A8 // 32 Read error, no data and BOM
90//dc.w $EFFF,$8100 // 31 Filemark read
91//dc.w $0FF7,$00C0 // 30 Illegal command
92
93// Command Register (write) [50000 | 3FF9C00 ]
94
95#define SC499_CMD_SELECT         0x00   // Select
96#define SC499_CMD_SEL_1          0x01   // select tape 1
97#define SC499_CMD_SEL_2          0x02   // select tape 2
98#define SC499_CMD_SEL_3          0x04   // select tape 3
99#define SC499_CMD_SEL_4          0x08   // select tape 4
100#define SC499_CMD_POSITION       0x20   // Position
101#define SC499_CMD_REWIND         0x21   // rewind tape
102#define SC499_CMD_ERASE          0x22   // erase tape
103#define SC499_CMD_RETEN          0x24   // retension tape
104#define SC499_CMD_WRITE_DATA     0x40   // Write Data
105#define SC499_CMD_WRITE_FILEMARK 0x60   // Write File Mark
106#define SC499_CMD_READ_DATA      0x80   // Read Data
107#define SC499_CMD_READ_FILE_MARK 0xa0   // Read File Mark
108#define SC499_CMD_READ_STATUS    0xc0   // Read Status
109#define SC499_CMD_RESERVED       0xe0   // Reserved
110#define SC499_CMD_NO_COMMAND     0xff   // no command
111
112#define SC499_CMD_TYPE_MASK      0xe0   // command type mask
113#define SC499_CMD_DATA_MASK      0x1f   // command data mask
114
115// Status Register (read only)
116
117#define SC499_STAT_IRQ 0x80   // active high, Interrupt request flag ('or' of rdy and exc), and done if dni is set.
118#define SC499_STAT_RDY 0x40   // active low, Ready from LSI chip.
119#define SC499_STAT_EXC 0x20   // active low, Exception, from LSI chip.
120#define SC499_STAT_DON 0x10   // active high, DMA done (from DMA logic)
121#define SC499_STAT_DIR 0x08   // active high, Direction, indicates direction of bus is from controller to DN3000.
122
123// Control Register (write only) [50001 | 3FF9C01 ]
124
125// Note: All of these bits are cleared automatically when writing to SC499_PORT_RSTDMA.
126// So SC499_CTR_IEN and SC499_CTR_DNI must be reprogrammed before the write to AR_START_DMA_PORT.
127
128#define SC499_CTR_RST 0x80    // 1=> Reset controller microprocessor.
129#define SC499_CTR_REQ 0x40    // 1=> Request to LSI chip.
130#define SC499_CTR_IEN 0x20    // 1=> Enables interrupts.
131#define SC499_CTR_DNI 0x10    // 1=> Enables DONE int, dni = 0 masks DONE int
132
133// ctape device data
134
135#define SC499_CTAPE_TAG "sc499_ctape"
136#define SC499_CTAPE_BLOCK_SIZE 512
137#define SC499_CTAPE_MAX_BLOCK_COUNT (60*1024*1024/SC499_CTAPE_BLOCK_SIZE)
138
139// mean time to read one block from ctape (should be 5-6 msec)
140#define SC499_CTAPE_READ_BLOCK_TIME 6
141
142// Timer type
143#define SC499_TIMER_1 1
144#define SC499_TIMER_2 2
145#define SC499_TIMER_3 3
146#define SC499_TIMER_4 4
147#define SC499_TIMER_5 5
148#define SC499_TIMER_6 6
149#define SC499_TIMER_7 7
150
151typedef struct _ctape_data ctape_data;
152struct _ctape_data
153{
154   device_image_interface *image;
155};
156
157/***************************************************************************
158    IMPLEMENTATION
159***************************************************************************/
160
161// device type definition
162const device_type SC499 = &device_creator<sc499_device>;
163
164//-------------------------------------------------
165// sc499_device - constructor
166//-------------------------------------------------
167
168sc499_device::sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
169    : device_t(mconfig, SC499, "Archive SC-499", tag, owner, clock)
170{
171   memset(static_cast<sc499_interface *>(this), 0, sizeof(sc499_interface));
172}
173
174//-------------------------------------------------
175//  static_set_interface - set the interface struct
176//-------------------------------------------------
177
178void sc499_device::static_set_interface(device_t &device, const sc499_interface &interface)
179{
180   sc499_device &sc499 = downcast<sc499_device &>(device);
181   static_cast<sc499_interface &>(sc499) = interface;
182}
183
184//-------------------------------------------------
185//  device_start - device-specific startup
186//-------------------------------------------------
187
188void sc499_device::device_start()
189{
190   // FIXME: temporary hack: we allow only one device:
191   sc499_device::m_device = this;
192
193   LOG1(("start sc499"));
194
195   m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this);
196   m_timer1 = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this);
197
198   device_t *ctape_device = machine().device(SC499_CTAPE_TAG);
199   ctape_data *ctape = (ctape_data *) downcast<legacy_device_base *> (ctape_device)->token();
200   m_image = ctape->image;
201
202   if (m_image->image_core_file() == NULL)
203   {
204       LOG2(("start sc499: no cartridge tape"));
205   }
206   else
207   {
208       LOG2(("start sc499: cartridge tape image is %s",m_image->filename()));
209   }
210
211   m_ctape_block_buffer = auto_alloc_array(machine(), UINT8, SC499_CTAPE_BLOCK_SIZE);
212   assert(m_ctape_block_buffer!= NULL);
213}
214
215//-------------------------------------------------
216//  device_reset - device-specific reset
217//-------------------------------------------------
218
219void sc499_device::device_reset()
220{
221   LOG1(("reset sc499"));
222
223   m_data = 0;
224   m_command = SC499_CMD_NO_COMMAND;
225   m_status  = SC499_STAT_RDY; // | SC499_STAT_EXC;
226   m_control = 0;
227
228   m_first_block_hack = 1;
229   m_nasty_readahead = 0;
230   m_read_block_pending = 0;
231
232   m_current_command = m_command;
233
234   m_data_error_counter = 0;
235   m_underrun_counter = 0;
236
237   m_image_length = 0;
238
239   check_tape();
240
241   m_data_index = 0;
242   m_ctape_block_index = 0;
243   m_tape_pos = 0;
244
245   irq_state = CLEAR_LINE;
246   dma_drq_state = CLEAR_LINE;
247}
248
249/*-------------------------------------------------
250 cpu_context - return a string describing the current CPU context
251 -------------------------------------------------*/
252
253const char *sc499_device::cpu_context()
254{
255   static char statebuf[64]; /* string buffer containing state description */
256
257   device_t *cpu = machine().device(MAINCPU);
258   osd_ticks_t t = osd_ticks();
259   int s = t / osd_ticks_per_second();
260   int ms = (t % osd_ticks_per_second()) / 1000;
261
262   /* if we have an executing CPU, output data */
263   if (cpu != NULL)
264   {
265      sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
266            cpu_get_previouspc(cpu), tag());
267   }
268   else
269   {
270      sprintf(statebuf, "%d.%03d", s, ms);
271   }
272   return statebuf;
273}
274
275/*-------------------------------------------------
276 tape_status_clear - clear bits in tape status
277 -------------------------------------------------*/
278
279void sc499_device::tape_status_clear(UINT16 value)
280{
281   m_tape_status &= ~value;
282   tape_status_set(0);
283}
284
285/*-------------------------------------------------
286 tape_status_set - set bits in tape status
287 -------------------------------------------------*/
288
289void sc499_device::tape_status_set(UINT16 value)
290{
291   m_tape_status |= value;
292   m_tape_status &= ~(SC499_ST0 | SC499_ST1);
293   if (m_tape_status & SC499_ST0_MASK)
294   {
295      m_tape_status |= SC499_ST0;
296   }
297   if (m_tape_status & SC499_ST1_MASK)
298   {
299      m_tape_status |= SC499_ST1;
300   }
301}
302
303/*-------------------------------------------------
304 check_tape - check tape
305 -------------------------------------------------*/
306
307void sc499_device::check_tape()
308{
309   m_tape_status = 0;
310   m_is_writable = m_image->exists() && m_image->is_writeable();
311
312   if (m_image->exists())
313   {
314      m_has_cartridge = 1; // we have a cartridge
315      tape_status_set(SC499_ST1_BOM); // Beginning of media (BOM)
316      if (!m_is_writable)
317      {
318         tape_status_set(SC499_ST0_WP);
319      }
320
321      if (m_image_length != m_image->length())
322      {
323         // tape has changed, get new size
324         m_image_length = m_image->length();
325         m_ctape_block_count = (UINT32)((m_image_length+SC499_CTAPE_BLOCK_SIZE-1) / SC499_CTAPE_BLOCK_SIZE);
326      }
327
328      LOG1(("check_tape: tape image is %s with %d blocks", m_image->filename(), m_ctape_block_count));
329   }
330   else
331   {
332      m_has_cartridge = 0; // we have no cartridge
333      tape_status_set(SC499_ST0_NOC); // Cartridge not in place
334      m_image_length = 0;
335      m_ctape_block_count = 0;
336
337       LOG1(("check_tape: no cartridge tape"));
338   }
339}
340
341/*-------------------------------------------------
342 timer_func - handle timer interrupts
343 -------------------------------------------------*/
344
345void sc499_device::timer_func(int timer_type)
346{
347   LOG2(("timer_func param=%d status=%x",timer_type, m_status));
348
349   switch (timer_type)
350   {
351   case SC499_TIMER_1: // set ready
352      m_status &= ~SC499_STAT_RDY;
353      if (m_control & SC499_CTR_IEN)
354      {
355         set_interrupt(ASSERT_LINE);
356         m_status |= SC499_STAT_IRQ;
357      }
358      break;
359
360   case SC499_TIMER_2: // set exception, clear interrupt (?)
361      m_status &= ~SC499_STAT_EXC;
362      m_status &= ~SC499_STAT_IRQ;
363      break;
364
365   case SC499_TIMER_3: // start dma to read data
366      set_dma_drq(ASSERT_LINE);
367      m_status |= SC499_STAT_RDY;
368      break;
369
370   case SC499_TIMER_4: // ready to read next status byte
371      m_status &= ~SC499_STAT_RDY;
372
373      switch (++m_data_index)
374      {
375      case 1: m_data = m_tape_status >> 8;  break;
376      case 2: m_data = m_tape_status & 0xff;    break;
377      case 3: m_data = m_data_error_counter >> 8; break;
378      case 4: m_data = m_data_error_counter & 0xff; break;
379      case 5: m_data = m_underrun_counter >> 8; break;
380      case 6: m_data = m_underrun_counter & 0xff; break;
381      default:
382         m_data_index=0;
383         m_command = SC499_CMD_NO_COMMAND;
384         m_current_command = m_command;
385         m_status &= ~SC499_STAT_DIR;
386         tape_status_clear(SC499_ST_CLEAR_ALL);
387         break;
388      }
389
390      if (m_control & SC499_CTR_IEN)
391      {
392         set_interrupt(ASSERT_LINE);
393         m_status |= SC499_STAT_IRQ;
394      }
395      break;
396
397   case SC499_TIMER_5: // read next data block for SC499_CMD_READ_DATA
398   case SC499_TIMER_6: // read next data block for SC499_CMD_READ_FILE_MARK
399      if (m_read_block_pending && (m_status & SC499_STAT_DIR))
400      {
401         // handle data underruns in a loaded Apollo emulation
402         // the real ctape will stop, go back and restart reading if appropriate
403         if (++m_underrun_counter >= 5000)
404         {
405            // stop tape (after 30 seconds) - probably the DMA handshake failed.
406            m_timer1->adjust(attotime::never, timer_type, attotime::never);
407            m_status &= ~SC499_STAT_EXC;
408            m_status &= ~SC499_STAT_DIR;
409            tape_status_clear(SC499_ST_CLEAR_ALL);
410            tape_status_set(SC499_ST_READ_ERROR);
411
412            LOG(("timer_func param=%d status=%x tape_pos=%d - read data underrun aborted at %d",
413                  timer_type, m_status, m_tape_pos, m_underrun_counter));
414         }
415         else
416         {
417            LOG2(("timer_func param=%d status=%x tape_pos=%d - read data underrun %d",
418                  timer_type, m_status, m_tape_pos, m_underrun_counter));
419         }
420         break;
421      }
422      else if ( m_tape_pos > m_ctape_block_count || !(m_status & SC499_STAT_RDY))
423      {
424         LOG1(("timer_func param=%d status=%x tape_pos=%d - end-of-tape or not ready",
425                        timer_type, m_status, m_tape_pos));
426         m_timer1->adjust(attotime::never, timer_type, attotime::never);
427         m_status &= ~SC499_STAT_EXC;
428         m_status &= ~SC499_STAT_DIR;
429         tape_status_clear(SC499_ST_CLEAR_ALL);
430         tape_status_set(SC499_ST_READ_ERROR);
431      }
432      else if (m_nasty_readahead > 0 )
433      {
434         m_nasty_readahead = 0;
435      }
436      else
437      {
438         if  (m_underrun_counter > 0)
439         {
440            LOG1(("timer_func param=%d status=%x tape_pos=%d - read data underrun ended at %d",
441                  timer_type, m_status, m_tape_pos, m_underrun_counter));
442         }
443
444         read_block();
445         m_underrun_counter = 0;
446         if (block_is_filemark())
447         {
448            m_timer1->adjust(attotime::never, timer_type, attotime::never);
449         }
450         else if (m_current_command == SC499_CMD_READ_DATA)
451         {
452            m_read_block_pending = 1;
453            m_status &= ~SC499_STAT_RDY;
454         }
455      }
456
457      if (m_control & SC499_CTR_IEN)
458      {
459         if (m_current_command == SC499_CMD_READ_DATA || (m_status & SC499_STAT_EXC) == 0)
460         {
461            set_interrupt(ASSERT_LINE);
462            m_status |= SC499_STAT_IRQ;
463         }
464      }
465
466      break;
467
468   case SC499_TIMER_7: // reset
469       // set exception
470      m_status &= ~SC499_STAT_EXC;
471      if (m_control & SC499_CTR_IEN)
472      {
473         set_interrupt(ASSERT_LINE);
474         m_status |= SC499_STAT_IRQ;
475      }
476      break;
477
478   default:
479      LOG(("timer_func param=%d UNEXPECTED",timer_type));
480      m_timer->reset();
481      break;
482   }
483
484}
485
486TIMER_CALLBACK( sc499_device::static_timer_func )
487{
488   reinterpret_cast<sc499_device *> (ptr)->timer_func(param);
489}
490
491/*-------------------------------------------------
492 set_interrupt - set the IRQ state
493 -------------------------------------------------*/
494
495void sc499_device::set_interrupt(enum line_state state)
496{
497   if (set_irq != NULL && state != irq_state)
498   {
499      LOG2(("set_interrupt(%d)",state));
500      (*set_irq)(this, state);
501      irq_state = state;
502   }
503}
504
505/*-------------------------------------------------
506 set_dma_drq - set dma request output
507 -------------------------------------------------*/
508
509void sc499_device::set_dma_drq(enum line_state state)
510{
511   if (dma_drq != NULL && state != dma_drq_state)
512   {
513      LOG2(("set_dma_drq(%d)",state));
514      (*dma_drq)(this, state);
515      dma_drq_state = state;
516   }
517}
518
519// -------------------------------------
520
521void sc499_device::log_command(UINT8 data)
522{
523   switch (data)
524   {
525   case SC499_CMD_SELECT:
526   case SC499_CMD_SEL_1:
527   case SC499_CMD_SEL_2:
528   case SC499_CMD_SEL_3:
529   case SC499_CMD_SEL_4:
530      LOG1(("write_command_port: %02x Select %x", data, data & 0x1f));
531      break;
532   case SC499_CMD_REWIND: // rewind tape
533      LOG1(("write_command_port: %02x Rewind Tape", data));
534      break;
535   case SC499_CMD_ERASE:  // erase tape
536      LOG1(("write_command_port: %02x Erase Tape", data));
537      break;
538   case SC499_CMD_RETEN:  // retention tape
539      LOG1(("write_command_port: %02x Retention Tape", data));
540      break;
541   case SC499_CMD_WRITE_DATA:
542      LOG1(("write_command_port: %02x Write Data %d ...", data, m_tape_pos));
543      break;
544   case SC499_CMD_WRITE_FILEMARK:
545      LOG1(("write_command_port: %02x Write File Mark %d", data, m_tape_pos));
546      break;
547   case SC499_CMD_READ_DATA:
548      LOG1(("write_command_port: %02x Read Data %d ...", data, m_tape_pos));
549      break;
550   case SC499_CMD_READ_FILE_MARK:
551      LOG1(("write_command_port: %02x Read File Mark %d", data, m_tape_pos));
552      break;
553   case SC499_CMD_READ_STATUS:
554      LOG1(("write_command_port: %02x Read Status (%04x %04x %04x)", data,
555            m_tape_status, m_data_error_counter, m_underrun_counter));
556      break;
557   case SC499_CMD_RESERVED: // Reserved
558   default:
559      LOG(("write_command_port: %02x Unexpected Command!", data));
560      break;
561   }
562}
563
564void sc499_device::do_command(UINT8 data)
565{
566   m_status |= SC499_STAT_RDY;
567   m_status &= ~SC499_STAT_DON;
568   m_read_block_pending = 0;
569
570   switch (data & SC499_CMD_TYPE_MASK)
571   {
572   case SC499_CMD_SELECT:
573      m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1);
574      break;
575
576   case SC499_CMD_POSITION:
577      switch (data)
578      {
579      case SC499_CMD_REWIND: // rewind tape
580         break;
581      case SC499_CMD_ERASE:  // erase tape
582         // TODO:
583         break;
584      case SC499_CMD_RETEN:  // retention tape
585         break;
586      }
587      m_first_block_hack = 0;
588      m_tape_pos = 0;
589      tape_status_clear(SC499_ST_CLEAR_ALL);
590      tape_status_set(SC499_ST1_BOM);
591
592      m_timer->adjust(attotime::from_msec(500), SC499_TIMER_4);
593      break;
594
595   case SC499_CMD_WRITE_DATA:
596      if (!m_is_writable)
597      {
598         m_status &= ~SC499_STAT_EXC;
599      }
600      m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1);
601      break;
602
603   case SC499_CMD_WRITE_FILEMARK:
604      if (!m_is_writable)
605      {
606         m_status &= ~SC499_STAT_EXC;
607      }
608      else
609      {
610         block_set_filemark();
611         write_block();
612      }
613      m_timer->adjust( attotime::from_msec(100), SC499_TIMER_1);
614      break;
615
616   case SC499_CMD_READ_DATA:
617      m_status |= SC499_STAT_DIR;
618      // start reading blocks from tape
619      m_nasty_readahead = 0;
620      m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_5, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME));
621      break;
622
623   case SC499_CMD_READ_FILE_MARK:
624      if (m_current_command == SC499_CMD_READ_DATA)
625      {
626         // SC499_CMD_READ_DATA pending
627         m_status &= ~SC499_STAT_DIR;
628         LOG1(("do_command: Read data -> Read File Mark at %d", m_tape_pos));
629      }
630      else
631      {
632         // start reading blocks from tape
633         m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_6, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME));
634      }
635      break;
636
637   case SC499_CMD_READ_STATUS:
638      m_status |= SC499_STAT_DIR;
639      m_status |= SC499_STAT_EXC;
640
641      set_interrupt(CLEAR_LINE);
642      set_dma_drq(CLEAR_LINE);
643      m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never);
644
645      m_data_index = 0;
646      m_timer->adjust( attotime::from_usec(100), SC499_TIMER_4);
647      break;
648
649   default:
650      tape_status_clear(SC499_ST_CLEAR_ALL);
651      tape_status_set(SC499_ST1 | SC499_ST1_ILL);
652      m_status &= ~SC499_STAT_EXC;
653      // Note: 100 usec is too fast for DN3000
654      m_timer->adjust( attotime::from_usec(200), SC499_TIMER_1);
655      break;
656   }
657}
658
659// -------------------------------------
660
661void sc499_device::do_reset()
662{
663   LOG1(("do_reset: Reset controller microprocessor"));
664
665   m_data = 0;
666   m_command = SC499_CMD_NO_COMMAND;
667   m_current_command = m_command;
668   m_status = ~(SC499_STAT_DIR | SC499_STAT_EXC);
669   m_control = 0;
670
671   if (m_has_cartridge)
672   {
673      tape_status_set(SC499_ST1_POR | SC499_ST1_BOM);
674   }
675
676   m_tape_pos = 0;
677   m_data_error_counter = 0;
678   m_underrun_counter = 0;
679
680   set_interrupt(CLEAR_LINE);
681   set_dma_drq(CLEAR_LINE);
682
683   m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never);
684}
685
686// -------------------------------------
687
688void sc499_device::write_command_port(UINT8 data)
689{
690   m_command = data;
691   log_command(data);
692}
693
694UINT8 sc499_device::read_data_port()
695{
696   static UINT8 m_last_data = 0xff;
697
698   // omit excessive logging
699   if (m_last_data != m_data)
700   {
701      LOG2(("read_data_port: %02x", m_data));
702      m_last_data = m_data;
703   }
704
705   if (m_control & SC499_CTR_IEN)
706   {
707      set_interrupt(CLEAR_LINE);
708      m_status &= ~SC499_STAT_IRQ;
709   }
710
711   return m_data;
712}
713
714void sc499_device::write_control_port( UINT8 data)
715{
716   LOG2(("write_control_port: %02x", data));
717
718   if ((data ^ m_control) & SC499_CTR_RST)
719   {
720      if (data & SC499_CTR_RST)
721      {
722         // SC499_CTR_RST has changed to 1
723         do_reset();
724      }
725      else
726      {
727         m_status |= SC499_STAT_EXC;
728         m_timer->adjust(attotime::from_msec(200), SC499_TIMER_7);
729      }
730   }
731
732   if ((data ^ m_control) & SC499_CTR_REQ)
733   {
734      // Request to LSI chip has changed
735      if (data & SC499_CTR_REQ)
736      {
737         LOG3(("write_control_port: Request to LSI chip = On"));
738
739         if (m_command == SC499_CMD_READ_STATUS) {
740            m_status |= SC499_STAT_EXC;
741         }
742
743         if (m_command == SC499_CMD_READ_FILE_MARK && m_current_command == SC499_CMD_READ_DATA)
744         {
745            m_current_command= SC499_CMD_READ_FILE_MARK;
746            m_status &= ~SC499_STAT_DIR;
747         }
748
749         if (!(m_status & SC499_STAT_DIR))
750         {
751            // write command and command data
752            // (SC499_STAT_RDY follows SC499_CTR_REQ)
753            m_status &= ~SC499_STAT_RDY;
754         }
755         else
756         {
757            m_status |= SC499_STAT_RDY;
758         }
759      }
760      else
761      {
762         LOG2(("write_control_port: Request to LSI chip = Off (%d)", m_data_index));
763
764         if (!(m_status & SC499_STAT_DIR))
765         {
766            do_command(m_command);
767            m_current_command = m_command;
768         }
769         else if (m_command == SC499_CMD_READ_STATUS)
770         {
771//            if (m_data_index > 0)
772            {
773               m_timer->adjust( attotime::from_usec(20), SC499_TIMER_4);
774            }
775         }
776      }
777   }
778   m_control = data;
779}
780
781UINT8 sc499_device::read_status_port()
782{
783   static UINT8 m_last_status = 0xff;
784
785   // omit excessive logging
786   if (m_last_status != m_status)
787   {
788      LOG2(("read_status_port: %02x", m_status));
789      m_last_status = m_status;
790   }
791
792   // reset pending interrupts
793   set_interrupt(CLEAR_LINE);
794   m_status &= ~SC499_STAT_IRQ;
795
796   return m_last_status;
797}
798
799// Start DMA (DMAGO). Any write to this register will cause DMAGO to be active.
800
801void sc499_device::write_dma_go( UINT8 data)
802{
803   LOG2(("write_dma_go: %02x", data));
804
805   m_status &= ~SC499_STAT_DON;
806
807   switch (data)
808   {
809   case 0:
810      // delay set_dma_drq(ASSERT_LINE);
811      // Note: 200 usec may fail for MD LD; 400 usec may fail for RBAK_SHELL; 500 usec may fail for DN3000
812      m_timer->adjust( attotime::from_msec(1), SC499_TIMER_3);
813
814// Note: proper sequence is:
815//      pc=3c4ad714 - ctape: write_dma_go: 00
816//      pc=3c4ad718 - ctape: write_control_port: 30
817//      pc=3c40ebda: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 00
818//      pc=3c40ebe8: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 22
819//      pc=3c40ebf4: apollo_dma_1_w: writing DMA Controller 1 at offset 0c = 00
820//      pc=3c40ec04: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = ff
821//      pc=3c40ec12: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = 01
822//      pc=3c40ec1e: apollo_dma_1_w: writing DMA Controller 1 at offset 0b = 45
823//      pc=3c40ec2e: apollo_dma_1_w: writing DMA Controller 1 at offset 0a = 01
824//      pc=3c41a154 - ctape: timer_func param=3 status=2f
825//      pc=3c41a154 - ctape: set_dma_drq(1)
826//      pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=1
827//      pc=3c41a154 - ctape: dack_read: data[0]=55 status=6f
828//      pc=3c41a154: dma write byte at offset 17f9c00+200 = 55
829//      pc=3c41a154: dma write byte at offset 17f9c00+2ff = 6d
830//      pc=3c41a154: dma write byte at offset 17f9c00+300 = 65
831//      pc=3c41a154 - ctape: dack_read: data[511]=60 status=6f
832//      pc=3c41a154: dma write byte at offset 17f9c00+3ff = 60
833//      pc=3c41a154 - dma8237_1: dma out eop state 00
834//      pc=3c41a154 - ctape: set_tc_state: block=21 state=0
835//      pc=3c41a154 - ctape: set_dma_drq(0)
836//      pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=0
837//      pc=3c41a154 - dma8237_1: dma out eop state 01
838//      pc=3c41a154 - ctape: set_tc_state: block=21 state=1
839
840      break;
841   }
842}
843
844// Reset DMA (RSTDMA). Any write to this register will cause RSTDMA to be active.
845
846void sc499_device::write_dma_reset( UINT8 data)
847{
848   LOG2(("write_dma_reset: %02x", data));
849
850   m_status &= ~SC499_STAT_DON;
851   m_control = 0;
852}
853
854void sc499_device::write_port(offs_t offset, UINT8 data)
855{
856   switch (offset)
857   {
858   case SC499_PORT_COMMAND: // write command
859      write_command_port(data);
860      break;
861   case SC499_PORT_CONTROL: // write control
862      write_control_port(data);
863      break;
864   case SC499_PORT_DMAGO: // write only, Start DMA
865      write_dma_go(data);
866      break;
867   case SC499_PORT_RSTDMA: // write only, Reset DMA
868      write_dma_reset(data);
869      break;
870   default:
871      LOG(("writing sc499 Register at offset %02x = %02x", offset, data));
872      break;
873   }
874}
875
876//READ8_DEVICE_HANDLER( sc499_r )
877UINT8 sc499_device::read_port(offs_t offset)
878{
879   UINT8 data = 0xff;
880
881   switch (offset)
882   {
883   case SC499_PORT_DATA: // read data (status data)
884      data = read_data_port();
885      break;
886   case SC499_PORT_STATUS: // read status
887      data=read_status_port();
888//      set_interrupt(CLEAR_LINE);
889      break;
890   default:
891      LOG(("reading sc499 Register at offset %02x = %02x", offset, data));
892      break;
893   }
894
895   return data;
896}
897
898void sc499_device::set_tc_state(int state)
899{
900   LOG2(("set_tc_state: block=%d state=%x", m_tape_pos-1, state));
901   if (state == 0)
902   {
903      m_status |= SC499_STAT_DON; // 37ec
904      set_dma_drq(CLEAR_LINE);
905
906      switch (m_current_command & SC499_CMD_TYPE_MASK)
907      {
908      case SC499_CMD_READ_DATA:
909         m_read_block_pending = 0;
910         break;
911
912      case SC499_CMD_WRITE_DATA:
913         m_status &= ~SC499_STAT_RDY;
914         if ((m_control & SC499_CTR_IEN) && (m_control & SC499_CTR_DNI))
915         {
916            set_interrupt(ASSERT_LINE);
917            m_status | SC499_STAT_IRQ;
918         }
919         break;
920      }
921   }
922}
923
924UINT8 sc499_device::dack_read() {
925   UINT8 data = 0xff;
926
927//   set_dma_drq(CLEAR_LINE);
928
929   if (m_ctape_block_index >= SC499_CTAPE_BLOCK_SIZE)
930   {
931      LOG3(("dack_read: read_block"));
932      read_block();
933      m_nasty_readahead++;
934
935      if (block_is_filemark())
936      {
937         set_dma_drq(CLEAR_LINE);
938         m_status &= ~SC499_STAT_EXC;
939         m_status &= ~SC499_STAT_DIR;
940      }
941   }
942
943   data = m_ctape_block_buffer[m_ctape_block_index++];
944   if (m_ctape_block_index < 2 || m_ctape_block_index > 511)
945   {
946      LOG2(("dack_read: data[%d]=%x status=%x",  m_ctape_block_index-1, data, m_status));
947   }
948
949//   if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE)
950//   {
951//      set_dma_drq(ASSERT_LINE);
952//   }
953
954   return data;
955}
956
957void sc499_device::dack_write(UINT8 data) {
958   LOG3(("dack_write: data=%x", data));
959
960   if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE)
961   {
962      m_ctape_block_buffer[m_ctape_block_index++] = data;
963   }
964
965   if (m_ctape_block_index == SC499_CTAPE_BLOCK_SIZE)
966   {
967      LOG3(("dack_write: write_block"));
968      write_block();
969   }
970}
971
972/*-------------------------------------------------
973 log_block - log block data
974 -------------------------------------------------*/
975
976void sc499_device::log_block(const char *text)
977{
978   int data_length = 16;
979
980   if (verbose > 0) {
981      int i;
982      logerror("%s: %s %d -", cpu_context(), text, m_tape_pos);
983      for (i = 0; i < data_length && i < SC499_CTAPE_BLOCK_SIZE; i++) {
984         logerror(" %02x", m_ctape_block_buffer[i]);
985      }
986
987      if (i < SC499_CTAPE_BLOCK_SIZE) {
988         logerror(" ...");
989      }
990
991      if (m_ctape_block_index > 0 && m_ctape_block_index != SC499_CTAPE_BLOCK_SIZE)
992      {
993         logerror(" block_index = %d !!!", m_ctape_block_index);
994      }
995
996      logerror("\n");
997   }
998}
999
1000/*-------------------------------------------------
1001 read_block - read block from m_tape_pos to m_ctape_block_buffer
1002 -------------------------------------------------*/
1003
1004void sc499_device::read_block()
1005{
1006   if (m_tape_pos == 0)
1007   {
1008      // check if tape has been replaced or removed
1009      check_tape();
1010   }
1011
1012   m_image->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET);
1013
1014   if (m_image->image_feof())
1015   {
1016      m_status &= ~SC499_STAT_EXC;
1017      m_status &= ~SC499_STAT_DIR;
1018      m_status &= ~SC499_STAT_DON;
1019      tape_status_clear(SC499_ST_CLEAR_ALL);
1020      tape_status_set(SC499_ST_READ_ERROR);
1021   }
1022   else
1023   {
1024      m_image->fread(m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE);
1025
1026      //   if (verbose > 1 || m_tape_pos % 100 == 0)
1027      {
1028         log_block("read_block");
1029      }
1030
1031      m_ctape_block_index = 0;
1032      m_tape_pos++;
1033
1034      if (m_first_block_hack)
1035      {
1036         // FIXME: we must read first block twice (in MD for 'di c' and 'ld' or 'ex ...')
1037         // why is this necessary???
1038         m_tape_pos = 0;
1039         LOG(("read_block - duplicating block %d", m_tape_pos));
1040      }
1041      m_first_block_hack = 0;
1042
1043      // we are no longer at Beginning of media (BOM)
1044      tape_status_clear(SC499_ST1_BOM);
1045
1046      if (block_is_filemark())
1047      {
1048         m_status &= ~SC499_STAT_EXC;
1049         m_status &= ~SC499_STAT_DIR;
1050         tape_status_clear(SC499_ST_CLEAR_ALL);
1051         tape_status_set(SC499_ST0_FM);
1052      }
1053      else
1054      {
1055         tape_status_clear(SC499_ST0_FM);
1056      }
1057   }
1058   //   if (m_tape_pos == 69400) verbose = 2;
1059}
1060
1061/*-------------------------------------------------
1062 write_block - write block from m_ctape_block_buffer to m_tape_pos
1063 -------------------------------------------------*/
1064
1065void sc499_device::write_block()
1066{
1067   log_block("write_block");
1068
1069   if (m_tape_pos == 0)
1070   {
1071      // check if tape has been replaced or removed
1072      check_tape();
1073   }
1074
1075   m_image->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET);
1076   m_image->fwrite(m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE);
1077   m_ctape_block_count = m_tape_pos;
1078   m_ctape_block_index = 0;
1079   m_tape_pos++;
1080
1081   // we are no longer at Beginning of media (BOM)
1082   tape_status_clear(SC499_ST1_BOM);
1083}
1084
1085/*-------------------------------------------------
1086 block_is_filemark - returns 1 is current block buffer data is filemark
1087 -------------------------------------------------*/
1088
1089int sc499_device::block_is_filemark()
1090{
1091   static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED};
1092
1093   int is_filemark = memcmp(m_ctape_block_buffer, fm_pattern, 4) == 0 &&
1094         memcmp(m_ctape_block_buffer, m_ctape_block_buffer+4, SC499_CTAPE_BLOCK_SIZE-4) == 0;
1095
1096   LOG3(("block_is_filemark for block %d = %d", m_tape_pos-1, is_filemark));
1097   return is_filemark;
1098}
1099
1100/*-------------------------------------------------
1101 block_set_filemark - set current block buffer data to filemark
1102 -------------------------------------------------*/
1103
1104void sc499_device::block_set_filemark()
1105{
1106   static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED};
1107
1108   memcpy(m_ctape_block_buffer, fm_pattern, 4);
1109   memcpy(m_ctape_block_buffer+4, m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE-4);
1110}
1111
1112//**************************************************************************
1113//  GLOBAL STUBS
1114//**************************************************************************
1115
1116READ8_DEVICE_HANDLER( sc499_r )
1117{
1118   return downcast<sc499_device *> (device)->read_port(offset);
1119}
1120
1121WRITE8_DEVICE_HANDLER( sc499_w )
1122{
1123   downcast<sc499_device *> (device)->write_port(offset, data);
1124}
1125
1126void sc499_set_tc_state(running_machine *machine, int state)
1127{
1128   sc499_device::m_device->set_tc_state(state);
1129}
1130
1131UINT8 sc499_dack_r(running_machine *machine)
1132{
1133   return sc499_device::m_device->dack_read();
1134}
1135
1136void sc499_dack_w(running_machine *machine, UINT8 data)
1137{
1138   sc499_device::m_device->dack_write(data);
1139}
1140
1141void sc499_set_verbose(int on_off)
1142{
1143   verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
1144}
1145
1146//##########################################################################
1147
1148DECLARE_LEGACY_IMAGE_DEVICE(SC499_CTAPE, sc499_ctape);
1149
1150/*-------------------------------------------------
1151    ctape device start callback
1152-------------------------------------------------*/
1153
1154static DEVICE_START( sc499_ctape )
1155{
1156   assert(device != NULL);
1157   assert(device->type() == SC499_CTAPE);
1158   ctape_data *ctape = (ctape_data *) downcast<legacy_device_base *>(device)->token();
1159
1160   ctape->image = dynamic_cast<device_image_interface *> (device);
1161}
1162
1163/*-------------------------------------------------
1164    ctape device get info callback
1165-------------------------------------------------*/
1166
1167DEVICE_GET_INFO( sc499_ctape )
1168{
1169   switch (state)
1170   {
1171      /* --- the following bits of info are returned as 64-bit signed integers --- */
1172      case DEVINFO_INT_TOKEN_BYTES:         info->i = sizeof(ctape_data); break;
1173      case DEVINFO_INT_INLINE_CONFIG_BYTES:   info->i = 0; break;
1174      case DEVINFO_INT_IMAGE_TYPE:         info->i = IO_MAGTAPE; break;
1175      case DEVINFO_INT_IMAGE_READABLE:      info->i = 1; break;
1176      case DEVINFO_INT_IMAGE_WRITEABLE:      info->i = 1; break;
1177      case DEVINFO_INT_IMAGE_CREATABLE:      info->i = 1; break;
1178
1179      /* --- the following bits of info are returned as pointers to data or functions --- */
1180      case DEVINFO_FCT_START:               info->start = DEVICE_START_NAME(sc499_ctape); break;
1181
1182      /* --- the following bits of info are returned as NULL-terminated strings --- */
1183      case DEVINFO_STR_NAME:               strcpy(info->s, "Cartridge Tape");   break;
1184      case DEVINFO_STR_FAMILY:            strcpy(info->s, "Cartridge Tape");   break;
1185      case DEVINFO_STR_VERSION:            strcpy(info->s, "1.0");            break;
1186
1187      case DEVINFO_STR_IMAGE_INSTANCE_NAME:      strcpy(info->s, "ctape");      break;
1188      case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME:   strcpy(info->s, "ct");         break;
1189      case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:      strcpy(info->s, "act");       break;
1190   }
1191}
1192
1193DEFINE_LEGACY_IMAGE_DEVICE(SC499_CTAPE, sc499_ctape);
1194
1195MACHINE_CONFIG_FRAGMENT( sc499_ctape )
1196   MCFG_DEVICE_ADD(SC499_CTAPE_TAG, SC499_CTAPE, 0)
1197MACHINE_CONFIG_END
src/mess/machine/sc499.h
r0r14540
1/*
2 * sc499.h - Archive Cartridge tape controller SC-499
3 *
4 *  Created on: February 21, 2011
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#pragma once
13
14#ifndef SC499_H_
15#define SC499_H_
16
17#include "emu.h"
18
19/***************************************************************************
20 FUNCTION PROTOTYPES
21 ***************************************************************************/
22
23READ8_DEVICE_HANDLER( sc499_r );
24WRITE8_DEVICE_HANDLER( sc499_w );
25
26void sc499_set_tc_state(running_machine *machine, int state);
27UINT8 sc499_dack_r(running_machine *machine);
28void sc499_dack_w(running_machine *machine, UINT8 data);
29
30void sc499_set_verbose(int on_off);
31
32//**************************************************************************
33//  DEVICE CONFIGURATION MACROS
34//**************************************************************************
35
36#define MCFG_SC499_ADD(_tag, _interface) \
37   MCFG_FRAGMENT_ADD( sc499_ctape ) \
38   MCFG_DEVICE_ADD(_tag, SC499, 0) \
39   sc499_device::static_set_interface(*device, _interface);
40
41//**************************************************************************
42//  TYPE DEFINITIONS
43//**************************************************************************
44
45typedef void (*sc499_set_irq)(const device_t *, int);
46typedef void (*sc499_dma_drq)(const device_t *,int);
47
48struct sc499_interface
49{
50   sc499_set_irq set_irq;
51   sc499_dma_drq dma_drq;
52   device_t *(*get_device)(running_machine*);
53};
54
55#define SC499_INTERFACE(name) const struct sc499_interface (name)
56
57// ======================> sc499_device
58
59class sc499_device: public device_t, public sc499_interface
60{
61public:
62   // construction/destruction
63   sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
64
65   // static configuration helpers
66   static void static_set_interface(device_t &device, const sc499_interface &interface);
67
68   int sc499_receive(const UINT8 data[], int length);
69   // device register I/O
70   UINT8 read_port(offs_t offset);
71   void write_port(offs_t offset, UINT8 data);
72
73   void set_tc_state(int state);
74   UINT8 dack_read();
75   void dack_write( UINT8 data);
76
77   // static pointer to myself (nasty: used for logging and dma ...)
78   static sc499_device *m_device;
79
80private:
81   // device-level overrides
82   virtual void device_start();
83   virtual void device_reset();
84
85   const char *cpu_context();
86
87   void tape_status_clear(UINT16 value);
88   void tape_status_set(UINT16 value);
89
90   void check_tape();
91
92   void timer_func(int param);
93   static TIMER_CALLBACK( static_timer_func );
94
95   void set_interrupt(enum line_state state);
96
97   void log_command(UINT8 data);
98   void do_command(UINT8 data);
99   void do_reset();
100
101   void set_dma_drq(enum line_state state);
102
103   void write_command_port( UINT8 data);
104   UINT8 read_data_port();
105   void write_control_port( UINT8 data);
106   UINT8 read_status_port();
107   void write_dma_go( UINT8 data);
108   void write_dma_reset( UINT8 data);
109
110   void log_block(const char * text);
111   void read_block();
112   void write_block();
113   int block_is_filemark();
114   void block_set_filemark();
115
116   UINT8 m_data;
117   UINT8 m_command;
118   UINT8 m_status;
119   UINT8 m_control;
120
121   UINT8 m_has_cartridge;
122   UINT8 m_is_writable;
123
124   UINT8 m_current_command;
125
126   UINT8 m_first_block_hack;
127   UINT8 m_nasty_readahead;
128   UINT8 m_read_block_pending;
129
130   UINT16 m_data_index;
131
132   UINT16 m_tape_status;         /* Drive exception flags */
133   UINT16 m_data_error_counter;   /* data error count: nr of blocks rewritten/soft read errors */
134   UINT16 m_underrun_counter;      /* underrun count: nr of times streaming was interrupted */
135
136   UINT32 m_tape_pos;
137   UINT32 m_ctape_block_count;
138   UINT32 m_ctape_block_index;
139   UINT64 m_image_length;
140
141    UINT8 *m_ctape_block_buffer;
142
143   device_image_interface *m_image;
144
145   enum line_state irq_state;
146   enum line_state dma_drq_state;
147
148   emu_timer * m_timer; // timer to delay functions
149   emu_timer * m_timer1; // timer to delay functions
150   int m_timer_type;
151};
152
153// device type definition
154extern const device_type SC499;
155
156MACHINE_CONFIG_EXTERN( sc499_ctape );
157
158#endif /* SC499_H_ */
src/mess/machine/apollo_eth.c
r0r14540
1/*
2 * apollo_eth.c - APOLLO ethernet proxy
3 *
4 *  Created on: Sep 19, 2011
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also:
11 *  http://www.linuxjournal.com/article/4659
12 *
13 *
14 *  TODO:
15 *  Scrap this unportable stuff, make 3c505 use the core Ethernet layer directly like the 3c503.
16 *
17 */
18
19#define VERBOSE 0
20
21#include "includes/apollo.h"
22
23#if 0
24
25int apollo_eth_transmit(device_t *device, const UINT8 data[], int length)
26{
27   return 1;
28}
29
30int apollo_eth_setfilter(device_t *device, int node_id)
31{
32   return 0;
33}
34
35void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
36{
37}
38
39#else  /* __linux__ */
40
41#include "machine/3c505.h"
42
43#include <unistd.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <sys/socket.h>
47#include <netpacket/packet.h>
48#include <net/ethernet.h>
49#include <sys/ioctl.h>
50#include <linux/if.h>
51#include <linux/filter.h>
52#include <netinet/in.h>
53
54#define ETH_BUFFER_SIZE 2048
55
56// TODO: should be configurable
57#define ETH_INTERFACE_NAME "eth0"
58//#define ETH_INTERFACE_NAME "vmnet0"
59
60static const char *eth_if_name;
61static int eth_if_index = -1;
62static int eth_socket = -1;
63static UINT8 eth_hw_address[ETHERNET_ADDR_SIZE];
64
65static apollo_eth_receive rx_callback = NULL;
66
67/***************************************************************************
68 log data
69 ***************************************************************************/
70
71static void log_data(const device_t *device, const char *type,
72      const UINT8 *data, int data_length) {
73   if (VERBOSE > 0) {
74      int i;
75      logerror("%s - %s: %s (length=%2x)", apollo_cpu_context(
76            device->machine().firstcpu), device->tag(), type, data_length);
77      for (i = 0; i < data_length; i++) {
78         logerror(" %02x", data[i]);
79      }
80      logerror("\n");
81   }
82}
83
84/***************************************************************************
85 apollo_eth_receive_packet
86 ***************************************************************************/
87
88static int apollo_eth_receive_packet(device_t *device)
89{
90   u_char rx_buffer[ETH_BUFFER_SIZE];
91   int packet_len;
92
93   do
94   {
95      packet_len = recv(eth_socket, rx_buffer, sizeof(rx_buffer), MSG_TRUNC);
96   } while (packet_len == -1 && errno == EINTR);
97
98   /* Check if an error occurred */
99   if (packet_len == -1)
100   {
101      switch (errno)
102      {
103      case EAGAIN:
104         return 0; /* no packet there */
105
106      case ENETDOWN:
107         // The device on which we're capturing went away.
108         DLOG1(("apollo_eth_receive_packet: the interface went down (error %d - %s)", errno, strerror(errno)));
109         return -1;
110
111      default:
112         DLOG(("apollo_eth_receive_packet: recv failed (error %d - %s)", errno, strerror(errno)));
113         return -1;
114      }
115   }
116
117   log_data(device, "apollo_eth_receive_packet", rx_buffer, packet_len);
118
119   /* Call the user supplied callback function */
120   if (rx_callback != NULL)
121   {
122      // threecom3c505_receive(device, tx_data_buffer, tx_data_length);
123      (*rx_callback)(device, rx_buffer, packet_len);
124   }
125
126   return 1;
127}
128
129/***************************************************************************
130 receive_interrupt
131 ***************************************************************************/
132
133static TIMER_CALLBACK(receive_interrupt)
134{
135   device_t *device = (device_t *) ptr;
136
137   /*
138    * Save the socket's current mode, and put it in non-blocking mode;
139    * we drain it by reading packets until we get an error
140    * (which is normally a "nothing more to be read" error).
141    */
142   int save_mode = fcntl(eth_socket, F_GETFL, 0);
143   if (save_mode == -1)
144   {
145      DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
146   }
147   else if (fcntl(eth_socket, F_SETFL, save_mode | O_NONBLOCK) < 0)
148   {
149      DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
150   }
151   else
152   {
153      int i = 0;
154      while (apollo_eth_receive_packet(device) > 0 && i++ < 4)
155         ;
156
157      fcntl(eth_socket, F_SETFL, save_mode);
158   }
159
160   machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
161}
162
163/***************************************************************************
164 apollo_eth_transmit - transmit an packet to the ethernet
165 ***************************************************************************/
166
167int apollo_eth_transmit(device_t *device, const UINT8 data[], int length) {
168
169   if (eth_socket != -1)
170   {
171      if (memcmp(data, eth_hw_address, ETHERNET_ADDR_SIZE) == 0)
172      {
173         // destination ethernet address is my own mac address
174         // TODO: should send data to "eth0"
175      }
176
177      if (send(eth_socket, data, length, 0) == -1) {
178         DLOG(("apollo_eth_transmit: send failed with error %d (%s)", errno, strerror(errno)));
179      } else {
180         log_data(device, "apollo_eth_transmit", data, length);
181      }
182   }
183
184   return 1;
185}
186
187/***************************************************************************
188 apollo_eth_setfilter - set the socket filter
189 ***************************************************************************/
190
191int apollo_eth_setfilter(device_t *device, int node_id)
192{
193   /*
194   tcpdump -i eth0 -dd ether dst 08:00:1e:01:ae:a5 or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01 or ether broadcast
195
196   (000) ld       [2]
197   (001) jeq      #0x1e01aea5      jt 2   jf 4
198   (002) ldh      [0]
199   (003) jeq      #0x800           jt 11   jf 12
200   (004) jeq      #0x1e000000      jt 6   jf 5
201   (005) jeq      #0x1e000001      jt 6   jf 8
202   (006) ldh      [0]
203   (007) jeq      #0x900           jt 11   jf 12
204   (008) jeq      #0xffffffff      jt 9   jf 12
205   (009) ldh      [0]
206   (010) jeq      #0xffff          jt 11   jf 12
207   (011) ret      #65535
208   (012) ret      #0
209   */
210   static struct sock_filter bpf_code[]= {
211      { 0x20, 0, 0, 0x00000002 },
212      { 0x15, 0, 2, 0x1e01aea5 },
213      { 0x28, 0, 0, 0x00000000 },
214      { 0x15, 7, 8, 0x00000800 },
215      { 0x15, 1, 0, 0x1e000000 },
216      { 0x15, 0, 2, 0x1e000001 },
217      { 0x28, 0, 0, 0x00000000 },
218      { 0x15, 3, 4, 0x00000900 },
219      { 0x15, 0, 3, 0xffffffff },
220      { 0x28, 0, 0, 0x00000000 },
221      { 0x15, 0, 1, 0x0000ffff },
222      { 0x6, 0, 0, 0x0000ffff },
223      { 0x6, 0, 0, 0x00000000 }
224   };
225
226   if (eth_socket != -1)
227   {
228      struct sock_fprog filter;
229      filter.len = sizeof(bpf_code) / sizeof(sock_filter);
230      filter.filter = bpf_code;
231
232      // set node id in filter
233      bpf_code[1].k = (bpf_code[1].k & 0xff000000) | (node_id & 0x00ffffff);
234
235      /* Attach the filter to the socket */
236      if (setsockopt(eth_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter,
237            sizeof(filter)) < 0)
238      {
239         DLOG(("apollo_eth_setfilter: failed with error %d (%s)", errno, strerror(errno)));
240         return 0;
241      }
242      else
243      {
244         DLOG1(("apollo_eth_setfilter: set filter for node id %x", node_id & 0x00ffffff));
245      }
246   }
247   return 1;
248}
249
250/***************************************************************************
251 apollo_eth_init - specify node id and transmitter call back function
252 ***************************************************************************/
253
254void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
255{
256   rx_callback = rx_data;
257
258   eth_if_name = ETH_INTERFACE_NAME;
259   eth_if_index = -1;
260   memset(eth_hw_address, 0 , sizeof(eth_hw_address));
261
262   // Note: Only  processes  with effective UID 0 or the CAP_NET_RAW capability may open packet sockets.
263   // see also: man 7 packet
264
265   eth_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
266   if (eth_socket == -1)
267   {
268      if (errno == EPERM)
269      {
270         DLOG(("apollo_eth_init: %s - Ethernet access disabled", strerror(errno)));
271      }
272      else
273      {
274         DLOG1(("apollo_eth_init: socket failed (error %d - %s)", errno, strerror(errno)));
275      }
276   }
277   else
278   {
279      struct ifreq ifr;
280      memset(&ifr, 0, sizeof(ifr));
281      strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
282
283      // Get interface index
284      if (ioctl(eth_socket, SIOCGIFINDEX, &ifr) == -1)
285      {
286         DLOG(("apollo_eth_init: interface %s not found (error %d - %s)", eth_if_name, errno, strerror(errno)));
287         close(eth_socket);
288         eth_socket = -1;
289      }
290      else
291      {
292         eth_if_index = ifr.ifr_ifindex;
293
294         // Get hardware address
295         memset(&ifr, 0, sizeof(ifr));
296         (void) strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
297         if (ioctl(eth_socket, SIOCGIFHWADDR, (char *) &ifr) < 0)
298         {
299            DLOG(("apollo_eth_init: SIOCGIFHWADDR failed for %s (error %d - %s)", eth_if_name, errno, strerror(errno)));
300         }
301         else
302         {
303            memcpy(eth_hw_address, ifr.ifr_hwaddr.sa_data, sizeof(eth_hw_address));
304         }
305
306         struct sockaddr_ll sll;
307         memset(&sll, 0, sizeof(sll));
308         sll.sll_family = AF_PACKET;
309         sll.sll_ifindex = eth_if_index;
310         sll.sll_protocol = htons(ETH_P_ALL);
311
312         if (bind(eth_socket, (struct sockaddr *) &sll, sizeof(sll)) == -1)
313         {
314            DLOG(("apollo_eth_init: bind to interface %s failed (error %d - %s)", eth_if_name, errno, strerror(errno)));
315            close(eth_socket);
316            eth_socket = -1;
317         }
318         else
319         {
320            struct packet_mreq mr;
321            memset(&mr, 0, sizeof(mr));
322            mr.mr_ifindex = eth_if_index;
323            mr.mr_type = PACKET_MR_PROMISC;
324            if (setsockopt(eth_socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
325            {
326               DLOG(("apollo_eth_init: failed to set promiscuous mode (error %d - %s)", errno, strerror(errno)));
327               close(eth_socket);
328               eth_socket = -1;
329            }
330            else
331            {
332               // Set the socket buffer size to the specified value.
333               // by default request 2M for the ring buffer
334               int rx_bufsize = 2*1024*1024;
335               if (setsockopt(eth_socket, SOL_SOCKET, SO_RCVBUF, &rx_bufsize, sizeof(rx_bufsize)) == -1)
336               {
337                  DLOG(("apollo_eth_init: failed to set buffer size (error %d - %s)", errno, strerror(errno)));
338                  close(eth_socket);
339                  eth_socket = -1;
340               }
341               else
342               {
343                  device->machine().scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
344               }
345            }
346         }
347      }
348   }
349}
350#endif /* __linux__ */
src/mess/machine/apollo_dbg.c
r0r14540
1/*
2 * debug/apollo.c - APOLLO DN3500/DN3000 debug functions
3 *
4 *  Created on: Nov. 21, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#define VERBOSE 1
13
14#include "includes/apollo.h"
15#include "cpu/m68000/m68kcpu.h"
16
17//------------------------------------------------------
18//         TRAP 0
19//------------------------------------------------------
20
21static const char* trap0[] = {
22/* 0x00 */NULL, NULL,
23/* 0x01 */"FIM_$GET_FIM_ADDR", "",
24/* 0x02 */NULL, NULL,
25/* 0x03 */"DTTY_$RELOAD_FONT", "",
26/* 0x04 */"FILE_$UNLOCK_ALL", "",
27/* 0x05 */NULL, NULL,
28/* 0x06 */NULL, NULL,
29/* 0x07 */"PROC2_$MY_PID", "",
30/* 0x08 */"SMD_$OP_WAIT_U", "",
31/* 0x09 */"TPAD_$RE_RANGE", "",
32/* 0x0a */NULL, NULL,
33/* 0x0b */NULL, NULL,
34/* 0x0c */NULL, NULL,
35/* 0x0d */"ACL_$UP", "",
36/* 0x0e */"ACL_$DOWN", "",
37/* 0x0f */NULL, NULL,
38/* 0x10 */"TPAD_$INQ_DTYPE", "",
39/* 0x11 */NULL, NULL,
40/* 0x12 */"CACHE_$CLEAR", "",
41/* 0x13 */"RIP_$ANNOUNCE_NS", "",
42/* 0x14 */NULL, NULL,
43/* 0x15 */NULL, NULL,
44/* 0x16 */NULL, NULL,
45/* 0x17 */NULL, NULL,
46/* 0x18 */"PROC2_$DELIVER_PENDING", "",
47/* 0x19 */"PROC2_$COMPLETE_FORK", "",
48/* 0x1a */"PACCT_$STOP", "",
49/* 0x1b */"PACCT_$ON", "",
50/* 0x1c */"ACL_$GET_LOCAL_LOCKSMITH", "",
51/* 0x1d */"ACL_$IS_SUSER", "",
52/* 0x1e */NULL, NULL,
53/* 0x1f */"SMD_$N_DEVICES", "",
54/* 0x20 */"PROC1_$GET_MAXID", "",
55/* 0x21 */"THREAD_$DELETE", "",
56/* 0x22 */"THREAD_$SELF_OS", "",
57/* 0x23 */"THREAD_$NUMBER_THREADS", "",
58/* 0x24 */"ACL_$GET_PROTECT_OPTION", "",
59/* 0x25 */"ACL_$PROTECT_CHECK", "",
60/* 0x26 */"THREAD_$YIELD", "" };
61
62//------------------------------------------------------
63//         TRAP1
64//------------------------------------------------------
65
66static const char* trap1[] = {
67/* 0x00 */NULL, NULL,
68/* 0x01 */NULL, NULL,
69/* 0x02 */"FIM_$INSTALL", "x",
70/* 0x03 */"NETWORK_$READ_SERVICE", "x",
71/* 0x04 */"PROC1_$GET_CPUT", "x",
72/* 0x05 */"SET_LITES_LOC", "x",
73/* 0x06 */"TIME_$CLOCK", "x",
74/* 0x07 */"ASKNODE_$READ_FAILURE_REC", "x",
75/* 0x08 */"CAL_$APPLY_LOCAL_OFFSET", "x",
76/* 0x09 */"CAL_$GET_INFO", "x",
77/* 0x0a */"CAL_$GET_LOCAL_TIME", "x",
78/* 0x0b */"CAL_$REMOVE_LOCAL_OFFSET", "x",
79/* 0x0c */"CAL_$SET_DRIFT", "x",
80/* 0x0d */"DISK_$GET_ERROR_INFO", "x",
81/* 0x0e */NULL, NULL,
82/* 0x0f */"MSG_$CLOSE", "x",
83/* 0x10 */"PROC2_$WHO_AM_I", "u",
84/* 0x11 */"SMD_$CLEAR_KBD_CURSOR", "x",
85/* 0x12 */NULL, NULL,
86/* 0x13 */NULL, NULL,
87/* 0x14 */"SMD_$SEND_RESPONSE", "x",
88/* 0x15 */"SMD_$STOP_TP_CURSOR", "x",
89/* 0x16 */NULL, NULL,
90/* 0x17 */NULL, NULL,
91/* 0x18 */"SMD_$UNMAP_DISPLAY_U", "x",
92/* 0x19 */"UID_$GEN", "x",
93/* 0x1a */"TONE_$TIME", "x",
94/* 0x1b */"SMD_$INQ_DISP_TYPE", "x",
95/* 0x1c */NULL, NULL,
96/* 0x1d */NULL, NULL,
97/* 0x1e */NULL, NULL,
98/* 0x1f */"TPAD_$SET_CURSOR", "x",
99/* 0x20 */NULL, NULL,
100/* 0x21 */NULL, NULL,
101/* 0x22 */"NAME_$GET_WDIR_UID", "u",
102/* 0x23 */"NAME_$GET_NDIR_UID", "u",
103/* 0x24 */"NAME_$GET_ROOT_UID", "u",
104/* 0x25 */"NAME_$GET_NODE_UID", "u",
105/* 0x26 */"NAME_$GET_NODE_DATA_UID", "u",
106/* 0x27 */"NAME_$GET_CANNED_ROOT_UID", "u",
107/* 0x28 */"MSG_$GET_MY_NET", "x",
108/* 0x29 */"MSG_$GET_MY_NODE", "x",
109/* 0x2a */NULL, NULL,
110/* 0x2b */NULL, NULL,
111/* 0x2c */NULL, NULL,
112/* 0x2d */NULL, NULL,
113/* 0x2e */NULL, NULL,
114/* 0x2f */NULL, NULL,
115/* 0x30 */"GPU_$INIT", "x",
116/* 0x31 */NULL, NULL,
117/* 0x32 */"SMD_$INIT_STATE", "x",
118/* 0x33 */"SMD_$CLR_TRK_RECT", "x",
119/* 0x34 */"PROC2_$GET_SIG_MASK", "x",
120/* 0x35 */"FIM_$FRESTORE", "x",
121/* 0x36 */"TIME_$GET_TIME_OF_DAY", "x",
122/* 0x37 */"PROC1_$GET_LOADAV", "x",
123/* 0x38 */"PROC2_$GET_BOOT_FLAGS", "x",
124/* 0x39 */NULL, NULL,
125/* 0x3a */"PROC2_$SET_TTY", "x",
126/* 0x3b */"OS_$SHUTDOWN", "x",
127/* 0x3c */"PBU_$FAULTED_UNITS", "x",
128/* 0x3d */"PROC2_$GET_CPU_USAGE", "x",
129/* 0x3e */NULL, NULL,
130/* 0x3f */NULL, NULL,
131/* 0x40 */NULL, NULL,
132/* 0x41 */"TIME_$GET_ADJUST", "x",
133/* 0x42 */"FILE_$SYNC", "x",
134/* 0x43 */"XPAGE_$IS_MAPPED", "x",
135/* 0x44 */"THREAD_$SUSPEND_FOR_FORK", "x",
136/* 0x45 */"THREAD_$RESUME_FOR_FORK", "x" };
137
138//------------------------------------------------------
139//         TRAP2
140//------------------------------------------------------
141
142static const char* trap2[] = {
143/* 0x00 */NULL, NULL,
144/* 0x01 */NULL, NULL,
145/* 0x02 */"FILE_$DELETE", "x,x",
146/* 0x03 */"EC2_$WAKEUP", "x,x",
147/* 0x04 */NULL, NULL,
148/* 0x05 */"ACL_$GET_SID", "x,x",
149/* 0x06 */"FILE_$MK_PERMANENT", "x,x",
150/* 0x07 */"FILE_$UNLOCK_VOL", "x,x",
151/* 0x08 */"CAL_$READ_TIMEZONE", "x,x",
152/* 0x09 */"CAL_$SEC_TO_CLOCK", "x,x",
153/* 0x0a */"CAL_$WRITE_TIMEZONE", "x,x",
154/* 0x0b */"DISK_$UNASSIGN", "x,x",
155/* 0x0c */"FILE_$FORCE_UNLOCK", "x,x",
156/* 0x0d */"FILE_$FW_FILE", "x,x",
157/* 0x0e */"FILE_$MK_IMMUTABLE", "x,x",
158/* 0x0f */"FILE_$PURIFY", "x,x",
159/* 0x10 */"GET_BUILD_TIME", "x,x",
160/* 0x11 */NULL, NULL,
161/* 0x12 */NULL, NULL,
162/* 0x13 */"MSG_$ALLOCATE", "x,x",
163/* 0x14 */"MSG_$OPEN", "x,x",
164/* 0x15 */"MSG_$WAIT", "x,x",
165/* 0x16 */NULL, NULL,
166/* 0x17 */NULL, NULL,
167/* 0x18 */"PBU_$DEVICE_INTERRUPTING", "x,x",
168/* 0x19 */"PBU_$DISABLE_DEVICE", "x,x",
169/* 0x1a */"PBU_$ENABLE_DEVICE", "x,x",
170/* 0x1b */"PBU_$FREE_MAP", "x,x",
171/* 0x1c */"PROC2_$QUIT", "x,x",
172/* 0x1d */"PROC2_$RESUME", "x,x",
173/* 0x1e */"PROC2_$SUSPEND", "x,x",
174/* 0x1f */NULL, NULL,
175/* 0x20 */NULL, NULL,
176/* 0x21 */NULL, NULL,
177/* 0x22 */NULL, NULL,
178/* 0x23 */NULL, NULL,
179/* 0x24 */NULL, NULL,
180/* 0x25 */NULL, NULL,
181/* 0x26 */"SMD_$MAP_DISPLAY_U", "x,x",
182/* 0x27 */"SMD_$MOVE_KBD_CURSOR", "x,x",
183/* 0x28 */NULL, NULL,
184/* 0x29 */"SMD_$RETURN_DISPLAY", "x,x",
185/* 0x2a */NULL, NULL,
186/* 0x2b */NULL, NULL,
187/* 0x2c */NULL, NULL,
188/* 0x2d */NULL, NULL,
189/* 0x2e */"PEB_$GET_INFO", "x,x",
190/* 0x2f */NULL, NULL,
191/* 0x30 */"EC2_$GET_VAL", "x,x",
192/* 0x31 */"AST_$ADD_ASTES", "x,x",
193/* 0x32 */"PBU_$DISSOC", "x,x",
194/* 0x33 */"PROC2_$MAKE_ORPHAN", "x,x",
195/* 0x34 */"FILE_$DELETE_FORCE", "x,x",
196/* 0x35 */"FILE_$DELETE_WHEN_UNLOCKED", "x,x",
197/* 0x36 */"FILE_$MK_TEMPORARY", "x,x",
198/* 0x37 */NULL, NULL,
199/* 0x38 */NULL, NULL,
200/* 0x39 */NULL, NULL,
201/* 0x3a */NULL, NULL,
202/* 0x3b */"SMD_$INQ_KBD_CURSOR", "x,x",
203/* 0x3c */"ACL_$ENTER_SUBS", "u,x",
204/* 0x3d */NULL, NULL,
205/* 0x3e */NULL, NULL,
206/* 0x3f */NULL, NULL,
207/* 0x40 */NULL, NULL,
208/* 0x41 */NULL, NULL,
209/* 0x42 */"FILE_$DELETE_FORCE_WHEN_UNLOCKED", "x,x",
210/* 0x43 */NULL, NULL,
211/* 0x44 */"CT_$ACQUIRE", "x,x",
212/* 0x45 */"HINT_$ADD", "x,x",
213/* 0x46 */"DIR_$FIX_DIR", "x,x",
214/* 0x47 */"NAME_$SET_WDIRUS", "u,x",
215/* 0x48 */"NAME_$SET_NDIRUS", "u,x",
216/* 0x49 */NULL, NULL,
217/* 0x4a */NULL, NULL,
218/* 0x4b */"MSG_$CLOSEI", "x,x",
219/* 0x4c */"NETWORK_$ADD_PAGE_SERVERS", "x,x",
220/* 0x4d */"NETWORK_$ADD_REQUEST_SERVERS", "x,x",
221/* 0x4e */"ACL_$ADD_PROJ", "x,x",
222/* 0x4f */"ACL_$DELETE_PROJ", "x,x",
223/* 0x50 */NULL, NULL,
224/* 0x51 */NULL, NULL,
225/* 0x52 */"SMD_$SET_TP_REPORTING", "x,x",
226/* 0x53 */"SMD_$DISABLE_TRACKING", "x,x",
227/* 0x54 */NULL, NULL,
228/* 0x55 */NULL, NULL,
229/* 0x56 */NULL, NULL,
230/* 0x57 */NULL, NULL,
231/* 0x58 */"HINT_$ADDI", "x,x",
232/* 0x59 */NULL, NULL,
233/* 0x5a */NULL, NULL,
234/* 0x5b */"PBU_$ALLOCATE_EC", "x,x",
235/* 0x5c */"SMD_$SET_DISP_UNIT", "x,x",
236/* 0x5d */"SMD_$VIDEO_CTL", "x,x",
237/* 0x5e */"SMD_$SET_CURSOR_POS", "x,x",
238/* 0x5f */"TERM_$SEND_KBD_STRING", "x,x",
239/* 0x60 */"AUDIT_$CONTROL", "x,x",
240/* 0x61 */"PROC2_$SIGBLOCK", "x,x",
241/* 0x62 */"PROC2_$SIGSETMASK", "x,x",
242/* 0x63 */"PROC2_$SIGPAUSE", "x,x",
243/* 0x64 */"ACL_$FIPS_CTL", "x,x",
244/* 0x65 */"AS_$GET_ADDR", "x,x",
245/* 0x66 */"PROC2_$GET_ASID", "x,x",
246/* 0x67 */"TTY_$K_FLUSH_INPUT", "x,x",
247/* 0x68 */"TTY_$K_FLUSH_OUTPUT", "x,x",
248/* 0x69 */"TTY_$K_DRAIN_OUTPUT", "x,x",
249/* 0x6a */"PROC2_$DEBUG", "x,x",
250/* 0x6b */"PROC2_$UNDEBUG", "x,x",
251/* 0x6c */"ACL_$DEF_ACLDATA", "x,x",
252/* 0x6d */"PROC2_$OVERRIDE_DEBUG", "x,x",
253/* 0x6e */"TIME_$SET_TIME_OF_DAY", "x,x",
254/* 0x6f */"CAL_$DECODE_TIME", "x,x",
255/* 0x70 */"ACL_$INHERIT_SUBSYS", "x,x",
256/* 0x71 */"ACL_$SET_LOCAL_LOCKSMITH", "x,x",
257/* 0x72 */NULL, NULL,
258/* 0x73 */"SMD_$DISSOC", "x,x",
259/* 0x74 */"SMD_$BUSY_WAIT", "x,x",
260/* 0x75 */"TTY_$K_OLD_RESET", "x,x",
261/* 0x76 */NULL, NULL,
262/* 0x77 */NULL, NULL,
263/* 0x78 */NULL, NULL,
264/* 0x79 */"SCSI_$ABORT_OPERATION", "x,x",
265/* 0x7a */"SCSI_$RELEASE", "x,x",
266/* 0x7b */"SCSI_$RESET_DEVICE", "x,x",
267/* 0x7c */NULL, NULL,
268/* 0x7d */"TPAD_$RE_RANGE_UNIT", "x,x",
269/* 0x7e */"DISK_$FORMAT_WHOLE", "x,x",
270/* 0x7f */NULL, NULL,
271/* 0x80 */NULL, NULL,
272/* 0x81 */NULL, NULL,
273/* 0x82 */NULL, NULL,
274/* 0x83 */NULL, NULL,
275/* 0x84 */"SMD_$SEND_UNIT_RESPONSE", "x,x",
276/* 0x85 */NULL, NULL,
277/* 0x86 */"MST_$FW_XTAL", "x,x",
278/* 0x87 */"THREAD_$TERMINATE", "x,x",
279/* 0x88 */"THREAD_$TERMINATE_ALL", "u,x",
280/* 0x89 */"THREAD_$SUSPEND", "x,x",
281/* 0x8a */"THREAD_$RESUME", "x,x",
282/* 0x8b */"THREAD_$HANDLE_SIGNALS", "x,x",
283/* 0x8c */"THREAD_$ABORT", "x,x",
284/* 0x8d */"ACL_$SET_PROTECT_OPTION", "x,x",
285/* 0x8e */"TTY_$K_SUSPEND_INPUT", "x,x",
286/* 0x8f */"TTY_$K_RESUME_INPUT", "x,x",
287/* 0x90 */"TTY_$K_SUSPEND_OUTPUT", "x,x",
288/* 0x91 */"TTY_$K_RESUME_OUTPUT", "x,x" };
289
290//------------------------------------------------------
291//         TRAP3
292//------------------------------------------------------
293
294static const char* trap3[] = {
295/* 0x00 */"PBU2_$DMA_STOP", "x,x,x",
296/* 0x01 */NULL, NULL,
297/* 0x02 */"FILE_$CREATE", "x,x,x",
298/* 0x03 */"FILE_$UNLOCK", "u,x,x",
299/* 0x04 */"FILE_$TRUNCATE", "u,x,x",
300/* 0x05 */"MST_$UNMAPS", "x,x,x",
301/* 0x06 */"VFMT_$WRITE", "s,x,x",
302/* 0x07 */"FILE_$ATTRIBUTES", "x,x,x",
303/* 0x08 */"FILE_$SET_LEN", "x,x,x",
304/* 0x09 */"FILE_$SET_TYPE", "x,x,x",
305/* 0x0a */NULL, NULL,
306/* 0x0b */NULL, NULL,
307/* 0x0c */NULL, NULL,
308/* 0x0d */NULL, NULL,
309/* 0x0e */"NETWORK_$SET_SERVICE", "x,x,x",
310/* 0x0f */"ASKNODE_$WHO", "s,x,x",
311/* 0x10 */"FILE_$ACT_ATTRIBUTES", "x,x,x",
312/* 0x11 */"FILE_$LOCATE", "x,x,x",
313/* 0x12 */"FILE_$NEIGHBORS", "x,x,x",
314/* 0x13 */"FILE_$READ_LOCK_ENTRYU", "x,x,x",
315/* 0x14 */"FILE_$SET_ACL", "x,x,x",
316/* 0x15 */"FILE_$SET_DIRPTR", "x,x,x",
317/* 0x16 */"FILE_$SET_TROUBLE", "x,x,x",
318/* 0x17 */NULL, NULL,
319/* 0x18 */NULL, NULL,
320/* 0x19 */NULL, NULL,
321/* 0x1a */NULL, NULL,
322/* 0x1b */NULL, NULL,
323/* 0x1c */"PBU_$DMA_STOP", "x,x,x",
324/* 0x1d */"PBU_$SETDOWN", "x,x,x",
325/* 0x1e */"PBU_$SETUP", "x,x,x",
326/* 0x1f */"PROC2_$LIST", "x,x,x",
327/* 0x20 */"FIM_$SINGLE_STEP", "x,x,x",
328/* 0x21 */"SMD_$ASSOC", "x,x,x",
329/* 0x22 */"SMD_$BORROW_DISPLAY", "x,x,x",
330/* 0x23 */NULL, NULL,
331/* 0x24 */NULL, NULL,
332/* 0x25 */"SMD_$SET_TP_CURSOR", "x,x,x",
333/* 0x26 */"TIME_$WAIT", "x,x,x",
334/* 0x27 */"RINGLOG_$CNTL", "x,x,x",
335/* 0x28 */"SMD_$ALLOC_HDM", "x,x,x",
336/* 0x29 */"SMD_$FREE_HDM", "x,x,x",
337/* 0x2a */NULL, NULL,
338/* 0x2b */"OS_$GET_EC", "x,x,x",
339/* 0x2c */"TIME_$GET_EC", "x,x,x",
340/* 0x2d */NULL, NULL,
341/* 0x2e */"PROC2_$UPID_TO_UID", "x,u,x",
342/* 0x2f */"MSG_$GET_EC", "x,x,x",
343/* 0x30 */"DISK_$AS_OPTIONS", "x,x,x",
344/* 0x31 */"SMD_$GET_EC", "x,x,x",
345/* 0x32 */"NAME_$SET_ACL", "x,x,x",
346/* 0x33 */"FILE_$SET_REFCNT", "x,x,x",
347/* 0x34 */NULL, NULL,
348/* 0x35 */"PROC1_$GET_INFO", "x,x,x",
349/* 0x36 */NULL, NULL,
350/* 0x37 */NULL, NULL,
351/* 0x38 */NULL, NULL,
352/* 0x39 */NULL, NULL,
353/* 0x3a */NULL, NULL,
354/* 0x3b */NULL, NULL,
355/* 0x3c */"AS_$GET_INFO", "x,x,x",
356/* 0x3d */"FILE_$SET_DTM", "x,x,x",
357/* 0x3e */"FILE_$SET_DTU", "x,x,x",
358/* 0x3f */NULL, NULL,
359/* 0x40 */"LOG_$READ", "x,x,x",
360/* 0x41 */"PROC2_$SET_PGROUP", "x,x,x",
361/* 0x42 */"SMD_$SET_BLANK_TIMEOUT", "x,x,x",
362/* 0x43 */"SMD_$INQ_BLANK_TIMEOUT", "x,x,x",
363/* 0x44 */"FILE_$REMOVE_WHEN_UNLOCKED", "x,x,x",
364/* 0x45 */"CT_$RELEASE", "x,x,x",
365/* 0x46 */"PROC2_$UPGID_TO_UID", "x,x,x",
366/* 0x47 */"TIME_$GET_ITIMER", "x,x,x",
367/* 0x48 */"DIR_$SET_DAD", "x,x,x",
368/* 0x49 */NULL, NULL,
369/* 0x4a */NULL, NULL,
370/* 0x4b */NULL, NULL,
371/* 0x4c */NULL, NULL,
372/* 0x4d */NULL, NULL,
373/* 0x4e */NULL, NULL,
374/* 0x4f */"RIP_$TABLE", "x,x,x",
375/* 0x50 */"FILE_$LOCATEI", "x,x,x",
376/* 0x51 */"MSG_$OPENI", "x,x,x",
377/* 0x52 */"MSG_$ALLOCATEI", "x,x,x",
378/* 0x53 */"MSG_$WAITI", "x,x,x",
379/* 0x54 */"ACL_$SET_PROJ_LIST", "x,x,x",
380/* 0x55 */"ACL_$GET_RE_SIDS", "x,x,x",
381/* 0x56 */NULL, NULL,
382/* 0x57 */"MSG_$SET_HPIPC", "x,x,x",
383/* 0x58 */"DIR_$VALIDATE_ROOT_ENTRY", "x,x,x",
384/* 0x59 */"SMD_$ENABLE_TRACKING", "x,x,x",
385/* 0x5a */"FILE_$READ_LOCK_ENTRYUI", "x,x,x",
386/* 0x5b */NULL, NULL,
387/* 0x5c */"ROUTE_$SERVICE", "x,x,x",
388/* 0x5d */NULL, NULL,
389/* 0x5e */NULL, NULL,
390/* 0x5f */NULL, NULL,
391/* 0x60 */"PBU_$ADVANCE_EC", "x,x,x",
392/* 0x61 */"PBU_$RELEASE_EC", "x,x,x",
393/* 0x62 */NULL, NULL,
394/* 0x63 */"SMD_$GET_IDM_EVENT", "x,x,x",
395/* 0x64 */"MSG_$TEST_FOR_MESSAGE", "x,x,x",
396/* 0x65 */"SMD_$ADD_TRK_RECT", "x,x,x",
397/* 0x66 */"SMD_$DEL_TRK_RECT", "x,x,x",
398/* 0x67 */"SMD_$SET_KBD_TYPE", "x,x,x",
399/* 0x68 */NULL, NULL,
400/* 0x69 */"FILE_$SET_AUDITED", "x,x,x",
401/* 0x6a */"PROC2_$ACKNOWLEDGE", "x,x,x",
402/* 0x6b */"PROC2_$GET_MY_UPIDS", "x,x,x",
403/* 0x6c */"TTY_$K_INQ_INPUT_FLAGS", "x,x,x",
404/* 0x6d */"TTY_$K_INQ_OUTPUT_FLAGS", "x,x,x",
405/* 0x6e */"TTY_$K_INQ_ECHO_FLAGS", "x,x,x",
406/* 0x6f */"TTY_$K_SET_INPUT_BREAK_MODE", "x,x,x",
407/* 0x70 */"TTY_$K_INQ_INPUT_BREAK_MODE", "x,x,x",
408/* 0x71 */"TTY_$K_SET_PGROUP", "x,x,x",
409/* 0x72 */"TTY_$K_INQ_PGROUP", "x,x,x",
410/* 0x73 */"TTY_$K_SIMULATE_TERMINAL_INPUT", "x,x,x",
411/* 0x74 */"TTY_$K_INQ_FUNC_ENABLED", "x,x,x",
412/* 0x75 */"SIO_$K_TIMED_BREAK", "x,x,x",
413/* 0x76 */"FILE_$SET_DEVNO", "x,x,x",
414/* 0x77 */"XPD_$SET_PTRACE_OPTS", "x,x,x",
415/* 0x78 */"XPD_$INQ_PTRACE_OPTS", "x,x,x",
416/* 0x79 */"FILE_$SET_MAND_LOCK", "x,x,x",
417/* 0x7a */"TIME_$SET_CPU_LIMIT", "x,x,x",
418/* 0x7b */"CAL_$WEEKDAY", "x,x,x",
419/* 0x7c */"SIO_$K_SIGNAL_WAIT", "x,x,x",
420/* 0x7d */"TERM_$SET_DISCIPLINE", "x,x,x",
421/* 0x7e */"PROC2_$SET_SERVER", "x,x,x",
422/* 0x7f */"PACCT_$START", "x,x,x",
423/* 0x80 */"FILE_$SET_DTU_F", "x,x,x",
424/* 0x81 */"PROC2_$PGUID_TO_UPGID", "x,x,x",
425/* 0x82 */"TERM_$INQ_DISCIPLINE", "x,x,x",
426/* 0x83 */"PBU_$DMA_STATUS", "x,x,x",
427/* 0x84 */NULL, NULL,
428/* 0x85 */"MST_$UNMAPS_AND_FREE_AREA", "x,x,x",
429/* 0x86 */"SMD_$ASSOC_CSRS", "x,x,x",
430/* 0x87 */"SMD_$INQ_DISP_INFO", "x,x,x",
431/* 0x88 */"SMD_$INQ_DISP_UID", "x,x,x",
432/* 0x89 */"SMD_$DISPLAY_LOGO", "x,x,x",
433/* 0x8a */"TERM_$SET_REAL_LINE_DISCIPLINE", "x,x,x",
434/* 0x8b */"TIME_$ADJUST_TIME_OF_DAY", "x,x,x",
435/* 0x8c */"PROC2_$UID_TO_UPID", "x,x,x",
436/* 0x8d */"PROC2_$SET_SESSION_ID", "x,x,x",
437/* 0x8e */"SMD_$GET_UNIT_EVENT", "x,x,x",
438/* 0x8f */"TPAD_$SET_UNIT_CURSOR", "x,x,x",
439/* 0x90 */"TPAD_$SET_PUNCH_IMPACT", "x,x,x",
440/* 0x91 */"TPAD_$INQ_PUNCH_IMPACT", "x,x,x",
441/* 0x92 */"TTY_$K_INQ_SESSION_ID", "x,x,x",
442/* 0x93 */"TTY_$K_SET_SESSION_ID", "x,x,x",
443/* 0x94 */NULL, NULL,
444/* 0x95 */NULL, NULL,
445/* 0x96 */NULL, NULL,
446/* 0x97 */NULL, NULL,
447/* 0x98 */"SMD_$SHARE_DEVICE", "x,x,x",
448/* 0x99 */"SMD_$SET_UNIT_CURSOR_POS", "x,x,x",
449/* 0x9a */"SMD_$CLR_AND_LOAD_TRK_RECT", "x,x,x",
450/* 0x9b */"PROC2_$GET_PARM", "x,x,x",
451/* 0x9c */NULL, NULL,
452/* 0x9d */NULL, NULL,
453/* 0x9e */NULL, NULL,
454/* 0x9f */"FILE_$CW_READ", "x,x,x",
455/* 0xa0 */"FILE_$CW_WRITE", "x,x,x",
456/* 0xa1 */"MST_$TRUNC_XTAL", "x,x,x",
457/* 0xa2 */"MST_$SET_LEN_XTAL", "x,x,x",
458/* 0xa3 */"THREAD_$CREATE", "x,x,x",
459/* 0xa4 */"THREAD_$CLEANUP", "x,x,x",
460/* 0xa5 */"THREAD_$SET_INH_PTR", "x,x,x",
461/* 0xa6 */"SMD_$BORROW_DISPLAY_AND_KBD", "x,x,x",
462/* 0xa7 */"THREAD_$CLEANUP_ALL", "x,x,x",
463/* 0xa8 */"DIR_$ADD_MOUNT", "x,x,x",
464/* 0xa9 */"DIR_$REMOVE_MOUNT", "x,x,x",
465/* 0xaa */NULL, NULL,
466/* 0xab */"TTY_$K_RESET", "x,x,x",
467/* 0xac */"MST_$SHADOW_MAP", "x,x,x",
468/* 0xad */NULL, NULL };
469
470//------------------------------------------------------
471//         TRAP4
472//------------------------------------------------------
473
474static const char* trap4[] = {
475/* 0x00 */NULL, NULL,
476/* 0x01 */"MST_$SET_GUARD", "u,x,x,x",
477/* 0x02 */"MST_$UNMAP_GLOBAL", "u,x,x,x",
478/* 0x03 */"MST_$GET_UID", "x,u,x,x",
479/* 0x04 */"EC2_$WAIT", "x,x,x,x",
480/* 0x05 */"FILE_$READ_LOCK_ENTRY", "x,x,x,x",
481/* 0x06 */"MST_$UNMAP", "u,x,x,x",
482/* 0x07 */"MST_$GROW_AREA", "x,x,x,x",
483/* 0x08 */NULL, NULL,
484/* 0x09 */NULL, NULL,
485/* 0x0a */NULL, NULL,
486/* 0x0b */NULL, NULL,
487/* 0x0c */"TERM_$CONTROL", "x,x,x,x",
488/* 0x0d */"TERM_$READ", "x,s,x,x",
489/* 0x0e */"TERM_$WRITE", "x,x,x,x",
490/* 0x0f */"DISK_$FORMAT", "x,x,x,x",
491/* 0x10 */"DISK_$LV_ASSIGN", "x,x,x,x",
492/* 0x11 */"FILE_$FW_PARTIAL", "x,x,x,x",
493/* 0x12 */NULL, NULL,
494/* 0x13 */NULL, NULL,
495/* 0x14 */NULL, NULL,
496/* 0x15 */NULL, NULL,
497/* 0x16 */NULL, NULL,
498/* 0x17 */NULL, NULL,
499/* 0x18 */NULL, NULL,
500/* 0x19 */NULL, NULL,
501/* 0x1a */NULL, NULL,
502/* 0x1b */NULL, NULL,
503/* 0x1c */NULL, NULL,
504/* 0x1d */NULL, NULL,
505/* 0x1e */NULL, NULL,
506/* 0x1f */NULL, NULL,
507/* 0x20 */NULL, NULL,
508/* 0x21 */NULL, NULL,
509/* 0x22 */NULL, NULL,
510/* 0x23 */"PBU_$WAIT", "x,x,x,x",
511/* 0x24 */"PBU_$GET_PTR", "x,x,x,x",
512/* 0x25 */"PCHIST_$CNTL", "x,x,x,x",
513/* 0x26 */"PROC2_$GET_INFO", "u,x,x,x",
514/* 0x27 */NULL, NULL,
515/* 0x28 */NULL, NULL,
516/* 0x29 */NULL, NULL,
517/* 0x2a */"SMD_$SIGNAL", "x,x,x,x",
518/* 0x2b */NULL, NULL,
519/* 0x2c */NULL, NULL,
520/* 0x2d */"TERM_$INQUIRE", "x,x,x,x",
521/* 0x2e */NULL, NULL,
522/* 0x2f */NULL, NULL,
523/* 0x30 */NULL, NULL,
524/* 0x31 */"TERM_$GET_EC", "x,x,x,x",
525/* 0x32 */NULL, NULL,
526/* 0x33 */"PBU_$GET_EC", "x,x,x,x",
527/* 0x34 */NULL, NULL,
528/* 0x35 */NULL, NULL,
529/* 0x36 */NULL, NULL,
530/* 0x37 */NULL, NULL,
531/* 0x38 */"TERM_$READ_COND", "x,x,x,x",
532/* 0x39 */NULL, NULL,
533/* 0x3a */NULL, NULL,
534/* 0x3b */"PBU2_$WIRE", "x,x,x,x",
535/* 0x3c */"PROC2_$SET_NAME", "x,x,x,x",
536/* 0x3d */"PROC2_$SET_PRIORITY", "x,x,x,x",
537/* 0x3e */"PROC2_$GET_EC", "u,x,x,x",
538/* 0x3f */"PROC2_$LIST_PGROUP", "x,x,x,x",
539/* 0x40 */NULL, NULL,
540/* 0x41 */NULL, NULL,
541/* 0x42 */NULL, NULL,
542/* 0x43 */"CT_$CONTROL", "x,x,x,x",
543/* 0x44 */"CT_$WAIT", "x,x,x,x",
544/* 0x45 */"DIR_$DROP_DIRU", "x,x,x,x",
545/* 0x46 */"DIR_$SET_DEFAULT_ACL", "x,x,x,x",
546/* 0x47 */"DIR_$GET_DEFAULT_ACL", "x,x,x,x",
547/* 0x48 */"NAME_$READ_DIRS_PS", "x,x,x,x",
548/* 0x49 */NULL, NULL,
549/* 0x4a */"ACL_$GET_PROJ_LIST", "x,x,x,x",
550/* 0x4b */"MST_$CHANGE_RIGHTS", "x,x,x,x",
551/* 0x4c */NULL, NULL,
552/* 0x4d */"FILE_$READ_LOCK_ENTRYI", "x,x,x,x",
553/* 0x4e */"ROUTE_$INCOMING", "x,x,x,x",
554/* 0x4f */NULL, NULL,
555/* 0x50 */"SMD_$INQ_KBD_TYPE", "x,x,x,x",
556/* 0x51 */"ROUTE_$GET_EC", "x,x,x,x",
557/* 0x52 */NULL, NULL,
558/* 0x53 */"SMD_$DM_COND_EVENT_WAIT", "x,x,x,x",
559/* 0x54 */"DISK_$READ_MFG_BADSPOTS", "x,x,x,x",
560/* 0x55 */"DISK_$GET_MNT_INFO", "x,x,x,x",
561/* 0x56 */"PROC2_$SET_SIG_MASK", "x,x,x,x",
562/* 0x57 */"PROC2_$SIGRETURN", "x,x,x,x",
563/* 0x58 */"PROC2_$WAIT", "x,x,x,x",
564/* 0x59 */"PROC2_$SIGNAL", "x,x,x,x",
565/* 0x5a */"PROC2_$SIGNAL_PGROUP", "x,x,x,x",
566/* 0x5b */"PROC2_$GET_CR_REC", "x,x,x,x",
567/* 0x5c */"TTY_$K_SET_FUNC_CHAR", "x,x,x,x",
568/* 0x5d */"TTY_$K_INQ_FUNC_CHAR", "x,x,x,x",
569/* 0x5e */"TTY_$K_SET_INPUT_FLAG", "x,x,x,x",
570/* 0x5f */"TTY_$K_SET_OUTPUT_FLAG", "x,x,x,x",
571/* 0x60 */"TTY_$K_SET_ECHO_FLAG", "x,x,x,x",
572/* 0x61 */"TTY_$K_ENABLE_FUNC", "x,x,x,x",
573/* 0x62 */"SIO_$K_SET_PARAM", "x,x,x,x",
574/* 0x63 */"SIO_$K_INQ_PARAM", "x,x,x,x",
575/* 0x64 */"FILE_$SET_MGR_ATTR", "x,x,x,x",
576/* 0x65 */"XPD_$GET_REGISTERS", "x,x,x,x",
577/* 0x66 */"XPD_$PUT_REGISTERS", "x,x,x,x",
578/* 0x67 */"FILE_$RESERVE", "u,x,x,x",
579/* 0x68 */NULL, NULL,
580/* 0x69 */"ACL_$GET_RES_SIDS", "x,x,x,x",
581/* 0x6a */"FILE_$FW_PAGES", "x,x,x,x",
582/* 0x6b */"PROC2_$SET_ACCT_INFO", "s,x,x,x",
583/* 0x6c */"FILE_$IMPORT_LK", "x,x,x,x",
584/* 0x6d */"FILE_$UNLOCK_D", "u,x,x,x",
585/* 0x6e */"FILE_$SET_LEN_D", "x,x,x,x",
586/* 0x6f */"FILE_$TRUNCATE_D", "x,x,x,x",
587/* 0x70 */"FILE_$SET_DTM_F", "x,x,x,x",
588/* 0x71 */"TTY_$K_SET_FLAG", "x,x,x,x",
589/* 0x72 */NULL, NULL,
590/* 0x73 */"MST_$UNMAP_AND_FREE_AREA", "x,x,x,x",
591/* 0x74 */NULL, NULL,
592/* 0x75 */"PROC2_$NAME_TO_UID", "S,w,u,x",
593/* 0x76 */NULL, NULL,
594/* 0x77 */NULL, NULL,
595/* 0x78 */NULL, NULL,
596/* 0x79 */"SCSI_$GET_EC", "x,x,x,x",
597/* 0x7a */"SCSI_$GET_INFO", "x,x,x,x",
598/* 0x7b */"SCSI_$SETUP", "x,x,x,x",
599/* 0x7c */"SCSI_$WIRE", "x,x,x,x",
600/* 0x7d */"MSG_$SHARE_SOCKET", "x,x,x,x",
601/* 0x7e */"TTY_$K_INQ_DELAY", "x,x,x,x",
602/* 0x7f */"TTY_$K_SET_DELAY", "x,x,x,x",
603/* 0x80 */NULL, NULL,
604/* 0x81 */NULL, NULL,
605/* 0x82 */"PROC2_$PGROUP_INFO", "x,x,x,x",
606/* 0x83 */"PROC2_$SET_PARM", "x,x,x,x",
607/* 0x84 */NULL, NULL,
608/* 0x85 */NULL, NULL,
609/* 0x86 */"XPAGE_$PAGER_RENDEZVOUS", "x,x,x,x",
610/* 0x87 */"FILE_$SET_DEVNO32", "x,x,x,x",
611/* 0x88 */"MST_$SET_LIMIT", "x,x,x,x",
612/* 0x89 */"THREAD_$SET_PRIORITY", "x,x,x,x",
613/* 0x8a */"THREAD_$INFO", "x,x,x,x",
614/* 0x8b */"TTY_$K_SET_DELAY_STYLE", "x,x,x,x",
615/* 0x8c */"TTY_$K_INQ_DELAY_STYLE", "x,x,x,x" };
616
617//------------------------------------------------------
618//         TRAP5
619//------------------------------------------------------
620
621static const char* trap5[] = {
622/* 0x00 */NULL, NULL,
623/* 0x01 */"MST_$MAP_AREA", "x,x,x,u,x",
624/* 0x02 */NULL, NULL,
625/* 0x03 */NULL, NULL,
626/* 0x04 */NULL, NULL,
627/* 0x05 */"ACL_$RIGHTS", "x,x,x,x,x",
628/* 0x06 */NULL, NULL,
629/* 0x07 */"ASKNODE_$INFO", "x,x,x,x,x",
630/* 0x08 */"DISK_$AS_READ", "x,x,x,x,x",
631/* 0x09 */"DISK_$AS_WRITE", "x,x,x,x,x",
632/* 0x0a */NULL, NULL,
633/* 0x0b */NULL, NULL,
634/* 0x0c */NULL, NULL,
635/* 0x0d */NULL, NULL,
636/* 0x0e */NULL, NULL,
637/* 0x0f */NULL, NULL,
638/* 0x10 */NULL, NULL,
639/* 0x11 */"PBU_$GET_DCTE", "x,x,x,x,x",
640/* 0x12 */"PBU_$READ_CSR", "x,x,x,x,x",
641/* 0x13 */"PBU_$CONTROL", "x,x,x,x,x",
642/* 0x14 */"PBU2_$WIRE_MAP", "x,x,x,x,x",
643/* 0x15 */"PBU_$WRITE_CSR", "x,x,x,x,x",
644/* 0x16 */"TPAD_$INQUIRE", "x,x,x,x,x",
645/* 0x17 */"TPAD_$SET_MODE", "x,x,x,x,x",
646/* 0x18 */"VFMT_$MAIN", "x,x,x,x,x",
647/* 0x19 */"VOLX_$GET_INFO", "x,x,x,x,x",
648/* 0x1a */"VTOC_$GET_UID", "x,x,x,x,x",
649/* 0x1b */"NETLOG_$CNTL", "x,x,x,x,x",
650/* 0x1c */"PROC2_$GET_UPIDS", "x,x,x,x,x",
651/* 0x1d */NULL, NULL,
652/* 0x1e */NULL, NULL,
653/* 0x1f */"PBU2_$ALLOCATE_MAP", "x,x,x,x,x",
654/* 0x20 */"PBU2_$MAP", "x,x,x,x,x",
655/* 0x21 */"PBU2_$UNMAP", "x,x,x,x,x",
656/* 0x22 */"PBU2_$UNWIRE", "x,x,x,x,x",
657/* 0x23 */"MST_$GET_UID_ASID", "x,x,x,x,x",
658/* 0x24 */"MST_$INVALIDATE", "x,x,u,x,x",
659/* 0x25 */"FILE_$INVALIDATE", "x,x,x,x,x",
660/* 0x26 */NULL, NULL,
661/* 0x27 */NULL, NULL,
662/* 0x28 */NULL, NULL,
663/* 0x29 */"MST_$SET_TOUCH_AHEAD_CNT", "x,x,x,x,x",
664/* 0x2a */"OS_$CHKSUM", "x,x,x,x,x",
665/* 0x2b */"FILE_$GET_SEGMENT_MAP", "x,x,x,x,x",
666/* 0x2c */NULL, NULL,
667/* 0x2d */"PBU2_$ASSOC", "x,x,x,x,x",
668/* 0x2e */"FILE_$UNLOCK_PROC", "x,x,x,x,x",
669/* 0x2f */"CT_$READ", "x,x,x,x,x",
670/* 0x30 */"CT_$WRITE", "x,x,x,x,x",
671/* 0x31 */"DIR_$ADDU", "u,S,w,u,x",
672/* 0x32 */"DIR_$DROPU", "x,x,x,x,x",
673/* 0x33 */"DIR_$CREATE_DIRU", "x,x,x,x,x",
674/* 0x34 */"DIR_$ADD_BAKU", "x,x,x,x,x",
675/* 0x35 */NULL, NULL,
676/* 0x36 */NULL, NULL,
677/* 0x37 */NULL, NULL,
678/* 0x38 */"DIR_$ADD_HARD_LINKU", "x,x,x,x,x",
679/* 0x39 */NULL, NULL,
680/* 0x3a */"RIP_$UPDATE", "x,x,x,x,x",
681/* 0x3b */"DIR_$DROP_LINKU", "x,x,x,x,x",
682/* 0x3c */"ACL_$CHECK_RIGHTS", "x,x,x,x,x",
683/* 0x3d */"DIR_$DROP_HARD_LINKU", "x,x,x,x,x",
684/* 0x3e */"ROUTE_$OUTGOING", "x,x,x,x,x",
685/* 0x3f */NULL, NULL,
686/* 0x40 */NULL, NULL,
687/* 0x41 */NULL, NULL,
688/* 0x42 */"NET_$GET_INFO", "x,x,x,x,x",
689/* 0x43 */"DIR_$GET_ENTRYU", "x,x,x,x,x",
690/* 0x44 */"AUDIT_$LOG_EVENT", "x,x,x,x,x",
691/* 0x45 */"FILE_$SET_PROT", "x,x,x,x,x",
692/* 0x46 */"TTY_$K_GET", "x,x,s,x,x",
693/* 0x47 */"TTY_$K_PUT", "x,x,S,w,x",
694/* 0x48 */"PROC2_$ALIGN_CTL", "x,x,x,x,x",
695/* 0x49 */NULL, NULL,
696/* 0x4a */"XPD_$READ_PROC", "x,x,x,x,x",
697/* 0x4b */"XPD_$WRITE_PROC", "x,x,x,x,x",
698/* 0x4c */"DIR_$SET_DEF_PROTECTION", "x,x,x,x,x",
699/* 0x4d */"DIR_$GET_DEF_PROTECTION", "x,x,x,x,x",
700/* 0x4e */"ACL_$COPY", "u,u,x,x,x",
701/* 0x4f */"ACL_$CONVERT_FUNKY_ACL", "x,x,x,x,x",
702/* 0x50 */"DIR_$SET_PROTECTION", "x,x,x,x,x",
703/* 0x51 */"FILE_$OLD_AP", "x,x,x,x,x",
704/* 0x52 */"ACL_$SET_RE_ALL_SIDS", "x,x,x,x,x",
705/* 0x53 */"ACL_$GET_RE_ALL_SIDS", "x,x,x,x,x",
706/* 0x54 */"FILE_$EXPORT_LK", "x,x,x,x,x",
707/* 0x55 */"FILE_$CHANGE_LOCK_D", "x,x,x,x,x",
708/* 0x56 */"XPD_$READ_PROC_ASYNC", "x,x,x,x,x",
709/* 0x57 */NULL, NULL,
710/* 0x58 */"SMD_$MAP_DISPLAY_MEMORY", "x,x,x,x,x",
711/* 0x59 */NULL, NULL,
712/* 0x5a */NULL, NULL,
713/* 0x5b */NULL, NULL,
714/* 0x5c */NULL, NULL,
715/* 0x5d */"SCSI_$UNWIRE", "x,x,x,x,x",
716/* 0x5e */"SMD_$UNMAP_DISPLAY_MEMORY", "x,x,x,x,x",
717/* 0x5f */"SMD_$SET_COLOR_TABLE", "x,x,x,x,x",
718/* 0x60 */"RIP_$TABLE_D", "x,x,x,x,x",
719/* 0x61 */NULL, NULL,
720/* 0x62 */"SMD_$DEVICE_INFO", "x,x,x,x,x",
721/* 0x63 */NULL, NULL,
722/* 0x64 */NULL, NULL,
723/* 0x65 */"THREAD_$GET_STATE", "x,x,x,p,x",
724/* 0x66 */"THREAD_$SET_STATE", "x,x,x,p,x",
725/* 0x67 */"THREAD_$SET_STACK", "x,u,x,x,x",
726/* 0x68 */NULL, NULL };
727
728//------------------------------------------------------
729//         TRAP7
730//------------------------------------------------------
731
732static const char* trap7[] = {
733/* 0x00 */"FILE_$LOCK", "u,x,x,x,x,x,x",
734/* 0x01 */"VFMT_$WRITE", "s,x,x,x,x,x,x",
735/* 0x02 */"MST_$MAP_AREA_AT", "x,x,x,x,x,x,x",
736/* 0x03 */NULL, NULL,
737/* 0x04 */NULL, NULL,
738/* 0x05 */NULL, NULL,
739/* 0x06 */NULL, NULL,
740/* 0x07 */NULL, NULL,
741/* 0x08 */NULL, NULL,
742/* 0x09 */NULL, NULL,
743/* 0x0a */NULL, NULL,
744/* 0x0b */NULL, NULL,
745/* 0x0c */NULL, NULL,
746/* 0x0d */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x",
747/* 0x0e */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x",
748/* 0x0f */"STOP_$WATCH", "x,x,x,x,x,x,x",
749/* 0x10 */NULL, NULL,
750/* 0x11 */NULL, NULL,
751/* 0x12 */"ASKNODE_$GET_INFO", "x,x,x,x,x,x,x",
752/* 0x13 */"DISK_$DIAG_IO", "x,x,x,x,x,x,x",
753/* 0x14 */NULL, NULL,
754/* 0x15 */NULL, NULL,
755/* 0x16 */NULL, NULL,
756/* 0x17 */"CT_$DIAG", "x,x,x,x,x,x,x",
757/* 0x18 */"TIME_$SET_ITIMER", "x,x,x,x,x,x,x",
758/* 0x19 */"OSINFO_$GET_STATS", "x,x,x,x,x,x,x",
759/* 0x1a */"DIR_$CNAMEU", "x,x,x,x,x,x,x",
760/* 0x1b */"DIR_$DELETE_FILEU", "u,S,w,x,x,x,x",
761/* 0x1c */"DIR_$ADD_LINKU", "x,x,x,x,x,x,x",
762/* 0x1d */NULL, NULL,
763/* 0x1e */NULL, NULL,
764/* 0x1f */NULL, NULL,
765/* 0x20 */NULL, NULL,
766/* 0x21 */"ASKNODE_$WHO_REMOTE", "x,x,x,x,x,x,x",
767/* 0x22 */"MST_$REMAP", "x,x,x,x,x,x,x",
768/* 0x23 */"DIR_$ROOT_ADDU", "x,x,x,x,x,x,x",
769/* 0x24 */NULL, NULL,
770/* 0x25 */NULL, NULL,
771/* 0x26 */NULL, NULL,
772/* 0x27 */NULL, NULL,
773/* 0x28 */"ASKNODE_$WHO_NOTOPO", "x,x,x,x,x,x,x",
774/* 0x29 */"NET_$OPEN", "x,x,x,x,x,x,x",
775/* 0x2a */"NET_$CLOSE", "x,x,x,x,x,x,x",
776/* 0x2b */"NET_$IOCTL", "x,x,x,x,x,x,x",
777/* 0x2c */"DIR_$FIND_UID", "u,u,x,S,w,x,x",
778/* 0x2d */"FILE_$GET_ATTRIBUTES", "u,x,x,x,x,x,-",
779/* 0x2e */NULL, NULL,
780/* 0x2f */"PCHIST_$UNIX_PROFIL_CNTL", "x,x,x,x,x,x,x",
781/* 0x30 */"XPD_$RESTART", "x,x,x,x,x,x,x",
782/* 0x31 */"FILE_$GET_ATTR_INFO", "u,x,x,x,x,x,p",
783/* 0x32 */"ACL_$PRIM_CREATE", "x,x,x,x,x,x,x",
784/* 0x33 */"PROC2_$GET_REGS", "x,x,x,x,x,x,x",
785/* 0x34 */"ACL_$CONVERT_TO_9ACL", "x,x,x,x,x,x,x",
786/* 0x35 */"ACL_$SET_RES_ALL_SIDS", "x,x,x,x,x,x,x",
787/* 0x36 */"ACL_$GET_RES_ALL_SIDS", "x,x,x,x,x,x,x",
788/* 0x37 */"FILE_$LOCK_D", "u,x,x,x,x,x,p",
789/* 0x38 */"FILE_$CREATE_IT", "x,x,u,x,u,x,u",
790/* 0x39 */"ACL_$RIGHTS_CHECK", "x,x,x,x,x,x,x",
791/* 0x3a */"RIP_$UPDATE_D", "x,x,x,x,x,x,x",
792/* 0x3b */"VOLX_$SWAPON", "x,x,x,x,x,x,x",
793/* 0x3c */"MST_$ADDMAP", "x,x,x,x,x,x,x", };
794
795//------------------------------------------------------
796//         TRAP8
797//------------------------------------------------------
798
799static const char* trap8[] = {
800
801/* 0x00 - 0x07 */"MST_$MAP", "u,x,x,x,x,x,x",
802/* 0x01 - 0x08 */"MST_$MAP_AT", "x,u,x,x,x,x,x,x",
803/* 0x02 - 0x07 */"MST_$MAP_GLOBAL", "u,x,x,x,x,x,x",
804/* 0x03 - 0x0A */"VFMT_$WRITE", "s,x,x,x,x,x,x,x,x,x",
805/* 0x04 - 0x06 */"VOLX_$DISMOUNT", "x,x,x,x,x,x",
806/* 0x05 - 0x06 */"VOLX_$GET_UIDS", "x,x,x,x,x,x",
807/* 0x06 - 0x07 */NULL, NULL,
808/* 0x07 - 0x07 */"DISK_$PV_ASSIGN", "x,x,x,x,x,x,x",
809/* 0x08 - 0x0B */"MSG_$RCV", "x,x,x,x,x,x,x,x,x,x,x",
810/* 0x09 - 0x10 */"MSG_$SAR", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
811/* 0x0a - 0x0A */"MSG_$SEND", "x,x,x,x,x,x,x,x,x,x",
812/* 0x0b - 0x06 */NULL, NULL,
813/* 0x0c - 0x07 */"SMD_$LOAD_CRSR_BITMAP", "x,x,x,x,x,x,x",
814/* 0x0d - 0x07 */"SMD_$READ_CRSR_BITMAP", "x,x,x,x,x,x,x",
815/* 0x0e - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x",
816/* 0x0f - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x",
817/* 0x10 - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x",
818/* 0x11 - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x",
819/* 0x12 - 0x06 */"CAL_$WRITE_CALENDAR", "x,x,x,x,x,x",
820/* 0x13 - 0x08 */"MSG_$RCV_CONTIG", "x,x,x,x,x,x,x,x",
821/* 0x14 - 0x06 */"OSINFO_$GET_MMAP", "x,x,x,x,x,x",
822/* 0x15 - 0x06 */"ASKNODE_$INTERNET_INFO", "x,x,x,x,x,x",
823/* 0x16 - 0x07 */"MST_$GET_VA_INFO", "x,x,x,x,x,x,x",
824/* 0x17 - 0x0D */"MSG_$SENDI", "x,x,x,x,x,x,x,x,x,x,x,x,x",
825/* 0x18 - 0x0F */"MSG_$RCVI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
826/* 0x19 - 0x0C */"MSG_$RCV_CONTIGI", "x,x,x,x,x,x,x,x,x,x,x,x",
827/* 0x1a - 0x11 */"MSG_$SARI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
828/* 0x1b - 0x06 */NULL, NULL,
829/* 0x1c - 0x0E */"MSG_$SEND_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x,x",
830/* 0x1d - 0x07 */"PBU_$WIRE_SPECIAL", "x,x,x,x,x,x,x",
831/* 0x1e - 0x06 */"PBU_$DMA_START", "x,x,x,x,x,x",
832/* 0x1f - 0x08 */NULL, NULL,
833/* 0x20 - 0x07 */"MST_$MAP_TOP", "x,x,x,x,x,x,x",
834/* 0x21 - 0x08 */"NET_$SEND", "x,x,x,x,x,x,x,x",
835/* 0x22 - 0x08 */"NET_$RCV", "x,x,x,x,x,x,x,x",
836/* 0x23 - 0x08 */"DIR_$DIR_READU", "u,S,w,x,x,x,x,x",
837/* 0x24 - 0x07 */"DIR_$READ_LINKU", "x,x,x,x,x,x,x",
838/* 0x25 - 0x07 */"PBU2_$DMA_START", "x,x,x,x,x,x,x",
839/* 0x26 - 0x09 */NULL, NULL,
840/* 0x27 - 0x09 */NULL, NULL,
841/* 0x28 - 0x07 */"PROC2_$COMPLETE_VFORK", "x,x,x,x,x,x,x",
842/* 0x29 - 0x07 */NULL, NULL,
843/* 0x2a - 0x06 */NULL, NULL,
844/* 0x2b - 0x0A */"DIR_$RESOLVE", "S,w,u,u,x,x,x,x,x,x",
845/* 0x2c - 0x08 */"VOLX_$MOUNT", "x,x,x,x,x,x,x,x",
846/* 0x2d - 0x06 */"ACL_$IMAGE", "x,x,x,x,x,x",
847/* 0x2e - 0x09 */"DISK_$PV_ASSIGN_N", "x,x,x,x,x,x,x,x,x",
848/* 0x2f - 0x07 */"DISK_$AS_XFER_MULTI", "x,x,x,x,x,x,x",
849/* 0x30 - 0x07 */"PROC2_$FORK", "x,x,x,x,x,x,x",
850/* 0x31 - 0x06 */"SCSI_$DO_COMMAND", "x,x,x,x,x,x",
851/* 0x32 - 0x07 */"SCSI_$WAIT", "x,x,x,x,x,x,x",
852/* 0x33 - 0x0A */"PROC2_$CREATE", "x,x,x,x,x,x,x,x,x,x",
853/* 0x34 - 0x06 */"TPAD_$SET_UNIT_MODE", "x,x,x,x,x,x",
854/* 0x35 - 0x06 */"TPAD_$INQUIRE_UNIT", "x,x,x,x,x,x",
855/* 0x36 - 0x0B */"SCSI_$DO_SYS_DEVICE_CMD", "x,x,x,x,x,x,x,x,x,x,x",
856/* 0x37 - 0x0D */"MSG_$RCV_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x",
857/* 0x38 - 0x06 */"VOLX_$VOL_INFO", "x,x,x,x,x,x",
858/* 0x39 - 0x08 */"MST_$MAP_XTAL", "x,x,x,x,x,x,x,x",
859/* 0x3a - 0x08 */"MST_$MAP_U", "x,u,x,x,x,x,x,x",
860/* 0x3b - 0x06 */"MST_$GET_INFO_BY_VA", "x,x,x,x,x,x",
861/* 0x3c - 0x06 */"VOLX_$QUOTA_CONTROL", "x,x,x,x,x,x",
862/* 0x3d - 0x06 */"VOLX_$READ_QUOTA_TABLE", "x,x,x,x,x,x",
863/* 0x3e - 0x06 */"THREAD_$LIST", "x,x,x,x,x,x",
864/* 0x3f - 0x07 */"SCSI_$DO_COMMAND_2", "x,x,x,x,x,x,x" };
865
866// get parameter string for parameter type and value at addr
867
868static const char *get_param(m68ki_cpu_core *m68k, UINT32 addr, char type)
869{
870   UINT32 value = ~0;
871
872   // FIXME:
873   static char sb[256];
874
875   int i;
876   char ch;
877   int maxlen = sizeof(sb) - 2;
878   UINT32 value1;
879
880   sb[0] = 0;
881
882   if (!m68k->mmu_tmp_buserror_occurred)
883   {
884      value = m68k->memory.read32(addr);
885      if (!m68k->mmu_tmp_buserror_occurred && (value != ~0))
886      {
887         switch (type)
888         {
889         case 'S': // string w/o terminating 0
890            value1 = m68k->memory.read32(addr + 4);
891            if (!m68k->mmu_tmp_buserror_occurred && (value1 != ~0))
892            {
893               maxlen = m68k->memory.read16(value1);
894               if (maxlen > sizeof(sb) - 2)
895               {
896                  maxlen = sizeof(sb) - 2;
897               }
898            }
899         case 's': // string
900            i = 0;
901            sb[i++] = '"';
902            while (i <= maxlen && (ch = m68k->memory.read8(value++)) != 0
903                  && !m68k->mmu_tmp_buserror_occurred)
904            {
905               sb[i++] = ch < 32 ? '.' : ch;
906            }
907            sb[i++] = '"';
908            sb[i] = 0;
909            break;
910         case 'b': // byte (1 byte)
911            sprintf(sb, "0x%x", m68k->memory.read8(value));
912            break;
913         case 'p': // pointer
914            sprintf(sb, "0x%x", value);
915            break;
916         case 'w': // word (2 byte)
917            sprintf(sb, "0x%x", m68k->memory.read16(value));
918            break;
919         case 'x': // default  (hex 32 bit)
920            sprintf(sb, "0x%x", m68k->memory.read32(value));
921            break;
922         case 'u': // uid
923            sprintf(sb, "%08x.%08x", m68k->memory.read32(value),
924                  m68k->memory.read32(value + 4));
925            break;
926         default:
927            sprintf(sb, "%c", type);
928            break;
929         }
930      }
931      m68k->mmu_tmp_buserror_occurred = 0;
932   }
933   return sb;
934}
935
936// get the svc call string
937
938static const char* get_svc_call(m68ki_cpu_core *m68k, int trap_no,
939      int trap_code,  char *sb)
940{
941   UINT32 sp = REG_A(m68k)[7];
942   UINT32 pa;
943   const char * name = NULL;
944   const char * param = NULL;
945
946   switch (trap_no)
947   {
948   case 0:
949      if (trap_no < sizeof(trap0) / 8)
950      {
951         name = trap0[trap_code * 2];
952         param = trap0[trap_code * 2 + 1];
953      }
954      break;
955   case 1:
956      if (trap_no < sizeof(trap1) / 8)
957      {
958         name = trap1[trap_code * 2];
959         param = trap1[trap_code * 2 + 1];
960      }
961      break;
962   case 2:
963      if (trap_no < sizeof(trap2) / 8)
964      {
965         name = trap2[trap_code * 2];
966         param = trap2[trap_code * 2 + 1];
967      }
968      break;
969   case 3:
970      if (trap_no < sizeof(trap3) / 8)
971      {
972         name = trap3[trap_code * 2];
973         param = trap3[trap_code * 2 + 1];
974      }
975      break;
976   case 4:
977      if (trap_no < sizeof(trap4) / 8)
978      {
979         name = trap4[trap_code * 2];
980         param = trap4[trap_code * 2 + 1];
981      }
982      break;
983   case 5:
984      if (trap_no < sizeof(trap5) / 8)
985      {
986         name = trap5[trap_code * 2];
987         param = trap5[trap_code * 2 + 1];
988      }
989      break;
990   case 7:
991      if (trap_no < sizeof(trap7) / 8)
992      {
993         name = trap7[trap_code * 2];
994         param = trap7[trap_code * 2 + 1];
995      }
996      break;
997   case 8:
998      if (trap_no < sizeof(trap8) / 8)
999      {
1000         name = trap8[trap_code * 2];
1001         param = trap8[trap_code * 2 + 1];
1002      }
1003      break;
1004   }
1005
1006   sb[0] = '\0';
1007
1008   if (name == NULL)
1009   {
1010      strcat(sb, "???");
1011   }
1012   else
1013   {
1014      strcat(sb, name);
1015      if (param != NULL)
1016      {
1017         int i;
1018         strcat(sb, "(");
1019         for (i = 0, pa = sp + 4; param[i] != '\0'; i++)
1020         {
1021            switch (param[i])
1022            {
1023            case ',':
1024               strcat(sb, ", ");
1025               pa += 4;
1026               break;
1027            default:
1028               strcat(sb, get_param(m68k, pa, param[i]));
1029               break;
1030            }
1031         }
1032         strcat(sb, ")");
1033      }
1034   }
1035   return sb;
1036}
1037
1038static const char * disassemble(m68ki_cpu_core *m68k, offs_t pc, char* sb)
1039{
1040   UINT8 oprom[10];
1041   UINT8 opram[10];
1042   UINT32 options = 0;
1043
1044   // remember bus error state
1045   UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred;
1046   UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address;
1047
1048   m68k->mmu_tmp_buserror_occurred = 0;
1049   m68k->mmu_tmp_rw = 1;
1050
1051   int i;
1052   for (i = 0; i < sizeof(oprom); i++)
1053   {
1054      oprom[i] = opram[i] = m68k->memory.read8(pc + i);
1055      if (m68k->mmu_tmp_buserror_occurred)
1056      {
1057
1058         sprintf(sb, "- (apollo_disassemble failed at %08x)", pc + i);
1059
1060         // restore previous bus error state
1061         m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
1062         m68k->mmu_tmp_buserror_address = tmp_buserror_address;
1063
1064         return sb;
1065      }
1066   }
1067   m68k->device->disassemble(sb, pc, oprom, opram, options);
1068
1069   // restore previous bus error state
1070   m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
1071   m68k->mmu_tmp_buserror_address = tmp_buserror_address;
1072
1073   return sb;
1074}
1075
1076static const UINT16 *get_data(m68ki_cpu_core *m68k, offs_t addr)
1077{
1078   static UINT16 data[4];
1079
1080   // remember bus error state
1081   UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred;
1082   UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address;
1083
1084   m68k->mmu_tmp_buserror_occurred = 0;
1085   m68k->mmu_tmp_rw = 1;
1086
1087   int i;
1088   for (i = 0; i < sizeof(data); i += 2)
1089   {
1090      data[i/2] = m68k->memory.read16(addr + i);
1091   }
1092
1093   // restore previous bus error state
1094   m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
1095   m68k->mmu_tmp_buserror_address = tmp_buserror_address;
1096
1097   return data;
1098}
1099
1100//-------------------------------------------------
1101//  instruction_hook - should be called by the CPU core
1102//  before executing each instruction
1103//-------------------------------------------------
1104
1105int apollo_debug_instruction_hook(device_t *device, offs_t curpc)
1106{
1107   // trap data remembered for next rte
1108   static struct {
1109      UINT32 pc;
1110      UINT32 sp;
1111      UINT16 trap_no;
1112      UINT16 trap_code;
1113   } trap = { 0, 0, 0, 0 };
1114
1115   if (apollo_config( APOLLO_CONF_TRAP_TRACE | APOLLO_CONF_FPU_TRACE))
1116   {
1117      UINT32 ppc_save;
1118      UINT16 ir;
1119      m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token();
1120      m68k->mmu_tmp_buserror_occurred = 0;
1121
1122      /* Read next instruction */
1123      ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : m68k->memory.readimm16(REG_PC(m68k));
1124
1125      // apollo_cpu_context expects the PC of current opcode in REG_PPC (not the previous PC)
1126      ppc_save = REG_PPC(m68k);
1127      REG_PPC(m68k) = REG_PC(m68k);
1128
1129      if (m68k->mmu_tmp_buserror_occurred)
1130      {
1131         m68k->mmu_tmp_buserror_occurred = 0;
1132         // give up
1133      }
1134      else if ((ir & 0xff00) == 0xf200 && (apollo_config(   APOLLO_CONF_FPU_TRACE)))
1135      {
1136         char sb[256];
1137         LOG(("%s sp=%08x FPU: %x %s", apollo_cpu_context(device->machine().firstcpu),
1138               REG_A(m68k)[7], ir, disassemble(m68k, REG_PC(m68k), sb)));
1139      }
1140      else if (!m68k->pmmu_enabled)
1141      {
1142         // skip
1143      }
1144      else if (ir == 0x4e73) // RTE
1145      {
1146         const UINT16 *data = get_data(m68k, REG_A(m68k)[7]);
1147         if ( REG_USP(m68k) == 0 && (data[0] & 0x2000) == 0) {
1148            LOG(("%s sp=%08x RTE: sr=%04x pc=%04x%04x v=%04x usp=%08x",
1149               apollo_cpu_context(device->machine().firstcpu),
1150               REG_A(m68k)[7], data[0], data[1], data[2], data[3], REG_USP(m68k)));
1151         }
1152      }
1153      else if ((ir & 0xfff0) == 0x4e40 && (ir & 0x0f) <= 8 && apollo_config(APOLLO_CONF_TRAP_TRACE))
1154      {
1155         // trap n
1156         trap.pc = REG_PC(m68k);
1157         trap.sp = REG_A(m68k)[7];
1158         trap.trap_no = ir & 0x0f;
1159         trap.trap_code = REG_D(m68k)[0] & 0xffff;
1160
1161         char sb[1000];
1162         LOG(("%s sp=%08x Domain/OS SVC: trap %x 0x%02x: %s",
1163               apollo_cpu_context(device->machine().firstcpu), trap.sp,
1164               trap.trap_no, trap.trap_code,
1165               get_svc_call(m68k, trap.trap_no, trap.trap_code, sb)));
1166
1167      }
1168      else if (trap.pc == REG_PC(m68k) - 2 && trap.sp == REG_A(m68k)[7])
1169      {
1170         // rte
1171         char sb[1000];
1172         LOG(("%s sp=%08x Domain/OS SVC:              %s D0=0x%x",
1173               apollo_cpu_context(device->machine().firstcpu), trap.sp,
1174               get_svc_call(m68k, trap.trap_no, trap.trap_code, sb), REG_D(m68k)[0]));
1175
1176         trap.pc = 0;
1177         trap.sp = 0;
1178         trap.trap_no = 0;
1179         trap.trap_code = 0;
1180      }
1181      // restore previous PC
1182      REG_PPC(m68k) = ppc_save;
1183   }
1184    return 0;
1185}
src/mess/machine/apollo_net.c
r0r14540
1/*
2 * apollo_net.c - simple APOLLO netserver emulation (netman, ARP, IP echo, ...)
3 *
4 *  Created on: May 12, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also:
11 *  - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf
12 */
13
14#define VERBOSE 0
15
16// FIXME: these three should not be hardcoded
17#define NETSERVER_NODE_ID     0x012340
18#define NETSERVER_IP_ADDRESS  {192,168,2,3}    /* 192.168.2.3 */
19#define NETSERVER_ROOT_PATH   "apollo"
20
21#include "includes/apollo.h"
22#include "machine/3c505.h"
23
24typedef struct {
25   UINT8 dest[6];
26   UINT8 source[6];
27   UINT16 proto;
28} ethernet_header;
29
30typedef struct
31{
32   UINT8 version;
33   UINT8 tos;
34   UINT16 tot_len;
35   UINT16 id;
36   UINT16 frag_off;
37   UINT8 ttl;
38   UINT8 protocol;
39   UINT16 check;
40   UINT32 saddr;
41   UINT32 daddr;
42} ip_header;
43
44typedef struct
45{
46   UINT8 type;
47   UINT8 code;
48   UINT16 checksum;
49   UINT16 id;
50   UINT16 sequence;
51} icmp_header;
52
53//typedef struct {
54//   UINT16 version;
55//   UINT16 checksum;
56//   UINT16 packet_type;
57//   UINT16 control_header;
58//   UINT16 header_length;
59//   UINT16 header_data_length;
60//   UINT16 transaction_id;
61//} control_header;
62//
63//typedef struct {
64//   UINT16 length;
65//   UINT16 current;
66//   UINT16 source_socket;
67//   UINT16 new_route;
68//} packet_address;
69
70#define ETHERNET_HEADER_SIZE sizeof(ethernet_header)
71
72/* Ethernet protocol ID's */
73#define ETHERNET_PACKET_TYPE_IP 0x0800   /* IP */
74#define ETHERNET_PACKET_TYPE_ARP 0x0806  /* Address resolution */
75#define ETHERNET_PACKET_TYPE_APOLLO 0x8019
76
77#define ETHERNET_APOLLO_PREFIX 0x08001e
78#define ETHERNET_APOLLO_DOMAIN_PREFIX 0x09001e
79
80#define ICMP_ECHOREPLY      0   /* Echo Reply         */
81#define ICMP_ECHO          8   /* Echo Request         */
82
83#define PACKET_HEADER_SIZE 64
84
85// #define ETH_BUFFER_SIZE 2000
86
87// Note: these three pathnames are hardcoded in Apollo DomainOS; don't change them
88#define APOLLO_NETBOOT_PATH "/sys/net/netboot"
89#define APOLLO_SAU7_PATH "/sau7"
90#define APOLLO_SAU8_PATH "/sau8"
91#define APOLLO_SAU14_PATH "/sau14"
92
93static emu_file *current_file = NULL;
94
95static UINT16 current_sector = 0;
96static UINT16 current_last_sector = 0;
97static char current_pathname[256];
98
99static UINT8 current_rx_data_buffer[ETH_BUFFER_SIZE];
100static int current_rx_data_length;
101
102static apollo_netserver_transmit tx_callback = NULL;
103
104static UINT32 my_node_id;
105static UINT8 my_ip_address[4] = NETSERVER_IP_ADDRESS;  /* 192.168.2.3 */
106static UINT8 my_mac_address[6];
107
108static astring root_path;
109
110// boot_$volun (find partner node)
111static UINT8 response_0006[] = {
112   0x00,0x01,                      // 0x40:
113   0x00,0x01,
114   0x00,0x07,                      // 0x44: packet type (07 = 06+1)
115   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
116   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117   0x00,0x00,0x00,0x00,0x00,0x00
118};
119
120static UINT8 list_directory_header[] = {
121   0x00,0x01,                      // 0x40:
122   0x00,0x01,
123   0x00,0x0d,                      // 0x44: packet type (0d = 0c+1)
124   0x00,0x00,0x00,0x00,            // 0x46:
125   0x00,0x01,0x00,0x01,
126   0x73,0x61,0x6d,0x62,0x61,0x2f,0x73,0x61,0x75,0x37, // "samba/sau7"
127   0x00,0x00,0x28,0xd8,0x00,0x00,0x00,0x00,
128   0x75,0x37,0xd8,0xa0,0x76,0x08,0xb5,0x52,
129   0x75,0x37,0xe6,0xc6,0x75,0x37,0xd8,0xac
130};
131
132static UINT8 receive_data_header[] = {
133    0x00,0x01,                      // 0x40:
134    0x00,0x01,                      // 0x42:
135    0x00,0x09,                      // 0x44: packet type (09 = 08+1)
136    0x00,0x00,0x00,0x00,            // 0x46:
137    0x00,0x13,0xfc,0xaf,            // 0x4A: high
138    0x00,0x13,0xd8,0x00,            // 0x4E: low
139    0x00,0x13,0xd8,0x2a,            // 0x52: start
140    0x00,0x13,0xd8,0x00,            // 0x56: current load address
141    0x00,0x00                       // 0x5a:
142};
143
144static UINT8 not_found_data_header[] = {
145   0x00,0x01,                      // 0x40:
146   0x00,0x01,                      // 0x42: ?
147   0x00,0x13,                      // 0x44: packet type (13 = 12+1)
148   0x00,0x0e,0x00,0x07,
149   0x00,0x12,                      // 0x4a = string length
150   0x2f,0x2f,0x73,0x61,0x6d,0x62,0x61,0x2f, 0x73,0x61,0x75,0x37,0x2f,0x78,0x78,0x78, /*//samba/sau7/xxxxx */
151   0x78,0x78,
152
153   0x07,0x48,0x00,0x08,0x07,0x6a,0x00,0x08, 0x07,0x6c,0x00,0x04,0x0c,0x94
154};
155
156// boot_$get_uids
157static UINT8 response_070a[] = {
158   0x00,0x01,                               // 0x40:
159   0x00,0x01,
160   0x00,0x0b,                               // 0x44: packet type (0b = 0a+1)
161   0x00,0x00,0x00,0x00,
162   // d993195c (2010-04-28 07:27:15)
163   0xd9,0x93,0x19,0x5c,0x60,0x04,0x20,0xe8, // FIXME: UID of OS paging file (?)
164   // 7742b564 (1996-08-14 19:12:59)
165   0x77,0x42,0xb5,0x64,0xf0,0x04,0x20,0xe8, // 7742B564.F00420E8 is UID of //
166   0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8  // 7742B564.E00420E8 is UID of / (resp. //samba)
167};
168
169// get (dex) file parameters
170static UINT8 response_0718[] = {
171   0x00,0x01,                      // 0x40:
172   0x00,0x01,                      // 0x42:
173   0x00,0x19,                      // 0x44: packet type (19 = 18+1)
174   0x00,0x00,0x00,0x00,            // 0x46:
175   0x01,
176   0x01,                           // 0x4b: systyp (1=dir, 0=file) i.e. is directory
177   0x90,0x00,
178   0x77,0x43,0x02,0x58,0xe0,0x04,0x20,0xe8, // 0x4e: source UID
179   0x00,0x00,                      // 0x56
180   0x00,0x00,                      // 0x58: file type (0x0321 = UASC file)
181   0x00,0x00,0x00,0x00,            // 0x5A:
182   0x77,0x43,0x02,0x58,0xe8,0x04,0x20,0xe8, // 0x5E: source UID
183   0x00,0x00,0x10,0x00,            // 0x66: file size
184   0x00,0x00,0x00,0x04,            // 0x6A: n sectors (?)
185   0xd9,0x8f,0xb5,0xef,            // 0x6E:
186   0x80,0x27,0x94,0x1e,            // 0x72:
187   0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8, // source UID
188   0x8d,0x15,0x00,0x02,
189   0x00,0x00,0x00,0x00,
190   0x00,0x00,0x00,0x00
191};
192
193static UINT8 get_byte(const UINT8 *data) {
194   return data[0];
195}
196
197static void set_byte(UINT8 *data, const UINT8 value) {
198   data[0] = value;
199}
200
201static UINT16 get_word(const UINT8 *data) {
202   return (data[0] << 8) | data[1];
203}
204
205static void set_word(UINT8 *data, const UINT16 value) {
206   data[0] = value >> 8;
207   data[1] = value & 0xff;
208}
209
210static UINT32 get_3byte(const UINT8 *data) {
211   return (((data[0] << 8) | data[1]) << 8) | data[2];
212}
213
214static void set_3byte(UINT8 *data, const UINT32 value) {
215   data[0] = (value >> 16) & 0xff;
216   data[1] = (value >> 8) & 0xff;
217   data[2] = value & 0xff;
218}
219
220static UINT32 get_long(const UINT8 *data) {
221   return (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
222}
223
224static void set_long(UINT8 *data, const UINT32 value) {
225   data[0] = (value >> 24) & 0xff;
226   data[1] = (value >> 16) & 0xff;
227   data[2] = (value >> 8) & 0xff;
228   data[3] = value & 0xff;
229}
230
231static char *get_string(const UINT8 *data) {
232   static char sb[256];
233   int i;
234   int stringLength = get_word(data);
235   for (i = 0; i < stringLength && i < sizeof(sb) - 1; i++) {
236      sb[i] = data[i + 2];
237   }
238   sb[stringLength] = 0;
239   return sb;
240}
241
242static char *get_file_name(const UINT8 *data) {
243   char * s = get_string(data);
244   int i = strlen(s);
245   while (--i >= 0) {
246      s[i] = tolower(s[i]);
247   }
248   return s;
249}
250
251static int get_file_size(const char *path) {
252   int file_size = 0;
253   emu_file file(OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
254   file_error filerr = file.open(path);
255   if (filerr == FILERR_NONE)
256   {
257      file_size = file.size();
258      file.close();
259   }
260   LOG1(("##### %s - file_size=%d",path, file_size));
261   return file_size;
262}
263
264static int is_directory(const char *path) {
265   int is_directory = 0;
266   osd_directory *curdir;
267   if ((curdir = osd_opendir(path)) != NULL)
268   {
269      osd_closedir(curdir);
270      is_directory = 1;
271   }
272   LOG1(("##### %s - is_directory=%d",path, is_directory));
273   return is_directory;
274}
275
276static int get_file_type(const char *path) {
277   if (!is_directory(path)) {
278      const char *suffix = path + strlen(path);
279      while (suffix != path && *--suffix != '.') {
280      }
281
282      if (strcmp(suffix, ".cmd") == 0 || strcmp(suffix, ".hlp") == 0) {
283         return 0x0321; // UASC file
284      }
285   }
286   return 0;
287}
288
289static int set_ethernet_header(UINT8 *data, UINT8 client_ethernet_address[6]) {
290   memcpy(data + 0, client_ethernet_address, 6);
291   set_3byte(data + 6, ETHERNET_APOLLO_PREFIX);
292   set_3byte(data + 9, my_node_id);
293   set_word(data + 12, ETHERNET_PACKET_TYPE_APOLLO);
294   return ETHERNET_HEADER_SIZE;
295}
296
297//static int set_packet_header1(UINT8 *packet_buffer, UINT32 dest_node_id,
298//      UINT32 source_node_id) {
299//
300//   //0000  08 00 1e 02 61 6d 08 00  1e 04 20 e8 80 19 ff ff
301//   //0010  00 20 00 be 00 00 47 11  08 00 1e 02 61 6d 06 20
302//   //0020  00 00 00 00 08 00 1e 04  20 e8 00 01 00 02 61 6d
303//   //0030  20 00 00 00 00 04 20 e8  02 00 20 00 00 4e 00 02
304//   //0040  00 00 00 00 2e 04 00 01  20 e8 00 01 00 04 20 e8
305//
306//   //0050  61 6d 06 20 ff ff 00 20  00 04 00 00 47 11 00 00
307//   //0060  00 02 61 6d 06 20 00 00  00 00 00 00 00 04 20 e8
308//   //0070  00 01 00 00 00 00 80 31  00 01
309//
310//   set_packet_header(packet_buffer, dest_node_id, source_node_id);
311//   set_word(packet_buffer + 8, 0x4711); // Apollo network number
312//   set_word(packet_buffer + 16, 0x0620); // ? was 0x0000
313//   set_word(packet_buffer + 28, 0x0001); // ? was 0x0003
314
315//   set_long(packet_buffer + 34, 0x20000000L); // ? was 0x24000000L
316//   set_long(packet_buffer + 42, 0x02002000L); // ? was 0x01002400L
317//   set_word(packet_buffer + 46, 0x004e); // ? data_size + 0x22
318//   set_word(packet_buffer + 48, 0x0002); // ? data_size
319//   set_word(packet_buffer + 54, 0x2e04); // ? 0x0401
320//   set_word(packet_buffer + 56, 0x0001); // ? 0x0003
321//   set_word(packet_buffer + 60, 0x616d);
322//   set_word(packet_buffer + 62, 0x0000);
323//   return PACKET_HEADER_SIZE;
324//}
325
326static int set_packet_header(UINT8 *packet_buffer, UINT32 dest_node_id,
327      UINT32 source_node_id) {
328   // --------- apollo header --------------
329   set_word(packet_buffer, 0xffff);
330   //   set_word(packet_buffer + 2, data_size + PACKET_HEADER_SIZE);
331   set_word(packet_buffer + 4, 0x00be);
332   set_word(packet_buffer + 6, 0x0000);
333   set_word(packet_buffer + 8, 0x0000); // Apollo network number
334   set_3byte(packet_buffer + 10, ETHERNET_APOLLO_PREFIX);
335   set_3byte(packet_buffer + 13, dest_node_id);
336   set_word(packet_buffer + 16, 0x0000);
337   set_word(packet_buffer + 18, 0x0000);
338   set_word(packet_buffer + 20, 0x0000);
339   set_3byte(packet_buffer + 22, ETHERNET_APOLLO_PREFIX);
340   set_3byte(packet_buffer + 25, source_node_id);
341   set_word(packet_buffer + 28, 0x0003);
342   // --------- data header --------------
343   set_long(packet_buffer + 30, dest_node_id);
344   set_long(packet_buffer + 34, 0x24000000L);
345   set_long(packet_buffer + 38, source_node_id);
346   set_long(packet_buffer + 42, 0x01002400L);
347   //   set_word(packet_buffer + 46, data_size + 0x22);
348   //   set_word(packet_buffer + 48, data_size);
349   set_word(packet_buffer + 50, 0x0000);
350   set_word(packet_buffer + 52, 0x0000);
351   // --------- data --------------
352   set_word(packet_buffer + 54, 0x0401);
353   set_word(packet_buffer + 56, 0x0003);
354   set_word(packet_buffer + 58, 0x20e8);
355   set_word(packet_buffer + 60, 0x616d);
356   set_word(packet_buffer + 62, 0x0000);
357   return PACKET_HEADER_SIZE;
358}
359
360static int set_packet(UINT8 *packet_buffer, UINT8 *packet_data,
361      int packet_data_size) {
362   set_word(packet_buffer + 2, packet_data_size + PACKET_HEADER_SIZE);
363   set_word(packet_buffer + 46, packet_data_size + 0x22);
364   set_word(packet_buffer + 48, packet_data_size);
365
366   memcpy(packet_buffer + PACKET_HEADER_SIZE, packet_data, packet_data_size);
367
368   return packet_data_size;
369}
370
371static int get_packet_size(UINT8 *packet_buffer) {
372   return get_word(packet_buffer + 2);
373}
374
375static int get_dir_data(const char *pathname, UINT8 *packet_buffer) {
376   int nBytes, lineLength;
377   char *data_buffer;
378   osd_directory *curdir;
379   const osd_directory_entry *dir;
380
381   char dir_path[1024];
382   strcpy(dir_path, root_path);
383   strcat (dir_path, pathname);
384
385   set_packet(packet_buffer, list_directory_header,
386         sizeof(list_directory_header));
387   data_buffer = (char *) (packet_buffer + get_packet_size(packet_buffer));
388
389   strcpy(data_buffer, "\n\r");
390   strcat(data_buffer, pathname);
391   strcat(data_buffer, "\n\r");
392
393   if ((curdir = osd_opendir(dir_path)) == NULL)
394   {
395      strcat(data_buffer, "Error: failed to open directory ");
396      strcat(data_buffer, dir_path);
397      strcat(data_buffer, "\r\n");
398   }
399   else
400   {
401      osd_closedir(curdir);
402
403      // open a path to the netserver directory
404      file_enumerator path(dir_path);
405
406      lineLength = 99;
407      while ((dir = path.next()) != NULL)
408      {
409         int length = strlen(dir->name);
410         LOG1(("##### %d %s",length, dir->name));
411
412         if (strcmp(dir->name, ".") != 0 && strcmp(dir->name, "..") != 0)
413         {
414            lineLength += 3 + strlen(dir->name);
415            if (lineLength > 72) {
416               strcat(data_buffer, "\n\r");
417               lineLength = 3 + strlen(dir->name);
418            }
419            strcat(data_buffer, "   ");
420            strcat(data_buffer, dir->name);
421         }
422      }
423      strcat(data_buffer, "\n\r");
424   }
425
426   nBytes = strlen(data_buffer);
427   nBytes = (nBytes + 1) & 0xfffffffe;
428
429   set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
430   set_word(packet_buffer + 50, nBytes);
431
432   return nBytes + sizeof(list_directory_header);
433}
434
435static int get_file_data(const char *pathname, UINT8 *packet_buffer,
436      UINT16 first_sector, UINT16 last_sector) {
437   UINT8 *packet_data = packet_buffer + PACKET_HEADER_SIZE;
438   UINT8 *data_buffer;
439   int nBytes;
440   UINT32 fileSize = 0;
441   file_error filerr;
442
443   if(current_file == NULL)
444   {
445      current_file = global_alloc(emu_file(root_path, OPEN_FLAG_READ));
446      // skip leading '/'
447      filerr = current_file->open( pathname+1);
448
449      if (filerr != FILERR_NONE)
450      {
451         global_free(current_file);
452         current_file = NULL;
453      }
454
455      fileSize = current_file == NULL ? 0 : current_file->size();
456      current_sector = 0;
457
458      LOG1(("##### %s - %s filerr=%d fileSize=%d", root_path.cstr(), pathname, filerr, fileSize));
459   } else {
460      current_sector++;
461   }
462   current_last_sector = last_sector;
463
464   if (current_file == NULL)
465   {
466      set_packet(packet_buffer, not_found_data_header,
467            sizeof(not_found_data_header));
468
469      set_word(packet_data + 0x0A, strlen(pathname));
470      strncpy((char *) packet_data + 0x0C, pathname, 0x24);
471      return sizeof(not_found_data_header);
472   } else {
473      set_packet(packet_buffer, receive_data_header,
474            sizeof(receive_data_header));
475
476      data_buffer = (packet_buffer + get_packet_size(packet_buffer));
477
478      nBytes = current_file->read(data_buffer, 1024);
479
480      if (nBytes < 0) {
481         nBytes = 0;
482      }
483
484      // help in dex will fail, if size is odd (5.5.2010 - ost)
485      nBytes = (nBytes + 1) & 0xfffffffe;
486
487      if (nBytes < 1024)
488      {
489         current_file->close();
490         global_free(current_file);
491         current_file = NULL;
492      }
493      else if (current_sector == 0) {
494         // set header addresses from first sector read
495         UINT32 low = get_long(data_buffer + 0);
496         UINT32 start = get_long(data_buffer + 4);
497         UINT32 high = low + fileSize - 1;
498
499         set_long(receive_data_header + 0x0A, high);
500         set_long(receive_data_header + 0x0E, low);
501         set_long(receive_data_header + 0x12, start);
502         set_long(receive_data_header + 0x16, low);
503
504         set_packet(packet_buffer, receive_data_header,
505               sizeof(receive_data_header));
506      }
507
508      if (VERBOSE > 1) {
509         LOG1(("##### %s: 3C505 current address = %0x first/last/current sector = %0x / %0x / %0x",
510                     pathname, get_long(receive_data_header + 0x16), first_sector, last_sector, current_sector));
511      }
512
513      set_long(receive_data_header + 0x16, get_long(receive_data_header + 0x16) + nBytes);
514      set_word(packet_data + 0x1A, nBytes < 1024 ? 0xffff : current_sector == last_sector ? 0x00ff : 0);
515
516      set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
517      set_word(packet_buffer + 50, nBytes);
518
519      return nBytes + sizeof(receive_data_header);
520   }
521}
522
523static void log_data(const device_t *device, const char *type,
524      const UINT8 *data, int data_length) {
525   if (VERBOSE > 1) {
526      int i;
527      logerror("%s - %s: Net Server %s Data (length=%2x)", apollo_cpu_context(
528            device->machine().firstcpu), device->tag(), type, data_length);
529      for (i = 0; i < data_length; i++) {
530         logerror(" %02x", data[i]);
531      }
532      logerror("\n");
533   }
534}
535
536static UINT16 get_socket(const UINT8 rx_data_buffer[], int rx_data_length) {
537
538   const UINT8 * packet_buffer = rx_data_buffer + ETHERNET_HEADER_SIZE;
539   int packet_length = rx_data_length - ETHERNET_HEADER_SIZE;
540
541   UINT16 socket = packet_length < 0x11 ? 0xffff : get_word(packet_buffer + 0x10); // 0x10: dest socket
542
543   return socket;
544}
545
546/***************************************************************************
547 netman server
548 ***************************************************************************/
549
550static int netman_server(const device_t *device,
551      const UINT8 rx_data_buffer[], int rx_data_length, UINT8 tx_data_buffer[]) {
552   UINT16 service;
553   UINT16 node_type; // SAU7, SAU8 or SAU14
554   char pathname[256];
555
556   int tx_data_length;
557
558   UINT8 *packet_buffer = tx_data_buffer + ETHERNET_HEADER_SIZE;
559
560   UINT32 client_node_id;
561   UINT8 client_ethernet_address[6];
562
563   UINT16 last_sector;
564   UINT16 first_sector;
565
566   client_node_id = get_3byte(rx_data_buffer + 9);
567   memcpy(client_ethernet_address, rx_data_buffer + 6, 6);
568
569   log_data(device, "Rx", rx_data_buffer, rx_data_length);
570
571   // strip off the ethernet header;
572   rx_data_buffer += ETHERNET_HEADER_SIZE;
573   rx_data_length -= ETHERNET_HEADER_SIZE;
574
575   service = (rx_data_length > 0x45) ? get_word(rx_data_buffer + 0x44) : 0xffff;
576   first_sector = (rx_data_length > 0x6b) ? get_word(rx_data_buffer + 0x6a) : 0;
577   // FIXME: hack
578//   last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0;
579   last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0x0f;
580
581   set_ethernet_header(tx_data_buffer, client_ethernet_address);
582   set_packet_header(packet_buffer, client_node_id, my_node_id);
583
584   node_type = service >> 8;
585
586   switch (service & 0xff) {
587   case 6: // boot_$volun (find partner node)
588      DLOG1(("Net Server service=%04x (boot_$volun)", service));
589      set_packet(packet_buffer, response_0006, sizeof(response_0006));
590      break;
591
592   case 8: // boot_$sysboot  (get netboot)
593      get_file_data(APOLLO_NETBOOT_PATH, packet_buffer, first_sector, last_sector);
594      DLOG1(("Net Server service=%04x (boot_$sysboot - sector %x of %x-%x)", service, current_sector, first_sector, last_sector));
595      break;
596   case 0x0a: // boot_$get_uids    (get UIDs for OS paging file, network root and the node entry directory)
597      set_packet(packet_buffer, response_070a, sizeof(response_070a));
598      DLOG1(("Net Server service=%04x (boot_$get_uids)", service));
599      break;
600   case 0x0c: // boot_$mult_ld (list directory for sau7, SAU8, SAU14)
601      get_dir_data( node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH, packet_buffer);
602      DLOG1(("Net Server service=%04x (boot_$mult_ld)", service));
603      break;
604   case 0x12: // boot_$load    (ex /sau7/self_test, domain_os, ...)
605      strcpy(pathname, node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH);
606      strcat(pathname, "/");
607      strcat(pathname, get_file_name(rx_data_buffer + 0x48));
608      get_file_data(pathname, packet_buffer, first_sector, last_sector);
609      DLOG1(("Net Server service=%04x (boot_$load %s - sector %x of %x-%x)", service, pathname, current_sector, first_sector, last_sector));
610      break;
611   case 0x18: // boot_$set_path (set current path and get attributes of current path)
612      set_packet(packet_buffer, response_0718, sizeof(response_0718));
613
614      if (get_long(rx_data_buffer + 0x6e) == 0L && get_long(rx_data_buffer + 0x72) == 0L) {
615         // reset path name to root dir
616         strcpy(current_pathname, root_path);
617      }
618
619      // FIXME: why is this necessary???
620      if (is_directory(current_pathname)) {
621         strcat(current_pathname, "/");
622         strcat(current_pathname, get_file_name(rx_data_buffer + 0x48));
623      }
624
625      // 0x4b: systyp (1=dir, 0=file)
626      set_byte(packet_buffer + 0x4b, is_directory(current_pathname));
627      set_word(packet_buffer + 0x58, get_file_type(current_pathname));
628      set_long(packet_buffer + 0x66, get_file_size(current_pathname));
629
630      DLOG1(("Net Server service=%04x (boot_$set_path %s)", service, current_pathname + strlen(root_path)));
631      break;
632   case 0x1a: // boot_$load_file (?): load /sau7/cmd/startup.cmd, /sau7/cpu.dex, ...
633      get_file_data(current_pathname + strlen(root_path), packet_buffer, first_sector, last_sector);
634      DLOG1(("Net Server service=%04x (boot_$load_file %s - sector %x of %x-%x)", service, current_pathname + strlen(root_path), current_sector, first_sector, last_sector));
635      break;
636   default:
637      DLOG(("Net Server - unexpected service %04x", service&0xff));
638      return 0;
639   }
640
641   set_word(packet_buffer + 0x44, (service & 0xff) + 1); // 0x44: response packet type
642
643   tx_data_length = ETHERNET_HEADER_SIZE + get_packet_size(packet_buffer);
644
645   log_data(device, "Tx", tx_data_buffer, tx_data_length);
646   return tx_data_length;
647}
648
649static int is_ethernet_broadcast_address(const UINT8 ethernet_header[]) {
650   return get_3byte(ethernet_header + 0) == 0xffffff && //
651         get_3byte(ethernet_header + 3) == 0xffffff;
652}
653
654static int is_apollo_multicast_address(const UINT8 ethernet_header[]) {
655   return get_3byte(ethernet_header + 0) == ETHERNET_APOLLO_DOMAIN_PREFIX && //
656         (get_3byte(ethernet_header + 3) == 0L || get_3byte(ethernet_header + 3) == 1L);
657}
658
659static int is_my_ethernet_address(const UINT8 mac_address[]) {
660   return memcmp(mac_address, my_mac_address, 6) == 0;
661}
662
663static int is_my_ip_address(const UINT8 ip_address[]) {
664   return memcmp (ip_address, my_ip_address, 4) == 0;
665}
666
667static int is_my_node_id(const UINT8 node_id[]) {
668   return get_long(node_id) == my_node_id;
669}
670
671static int ethernet_packet_is_for_me(const UINT8 ethernet_header[],
672      const int data_length) {
673   return data_length >= ETHERNET_HEADER_SIZE && (
674         is_ethernet_broadcast_address(ethernet_header) ||
675         is_apollo_multicast_address(ethernet_header) ||
676         is_my_ethernet_address(ethernet_header));
677}
678
679static int is_apollo_request(const UINT8 ethernet_header[],
680      const int data_length) {
681
682   return data_length >= 0x30 && //
683      get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_APOLLO;
684}
685
686static int is_apollo_arp_request(const UINT8 ethernet_header[], const int data_length) {
687   return data_length >= 0x30 && //
688         get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
689         get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_APOLLO && //
690         is_apollo_multicast_address(ethernet_header) && //
691         is_my_node_id(ethernet_header + 0x26);
692}
693
694static int is_ip_arp_request(const UINT8 ethernet_header[], const int data_length) {
695   return data_length >= 0x30 && //
696         get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
697         get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_IP && //
698         is_ethernet_broadcast_address(ethernet_header) && //
699         is_my_ip_address (ethernet_header + 0x26);
700}
701
702static int is_ip_echo_request(const UINT8 ethernet_header[], const int data_length) {
703   return data_length >= 0x30 && //
704         get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_IP && //
705            get_byte(ethernet_header + 0x22) == ICMP_ECHO && //
706            is_my_ethernet_address(ethernet_header);
707}
708
709static UINT16 in_checksum(UINT8 *ptr, UINT32 nbytes)
710{
711   UINT32 sum = 0;
712   while (nbytes > 1)
713   {
714      // MSB first
715      sum += (*ptr++) << 8;
716      sum += *ptr++;
717      nbytes -=2;
718   }
719   if (nbytes == 1)
720   {
721      sum += (*ptr++) << 8;
722   }
723   sum = (sum >> 16) + (sum & 0xffff);
724   sum += (sum >> 16);
725
726   return (~sum) & 0xffff;
727}
728
729/***************************************************************************
730 simple ARP Server emulation
731 ***************************************************************************/
732
733static int arp_server(const device_t *device,
734      const UINT8 rx_data[], int rx_data_length,
735      UINT8 tx_data[]) {
736
737//   static UINT8 arp_response[] = {
738//      0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x00: Ethernet address of destination
739//      0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x06: Ethernet address of sender
740//      0x08,0x06,                     // 0x0c: Protocol type
741//      0x00,0x01,                     // 0x0e: Hardware address space
742//      0x80,0x19,                     // 0x10: Protocol address space
743//      0x06,                          // 0x12: byte length of each hardware address
744//      0x04,                          // 0x13: byte length of each protocol address
745//      0x00,0x02,                     // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
746//      0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x16: Hardware address of sender of this packet
747//      0x00,0x04,0x20,0xe8,           // 0x1c: Protocol address of sender of this packet
748//      0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x20: Hardware address of target of this packet (if known)
749//      0x00,0x02,0x61,0x6d,           // 0x26: Protocol address of target
750//      ...
751//   };
752
753   UINT16 tx_data_length = rx_data_length;
754   memcpy(tx_data, rx_data, tx_data_length);
755
756   // 0x00: Ethernet address of destination
757   memcpy(tx_data + 0x00, rx_data + 0x06, 6);
758   // 0x06: Ethernet address of sender
759   memcpy(tx_data + 0x06, my_mac_address, 6);
760   // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
761   set_word(tx_data + 0x14, 2);
762   // 0x16: Hardware address of sender
763   memcpy(tx_data + 0x16, my_mac_address, 6);
764   // 0x1c: Protocol address of sender
765   memcpy(tx_data + 0x1c, rx_data + 0x26, 4);
766   // 0x20: Hardware address of target (if known)
767   memcpy(tx_data + 0x20, rx_data + 0x16, 6);
768   // 0x26: Protocol address of target
769   memcpy(tx_data + 0x26, rx_data + 0x1c, 4);
770
771   log_data(device, "ARP Rx", rx_data, rx_data_length);
772   log_data(device, "ARP Tx", tx_data, tx_data_length);
773   return tx_data_length;
774}
775
776/***************************************************************************
777 simple Echo (ping) Server emulation
778 ***************************************************************************/
779
780static int echo_server(const device_t *device,
781      const UINT8 rx_data[], int rx_data_length,
782      UINT8 tx_data[]) {
783
784    static const UINT32 ip_offset = sizeof(ethernet_header);
785    static const UINT32 icmp_offset = ip_offset + sizeof(ip_header);
786
787   UINT16 tx_data_length = rx_data_length;
788   memcpy(tx_data, rx_data, tx_data_length);
789
790   // 0x00: Ethernet address of destination
791   memcpy(tx_data + 0x00, rx_data + 0x06, 6);
792   // 0x06: Ethernet address of sender
793   memcpy(tx_data + 0x06, rx_data + 0x00, 6);
794   // 0x12: ip.id
795   set_word(tx_data + 0x12, 0x0573);
796   // 0x18: ip.checksum
797   set_word(tx_data + 0x18, 0);
798   set_word(tx_data + 0x18, in_checksum(tx_data + ip_offset, sizeof(ip_header)));
799
800   // 0x1a: Protocol address of sender
801   memcpy(tx_data + 0x1a, rx_data + 0x1e, 4);
802   // 0x1e: Protocol address of target
803   memcpy(tx_data + 0x1e, rx_data + 0x1a, 4);
804   // 0x22: icmp.type
805   set_byte(tx_data + 0x22, ICMP_ECHOREPLY);
806   // 0x24: icmp.cksump
807   set_word(tx_data + 0x24, 0);
808   set_word(tx_data + 0x24, in_checksum(tx_data + icmp_offset, tx_data_length-icmp_offset));
809
810   log_data(device, "Echo Rx", rx_data, rx_data_length);
811   log_data(device, "Echo Tx", tx_data, tx_data_length);
812   return tx_data_length;
813}
814
815/***************************************************************************
816 netserver
817 ***************************************************************************/
818
819static int netserver(const device_t *device,
820      const UINT8 rx_data[], int rx_data_length,
821      UINT8 tx_data[]) {
822
823   if (!ethernet_packet_is_for_me(rx_data, rx_data_length))
824      return 0; // skip
825   else if (is_apollo_request(rx_data, rx_data_length))
826   {
827      UINT16 socket = get_socket(rx_data, rx_data_length);
828
829      switch (socket) {
830      case 1: // Paging socket
831         break;
832      case 2: // File socket
833//         return file_server(device, rx_data, rx_data_length, tx_data);
834         break;
835      case 3: // NETMAN socket
836         return netman_server(device, rx_data, rx_data_length, tx_data);
837      case 4: // Information socket
838         break;
839      case 5: // Receives internet asknode "who" replies
840         break;
841      case 6: // File server overflow socket
842         break;
843      case 7: // Software diagnostic socket
844         break;
845      case 8: // routing information protocol (RIP) socket
846         break;
847      case 9: // Mailbox socket
848         break;
849      case 10: // NS Helper socket
850         break;
851      case 11: // TCP/IP
852         break;
853      case 12: // ?
854         break;
855      default:
856         break;
857      }
858
859      DLOG1(("Net Server - socket %d not yet supported", socket));
860      return 0;
861   } else if (is_apollo_arp_request(rx_data, rx_data_length)) {
862      return arp_server(device, rx_data, rx_data_length, tx_data);
863   } else if (is_ip_arp_request(rx_data, rx_data_length)) {
864      return arp_server(device, rx_data, rx_data_length, tx_data);
865   } else if (is_ip_echo_request(rx_data, rx_data_length)) {
866      return echo_server(device, rx_data, rx_data_length, tx_data);
867   } else {
868      log_data(device, "unexpected Rx", rx_data, rx_data_length);
869      return 0;
870   }
871}
872
873/***************************************************************************
874 receive_interrupt
875 ***************************************************************************/
876
877static TIMER_CALLBACK(receive_interrupt) {
878   device_t *device = (device_t *)ptr;
879
880   UINT8 tx_data_buffer[ETH_BUFFER_SIZE];
881
882   int tx_data_length = netserver(device, current_rx_data_buffer, current_rx_data_length, tx_data_buffer);
883
884   DLOG2(("Net Server rx/tx_data_length = %x/%x current_sector=%x current_last_sector=%x",
885         current_rx_data_length, tx_data_length, current_sector, current_last_sector ));
886
887   if (tx_data_length > 0 && tx_callback != NULL) {
888      // threecom3c505_receive(device, tx_data_buffer, tx_data_length);
889      (*tx_callback)(device, tx_data_buffer, tx_data_length);
890   }
891
892   if (current_file != NULL && current_sector < current_last_sector)
893   {
894      // more packets pending
895      machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
896   } else {
897      current_rx_data_length = 0;
898   }
899}
900
901/***************************************************************************
902 apollo_netserver_receive - receive and process an ethernet packet
903 ***************************************************************************/
904
905int apollo_netserver_receive(device_t *device, const UINT8 rx_data_buffer[],
906      int rx_data_length)
907{
908   if (!ethernet_packet_is_for_me(rx_data_buffer, rx_data_length))
909   {
910      return 1; // skip packet
911   }
912   else if (current_rx_data_length > 0)
913   {
914      LOG(("!!!! apollo_netserver_receive: busy - skipped data with length %02x",rx_data_length));
915      return 0;
916   }
917   else
918   {
919      memcpy(current_rx_data_buffer, rx_data_buffer, rx_data_length);
920      current_rx_data_length = rx_data_length;
921
922      // delay response to multicast requests
923      int ms = is_apollo_multicast_address(rx_data_buffer) ? 100 : 1;
924      device->machine().scheduler().timer_set(attotime::from_msec(ms), FUNC(receive_interrupt), 0, device);
925      return 1;
926   }
927}
928
929/***************************************************************************
930 apollo_netserver_init - specify the transmitter call back function
931 ***************************************************************************/
932
933void apollo_netserver_init(const char *root_path, apollo_netserver_transmit tx_data)
934{
935   ::root_path.cat(root_path);
936   ::root_path.cat(PATH_SEPARATOR);
937   ::root_path.cat(NETSERVER_ROOT_PATH);
938
939   ::tx_callback = tx_data;
940
941   my_node_id = NETSERVER_NODE_ID;
942   set_3byte(my_mac_address, ETHERNET_APOLLO_PREFIX);
943   set_3byte(my_mac_address + 3, my_node_id);
944
945   current_rx_data_length = 0;
946}
src/mess/machine/omti8621.c
r0r14540
1/*
2 * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00)
3 *
4 *  Created on: August 30, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  see also:
11 *  * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf
12 */
13
14#define VERBOSE 0
15
16static int verbose = VERBOSE;
17
18#include "machine/omti8621.h"
19#include "image.h"
20
21#define LOG(x)   { logerror ("%s: ", cpu_context(state->device)); logerror x; logerror ("\n"); }
22#define LOG1(x)   { if (verbose > 0) LOG(x)}
23#define LOG2(x)   { if (verbose > 1) LOG(x)}
24#define LOG3(x)   { if (verbose > 2) LOG(x)}
25
26#define DLOG(x)   { logerror ("%s: ", cpu_context(disk->device)); logerror x; logerror ("\n"); }
27#define DLOG1(x)   { if (verbose > 0) DLOG(x)}
28#define DLOG2(x)   { if (verbose > 1) DLOG(x)}
29
30#define OMTI_DISK_SECTOR_SIZE 1056
31
32#define OMTI_DISK_TYPE_155_MB 0x607 // Micropolis 1355 (170 MB Dtype = 607)
33#define OMTI_DISK_TYPE_348_MB 0x604 // Maxtor EXT-4380-E (380 MB Dtype = 604)
34#define OMTI_DISK_TYPE_DEFAULT OMTI_DISK_TYPE_348_MB // new disks will have this type (and size)
35
36#define OMTI_MAX_BLOCK_COUNT 32
37
38#define OMTI_MAX_LUN 1
39#define OMTI_DISK0_TAG "omti_disk0"
40#define OMTI_DISK1_TAG "omti_disk1"
41
42#define CDB_SIZE 10
43
44/*
45 * I/O register offsets
46 */
47
48#define OMTI_PORT_DATA_IN    0x00    /* read, 8-bit */
49#define OMTI_PORT_DATA_OUT   0x00    /* write, 8-bit */
50#define OMTI_PORT_STATUS     0x01    /* read, 8-bit */
51#define OMTI_PORT_RESET      0x01    /* write, 8-bit */
52#define OMTI_PORT_CONFIG     0x02    /* read, 8-bit */
53#define OMTI_PORT_SELECT     0x02    /* write, 8-bit */
54#define OMTI_PORT_MASK       0x03    /* write only, 8-bit */
55
56// port status
57
58#define OMTI_STATUS_REQ  0x01 // Request (1 = request transfer of data via data in/out register)
59#define OMTI_STATUS_IO   0x02 // In/Out (1 = direction of transfer is from controller to host)
60#define OMTI_STATUS_CD   0x04 // Command/Data ( 1 = byte transfered is command or status byte)
61#define OMTI_STATUS_BUSY 0x08 // Busy (0 = controller is idle, 1 = controller selected)
62#define OMTI_STATUS_DREQ 0x10 // Data Request (0 = no DMA request, 1 = DMA cycle requested)
63#define OMTI_STATUS_IREQ 0x20 // Interrupt Request (0 = no interrupt, 1 = command complete)
64#define OMTI_STATUS_NU6  0x40 // not used
65#define OMTI_STATUS_NU7  0x80 // not used
66
67#define OMTI_CONFIG_W23  0x01 // jumper W23
68#define OMTI_CONFIG_W22  0x02 // jumper W22
69#define OMTI_CONFIG_W21  0x04 // jumper W21
70#define OMTI_CONFIG_W20  0x08 // jumper W20
71
72#define OMTI_MASK_DMAE  0x01 // DMA enable
73#define OMTI_MASK_INTE  0x02 // Interrupt enable
74
75#define OMTI_COMMAND_STATUS_ERROR 0x02 // error bit
76#define OMTI_COMMAND_STATUS_LUN 0x20 // drive 0 is 0
77
78#define OMTI_SENSE_CODE_NO_ERROR 0x00
79#define OMTI_SENSE_CODE_DRIVE_NOT_READY 0x04
80#define OMTI_SENSE_CODE_ADDRESS_VALID 0x80
81#define OMTI_SENSE_CODE_SECTOR_NOT_FOUND 0x14
82#define OMTI_SENSE_CODE_ECC_ERROR 0x11
83#define OMTI_SENSE_CODE_BAD_TRACK 0x19
84#define OMTI_SENSE_CODE_ALTERNATE_TRACK 0x1C
85#define OMTI_SENSE_CODE_INVALID_COMMAND 0x20
86#define OMTI_SENSE_CODE_ILLEGAL_ADDRESS 0x21
87
88enum {
89   OMTI_STATE_RESET,
90   OMTI_STATE_IDLE,
91   OMTI_STATE_SELECTION,
92   OMTI_STATE_COMMAND,
93   OMTI_STATE_DATA,
94   OMTI_STATE_STATUS,
95};
96
97// OMTI commands
98
99#define OMTI_CMD_TEST_DRIVE_READY 0x00
100#define OMTI_CMD_RECALIBRATE 0x01
101
102#define OMTI_CMD_REQUEST_SENSE 0x03
103#define OMTI_CMD_FORMAT_DRIVEUNIT 0x04
104#define OMTI_CMD_READ_VERIFY 0x05
105#define OMTI_CMD_FORMAT_TRACK 0x06
106#define OMTI_CMD_FORMAT_BAD_TRACK 0x07
107#define OMTI_CMD_READ 0x08
108
109#define OMTI_CMD_WRITE 0x0a
110#define OMTI_CMD_SEEK 0x0b
111
112#define OMTI_CMD_READ_SECTOR_BUFFER 0x0e
113#define OMTI_CMD_WRITE_SECTOR_BUFFER 0x0f
114
115#define OMTI_CMD_ASSIGN_ALTERNATE_TRACK 0x11
116
117#define OMTI_CMD_READ_DATA_TO_BUFFER 0x1e
118#define OMTI_CMD_WRITE_DATA_FROM_BUFFER 0x1f
119#define OMTI_CMD_COPY 0x20
120
121#define OMTI_CMD_READ_ESDI_DEFECT_LIST 0x37
122
123#define OMTI_CMD_RAM_DIAGNOSTICS 0xe0
124#define OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC 0xe4
125#define OMTI_CMD_READ_LONG 0xe5
126#define OMTI_CMD_WRITE_LONG 0xe6
127
128#define OMTI_CMD_READ_CONFIGURATION 0xec
129#define OMTI_CMD_INVALID_COMMAND 0xff
130
131typedef struct _disk_data disk_data;
132struct _disk_data
133{
134   device_t *device;
135    UINT16 type;
136    UINT16 cylinders;
137    UINT16 heads;
138   UINT16 sectors;
139   UINT32 sectorbytes;
140   UINT32 sector_count;
141
142   device_image_interface *image;
143
144   // configuration data
145   UINT8 config_data[10];
146
147   // ESDI defect list data
148   UINT8 esdi_defect_list[256];
149};
150
151typedef struct _omti8621_state omti8621_state;
152struct _omti8621_state {
153   device_t *device;
154   omti8621_set_irq irq_handler;
155
156   disk_data *disk[OMTI_MAX_LUN+1];
157
158   UINT16 jumper;
159
160   /* stored tc state - state present at pins */
161   int tc_state;
162
163   /* stored int state */
164   int int_state;
165
166   UINT8 omti_state;
167
168   UINT8 status_port;
169   UINT8 config_port;
170   UINT8 mask_port;
171
172   // command descriptor block
173   UINT8 command_buffer[CDB_SIZE];
174   int command_length;
175   int command_index;
176   int command_status;
177
178   // data buffer
179   UINT8 *sector_buffer;
180   UINT8 *data_buffer;
181   int data_length;
182   int data_index;
183
184   // sense data
185   UINT8 sense_data[4];
186
187   // these are used only to satisfy dex
188   UINT32 diskaddr_ecc_error;
189   UINT32 diskaddr_format_bad_track;
190   UINT8 alternate_track_buffer[4];
191   UINT32 alternate_track_address[2];
192};
193
194/***************************************************************************
195 get_safe_token - makes sure that the passed
196 in device is, in fact, a 8621 controller
197 ***************************************************************************/
198
199INLINE omti8621_state *get_safe_token(device_t *device) {
200   assert(device != NULL);
201   assert(device->type() == OMTI8621);
202   return (omti8621_state *) downcast<legacy_device_base *>(device)->token();
203}
204
205/***************************************************************************
206 cpu_context - return a string describing the current CPU context
207 ***************************************************************************/
208
209static const char *cpu_context(const device_t *device) {
210   static char statebuf[64]; /* string buffer containing state description */
211
212   device_t *cpu = device->machine().firstcpu;
213
214   /* if we have an executing CPU, output data */
215   if (cpu != NULL) {
216      osd_ticks_t t = osd_ticks();
217      int s = t / osd_ticks_per_second();
218      int ms = (t % osd_ticks_per_second()) / 1000;
219
220      sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
221            cpu_get_previouspc(cpu), device->tag());
222   } else {
223      strcpy(statebuf, "(no context)");
224   }
225   return statebuf;
226}
227
228/*-------------------------------------------------
229 set_interrupt - update the IRQ state
230 -------------------------------------------------*/
231
232static void set_interrupt(const omti8621_state *state, enum line_state line_state) {
233   if (state->irq_handler != NULL) {
234      LOG2(("set_interrupt: status_port=%x", state->status_port));
235      (*state->irq_handler)(&state->device->machine(), line_state);
236   }
237}
238
239static TIMER_CALLBACK(set_interrupt_caba ) {
240   const omti8621_state *state =(omti8621_state *)ptr;
241   set_interrupt(state, ASSERT_LINE);
242}
243
244/***************************************************************************
245 clear_sense_data - clear the sense data
246 ***************************************************************************/
247
248static void clear_sense_data(omti8621_state *state) {
249   LOG2(("clear_sense_data"));
250   memset(state->sense_data, 0, sizeof(state->sense_data));
251}
252
253/***************************************************************************
254 set_sense_data - set the sense data from code and command descriptor block
255 ***************************************************************************/
256
257static void set_sense_data(omti8621_state *state, UINT8 code, const UINT8 * cdb) {
258   LOG2(("set_sense_data code=%x", code));
259   state->sense_data[0]=code;
260   state->sense_data[1]=cdb[1];
261   state->sense_data[2]=cdb[2];
262   state->sense_data[3]=cdb[3];
263}
264
265/***************************************************************************
266 set_configuration_data - set the configuration data for drive lun
267 ***************************************************************************/
268
269static void set_configuration_data(omti8621_state *state, UINT8 lun) {
270   LOG2(("set_configuration_data lun=%x", lun));
271
272   // initialize the configuration data
273   disk_data *disk = state->disk[lun];
274
275   disk->config_data[0] = (disk->cylinders - 1) >> 8; // Number of Cylinders (MSB)
276   disk->config_data[1] = (disk->cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1)
277   disk->config_data[2] = disk->heads - 1; // Number of Heads (-1)
278   disk->config_data[3] = disk->sectors - 1; // Number of Sectors (-1)
279   disk->config_data[4] = 0x02; // Drive Configuration Word (MSB)
280   disk->config_data[5] = 0x44; // Drive Configuration Word (LSB)
281   disk->config_data[6] = 0x00; // ISG AFTER INDEX
282   disk->config_data[7] = 0x00; // PLO SYN Field (ID)
283   disk->config_data[8] = 0x00; // PLO SYN Field (DATA)
284   disk->config_data[9] = 0x00; // ISG AFTER SECTOR
285}
286
287/***************************************************************************
288 omti_reset - reset the OMTI controller
289 ***************************************************************************/
290
291static void omti_reset(omti8621_state *state) {
292   LOG2(("omti_reset"));
293
294   // should go from reset to idle after 100 us
295   // state->omti_state = OMTI_STATE_RESET;
296   state->omti_state = OMTI_STATE_IDLE;
297
298   state->status_port =  OMTI_STATUS_NU6 | OMTI_STATUS_NU7;
299   state->config_port = ~state->jumper;
300   state->mask_port = 0;
301
302   // default the sector data buffer with model and status information
303   // (i.e. set sector data buffer for cmd=0x0e READ SECTOR BUFFER)
304
305   memset(state->sector_buffer, 0, OMTI_DISK_SECTOR_SIZE);
306   memcpy(state->sector_buffer, "8621VB.4060487xx", 0x10);
307   state->sector_buffer[0x10] = 0; // ROM Checksum error
308   state->sector_buffer[0x11] = 0; // Processor Register error
309   state->sector_buffer[0x12] = 0; // Buffer RAM error
310   state->sector_buffer[0x13] = 0; // Sequencer Register File error
311   state->sector_buffer[0x14] = 0xc0; // 32K buffer size
312   // TODO: add missing Default values for LUN 0, 1 and 3
313
314   state->command_length = 0;
315   state->command_index = 0;
316   state->command_status = 0;
317
318   state->data_index = 0;
319   state->data_length = 0;
320
321   clear_sense_data(state) ;
322
323   state->diskaddr_ecc_error = 0;
324   state->diskaddr_format_bad_track = 0;
325   state->alternate_track_address[0] = 0;
326   state->alternate_track_address[1] = 0;
327}
328
329/***************************************************************************
330 get_lun - get logical unit number from a command descriptor block (in bit 5)
331 ***************************************************************************/
332
333static UINT8 get_lun(const UINT8 * cdb)
334{
335   return   (cdb[1] & 0x20) >> 5;
336}
337
338/***************************************************************************
339 check_disk_address - check disk address, set sense data and return true for no error
340 ***************************************************************************/
341
342static UINT8 check_disk_address(omti8621_state *state, const UINT8 *cdb)
343{
344   UINT8 sense_code = OMTI_SENSE_CODE_NO_ERROR;
345   UINT8 lun = get_lun(cdb);
346   UINT16 head = cdb[1] & 0x1f;
347   UINT16 sector = cdb[2] & 0x3f;
348   UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
349   UINT8 block_count = cdb[4];
350   disk_data *disk = state->disk[lun];
351
352   UINT32 disk_track = cylinder * disk->heads + head;
353   UINT32 disk_addr = (disk_track * disk->sectors) + sector;
354
355   if (block_count > OMTI_MAX_BLOCK_COUNT) {
356      LOG(("########### check_disk_address: unexpected block count %x", block_count));
357      sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
358   }
359
360   if (lun > OMTI_MAX_LUN) {
361      sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
362   } else    if (!disk->image->exists()) {
363      sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
364   } else    if (sector >= OMTI_MAX_BLOCK_COUNT) {
365      sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
366   } else if (head >= disk->heads) {
367      sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
368   } else if (cylinder >= disk->cylinders) {
369      sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
370   } else if ( disk_track == state->diskaddr_format_bad_track && disk_track != 0) {
371      sense_code = OMTI_SENSE_CODE_BAD_TRACK;
372   } else if (disk_addr == state->diskaddr_ecc_error && disk_addr != 0) {
373      sense_code = OMTI_SENSE_CODE_ECC_ERROR;
374   } else if (disk_track == state->alternate_track_address[1] && disk_track != 0) {
375      sense_code = OMTI_SENSE_CODE_ALTERNATE_TRACK;
376   }
377
378   if (sense_code == OMTI_SENSE_CODE_NO_ERROR) {
379      clear_sense_data(state);
380   } else {
381      state->command_status |= OMTI_COMMAND_STATUS_ERROR;
382      set_sense_data(state, sense_code, cdb);
383   }
384   return sense_code == OMTI_SENSE_CODE_NO_ERROR;
385}
386
387/***************************************************************************
388 get_disk_track - get disk track from a command descriptor block
389 ***************************************************************************/
390
391static UINT32 get_disk_track(const omti8621_state *state, const UINT8 * cdb) {
392   UINT8 lun = get_lun(cdb);
393   UINT16 head = cdb[1] & 0x1f;
394   UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
395   return cylinder * state->disk[lun]->heads + head;
396}
397
398/***************************************************************************
399 get_disk_address - get disk address from a command descriptor block
400 ***************************************************************************/
401
402static UINT32 get_disk_address(const omti8621_state *state, const UINT8 * cdb) {
403   UINT8 lun = get_lun(cdb);
404   UINT16 sector = cdb[2] & 0x3f;
405   return get_disk_track(state, cdb) * state->disk[lun]->sectors + sector;
406}
407
408/***************************************************************************
409 set_data_transfer - setup for data transfer from/to data
410 ***************************************************************************/
411
412static void set_data_transfer(omti8621_state *state, UINT8 *data, UINT16 length) {
413   // set controller for read data transfer
414   state->omti_state = OMTI_STATE_DATA;
415   state->status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY;
416   state->status_port &= ~OMTI_STATUS_CD;
417
418   state->data_buffer = data;
419   state->data_length = length;
420   state->data_index = 0;
421}
422
423/***************************************************************************
424 read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer
425 ***************************************************************************/
426
427static void read_sectors_from_disk(omti8621_state *state, INT32 diskaddr,
428      UINT8 count, UINT8 lun) {
429
430   UINT8 *data_buffer = state->sector_buffer;
431   device_image_interface *image = state->disk[lun]->image;
432
433   while (count-- > 0) {
434      LOG2(("read_sectors_from_disk lun=%d diskaddr=%x", lun, diskaddr));
435
436      image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
437      image->fread( data_buffer, OMTI_DISK_SECTOR_SIZE);
438
439      diskaddr++;
440      data_buffer += OMTI_DISK_SECTOR_SIZE;
441   }
442}
443
444/***************************************************************************
445 write_sectors_to_disk - write sectors starting at diskaddr from sector_buffer
446 ***************************************************************************/
447
448static void write_sectors_to_disk(omti8621_state *state, INT32 diskaddr,
449      UINT8 count, UINT8 lun) {
450
451   UINT8 *data_buffer = state->sector_buffer;
452   device_image_interface *image = state->disk[lun]->image;
453
454   while (count-- > 0) {
455      LOG2(("write_sectors_to_disk lun=%d diskaddr=%x", lun, diskaddr));
456
457      image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
458      image->fwrite( data_buffer, OMTI_DISK_SECTOR_SIZE);
459
460      if (diskaddr == state->diskaddr_ecc_error) {
461         // reset previous ECC error
462         state->diskaddr_ecc_error = 0;
463      }
464
465      diskaddr++;
466      data_buffer += OMTI_DISK_SECTOR_SIZE;
467   }
468}
469
470/***************************************************************************
471 copy_sectors - copy sectors
472 ***************************************************************************/
473
474static void copy_sectors(omti8621_state *state, INT32 dst_addr, INT32 src_addr,
475      UINT8 count, UINT8 lun) {
476   device_image_interface *image = state->disk[lun]->image;
477
478   LOG2(("copy_sectors lun=%d src_addr=%x dst_addr=%x count=%x", lun, src_addr, dst_addr, count));
479
480   while (count-- > 0) {
481      image->fseek( src_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
482      image->fread( state->sector_buffer, OMTI_DISK_SECTOR_SIZE);
483
484      image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
485      image->fwrite( state->sector_buffer, OMTI_DISK_SECTOR_SIZE);
486
487      if (dst_addr == state->diskaddr_ecc_error) {
488         // reset previous ECC error
489         state->diskaddr_ecc_error = 0;
490      }
491
492      src_addr++;
493      dst_addr++;
494   }
495}
496
497/***************************************************************************
498 format track - format a track
499 ***************************************************************************/
500
501static void format_track(omti8621_state *state, const UINT8 * cdb) {
502   UINT8 lun = get_lun(cdb);
503   UINT32 disk_addr = get_disk_address(state, cdb);
504   UINT32 disk_track = get_disk_track(state, cdb);
505
506   if (state->diskaddr_ecc_error == disk_addr) {
507      // reset previous ECC error
508      state->diskaddr_ecc_error = 0;
509   }
510
511   if (state->diskaddr_format_bad_track == disk_track) {
512      // reset previous bad track formatting
513      state->diskaddr_format_bad_track = 0;
514   }
515
516   if (state->alternate_track_address[0] == disk_track) {
517      // reset source of alternate track address
518      state->alternate_track_address[0] = 0;
519   }
520
521   if (state->alternate_track_address[1] == disk_track) {
522      // reset alternate track address
523      state->alternate_track_address[1] = 0;
524   }
525
526   if (check_disk_address(state, cdb) ) {
527      if ((cdb[5] & 0x40) == 0) {
528         memset(state->sector_buffer, 0x6C, OMTI_DISK_SECTOR_SIZE * state->disk[lun]->sectors);
529      }
530      write_sectors_to_disk(state, disk_addr, state->disk[lun]->sectors, lun);
531   }
532
533}
534
535/***************************************************************************
536 set_esdi_defect_list - setup the (emty) ESDI defect list
537 ***************************************************************************/
538
539static void set_esdi_defect_list(omti8621_state *state, UINT8 lun, UINT8 head)
540{
541   disk_data *disk = state->disk[lun];
542
543   memset(disk->esdi_defect_list, 0, sizeof(disk->esdi_defect_list));
544   disk->esdi_defect_list[0] = 1; // month
545   disk->esdi_defect_list[1] = 1; // day
546   disk->esdi_defect_list[2] = 90; // year
547   disk->esdi_defect_list[3] = head;
548   memset(disk->esdi_defect_list+6, 0xff, 5); // end of defect list
549}
550
551/***************************************************************************
552 log_command - log command from a command descriptor block
553 ***************************************************************************/
554
555static void log_command(const omti8621_state *state,
556      const UINT8 cdb[], const UINT16 cdb_length) {
557   if (verbose > 0) {
558      int i;
559      logerror("%s: OMTI command ", cpu_context(state->device));
560      switch (cdb[0]) {
561      case OMTI_CMD_TEST_DRIVE_READY: // 0x00
562         logerror("Test Drive Ready");
563         break;
564      case OMTI_CMD_RECALIBRATE: // 0x01
565         logerror("Recalibrate");
566         break;
567      case OMTI_CMD_REQUEST_SENSE: // 0x03
568         logerror("Request Sense");
569         break;
570      case OMTI_CMD_READ_VERIFY: // 0x05
571         logerror("Read Verify");
572         break;
573      case OMTI_CMD_FORMAT_TRACK: // 0x06
574         logerror("Format Track");
575         break;
576      case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
577         logerror("Format Bad Track");
578         break;
579      case OMTI_CMD_READ: // 0x08
580         logerror("Read");
581         break;
582      case OMTI_CMD_WRITE: // 0x0A
583         logerror("Write");
584         break;
585      case OMTI_CMD_SEEK: // 0x0B
586         logerror("Seek");
587         break;
588      case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
589         logerror("Read Sector Buffer");
590         break;
591      case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
592         logerror("Write Sector Buffer");
593         break;
594      case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
595         logerror("Assign Alternate Track");
596         break;
597      case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
598         logerror("Read Data to Buffer");
599         break;
600      case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
601         logerror("Write Data from Buffer");
602         break;
603      case OMTI_CMD_COPY: // 0x20
604         logerror("Copy");
605         break;
606      case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
607         logerror("Read ESDI Defect List");
608         break;
609      case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
610         logerror("RAM. Diagnostic");
611         break;
612      case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
613         logerror("Controller Int. Diagnostic");
614         break;
615      case OMTI_CMD_READ_LONG: // 0xE5
616         logerror("Read Long");
617         break;
618      case OMTI_CMD_WRITE_LONG: // 0xE6
619         logerror("Write Long");
620         break;
621      case OMTI_CMD_READ_CONFIGURATION: // 0xEC
622         logerror("Read Configuration");
623         break;
624      case OMTI_CMD_INVALID_COMMAND: // 0xFF
625         logerror("Invalid Command");
626         break;
627      default:
628         logerror("!!! Unexpected Command !!!");
629      }
630//      logerror(" (%02x, length=%02x)", cdb[0], cdb_length);
631      for (i = 0; i < cdb_length; i++) {
632         logerror(" %02x", cdb[i]);
633      }
634
635      switch (cdb[0]) {
636      case OMTI_CMD_READ_VERIFY: // 0x05
637      case OMTI_CMD_READ: // 0x08
638      case OMTI_CMD_WRITE: // 0x0a
639      case OMTI_CMD_SEEK: // 0x0b
640      case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
641      case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
642      case OMTI_CMD_COPY: // 0x20
643         logerror(" (diskaddr=%x count=%x)", get_disk_address(state, cdb), cdb[4]);
644         break;
645      }
646      logerror("\n");
647   }
648}
649
650/***************************************************************************
651 log_data - log data in the common data buffer
652 ***************************************************************************/
653
654static void log_data(const omti8621_state *state) {
655   if (verbose > 0) {
656      int i;
657      logerror("%s: OMTI data (length=%02x)", cpu_context(state->device),
658            state->data_length);
659      for (i = 0; i < state->data_length && i < OMTI_DISK_SECTOR_SIZE; i++) {
660         logerror(" %02x", state->data_buffer[i]);
661      }
662
663      if (i < state->data_length) {
664         logerror(" ...");
665      }
666      logerror("\n");
667   }
668}
669
670/***************************************************************************
671 do_command
672 ***************************************************************************/
673
674static void do_command(omti8621_state *state,
675      const UINT8 cdb[], const UINT16 cdb_length) {
676
677   UINT8 lun = get_lun(cdb);
678   disk_data *disk = state->disk[lun];
679   int command_duration = 0; // ms
680
681   log_command( state, cdb, cdb_length);
682
683   // default to read status and status is successful completion
684   state->omti_state = OMTI_STATE_STATUS;
685   state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
686   state->command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0;
687
688   if (state->mask_port & OMTI_MASK_INTE) {
689      set_interrupt(state, CLEAR_LINE);
690   }
691
692   if (!disk->image->exists()) {
693      state->command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive
694   }
695
696   switch (cdb[0]) {
697   case OMTI_CMD_TEST_DRIVE_READY: // 0x00
698      if (!disk->image->exists())
699      {
700         set_sense_data(state, OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb);
701      }
702      break;
703
704   case OMTI_CMD_RECALIBRATE: // 0x01
705      break;
706
707   case OMTI_CMD_REQUEST_SENSE: // 0x03
708      set_data_transfer(state, state->sense_data, sizeof(state->sense_data));
709      break;
710
711   case OMTI_CMD_READ_VERIFY: // 0x05
712      check_disk_address(state, cdb);
713      break;
714
715   case OMTI_CMD_FORMAT_TRACK: // 0x06
716      format_track(state, cdb);
717      break;
718
719   case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
720      state->diskaddr_format_bad_track = get_disk_address(state, cdb);
721      break;
722
723   case OMTI_CMD_READ: // 0x08
724      if (check_disk_address(state, cdb)) {
725         // read data from controller
726         read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun);
727         set_data_transfer(state, state->sector_buffer,   OMTI_DISK_SECTOR_SIZE*cdb[4]);
728      }
729      break;
730
731   case OMTI_CMD_WRITE: // 0x0A
732      log_data(state);
733      if (check_disk_address(state, cdb)) {
734         write_sectors_to_disk(state, get_disk_address(state, cdb), cdb[4], lun);
735      }
736      break;
737
738   case OMTI_CMD_SEEK: // 0x0B
739      check_disk_address(state, cdb);
740      break;
741
742   case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
743      set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]);
744      break;
745
746   case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
747      log_data(state);
748      break;
749
750   case OMTI_CMD_COPY: // 0x20
751      if (check_disk_address(state, cdb) && check_disk_address(state, cdb+4)) {
752         // copy sectors
753         copy_sectors (state, get_disk_address(state,  cdb+4), get_disk_address(state, cdb), cdb[4], lun);
754      }
755      break;
756
757   case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
758      set_esdi_defect_list(state, get_lun(cdb), cdb[1] & 0x1f);
759      set_data_transfer(state, disk->esdi_defect_list, sizeof(disk->esdi_defect_list));
760      break;
761
762   case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
763      log_data(state);
764      state->alternate_track_address[0] = get_disk_track(state, cdb);
765      state->alternate_track_address[1] = get_disk_track(state, state->alternate_track_buffer-1);;
766      break;
767
768   case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
769      if (check_disk_address(state, cdb)) {
770         // read data from controller
771         read_sectors_from_disk (state, get_disk_address(state, cdb), cdb[4], lun);
772         // Domain/OS doesn't expect zero access time
773         command_duration += 1; // 1 ms is enough, average time would be 30 ms)
774      }
775      break;
776
777   case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
778      log_data(state);
779      if (check_disk_address(state, cdb)) {
780         write_sectors_to_disk(state, get_disk_address(state, cdb), cdb[4], lun);
781      }
782      break;
783
784   case  OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
785      break;
786
787   case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
788      break;
789
790   case OMTI_CMD_READ_LONG: // 0xE5
791      if (check_disk_address(state, cdb)) {
792         // read data from controller
793         read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun);
794         set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE+6);
795      }
796      break;
797
798   case OMTI_CMD_WRITE_LONG: // 0xE6
799      log_data(state);
800      if (check_disk_address(state, cdb)) {
801         UINT32 diskaddr =  get_disk_address(state, cdb);
802         write_sectors_to_disk(state, diskaddr, cdb[4], lun);
803         // this will spoil the ECC code
804         state->diskaddr_ecc_error = diskaddr;
805      }
806      break;
807
808   case OMTI_CMD_READ_CONFIGURATION: // 0xEC
809      set_configuration_data(state, get_lun(cdb));
810      set_data_transfer(state, disk->config_data, sizeof(disk->config_data));
811      break;
812
813   case OMTI_CMD_INVALID_COMMAND: // 0xFF
814      set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
815      state->command_status |= OMTI_COMMAND_STATUS_ERROR;
816      break;
817
818   default:
819      LOG(("do_command: UNEXPECTED command %02x",cdb[0]));
820      set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
821      state->command_status |= OMTI_COMMAND_STATUS_ERROR;
822      break;
823   }
824
825   if (state->mask_port & OMTI_MASK_INTE) {
826//      if (state->omti_state != OMTI_STATE_STATUS) {
827//         LOG(("do_command: UNEXPECTED omti_state %02x",state->omti_state));
828//      }
829      state->status_port |= OMTI_STATUS_IREQ;
830      if (command_duration == 0) {
831         set_interrupt(state, ASSERT_LINE);
832      } else {
833         // FIXME: should delay state->omti_state and state->status_port as well
834         state->device->machine().scheduler().timer_set(attotime::from_msec(command_duration), FUNC(set_interrupt_caba), 0, state);
835      }
836   }
837}
838
839/***************************************************************************
840 get_command_length
841 ***************************************************************************/
842
843static UINT8 get_command_length(UINT8 command_byte) {
844   return command_byte == OMTI_CMD_COPY ? 10 : 6;
845}
846
847/***************************************************************************
848 get_data
849 ***************************************************************************/
850
851static UINT16 get_data(omti8621_state *state) {
852   UINT16 data = 0xff;
853   if (state->data_index < state->data_length) {
854      data = state->data_buffer[state->data_index++] << 8;
855      data |= state->data_buffer[state->data_index++];
856      if (state->data_index >= state->data_length) {
857         state->omti_state = OMTI_STATE_STATUS;
858         state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
859         log_data(state);
860      }
861   } else {
862      LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)"));
863   }
864    return data;
865}
866
867/***************************************************************************
868 set_data
869 ***************************************************************************/
870
871static void set_data(omti8621_state *state, UINT16 data) {
872   if (state->data_index < state->data_length) {
873      state->data_buffer[state->data_index++] = data >> 8;
874      state->data_buffer[state->data_index++] = data & 0xff;
875      if (state->data_index >= state->data_length) {
876         do_command(state, state->command_buffer, state->command_index);
877      }
878   } else {
879      LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)"));
880   }
881}
882
883/***************************************************************************
884 DN3500 Disk Controller-AT Register at 0x4D000
885 ***************************************************************************/
886
887static WRITE8_DEVICE_HANDLER( omti8621_w8 ) {
888   omti8621_state *state = get_safe_token(device);
889
890   switch (offset) {
891   case OMTI_PORT_DATA_OUT: //  0x00
892      switch (state->omti_state) {
893      case OMTI_STATE_COMMAND:
894         LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data));
895         if (state->command_index == 0) {
896            state->command_length = get_command_length(data);
897         }
898
899         if (state->command_index < state->command_length) {
900            state->command_buffer[state->command_index++] = data;
901         } else {
902            LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data));
903         }
904
905         if (state->command_index == state->command_length) {
906            switch (state->command_buffer[0]) {
907            case OMTI_CMD_WRITE: // 0x0A
908               // TODO: check diskaddr
909               // Fall through
910            case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
911               set_data_transfer(state, state->sector_buffer,
912                     OMTI_DISK_SECTOR_SIZE * state->command_buffer[4]);
913               state->status_port &= ~OMTI_STATUS_IO;
914               break;
915
916            case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
917               set_data_transfer(state, state->alternate_track_buffer, sizeof(state->alternate_track_buffer));
918               state->status_port &= ~OMTI_STATUS_IO;
919               break;
920
921            case OMTI_CMD_WRITE_LONG: // 0xE6
922               // TODO: check diskaddr
923               set_data_transfer(state, state->sector_buffer,
924                     (OMTI_DISK_SECTOR_SIZE +6) * state->command_buffer[4]);
925               state->status_port &= ~OMTI_STATUS_IO;
926               break;
927
928            default:
929               do_command(state, state->command_buffer, state->command_index);
930               break;
931            }
932         }
933         break;
934
935      case OMTI_STATE_DATA:
936         LOG(("UNEXPECTED: writing OMTI 8621 Data Register at offset %02x = %02x", offset, data));
937         break;
938
939      default:
940         LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
941         break;
942      }
943      break;
944
945   case OMTI_PORT_RESET: // 0x01
946      LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data));
947      omti_reset(state);
948      break;
949
950   case OMTI_PORT_SELECT: // 0x02
951      LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
952      state->omti_state = OMTI_STATE_COMMAND;
953
954      state->status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD;
955      state->status_port &= ~OMTI_STATUS_IO;
956
957      state->command_status = 0;
958      state->command_index = 0;
959      break;
960
961   case OMTI_PORT_MASK: // 0x03
962      LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data));
963      state->mask_port = data;
964
965      if ((data & OMTI_MASK_INTE) == 0) {
966         state->status_port &= ~OMTI_STATUS_IREQ;
967         set_interrupt(state, CLEAR_LINE);
968      }
969
970      if ((data & OMTI_MASK_DMAE) == 0) {
971         state->status_port &= ~OMTI_STATUS_DREQ;
972      }
973      break;
974
975   default:
976      LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data));
977      break;
978   }
979}
980
981static READ8_DEVICE_HANDLER( omti8621_r8 ) {
982   omti8621_state *state = get_safe_token(device);
983   UINT8 data = 0xff;
984
985   static UINT8 last_data = 0xff;
986
987   switch (offset) {
988   case OMTI_PORT_DATA_IN: // 0x00
989      if (state->status_port && OMTI_STATUS_CD) {
990         data = state->command_status;
991         switch (state->omti_state) {
992         case OMTI_STATE_COMMAND:
993            LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
994            break;
995         case OMTI_STATE_STATUS:
996            state->omti_state = OMTI_STATE_IDLE;
997            state->status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD  | OMTI_STATUS_IO | OMTI_STATUS_REQ);
998            LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x", offset, data));
999            break;
1000         default:
1001            LOG(("UNEXPECTED reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
1002            break;
1003         }
1004      } else {
1005         LOG(("UNEXPECTED reading OMTI 8621 Data Register at offset %02x = %02x (status bit C/D = 0)", offset, data));
1006      }
1007      break;
1008
1009   case OMTI_PORT_STATUS: // 0x01
1010      data = state->status_port;
1011      // omit excessive logging
1012      if (data != last_data) {
1013         LOG2(("reading OMTI 8621 Status Register at offset %02x = %02x", offset, data));
1014//         last_data = data;
1015      }
1016      break;
1017
1018   case OMTI_PORT_CONFIG: // 0x02
1019      data = state->config_port;
1020      LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data));
1021      break;
1022
1023   case OMTI_PORT_MASK: // 0x03
1024      data = state->mask_port ;
1025      // win.dex will update the mask register with read-modify-write
1026      // LOG2(("reading OMTI 8621 Mask Register at offset %02x = %02x (UNEXPECTED!)", offset, data));
1027      break;
1028
1029   default:
1030      LOG(("UNEXPECTED reading OMTI 8621 Register at offset %02x = %02x", offset, data));
1031      break;
1032   }
1033
1034   return data;
1035}
1036
1037WRITE16_DEVICE_HANDLER(omti8621_w ) {
1038   omti8621_state *state = get_safe_token(device);
1039
1040   switch (mem_mask) {
1041   case 0x00ff:
1042      omti8621_w8(device, offset*2+1, data);
1043      break;
1044   case 0xff00:
1045      omti8621_w8(device, offset*2, data>>8);
1046      break;
1047   default:
1048      LOG3(("writing OMTI 8621 Data Word Register to %0x = %04x & %04x", offset, data, mem_mask));
1049      set_data(state, data);
1050      break;
1051   }
1052}
1053
1054READ16_DEVICE_HANDLER( omti8621_r ) {
1055   omti8621_state *state = get_safe_token(device);
1056   UINT16 data;
1057   switch (mem_mask) {
1058   case 0x00ff:
1059      data = omti8621_r8(device, offset*2+1);
1060      break;
1061   case 0xff00:
1062      data = omti8621_r8(device, offset*2) << 8;
1063      break;
1064   default:
1065      data = get_data(state);
1066      LOG3(("reading OMTI 8621 Data Word Register from %0x = %04x & %04x", offset, data, mem_mask));
1067      break;
1068   }
1069   return data;
1070}
1071
1072void omti8621_set_verbose(int on_off)
1073{
1074   verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
1075}
1076
1077/***************************************************************************
1078 omti8621_get_sector - get sector diskaddr of logical unit lun into data_buffer
1079 ***************************************************************************/
1080
1081UINT32 omti8621_get_sector(device_t *device, INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun)
1082{
1083   omti8621_state *state = get_safe_token(device);
1084   disk_data *disk = state->disk[lun];
1085
1086   if (disk->image == NULL || !disk->image->exists())
1087   {
1088      return 0;
1089   }
1090   else
1091   {
1092      LOG1(("omti8621_get_sector %x on lun %d", diskaddr, lun));
1093
1094      // restrict length to size of 1 sector (i.e. 1024 Byte)
1095      length = length < OMTI_DISK_SECTOR_SIZE ? length  : OMTI_DISK_SECTOR_SIZE;
1096
1097      disk->image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
1098      disk->image->fread(data_buffer, length);
1099
1100      return length;
1101   }
1102}
1103
1104
1105/***************************************************************************
1106 omti_set_jumper - set OMI jumpers
1107 ***************************************************************************/
1108
1109static void omti_set_jumper(omti8621_state *state, UINT16 disk_type)
1110{
1111   LOG1(("omti_set_jumper: disk type=%x", disk_type));
1112
1113   switch (disk_type)
1114   {
1115   case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
1116      state->jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23;
1117      break;
1118
1119   case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
1120   default:
1121      state->jumper = OMTI_CONFIG_W20;
1122      break;
1123   }
1124}
1125
1126/*-------------------------------------------------
1127    device start callback
1128-------------------------------------------------*/
1129
1130static DEVICE_START( omti8621 ) {
1131   omti8621_state *state = get_safe_token(device);
1132
1133   const omti8621_config *config =
1134         (const omti8621_config *) device->static_config();
1135
1136   /* validate basic stuff */
1137   assert(device != NULL);
1138   assert(device->type() == OMTI8621);
1139
1140   /* store a pointer back to the device */
1141   state->device = device;
1142
1143   // note: we must have state->device before we can log
1144   LOG2(("device_start_omti8621"));
1145
1146   state->irq_handler = config->set_irq;
1147
1148   state->sector_buffer = auto_alloc_array(device->machine(), UINT8,
1149         OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT);
1150   assert(state->sector_buffer != NULL);
1151
1152   device_t *device0 = device->machine().device(OMTI_DISK0_TAG);
1153   state->disk[0] = (disk_data *) downcast<legacy_device_base *>(device0)->token();
1154
1155   device_t *device1 = device->machine().device(OMTI_DISK1_TAG);
1156   state->disk[1] = (disk_data *) downcast<legacy_device_base *>(device1)->token();
1157}
1158
1159/*-------------------------------------------------
1160    device reset callback
1161-------------------------------------------------*/
1162
1163static DEVICE_RESET( omti8621 )
1164{
1165   omti8621_state *state = get_safe_token(device);
1166   LOG2(("device_reset_omti8621"));
1167
1168   omti_set_jumper(state, state->disk[0]->type);
1169   omti_reset(state);
1170}
1171
1172/*-------------------------------------------------
1173    device get info callback
1174-------------------------------------------------*/
1175
1176DEVICE_GET_INFO( omti8621 )
1177{
1178   switch (state)
1179   {
1180      /* --- the following bits of info are returned as 64-bit signed integers --- */
1181      case DEVINFO_INT_TOKEN_BYTES:         info->i = sizeof(omti8621_state);      break;
1182      case DEVINFO_INT_INLINE_CONFIG_BYTES:   info->i = sizeof(omti8621_config);      break;
1183
1184      /* --- the following bits of info are returned as pointers to data or functions --- */
1185      case DEVINFO_FCT_START:               info->start = DEVICE_START_NAME(omti8621); break;
1186      case DEVINFO_FCT_STOP:               /* Nothing */                     break;
1187      case DEVINFO_FCT_RESET:               info->reset = DEVICE_RESET_NAME(omti8621); break;
1188
1189      /* --- the following bits of info are returned as NULL-terminated strings --- */
1190      case DEVINFO_STR_NAME:               strcpy(info->s, "OMTI 8621");            break;
1191      case DEVINFO_STR_FAMILY:            strcpy(info->s, "Winchester Disk Controller");break;
1192      case DEVINFO_STR_VERSION:            strcpy(info->s, "1.0");               break;
1193      case DEVINFO_STR_SOURCE_FILE:         strcpy(info->s, __FILE__);            break;
1194      case DEVINFO_STR_CREDITS:            strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
1195   }
1196}
1197
1198DEFINE_LEGACY_DEVICE(OMTI8621, omti8621);
1199
1200//##########################################################################
1201
1202DECLARE_LEGACY_IMAGE_DEVICE(OMTI_DISK0, omti_disk0);
1203DECLARE_LEGACY_IMAGE_DEVICE(OMTI_DISK1, omti_disk1);
1204
1205/***************************************************************************
1206 get_safe_disk_token - makes sure that the passed in device is a OMTI disk
1207 ***************************************************************************/
1208
1209INLINE disk_data *get_safe_disk_token(device_t *device) {
1210   assert(device != NULL);
1211   assert(device->type() == OMTI_DISK0 || device->type() == OMTI_DISK1);
1212   return (disk_data *) downcast<legacy_device_base *>(device)->token();
1213}
1214
1215/***************************************************************************
1216 omti_disk_config - configure disk parameters
1217 ***************************************************************************/
1218
1219static void omti_disk_config(disk_data *disk, UINT16 disk_type)
1220{
1221   DLOG1(("omti_disk_config: configuring disk with type %x", disk_type));
1222
1223   switch (disk_type)
1224   {
1225   case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
1226      disk->cylinders = 1223;
1227      disk->heads = 15;
1228      disk->sectors = 18;
1229      break;
1230
1231   case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
1232   default:
1233      disk->cylinders = 1023;
1234      disk->heads = 8;
1235      disk->sectors = 18;
1236      break;
1237   }
1238
1239   disk->type = disk_type;
1240   disk->sectorbytes = OMTI_DISK_SECTOR_SIZE;
1241   disk->sector_count = disk->cylinders * disk->heads * disk->sectors;
1242}
1243
1244/*-------------------------------------------------
1245    device start callback
1246-------------------------------------------------*/
1247
1248static DEVICE_START( omti_disk )
1249{
1250   disk_data *disk = get_safe_disk_token(device);
1251
1252   disk->device = device;
1253   // note: we must have disk->device before we can log
1254
1255   disk->image = dynamic_cast<device_image_interface *> (disk->device);
1256
1257   if (disk->image->image_core_file() == NULL)
1258   {
1259       DLOG1(("device_start_omti_disk: no disk"));
1260   }
1261   else
1262   {
1263       DLOG1(("device_start_omti_disk: with disk image %s",disk->image->basename() ));
1264   }
1265
1266   // default disk type
1267   omti_disk_config(disk, OMTI_DISK_TYPE_DEFAULT);
1268}
1269
1270/*-------------------------------------------------
1271    device reset callback
1272-------------------------------------------------*/
1273
1274static DEVICE_RESET( omti_disk )
1275{
1276   disk_data *disk = get_safe_disk_token(device);
1277   DLOG1(("device_reset_omti_disk"));
1278
1279   if (disk->image->exists() && disk->image->fseek(0, SEEK_END) == 0)
1280   {
1281      UINT32 disk_size = (UINT32)(disk->image->ftell() / OMTI_DISK_SECTOR_SIZE);
1282      UINT16 disk_type = disk_size >= 300000 ? OMTI_DISK_TYPE_348_MB : OMTI_DISK_TYPE_155_MB;
1283      if (disk_type != disk->type) {
1284         DLOG1(("device_reset_omti_disk: disk size=%d blocks, disk type=%x", disk_size, disk_type ));
1285         omti_disk_config(disk, disk_type);
1286      }
1287   }
1288}
1289
1290/*-------------------------------------------------
1291   disk image create callback
1292-------------------------------------------------*/
1293
1294DEVICE_IMAGE_CREATE( omti_disk )
1295{
1296   disk_data *disk = get_safe_disk_token(&image.device());
1297   DLOG(("device_create_omti_disk: creating OMTI Disk with %d blocks", disk->sector_count));
1298
1299   int x;
1300   unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data
1301
1302
1303   memset(sectordata, 0x55, sizeof(sectordata));
1304   for (x = 0; x < disk->sector_count; x++)
1305   {
1306      if (image.fwrite(sectordata, OMTI_DISK_SECTOR_SIZE)
1307            < OMTI_DISK_SECTOR_SIZE)
1308      {
1309         return IMAGE_INIT_FAIL;
1310      }
1311   }
1312   return IMAGE_INIT_PASS;
1313}
1314
1315/*-------------------------------------------------
1316    device get info callback
1317-------------------------------------------------*/
1318
1319DEVICE_GET_INFO( omti_disk0 )
1320{
1321   switch (state)
1322   {
1323      /* --- the following bits of info are returned as 64-bit signed integers --- */
1324      case DEVINFO_INT_TOKEN_BYTES:         info->i = sizeof(disk_data);      break;
1325      case DEVINFO_INT_INLINE_CONFIG_BYTES:   info->i = 0;          break;
1326      case DEVINFO_INT_IMAGE_TYPE:         info->i = IO_HARDDISK;   break;
1327      case DEVINFO_INT_IMAGE_READABLE:      info->i = 1; break;
1328      case DEVINFO_INT_IMAGE_WRITEABLE:      info->i = 1; break;
1329      case DEVINFO_INT_IMAGE_CREATABLE:      info->i = 1; break;
1330
1331      /* --- the following bits of info are returned as pointers to data or functions --- */
1332      case DEVINFO_FCT_START:               info->start = DEVICE_START_NAME(omti_disk); break;
1333      case DEVINFO_FCT_STOP:               /* Nothing */                        break;
1334      case DEVINFO_FCT_RESET:               info->reset = DEVICE_RESET_NAME(omti_disk); break;
1335//      case DEVINFO_FCT_IMAGE_LOAD:         info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(omti_disk); break;
1336//      case DEVINFO_FCT_IMAGE_UNLOAD:         info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(omti_disk); break;
1337      case DEVINFO_FCT_IMAGE_CREATE:         info->f = (genf *)DEVICE_IMAGE_CREATE_NAME(omti_disk);   break;
1338
1339
1340      /* --- the following bits of info are returned as NULL-terminated strings --- */
1341      case DEVINFO_STR_NAME:               strcpy(info->s, "Winchester");   break;
1342      case DEVINFO_STR_FAMILY:            strcpy(info->s, "Winchester");   break;
1343      case DEVINFO_STR_VERSION:            strcpy(info->s, "1.0");         break;
1344      case DEVINFO_STR_SOURCE_FILE:         strcpy(info->s, __FILE__);      break;
1345      case DEVINFO_STR_CREDITS:            strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
1346
1347      case DEVINFO_STR_IMAGE_INSTANCE_NAME:      strcpy(info->s, "disk");   break;
1348      case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME:   strcpy(info->s, "disk");   break;
1349      case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:      strcpy(info->s, "awd");    break;
1350   }
1351}
1352
1353DEVICE_GET_INFO( omti_disk1 )
1354{
1355   switch (state)
1356   {
1357   /* --- the following bits of info are returned as NULL-terminated strings --- */
1358   case DEVINFO_STR_NAME:                  strcpy(info->s, "Winchester 1");   break;
1359   case DEVINFO_STR_IMAGE_INSTANCE_NAME:      strcpy(info->s, "disk1");         break;
1360   case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME:   strcpy(info->s, "disk1");         break;
1361
1362   default:                           DEVICE_GET_INFO_CALL( omti_disk0 ); break;
1363   }
1364}
1365
1366DEFINE_LEGACY_IMAGE_DEVICE(OMTI_DISK0, omti_disk0);
1367DEFINE_LEGACY_IMAGE_DEVICE(OMTI_DISK1, omti_disk1);
1368
1369MACHINE_CONFIG_FRAGMENT( omti_disk )
1370   MCFG_DEVICE_ADD(OMTI_DISK0_TAG, OMTI_DISK0, 0)
1371   MCFG_DEVICE_ADD(OMTI_DISK1_TAG, OMTI_DISK1, 0)
1372MACHINE_CONFIG_END
1373
src/mess/video/apollo.c
r0r14540
1/*
2 * video/apollo.c
3 *
4 *  Created on: May 12, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *
11 *  see also:
12 *  - Domain Series 3000/Series 4000 Hardware Architecture Handbook (Order No. 007861 Rev. 02)
13 *  - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf (page 12-16 ...)
14 */
15
16#define VERBOSE 0
17
18#include "includes/apollo.h"
19
20#include "apollo.lh"
21#include "apollo_15i.lh"
22
23
24/***************************************************************************
25 TYPE DEFINITIONS
26 ***************************************************************************/
27
28// monochrome 1280x1024
29#define SCREEN_DEVICE_ID_19I 0x09
30
31// monochrome 1024x800
32#define SCREEN_DEVICE_ID_15I 0x0b
33
34#define VIDEO_SCREEN_TAG "screen"
35
36// status register
37#define SR_BLANK        0x80
38#define SR_V_BLANK      0x40
39#define SR_H_SYNC       0x20
40#define SR_R_M_W        0x10
41#define SR_ALT          0x08
42#define SR_V_SYNC       0x04
43#define SR_H_CK         0x02
44#define SR_V_DATA       0x01
45
46// control register 0
47#define CR0_MODE(a)     ((a) >> 5)
48#define CR0_MODE_0      0
49#define CR0_MODE_1      1
50#define CR0_MODE_VECTOR 2
51#define CR0_MODE_3      3
52#define CR0_MODE_BLT    4
53#define CR0_MODE_NORMAL 7
54#define CR0_SHIFT(a)    ((a) & 0x1f)
55
56// control register 1
57#define CR1_INV         0x80
58#define CR1_DADDR_16    0x40
59#define CR1_DV_CK       0x40
60#define CR1_DH_CK       0x20
61#define CR1_ROP_EN      0x10
62#define CR1_RESET       0x08
63#define CR1_DP_CK       0x04
64#define CR1_SYNC_EN     0x02
65#define CR1_DISP_EN     0x01
66
67// control register 2
68#define CR2_S_DATA(a)   ((a) >> 6)
69#define CR2_CONST_ACCESS 0x00
70#define CR2_PIXEL_ACCESS 0x01
71#define CR2_SHIFT_ACCESS 0x02
72#define CR2_PLANE_ACCESS 0x03
73
74typedef struct _screen_data screen_data_t;
75struct _screen_data {
76   UINT16 width;
77   UINT16 height;
78   UINT16 buffer_width;
79   UINT16 buffer_height;
80
81   UINT8 status_register;
82   UINT8 device_id;
83   UINT16 write_enable_register;
84   UINT16 rop_register_0;
85   UINT16 diag_mem_request;
86   UINT8 cr0;
87   UINT8 cr1;
88   UINT8 cr2;
89   UINT8 cr3a;
90
91   UINT8 update_flag;
92   UINT8 update_pending;
93
94   UINT8 blt_cycle_count;
95   UINT32 guard_latch;
96   offs_t image_offset;
97
98   int h_clock;
99   int v_clock;
100   int pixel_clock;
101   int data_clock;
102
103   UINT16 *image_memory;
104   int image_memory_size;
105
106   screen_device *screen;
107};
108
109/*****************************************************************************
110 INLINE FUNCTIONS
111 *****************************************************************************/
112
113INLINE screen_data_t *get_safe_token(device_t *device) {
114   assert(device != NULL);
115   assert(device->type() == APOLLO_MONO15I || device->type() == APOLLO_MONO19I );
116   return (screen_data_t *)downcast<legacy_device_base *>(device)->token();
117}
118
119/***************************************************************************
120 Monochrome Controller Registers at 0x5d800 - 0x5dc07
121 ***************************************************************************/
122
123static void log_cr1(const char * text, device_t *device, screen_data_t *screen_data) {
124
125   DLOG1(("%s: cr0=%02x cr1=%02x sr=%02x pixel_clock=%3d/%3d bl=%d vb=%d vs=%d hs=%d hc=%d vck=%d hck=%d pck=%d vd=%d",
126         text,
127         screen_data->cr0,
128         screen_data->cr1,
129         screen_data->status_register,
130         screen_data->pixel_clock,
131         screen_data->data_clock,
132         screen_data->status_register & SR_BLANK ? 1 : 0,
133         screen_data->status_register & SR_V_BLANK ? 1 : 0,
134         screen_data->status_register & SR_V_SYNC ? 1 : 0,
135         screen_data->status_register & SR_H_SYNC ? 1 : 0,
136         screen_data->status_register & SR_H_CK ? 1 : 0,
137         screen_data->cr1 & CR1_DV_CK ? 1 : 0,
138         screen_data->cr1 & CR1_DH_CK ? 1 : 0,
139         screen_data->cr1 & CR1_DP_CK ? 1 : 0,
140         screen_data->status_register & SR_V_DATA ? 1 : 0));
141}
142
143static void set_cr1(device_t *device, screen_data_t *screen_data,
144      UINT8 data) {
145   UINT8 diffs = screen_data->cr1 ^ data;
146   screen_data->cr1 = data;
147
148//   if (screen_data->cr1 & CR1_SYNC_EN) {
149//      // normal mode
150//   } else
151
152   if ((screen_data->cr1 & CR1_RESET) == 0) {
153      if (diffs & CR1_RESET) {
154         screen_data->blt_cycle_count = 0;
155         screen_data->image_offset = 0;
156         screen_data->guard_latch = 0;
157
158         screen_data->h_clock = 0;
159         screen_data->v_clock = 0;
160         screen_data->pixel_clock = 0;
161         if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
162            screen_data->data_clock = -11; // TODO: why not 0 ????
163            screen_data->status_register = SR_H_CK | SR_V_BLANK | SR_H_SYNC
164                  | SR_V_SYNC;
165         } else {
166            screen_data->data_clock = -9; // TODO: why not 0 ????
167            screen_data->status_register = SR_V_BLANK | SR_V_SYNC;
168         }
169      }
170      log_cr1("CR1_RESET", device, screen_data);
171   } else {
172      if ((diffs & CR1_RESET) && (screen_data->cr1 & CR1_RESET) != 0) {
173         log_cr1("CR1_RESET", device, screen_data);
174      }
175
176      if ((diffs & CR1_DH_CK) && (screen_data->cr1 & CR1_DH_CK) == 0) {
177         if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
178            switch (screen_data->h_clock %= 108) {
179            case 8:
180               screen_data->status_register |= SR_BLANK;
181               break;
182            case 88:
183               screen_data->status_register &= ~SR_BLANK;
184               break;
185            case 93:
186               screen_data->status_register &= ~SR_H_SYNC;
187                  // trigger Dp_Ck
188                  diffs |= CR1_DP_CK;
189                  screen_data->cr1 &= ~CR1_DP_CK;
190               break;
191            case 104:
192               screen_data->status_register |= SR_H_SYNC;
193               break;
194            }
195         } else {
196            switch (screen_data->h_clock %= 84) {
197            case 1:
198               screen_data->status_register |= SR_H_SYNC;
199               break;
200            case 8:
201               screen_data->status_register |= SR_BLANK;
202               break;
203            case 72:
204               screen_data->status_register &= ~SR_BLANK;
205               break;
206            case 77:
207               screen_data->status_register &= ~SR_H_SYNC;
208               diffs |= CR1_DV_CK;
209               data &= ~CR1_DV_CK;
210               break;
211            }
212         }
213         screen_data->h_clock++;
214         log_cr1("CR1_DH_CK",device, screen_data);
215      }
216
217      if ((diffs & CR1_DV_CK) && (screen_data->cr1 & CR1_DV_CK) == 0) {
218         // this is used for disp.dex Test 19: Video RAM Shift Reg. Test
219         if (screen_data->device_id == SCREEN_DEVICE_ID_15I) {
220            switch (screen_data->v_clock %= 842) {
221            case 799:
222               screen_data->status_register &= ~SR_V_BLANK;
223               break;
224            case 804:
225               screen_data->status_register &= ~SR_V_SYNC;
226               break;
227            case 808:
228               screen_data->status_register |= SR_V_SYNC;
229               break;
230            case 841:
231               screen_data->status_register |= SR_V_BLANK;
232               break;
233            }
234            screen_data->v_clock++;
235            log_cr1("CR1_DV_CK",device, screen_data);
236         }
237      }
238
239      if ((diffs & CR1_DP_CK) && (screen_data->cr1 & CR1_DP_CK) == 0) {
240         if (screen_data->device_id == SCREEN_DEVICE_ID_19I) {
241            switch (screen_data->pixel_clock %= 1066) {
242            case 1023:
243               screen_data->status_register &= ~SR_V_BLANK;
244               break;
245            case 1028:
246               screen_data->status_register &= ~SR_V_SYNC;
247               break;
248            case 1032:
249               screen_data->status_register |= SR_V_SYNC;
250               break;
251            case 1065:
252               screen_data->status_register |= SR_V_BLANK;
253               break;
254            }
255         } else /*if (screen_data->pixel_clock == 0)*/ {
256            // this is used for disp.dex Test 6: Vertical Counter Test
257            switch (screen_data->pixel_clock %= 842) {
258            case 799:
259               screen_data->status_register &= ~SR_V_BLANK;
260               break;
261            case 804:
262               screen_data->status_register &= ~SR_V_SYNC;
263               break;
264            case 808:
265               screen_data->status_register |= SR_V_SYNC;
266               break;
267            case 841:
268               screen_data->status_register |= SR_V_BLANK;
269               break;
270            }
271         }
272
273         if ((screen_data->cr1 & CR1_DISP_EN) == 0) {
274            screen_data->status_register &= ~SR_V_DATA;
275         }else          {
276            UINT16 pixel = screen_data->image_memory[screen_data->data_clock / 16]
277                        & (0x8000 >> (screen_data->data_clock % 16));
278            pixel = (pixel ? 1 : 0)   ^ ((screen_data->cr1 & CR1_INV) ? 0 : 1);
279
280            if (pixel) {
281               screen_data->status_register |= SR_V_DATA;
282            } else {
283               screen_data->status_register &= ~SR_V_DATA;
284            }
285            screen_data->data_clock++;
286         }
287
288         screen_data->pixel_clock++;
289         if ((screen_data->pixel_clock % 8) == 0) {
290            screen_data->status_register ^= SR_H_CK;
291         }
292
293         log_cr1("CR1_DP_CK", device, screen_data);
294      }
295
296      if ((screen_data->status_register & SR_V_BLANK) == 0) {
297         screen_data->status_register &= ~SR_BLANK;
298      }
299
300      if (diffs & CR1_DISP_EN) {
301         // update screen
302         screen_data->update_flag = 1;
303      }
304   }
305}
306
307static void set_cr3(device_t *device, screen_data_t *screen_data, UINT8 data) {
308   screen_data->cr3a = data;
309   if ((data & 0x80) == 0) {
310      int shift = (data & 0x0f) >> 1;
311      UINT8 bit_mask = 1 << shift;
312      if (data & 0x01) {
313         set_cr1(device, screen_data, screen_data->cr1 | bit_mask);
314      } else {
315         set_cr1(device, screen_data, screen_data->cr1 & ~bit_mask);
316      }
317   }
318}
319
320READ16_DEVICE_HANDLER( apollo_mcr_r ) {
321   screen_data_t *screen_data = get_safe_token(device);
322   UINT16 data;
323   switch (offset & 0x203) {
324   case 0:
325   case 1:
326   case 2:
327   case 3:
328      data = (screen_data->status_register << 8)
329            | screen_data->device_id;
330      break;
331   case 0x200:
332      data = screen_data->cr0 << 8 | 0xff;
333      break;
334   case 0x201:
335      data = screen_data->cr1 << 8 | 0xff;
336      break;
337   case 0x202:
338      data = screen_data->cr2 << 8 | 0xff;
339      break;
340   case 0x203:
341      data = screen_data->cr3a << 8 | 0xff;
342      break;
343   default:
344      data = screen_data->device_id;
345      break;
346   }
347   DLOG1(("reading Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask));
348   return data;
349}
350
351WRITE16_DEVICE_HANDLER(apollo_mcr_w ) {
352   screen_data_t *screen_data = get_safe_token(device);
353   if (offset != 0 && data != 0)
354      DLOG1(("writing Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask));
355
356   switch (offset & 0x203) {
357   case 0:
358      screen_data->write_enable_register = data;
359      screen_data->blt_cycle_count = 0;
360      screen_data->status_register &= ~SR_ALT;
361      break;
362   case 1:
363      screen_data->rop_register_0 = data;
364      switch (data & 0x0f) {
365      case 0: // zero
366      case 3: // Source
367      case 0x0c: // ~Source
368      case 0x0f: // one
369         screen_data->status_register &= ~SR_R_M_W;
370         break;
371      default:
372         screen_data->status_register |= SR_R_M_W;
373         break;
374      }
375      break;
376   case 2:
377      // trigger memory refresh in diagnostic mode
378      screen_data->diag_mem_request = data;
379      break;
380   case 0x200:
381      screen_data->cr0 = data >> 8;
382      screen_data->blt_cycle_count = 0;
383      break;
384   case 0x201:
385      set_cr1(device, screen_data, data >> 8);
386      break;
387   case 0x202:
388      screen_data->cr2 = data >> 8;
389      break;
390   case 0x203:
391      set_cr3(device, screen_data, data >> 8);
392      break;
393   }
394}
395
396/***************************************************************************
397 Monochrome graphics memory space at FA0000 - FDFFFF
398 ***************************************************************************/
399
400static UINT32 get_source_data(screen_data_t *screen_data, UINT32 src_data) {
401   switch (CR2_S_DATA(screen_data->cr2)) {
402   case CR2_CONST_ACCESS: // 0x00
403      // set source to all ones (used for vectors)
404      src_data= 0xffff;
405      break;
406   case CR2_PIXEL_ACCESS: // 0x01
407      // replicate 4 LSB of data bus
408      src_data= src_data & 1 ? 0xffff : 0;
409      break;
410   case CR2_SHIFT_ACCESS: // 0x02
411      // replicate LSB of shifter
412      src_data = src_data & 0xffff;
413      break;
414   case CR2_PLANE_ACCESS: // 0x03
415      // use source data unchanged (normal use)
416      if (CR0_SHIFT(screen_data->cr0) >= 16) {
417         src_data = (src_data << 16) | (src_data >> 16);
418      }
419      src_data >>= (CR0_SHIFT(screen_data->cr0) & 0x0f);
420      break;
421   }
422   return src_data;
423}
424
425static UINT16 rop(screen_data_t *screen_data, UINT16 dest_data) {
426
427   UINT32 src_data = get_source_data(screen_data, screen_data->guard_latch);
428
429   if ((screen_data->cr1 & CR1_ROP_EN)
430         /*&& (CR2_S_DATA(screen_data->cr2) == CR2_PLANE_ACCESS)*/) {
431      switch (screen_data->rop_register_0 & 0x0f) {
432      case 0: // zero
433         src_data = 0;
434         break;
435      case 1: // Source AND Destination
436         src_data = src_data & dest_data;
437         break;
438      case 2: // Source AND ~Destination
439         src_data = src_data & (~dest_data);
440         break;
441      case 3: // Source
442         break;
443      case 4: // ~Source AND Destination
444         src_data = (~src_data) & dest_data;
445         break;
446      case 5: // Destination
447         src_data = dest_data;
448         break;
449      case 6: // Source XOR Destination
450         src_data = src_data ^ dest_data;
451         break;
452      case 7: // Source OR Destination
453         src_data = src_data | dest_data;
454         break;
455      case 8: // Source NOR Destination
456         src_data = ~(src_data | dest_data);
457         break;
458      case 9: // Source XNOR Destination
459         src_data = ~(src_data ^ dest_data);
460         break;
461      case 0x0a: // ~Destination
462         src_data = ~dest_data;
463         break;
464      case 0x0b: // Source OR ~Destination
465         src_data = src_data | (~dest_data);
466         break;
467      case 0x0c: // ~Source
468         src_data = ~src_data;
469         break;
470      case 0x0d: // ~Source OR Destination
471         src_data = (~src_data) | dest_data;
472         break;
473      case 0x0e: // Source NAND Destination
474         src_data = ~(src_data & dest_data);
475         break;
476      case 0x0f: // One
477         src_data = 0xffff;
478         break;
479      }
480   }
481
482   return src_data & 0xffff;
483}
484
485READ16_DEVICE_HANDLER( apollo_mgm_r ) {
486   screen_data_t *screen_data = get_safe_token(device);
487   UINT16 data;
488
489   if (CR0_MODE(screen_data->cr0) == CR0_MODE_0
490         && screen_data->blt_cycle_count > 0) {
491      offset = screen_data->image_offset;
492      screen_data->blt_cycle_count = 0;
493   }
494
495   if (offset >= screen_data->image_memory_size) {
496      // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000
497      DLOG1(("reading Monochrome Graphics Memory at invalid offset %05x", offset));
498      offset %= screen_data->image_memory_size;
499   }
500
501   switch (CR0_MODE(screen_data->cr0)) {
502   case CR0_MODE_VECTOR:
503      // vector or fill mode
504      UINT16 src_data, dest_data;
505      screen_data->status_register &= ~SR_ALT;
506
507      dest_data = screen_data->image_memory[offset];
508      src_data = rop(screen_data, dest_data);
509
510      src_data &= ~screen_data->write_enable_register;
511      dest_data &= (screen_data->write_enable_register | ~mem_mask);
512      screen_data->image_memory[offset] = dest_data | src_data;
513      data = screen_data->image_memory[offset];
514      break;
515   case CR0_MODE_3:
516      // CPU source BLT: read internal data bus
517      data = screen_data->guard_latch;
518      break;
519   default:
520      data = screen_data->image_memory[offset];
521      screen_data->guard_latch <<= 16;
522      screen_data->guard_latch |= data;
523      break;
524   }
525   DLOG1(("reading Monochrome Graphics Memory with mode %d: offset %05x = %04x & %04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask));
526   return data;
527}
528
529WRITE16_DEVICE_HANDLER( apollo_mgm_w ) {
530   screen_data_t *screen_data = get_safe_token(device);
531   UINT16 src_data, dest_data;
532   UINT32 dest_addr;
533
534   if (offset >= screen_data->image_memory_size) {
535      // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000
536      DLOG1(("writing Monochrome Graphics Memory at invalid offset %05x = %04x & %04x ", offset, data, mem_mask));
537      offset %= screen_data->image_memory_size;
538   }
539
540   DLOG1(("writing Monochrome Graphics Memory with mode %d: offset=%04x data=%04x mask=%04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask));
541   switch (CR0_MODE(screen_data->cr0)) {
542   case CR0_MODE_0:
543      // CPU destination BLT
544      // bus write to provide display memory address
545      // bus read to get data
546      screen_data->image_offset = offset;
547      screen_data->blt_cycle_count = 1;
548      break;
549   case CR0_MODE_1:
550      // Alternating BLT
551      // alternating bus writes provide src/dest address
552      // second write provides Write-enables
553      if (++screen_data->blt_cycle_count == 1) {
554         screen_data->status_register |= SR_ALT;
555         screen_data->guard_latch <<= 16;
556         screen_data->guard_latch |= screen_data->image_memory[offset];
557      } else {
558         screen_data->blt_cycle_count = 0;
559         screen_data->status_register &= ~SR_ALT;
560
561         dest_data = screen_data->image_memory[offset];
562         src_data = rop(screen_data, dest_data);
563
564         src_data &= (~data & mem_mask);
565         dest_data &= (data | ~mem_mask);
566         screen_data->image_memory[offset] = dest_data | src_data;
567      }
568      break;
569   case CR0_MODE_VECTOR:
570      // Vector or fill mode
571      // write provides Write-enables and address
572      screen_data->status_register &= ~SR_ALT;
573
574      dest_data = screen_data->image_memory[offset];
575      src_data = rop(screen_data, dest_data);
576
577      src_data &= (~data & mem_mask);
578      dest_data &= (data | ~mem_mask);
579      screen_data->image_memory[offset] = dest_data | src_data;
580      break;
581   case CR0_MODE_3:
582      // CPU source BLT
583      // bus write to provide src data
584      // bus write to provide Write-enables and address
585      if (++screen_data->blt_cycle_count == 1) {
586         screen_data->status_register |= SR_ALT;
587
588         // strange: must fix byte access for /systest/grtest on sr10.2
589         if (mem_mask == 0xff00)
590         {
591            data >>=8;
592            mem_mask >>= 8;
593         }
594
595         screen_data->guard_latch <<= 16;
596         screen_data->guard_latch |= data;
597
598      } else {
599         screen_data->blt_cycle_count = 0;
600         screen_data->status_register &= ~SR_ALT;
601
602         dest_data = screen_data->image_memory[offset];
603         dest_data &= (data | ~mem_mask);
604
605         src_data = rop(screen_data, dest_data);
606         src_data &= (~data & mem_mask);
607
608         screen_data->image_memory[offset] = dest_data | src_data;
609      }
610      break;
611   case CR0_MODE_BLT:
612      // Double access BLT
613      // bus write to provide src addr on address lines
614      // dest addr on data lines (16-bit WORD Offset)
615      screen_data->guard_latch <<= 16;
616      screen_data->guard_latch |= screen_data->image_memory[offset];
617
618      dest_addr = (data & mem_mask);
619      if (screen_data->device_id == SCREEN_DEVICE_ID_19I && (screen_data->cr1
620            & CR1_DADDR_16)) {
621         dest_addr += 0x10000;
622      }
623      dest_data = screen_data->image_memory[dest_addr];
624
625      src_data = rop(screen_data, dest_data);
626      src_data &= ~screen_data->write_enable_register;
627
628      dest_data &= (screen_data->write_enable_register | ~mem_mask);
629      screen_data->image_memory[dest_addr] = dest_data | src_data;
630      break;
631   case CR0_MODE_NORMAL:
632      screen_data->guard_latch <<= 16;
633      screen_data->guard_latch |= (data & mem_mask);;
634      dest_data = screen_data->image_memory[offset];
635      src_data = rop(screen_data, dest_data);
636
637      src_data &= ~screen_data->write_enable_register;
638      dest_data &= (screen_data->write_enable_register | ~mem_mask);
639      screen_data->image_memory[offset] = dest_data | src_data;
640      break;
641   default:
642      DLOG(("writing Monochrome Graphics Memory - unexpected cr0 mode %d", CR0_MODE(screen_data->cr0)));
643   }
644   screen_data->update_flag = 1;
645}
646
647/***************************************************************************
648 VIDEO HARDWARE
649 ***************************************************************************/
650
651static void apollo_screen_update(device_t *device, bitmap_ind16 &bitmap,
652      const rectangle &cliprect) {
653   screen_data_t *screen_data = get_safe_token(device);
654
655   UINT16 *source_ptr = screen_data->image_memory;
656   int x, y;
657   UINT16 data, mask;
658   UINT16 inverse = (screen_data->cr1 & CR1_INV) ? 0xffff : 0;
659
660   DLOG1(("apollo_screen_update: size=%0x rowpixels=%d", screen_data->image_memory_size, bitmap.rowpixels()));
661
662   if ((screen_data->cr1 & CR1_DISP_EN) == 0) {
663      // display is disabled
664      for (y = 0; y < screen_data->height; y++) {
665         int dest = 0;
666         for (x = 0; x < screen_data->width; x += 16) {
667            for (mask = 0x8000; mask; mask >>= 1) {
668               bitmap.pix16(y, dest++) = 0;
669            }
670         }
671         source_ptr += (screen_data->buffer_width - screen_data->width) / 16;
672      }
673   } else {
674      for (y = 0; y < screen_data->height; y++) {
675         int dest = 0;
676         for (x = 0; x < screen_data->width; x += 16) {
677            data = *source_ptr++ ^ inverse;
678            for (mask = 0x8000; mask; mask >>= 1) {
679               bitmap.pix16(y, dest++) = data & mask ? 0 : 1;
680            }
681         }
682         source_ptr += (screen_data->buffer_width - screen_data->width) / 16;
683      }
684   }
685}
686
687/*-------------------------------------------------
688    vblank_state_changed -
689   called on each state change of the VBLANK signal
690-------------------------------------------------*/
691
692static void vblank_state_changed(device_t *device, screen_device &screen, bool vblank_state)
693{
694   screen_data_t *screen_data = get_safe_token(device);
695
696   if ((screen_data->cr1 & CR1_RESET) && (screen_data->cr1 & CR1_SYNC_EN)) {
697      if (vblank_state) {
698         screen_data->status_register &= ~(SR_V_BLANK | SR_BLANK);
699         // faking V_DATA for disp.dex test 16
700         if (screen_data->image_memory[0]) {
701            screen_data->status_register |= SR_V_DATA;
702         }
703      } else {
704         screen_data->status_register |= (SR_V_BLANK | SR_BLANK);
705         screen_data->status_register &= ~SR_V_DATA;
706      }
707   }
708}
709
710VIDEO_START( apollo_screen ) {
711}
712
713SCREEN_UPDATE_IND16( apollo_screen ) {
714   // FIXME: omit using APOLLO_SCREEN_TAG
715   device_t *apollo_screen = screen.machine().device( APOLLO_SCREEN_TAG );
716   screen_data_t *screen_data = get_safe_token(apollo_screen);
717
718   int has_changed = 0;
719
720   if (screen_data->update_flag && !screen_data->update_pending) {
721      has_changed = 1;
722      screen_data->update_flag = 0;
723      screen_data->update_pending = 1;
724      apollo_screen_update(apollo_screen, bitmap, cliprect);
725      screen_data->update_pending = 0;
726   }
727   return has_changed ? 0 : UPDATE_HAS_NOT_CHANGED;
728}
729
730/***************************************************************************
731 MACHINE DRIVERS
732 ***************************************************************************/
733MACHINE_CONFIG_FRAGMENT( apollo_mono19i )
734      MCFG_DEFAULT_LAYOUT( layout_apollo )
735      MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER)
736      MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK)
737//      MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
738      MCFG_PALETTE_LENGTH(2)
739      MCFG_PALETTE_INIT(black_and_white)
740      // dot clock, htotal, hstart, hend, vtotal, vstart, vend
741      // MCFG_SCREEN_RAW_PARAMS(118000000, 1280, 0, 1728, 1024, 0, 1065)
742      MCFG_SCREEN_REFRESH_RATE(64)
743      MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(616))
744      MCFG_SCREEN_SIZE(1280, 1024)
745      MCFG_SCREEN_VISIBLE_AREA(0, 1279, 0, 1023)
746      MCFG_VIDEO_START(apollo_screen)
747      MCFG_SCREEN_UPDATE_STATIC(apollo_screen)
748MACHINE_CONFIG_END
749
750MACHINE_CONFIG_FRAGMENT( apollo_mono15i )
751      MCFG_DEFAULT_LAYOUT( layout_apollo_15i )
752      MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER)
753      MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK)
754//      MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
755      MCFG_PALETTE_LENGTH(2)
756      MCFG_PALETTE_INIT(black_and_white)
757      // dot clock, htotal, hstart, hend, vtotal, vstart, vend
758      // MCFG_SCREEN_RAW_PARAMS(85963000, 1024, 0, 1344, 800, 0, 842)
759      MCFG_SCREEN_REFRESH_RATE(76)
760      MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(657))
761      MCFG_SCREEN_SIZE(1024, 800)
762      MCFG_SCREEN_VISIBLE_AREA(0, 1023, 0, 799)
763      MCFG_VIDEO_START(apollo_screen)
764      MCFG_SCREEN_UPDATE_STATIC(apollo_screen)
765MACHINE_CONFIG_END
766
767/*-------------------------------------------------
768 DEVICE_START( apollo_mono19i/15i )
769 -------------------------------------------------*/
770
771static DEVICE_START( apollo_mono ) {
772   screen_data_t *screen_data = get_safe_token(device);
773
774   /* get the video screen  */
775   screen_data->screen = (screen_device *)device->machine().device(VIDEO_SCREEN_TAG);
776   assert(screen_data->screen != NULL);
777
778   /* allocate the memory image */
779   screen_data->image_memory_size = screen_data->buffer_height
780         * screen_data->buffer_width / 16;
781//   screen_data->image_memory = (UINT16 *) malloc(screen_data->image_memory_size * 2);
782   screen_data->image_memory = auto_alloc_array(device->machine(), UINT16, screen_data->image_memory_size);
783   assert(screen_data->image_memory != NULL);
784
785   DLOG1(("device start apollo screen buffer=%p size=%0x", screen_data->image_memory, screen_data->image_memory_size));
786}
787
788static DEVICE_START( apollo_mono19i ) {
789   screen_data_t *screen_data = get_safe_token(device);
790
791   memset(screen_data, 0, sizeof(screen_data_t));
792
793   // monochrome 1280x1024
794   screen_data->device_id = SCREEN_DEVICE_ID_19I;
795   screen_data->width = 1280;
796   screen_data->height = 1024;
797   screen_data->buffer_width = 2048;
798   screen_data->buffer_height = 1024;
799
800   device_start_apollo_mono(device);
801}
802
803static DEVICE_START( apollo_mono15i ) {
804   screen_data_t *screen_data = get_safe_token(device);
805
806   memset(screen_data, 0, sizeof(screen_data_t));
807
808   // monochrome 1024x800
809   screen_data->device_id = SCREEN_DEVICE_ID_15I;
810   screen_data->width = 1024;
811   screen_data->height = 800;
812   screen_data->buffer_width = 1024;
813   screen_data->buffer_height = 1024;
814
815   device_start_apollo_mono(device);
816}
817
818/*-------------------------------------------------
819 DEVICE_RESET( apollo_mono19i/15i )
820 -------------------------------------------------*/
821
822static DEVICE_RESET( apollo_mono19i ) {
823   screen_data_t *screen_data = get_safe_token(device);
824
825   DLOG1(("device reset apollo screen"));
826
827   memset(screen_data->image_memory, 0, screen_data->image_memory_size * 2);
828
829   /* register for VBLANK callbacks */
830   screen_data->screen->register_vblank_callback(vblank_state_delegate(FUNC(vblank_state_changed), device));
831}
832
833static DEVICE_RESET( apollo_mono15i ) {
834   DEVICE_RESET_CALL(apollo_mono19i);
835}
836
837/*-------------------------------------------------
838 DEVICE_GET_INFO( apollo_mono19i/15i )
839 -------------------------------------------------*/
840
841DEVICE_GET_INFO( apollo_mono19i ) {
842   switch (state) {
843   /* --- the following bits of info are returned as 64-bit signed integers --- */
844   case DEVINFO_INT_INLINE_CONFIG_BYTES:  info->i = 0; break;
845   case DEVINFO_INT_TOKEN_BYTES:          info->i = sizeof(screen_data_t); break;
846
847      /* --- the following bits of info are returned as pointers to data or functions --- */
848   case DEVINFO_FCT_START:                info->start = DEVICE_START_NAME(apollo_mono19i); break;
849   case DEVINFO_FCT_STOP:                 /* Nothing */ break;
850   case DEVINFO_FCT_RESET:                info->reset = DEVICE_RESET_NAME(apollo_mono19i);    break;
851
852      /* --- the following bits of info are returned as NULL-terminated strings --- */
853   case DEVINFO_STR_NAME:                 strcpy(info->s, "Apollo 19\" Monochrome Screen"); break;
854   case DEVINFO_STR_FAMILY:               strcpy(info->s, "Terminal"); break;
855   case DEVINFO_STR_VERSION:              strcpy(info->s, "1.0"); break;
856   case DEVINFO_STR_SOURCE_FILE:          strcpy(info->s, __FILE__); break;
857   case DEVINFO_STR_CREDITS:              strcpy(info->s, "Copyright the MESS Team"); break;
858   }
859}
860
861DEVICE_GET_INFO( apollo_mono15i ) {
862   switch (state) {
863   /* --- the following bits of info are returned as 64-bit signed integers --- */
864   case DEVINFO_INT_INLINE_CONFIG_BYTES:  info->i = 0; break;
865   case DEVINFO_INT_TOKEN_BYTES:          info->i = sizeof(screen_data_t); break;
866
867      /* --- the following bits of info are returned as pointers to data or functions --- */
868   case DEVINFO_FCT_START:                info->start = DEVICE_START_NAME(apollo_mono15i); break;
869   case DEVINFO_FCT_STOP:                 /* Nothing */ break;
870   case DEVINFO_FCT_RESET:                info->reset = DEVICE_RESET_NAME(apollo_mono15i);    break;
871
872      /* --- the following bits of info are returned as NULL-terminated strings --- */
873   case DEVINFO_STR_NAME:                 strcpy(info->s, "Apollo 15\" Monochrome Screen"); break;
874   case DEVINFO_STR_FAMILY:               strcpy(info->s, "Terminal"); break;
875   case DEVINFO_STR_VERSION:              strcpy(info->s, "1.0"); break;
876   case DEVINFO_STR_SOURCE_FILE:          strcpy(info->s, __FILE__); break;
877   case DEVINFO_STR_CREDITS:              strcpy(info->s, "Copyright the MESS Team"); break;
878   }
879}
880
881DEFINE_LEGACY_DEVICE(APOLLO_MONO19I, apollo_mono19i);
882DEFINE_LEGACY_DEVICE(APOLLO_MONO15I, apollo_mono15i);
src/mess/includes/apollo.h
r0r14540
1/*
2 * apollo.h - APOLLO DN3500/DN3000 driver includes
3 *
4 *  Created on: May 12, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 */
11
12#pragma once
13
14#ifndef APOLLO_H_
15#define APOLLO_H_
16
17#include "emu.h"
18
19#ifndef VERBOSE
20#define VERBOSE 0
21#endif
22
23#define LOG(x)  { logerror x; logerror ("\n"); apollo_check_log(); }
24#define LOG1(x) { if (VERBOSE > 0) LOG(x) }
25#define LOG2(x) { if (VERBOSE > 1) LOG(x) }
26#define DLOG(x) { logerror ("%s - %s: ", apollo_cpu_context(device->machine().device(MAINCPU)), device->tag()); LOG(x) }
27#define DLOG1(x) { if (VERBOSE > 0) DLOG(x) }
28#define DLOG2(x) { if (VERBOSE > 1) DLOG(x) }
29#define MLOG(x)  { logerror ("%s: ", apollo_cpu_context(machine.device(MAINCPU))); LOG(x) }
30#define MLOG1(x) { if (VERBOSE > 0) MLOG(x) }
31#define MLOG2(x) { if (VERBOSE > 1) MLOG(x) }
32#define SLOG(x)  { logerror ("%s: ", apollo_cpu_context(&space->device())); LOG(x) }
33#define SLOG1(x) { if (VERBOSE > 0) SLOG(x) }
34#define SLOG2(x) { if (VERBOSE > 1) SLOG(x) }
35
36#define  MAINCPU "maincpu"
37
38/*----------- debug/apollo.c -----------*/
39
40int apollo_debug_instruction_hook(device_t *device, offs_t curpc);
41
42/*----------- drivers/apollo.c -----------*/
43
44// return the current CPU context for log file entries
45const char *apollo_cpu_context(device_t *cpu);
46
47// enable/disable the FPU
48void apollo_set_cpu_has_fpu(device_t *device, int onoff);
49
50// check for excessive logging
51void apollo_check_log();
52
53// return 1 if node is DN3000 or DSP3000, 0 otherwise
54int apollo_is_dn3000(void);
55
56// return 1 if node is DSP3000 or DSP3500, 0 otherwise
57int apollo_is_dsp3x00(void);
58
59// get the ram configuration byte
60UINT8 apollo_get_ram_config_byte(void);
61
62//apollo_get_node_id - get the node id
63UINT32 apollo_get_node_id(void);
64
65 // should be called by the CPU core before executing each instruction
66int apollo_instruction_hook(device_t *device, offs_t curpc);
67
68void apollo_set_cache_status_register(UINT8 mask, UINT8 data);
69
70void apollo_terminal_write(UINT8 data);
71
72/*----------- machine/apollo.c -----------*/
73
74#define APOLLO_CONF_TAG "conf"
75#define APOLLO_FDC_TAG  "fdc"
76#define APOLLO_DMA1_TAG "dma8237_1"
77#define APOLLO_DMA2_TAG "dma8237_2"
78#define APOLLO_KBD_TAG  "kbd"
79#define APOLLO_PIC1_TAG "pic8259_master"
80#define APOLLO_PIC2_TAG "pic8259_slave"
81#define APOLLO_PTM_TAG  "ptm"
82#define APOLLO_RTC_TAG  "rtc"
83#define APOLLO_SIO_TAG  "sio"
84#define APOLLO_SIO2_TAG "sio2"
85#define APOLLO_ETH_TAG  "3c505"
86#define APOLLO_WDC_TAG  "omti8621"
87#define APOLLO_CTAPE_TAG "ctape"
88
89class apollo_state : public driver_device
90{
91public:
92//   apollo_state(running_machine &machine, const driver_device_config_base &config)
93//      : driver_device(machine, config) { }
94
95   apollo_state(const machine_config &mconfig, device_type type, const char *tag)
96         : driver_device(mconfig, type, tag) { }
97
98   device_t *dma8237_1;
99   device_t *dma8237_2;
100   device_t *pic8259_master;
101   device_t *pic8259_slave;
102};
103
104MACHINE_CONFIG_EXTERN( apollo );
105
106DRIVER_INIT( apollo );
107MACHINE_START( apollo );
108MACHINE_RESET( apollo );
109
110/*----------- machine/apollo_config.c -----------*/
111
112// configuration bit definitions
113
114#define APOLLO_CONF_SERVICE_MODE 0x001
115#define APOLLO_CONF_GERMAN_KBD   0x002
116#define APOLLO_CONF_DATE_1990    0x004
117#define APOLLO_CONF_NODE_ID      0x008
118#define APOLLO_CONF_IDLE_SLEEP   0x010
119#define APOLLO_CONF_TRAP_TRACE   0x020
120#define APOLLO_CONF_FPU_TRACE    0x040
121#define APOLLO_CONF_DISK_TRACE   0x080
122#define APOLLO_CONF_NET_TRACE    0x100
123
124// check configuration setting
125int apollo_config(int mask);
126
127INPUT_PORTS_EXTERN(apollo_config);
128
129/*----------- machine/apollo_csr.c -----------*/
130
131#define APOLLO_CSR_SR_SERVICE            0x0001
132#define APOLLO_CSR_SR_ATBUS_IO_TIMEOUT   0x0002
133#define APOLLO_CSR_SR_FP_TRAP            0x0004
134#define APOLLO_CSR_SR_INTERRUPT_PENDING  0x0008 // DN3000 only
135#define APOLLO_CSR_SR_PARITY_BYTE_MASK   0x00f0
136#define APOLLO_CSR_SR_CPU_TIMEOUT        0x0100
137#define APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT  0x2000
138#define APOLLO_CSR_SR_BIT15              0x8000
139#define APOLLO_CSR_SR_CLEAR_ALL          0x3ffe
140
141#define APOLLO_CSR_CR_INTERRUPT_ENABLE   0x0001
142#define APOLLO_CSR_CR_RESET_DEVICES         0x0002
143#define APOLLO_CSR_CR_FPU_TRAP_ENABLE    0x0004
144#define APOLLO_CSR_CR_FORCE_BAD_PARITY   0x0008
145#define APOLLO_CSR_CR_PARITY_BYTE_MASK   0x00f0
146
147UINT16 apollo_csr_get_control_register(void);
148UINT16 apollo_csr_get_status_register(void);
149void apollo_csr_set_status_register(UINT16 mask, UINT16 data);
150
151WRITE16_HANDLER( apollo_csr_status_register_w );
152READ16_HANDLER( apollo_csr_status_register_r );
153WRITE16_HANDLER( apollo_csr_control_register_w );
154READ16_HANDLER( apollo_csr_control_register_r );
155
156/*----------- machine/apollo_dma.c -----------*/
157
158WRITE8_HANDLER(apollo_dma_1_w );
159READ8_HANDLER( apollo_dma_1_r );
160
161WRITE8_HANDLER(apollo_dma_2_w );
162READ8_HANDLER( apollo_dma_2_r );
163
164WRITE8_HANDLER(apollo_dma_page_register_w );
165READ8_HANDLER( apollo_dma_page_register_r );
166
167WRITE16_HANDLER(apollo_address_translation_map_w );
168READ16_HANDLER( apollo_address_translation_map_r );
169
170/*----------- machine/apollo_pic.c -----------*/
171
172WRITE8_DEVICE_HANDLER(apollo_pic8259_master_w ) ;
173READ8_DEVICE_HANDLER( apollo_pic8259_master_r );
174
175WRITE8_DEVICE_HANDLER(apollo_pic8259_slave_w );
176READ8_DEVICE_HANDLER( apollo_pic8259_slave_r );
177
178IRQ_CALLBACK(apollo_pic_acknowledge);
179
180/*----------- machine/apollo_ptm.c -----------*/
181
182WRITE8_DEVICE_HANDLER( apollo_ptm_w );
183READ8_DEVICE_HANDLER( apollo_ptm_r );
184
185/*----------- machine/apollo_rtc.c -----------*/
186
187WRITE8_HANDLER( apollo_rtc_w );
188READ8_HANDLER( apollo_rtc_r );
189
190/*----------- machine/apollo_sio.c -----------*/
191
192void apollo_sio_rx_data( device_t* device, int ch, UINT8 data );
193
194READ8_DEVICE_HANDLER(apollo_sio_r);
195WRITE8_DEVICE_HANDLER(apollo_sio_w);
196
197/*----------- machine/apollo_sio2.c -----------*/
198
199READ8_DEVICE_HANDLER(apollo_sio2_r);
200WRITE8_DEVICE_HANDLER(apollo_sio2_w);
201
202/*----------- machine/apollo_fdc.c -----------*/
203
204READ8_HANDLER(apollo_fdc_r);
205WRITE8_HANDLER(apollo_fdc_w);
206
207/*----------- machine/apollo_eth.c -----------*/
208
209// ethernet transmitter
210
211int apollo_eth_transmit(device_t* device,
212      const UINT8 data_buffer[], const int data_length);
213
214int apollo_eth_setfilter(device_t *device, int node_id);
215// ethernet receiver callback
216
217typedef int (*apollo_eth_receive)(device_t *, const UINT8 *, int);
218
219void apollo_eth_init(device_t *device, apollo_eth_receive rx_data);
220
221/*----------- machine/apollo_net.c -----------*/
222
223// netserver receiver
224
225int apollo_netserver_receive(device_t* device,
226      const UINT8 rx_data_buffer[], const int rx_data_length);
227
228// transmitter callback
229
230typedef int (*apollo_netserver_transmit)(device_t *, const UINT8 *, int);
231
232void apollo_netserver_init(const char *root_path,  apollo_netserver_transmit tx_data);
233
234/*----------- video/apollo.c -----------*/
235
236#define APOLLO_SCREEN_TAG "apollo_screen"
237
238DECLARE_LEGACY_DEVICE(APOLLO_MONO19I, apollo_mono19i);
239
240#define MCFG_APOLLO_MONO19I_ADD(_tag) \
241   MCFG_FRAGMENT_ADD(apollo_mono19i) \
242   MCFG_DEVICE_ADD(_tag, APOLLO_MONO19I, 0)
243
244DEVICE_GET_INFO( apollo_mono19i );
245
246MACHINE_CONFIG_EXTERN( apollo_mono19i );
247
248DECLARE_LEGACY_DEVICE(APOLLO_MONO15I, apollo_mono15i);
249
250#define MCFG_APOLLO_MONO15I_ADD( _tag) \
251   MCFG_FRAGMENT_ADD(apollo_mono15i) \
252   MCFG_DEVICE_ADD(_tag, APOLLO_MONO15I, 0)
253
254DEVICE_GET_INFO( apollo_mono15i );
255
256MACHINE_CONFIG_EXTERN( apollo_mono15i );
257
258READ16_DEVICE_HANDLER( apollo_mcr_r ) ;
259WRITE16_DEVICE_HANDLER(apollo_mcr_w );
260
261READ16_DEVICE_HANDLER( apollo_mgm_r );
262WRITE16_DEVICE_HANDLER( apollo_mgm_w );
263
264#endif /* APOLLO_H_ */
src/mess/layout/apollo.lay
r0r14540
1<!-- 19" display for the Apollo DN3500 -->
2
3<mamelayout version="2">
4
5   <element name="internal_led"> <disk> <color red="1.0" green="1.0" blue="1.0" /> </disk> </element>
6   <element name="external_led"> <disk> <color red="0.666" green="0.555" blue="0.0" /> </disk> </element>
7   <element name="power_led"> <disk> <color red="0.0" green="1.0" blue="0.0" /> </disk> </element>
8
9   <element name="label_a"> <text string="A"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
10   <element name="label_b"> <text string="B"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
11   <element name="label_c"> <text string="C"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
12   <element name="label_d"> <text string="D"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
13   <element name="power_label"> <text string="PWR"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
14
15   <element name="f1s"> <text string="SHELL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
16   <element name="f1">  <text string="CMD"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
17   <element name="f2s"> <text string="CUT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
18   <element name="f2">  <text string="COPY"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
19   <element name="f3s"> <text string="UNDO"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
20   <element name="f3">  <text string="PASTE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
21   <element name="f4s"> <text string="MOVE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
22   <element name="f4">  <text string="GROW"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
23
24   <element name="f5s"> <text string="INS"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
25   <element name="f5">  <text string="MARK"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
26   <element name="f6s"> <text string="LINE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
27   <element name="f6">  <text string="DEL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
28   <element name="f7s"> <text string="CHAR"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
29   <element name="f7">  <text string="DEL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
30   <element name="f8s"> <text string=""> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
31   <element name="f8">  <text string="AGAIN"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
32
33   <element name="f9s"> <text string=""> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
34   <element name="f9">  <text string="READ"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
35   <element name="f10s"> <text string="SAVE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
36   <element name="f10">  <text string="EDIT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
37   <element name="f11s"> <text string="ABORT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
38   <element name="f11">  <text string="EXIT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
39   <element name="f12s"> <text string="HELP"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
40   <element name="f12">  <text string="HOLD"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
41
42   <element name="background">
43      <rect>
44         <bounds left="0" top="0" right="1" bottom="1" />
45         <color red="0.2" green="0.2" blue="0.2" />
46      </rect>
47   </element>
48
49   <view name="Apollo 19&quot; Monochrome">
50
51      <bezel element="background"> <bounds left="0" right="340" top="1024" bottom="1068" /> </bezel>
52      <bezel name="f1s" element="f1s"> <bounds left="0" right="80" top="1030" bottom="1046" /> </bezel>
53      <bezel name="f1"  element="f1"> <bounds left="0" right="80" top="1048" bottom="1064" /> </bezel>
54      <bezel name="f2s" element="f2s"> <bounds left="82" right="162" top="1030" bottom="1046" /> </bezel>
55      <bezel name="f2"  element="f2"> <bounds left="82" right="162" top="1048" bottom="1064" /> </bezel>
56      <bezel name="f3s" element="f3s"> <bounds left="164" right="246" top="1030" bottom="1046" /> </bezel>
57      <bezel name="f3"  element="f3"> <bounds left="164" right="246" top="1048" bottom="1064" /> </bezel>
58      <bezel name="f4s" element="f4s"> <bounds left="248" right="328" top="1030" bottom="1046" /> </bezel>
59      <bezel name="f4"  element="f4"> <bounds left="248" right="328" top="1048" bottom="1064" /> </bezel>
60
61      <bezel element="background"> <bounds left="343" right="682" top="1024" bottom="1068" /> </bezel>
62      <bezel name="f5s" element="f5s"> <bounds left="350" right="430" top="1030" bottom="1046" /> </bezel>
63      <bezel name="f5"  element="f5"> <bounds left="350" right="430" top="1048" bottom="1064" /> </bezel>
64      <bezel name="f6s" element="f6s"> <bounds left="432" right="512" top="1030" bottom="1046" /> </bezel>
65      <bezel name="f6"  element="f6"> <bounds left="432" right="512" top="1048" bottom="1064" /> </bezel>
66      <bezel name="f7s" element="f7s"> <bounds left="514" right="594" top="1030" bottom="1046" /> </bezel>
67      <bezel name="f7"  element="f7"> <bounds left="514" right="594" top="1048" bottom="1064" /> </bezel>
68      <bezel name="f8s" element="f8s"> <bounds left="597" right="677" top="1030" bottom="1046" /> </bezel>
69      <bezel name="f8"  element="f8"> <bounds left="597" right="677" top="1048" bottom="1064" /> </bezel>
70
71      <bezel element="background"> <bounds left="685" right="1023" top="1024" bottom="1068" /> </bezel>
72      <bezel name="f9s" element="f9s"> <bounds left="697" right="777" top="1030" bottom="1046" /> </bezel>
73      <bezel name="f9"  element="f9"> <bounds left="697" right="777" top="1048" bottom="1064" /> </bezel>
74      <bezel name="f10s" element="f10s"> <bounds left="779" right="859" top="1030" bottom="1046" /> </bezel>
75      <bezel name="f10"  element="f10"> <bounds left="779" right="859" top="1048" bottom="1064" /> </bezel>
76      <bezel name="f11s" element="f11s"> <bounds left="861" right="941" top="1030" bottom="1046" /> </bezel>
77      <bezel name="f11"  element="f11"> <bounds left="861" right="941" top="1048" bottom="1064" /> </bezel>
78      <bezel name="f12s" element="f12s"> <bounds left="943" right="1023" top="1030" bottom="1046" /> </bezel>
79      <bezel name="f12"  element="f12"> <bounds left="943" right="1023" top="1048" bottom="1064" /> </bezel>
80
81      <bezel element="background"> <bounds left="1026" right="1279" top="1024" bottom="1068" /> </bezel>
82
83      <bezel name="label_a" element="label_a"> <bounds left="1056" right="1070" top="1030" bottom="1046" /> </bezel>
84      <bezel name="external_led_a" element="external_led"> <bounds left="1074" right="1086" top="1032" bottom="1044" /> </bezel>
85
86      <bezel name="label_b" element="label_b"> <bounds left="1094" right="1106" top="1030" bottom="1046" /> </bezel>
87      <bezel name="external_led_b" element="external_led"> <bounds left="1112" right="1124" top="1032" bottom="1044" /> </bezel>
88
89      <bezel name="label_c" element="label_c"> <bounds left="1132" right="1144" top="1030" bottom="1046" /> </bezel>
90      <bezel name="external_led_c" element="external_led"> <bounds left="1150" right="1162" top="1032" bottom="1044" /> </bezel>
91
92      <bezel name="label_d" element="label_d"> <bounds left="1170" right="1182" top="1030" bottom="1046" /> </bezel>
93      <bezel name="external_led_d" element="external_led"> <bounds left="1188" right="1200" top="1032" bottom="1044" /> </bezel>
94
95      <bezel name="power_label" element="power_label"> <bounds left="1208" right="1240" top="1030" bottom="1046" /> </bezel>
96      <bezel name="power_led" element="power_led"> <bounds left="1246" right="1258" top="1032" bottom="1044" /> </bezel>
97
98      <bezel name="internal_led_1" element="internal_led"> <bounds left="1074" right="1086" top="1050" bottom="1062" /> </bezel>
99      <bezel name="internal_led_2" element="internal_led"> <bounds left="1112" right="1124" top="1050" bottom="1062" /> </bezel>
100      <bezel name="internal_led_3" element="internal_led"> <bounds left="1150" right="1162" top="1050" bottom="1062" /> </bezel>
101      <bezel name="internal_led_4" element="internal_led"> <bounds left="1188" right="1200" top="1050" bottom="1062" /> </bezel>
102
103      <screen index="0">
104         <bounds x="0" y="0" width="1280" height="1024" />
105      </screen>
106   </view>
107
108   <view name="SXGA Screen">
109      <screen index="0">
110         <bounds x="0" y="0" width="1280" height="1024" />
111      </screen>
112   </view>
113
114</mamelayout>
src/mess/layout/apollo_dsp.lay
r0r14540
1<!-- terminal display for the Apollo DSP3x00 -->
2
3<mamelayout version="2">
4
5   <element name="internal_led"> <disk> <color red="1.0" green="1.0" blue="1.0" /> </disk> </element>
6   <element name="external_led"> <disk> <color red="0.666" green="0.555" blue="0.0" /> </disk> </element>
7   <element name="power_led">    <disk> <color red="0.0" green="1.0" blue="0.0" /> </disk> </element>
8   <element name="label_a">      <text string="A"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
9   <element name="label_b">      <text string="B"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
10   <element name="label_c">      <text string="C"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
11   <element name="label_d">      <text string="D"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
12   <element name="power_label">  <text string="PWR"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
13
14   <element name="background">
15      <rect>
16         <bounds left="0" top="0" right="1" bottom="1" />
17         <color red="0.2" green="0.2" blue="0.2" />
18      </rect>
19   </element>
20
21   <view name="Apollo DSP Terminal">
22      <bezel element="background">
23         <bounds left="0" right="639" top="480" bottom="502" />
24      </bezel>
25
26      <bezel name="internal_led_1" element="internal_led"> <bounds left="5"  right="17" top="485" bottom="497" /> </bezel>
27      <bezel name="internal_led_2" element="internal_led"> <bounds left="25" right="37" top="485" bottom="497" /> </bezel>
28      <bezel name="internal_led_3" element="internal_led"> <bounds left="45" right="57" top="485" bottom="497" /> </bezel>
29      <bezel name="internal_led_4" element="internal_led"> <bounds left="65" right="77" top="485" bottom="497" /> </bezel>
30
31      <bezel name="label_a" element="label_a">             <bounds left="428" right="442" top="482" bottom="500" /> </bezel>
32      <bezel name="external_led_a" element="external_led"> <bounds left="446" right="458" top="485" bottom="497" /> </bezel>
33      <bezel name="label_b" element="label_b">             <bounds left="466" right="478" top="482" bottom="500" /> </bezel>
34      <bezel name="external_led_b" element="external_led"> <bounds left="484" right="496" top="485" bottom="497" /> </bezel>
35      <bezel name="label_c" element="label_c">             <bounds left="504" right="516" top="482" bottom="500" /> </bezel>
36      <bezel name="external_led_c" element="external_led"> <bounds left="522" right="534" top="485" bottom="497" /> </bezel>
37      <bezel name="label_d" element="label_d">             <bounds left="542" right="554" top="482" bottom="500" /> </bezel>
38      <bezel name="external_led_d" element="external_led"> <bounds left="560" right="572" top="485" bottom="497" /> </bezel>
39      <bezel name="power_label" element="power_label">     <bounds left="580" right="612" top="482" bottom="500" /> </bezel>
40      <bezel name="power_led" element="power_led">         <bounds left="618" right="630" top="485" bottom="497" /> </bezel>
41
42      <screen index="0">
43         <bounds x="0" y="0" width="640" height="480" />
44      </screen>
45   </view>
46
47</mamelayout>
src/mess/layout/apollo_15i.lay
r0r14540
1<!-- 15" display for the Apollo DN3500 -->
2
3<mamelayout version="2">
4
5   <element name="internal_led"> <disk> <color red="1.0" green="1.0" blue="1.0" /> </disk> </element>
6   <element name="external_led"> <disk> <color red="0.666" green="0.555" blue="0.0" /> </disk> </element>
7   <element name="power_led"> <disk> <color red="0.0" green="1.0" blue="0.0" /> </disk> </element>
8
9   <element name="label_a"> <text string="A"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
10   <element name="label_b"> <text string="B"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
11   <element name="label_c"> <text string="C"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
12   <element name="label_d"> <text string="D"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
13   <element name="power_label"> <text string="PWR"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
14
15   <element name="f1s"> <text string="SHELL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
16   <element name="f1">  <text string="CMD"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
17   <element name="f2s"> <text string="CUT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
18   <element name="f2">  <text string="COPY"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
19   <element name="f3s"> <text string="UNDO"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
20   <element name="f3">  <text string="PASTE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
21   <element name="f4s"> <text string="MOVE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
22   <element name="f4">  <text string="GROW"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
23
24   <element name="f5s"> <text string="INS"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
25   <element name="f5">  <text string="MARK"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
26   <element name="f6s"> <text string="LINE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
27   <element name="f6">  <text string="DEL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
28   <element name="f7s"> <text string="CHAR"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
29   <element name="f7">  <text string="DEL"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
30   <element name="f8s"> <text string=""> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
31   <element name="f8">  <text string="AGAIN"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
32
33   <element name="f9s"> <text string=""> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
34   <element name="f9">  <text string="READ"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
35   <element name="f10s"> <text string="SAVE"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
36   <element name="f10">  <text string="EDIT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
37   <element name="f11s"> <text string="ABORT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
38   <element name="f11">  <text string="EXIT"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
39   <element name="f12s"> <text string="HELP"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
40   <element name="f12">  <text string="HOLD"> <color red="1.0" green="1.0" blue="1.0" /> </text> </element>
41
42   <element name="background">
43      <rect>
44         <bounds left="0" top="0" right="1" bottom="1" />
45         <color red="0.2" green="0.2" blue="0.2" />
46      </rect>
47   </element>
48
49   <view name="Apollo 15&quot; Monochrome">
50
51      <bezel element="background">     <bounds left="0" right="253" top="800" bottom="844" /> </bezel>
52      <bezel name="f1s" element="f1s"> <bounds left="0" right="60" top="806" bottom="822" /> </bezel>
53      <bezel name="f1"  element="f1"> <bounds left="0" right="60" top="824" bottom="840" /> </bezel>
54      <bezel name="f2s" element="f2s"> <bounds left="62" right="122" top="806" bottom="822" /> </bezel>
55      <bezel name="f2"  element="f2"> <bounds left="62" right="122" top="824" bottom="840" /> </bezel>
56      <bezel name="f3s" element="f3s"> <bounds left="124" right="184" top="806" bottom="822" /> </bezel>
57      <bezel name="f3"  element="f3"> <bounds left="124" right="184" top="824" bottom="840" /> </bezel>
58      <bezel name="f4s" element="f4s"> <bounds left="188" right="248" top="806" bottom="822" /> </bezel>
59      <bezel name="f4"  element="f4"> <bounds left="188" right="248" top="824" bottom="840" /> </bezel>
60
61      <bezel element="background">     <bounds left="256" right="510" top="800" bottom="844" /> </bezel>
62      <bezel name="f5s" element="f5s"> <bounds left="256" right="316" top="806" bottom="822" /> </bezel>
63      <bezel name="f5"  element="f5"> <bounds left="256" right="316" top="824" bottom="840" /> </bezel>
64      <bezel name="f6s" element="f6s"> <bounds left="320" right="386" top="806" bottom="822" /> </bezel>
65      <bezel name="f6"  element="f6"> <bounds left="320" right="384" top="824" bottom="840" /> </bezel>
66      <bezel name="f7s" element="f7s"> <bounds left="384" right="444" top="806" bottom="822" /> </bezel>
67      <bezel name="f7"  element="f7"> <bounds left="384" right="444" top="824" bottom="840" /> </bezel>
68      <bezel name="f8s" element="f8s"> <bounds left="450" right="510" top="806" bottom="822" /> </bezel>
69      <bezel name="f8"  element="f8"> <bounds left="450" right="510" top="824" bottom="840" /> </bezel>
70
71      <bezel element="background">     <bounds left="513" right="766" top="800" bottom="844" /> </bezel>
72      <bezel name="f9s" element="f9s"> <bounds left="514" right="575" top="806" bottom="822" /> </bezel>
73      <bezel name="f9"  element="f9"> <bounds left="514" right="574" top="824" bottom="840" /> </bezel>
74      <bezel name="f10s" element="f10s"> <bounds left="578" right="638" top="806" bottom="822" /> </bezel>
75      <bezel name="f10"  element="f10"> <bounds left="578" right="638" top="824" bottom="840" /> </bezel>
76      <bezel name="f11s" element="f11s"> <bounds left="642" right="702" top="806" bottom="822" /> </bezel>
77      <bezel name="f11"  element="f11"> <bounds left="642" right="702" top="824" bottom="840" /> </bezel>
78      <bezel name="f12s" element="f12s"> <bounds left="706" right="766" top="806" bottom="822" /> </bezel>
79      <bezel name="f12"  element="f12"> <bounds left="706" right="766" top="824" bottom="840" /> </bezel>
80
81      <bezel element="background"> <bounds left="769" right="1023" top="800" bottom="844" /> </bezel>
82
83      <bezel name="label_a" element="label_a"> <bounds left="800" right="814" top="806" bottom="822" /> </bezel>
84      <bezel name="external_led_a" element="external_led"> <bounds left="818" right="830" top="808" bottom="820" /> </bezel>
85
86      <bezel name="label_b" element="label_b"> <bounds left="838" right="850" top="806" bottom="822" /> </bezel>
87      <bezel name="external_led_b" element="external_led"> <bounds left="856" right="868" top="808" bottom="820" /> </bezel>
88
89      <bezel name="label_c" element="label_c"> <bounds left="876" right="888" top="806" bottom="822" /> </bezel>
90      <bezel name="external_led_c" element="external_led"> <bounds left="894" right="906" top="808" bottom="820" /> </bezel>
91
92      <bezel name="label_d" element="label_d"> <bounds left="914" right="926" top="806" bottom="822" /> </bezel>
93      <bezel name="external_led_d" element="external_led"> <bounds left="932" right="944" top="808" bottom="820" /> </bezel>
94
95      <bezel name="power_label" element="power_label"> <bounds left="952" right="984" top="806" bottom="822" /> </bezel>
96      <bezel name="power_led" element="power_led"> <bounds left="990" right="1002" top="808" bottom="820" /> </bezel>
97
98      <bezel name="internal_led_1" element="internal_led"> <bounds left="818" right="830" top="826" bottom="838" /> </bezel>
99      <bezel name="internal_led_2" element="internal_led"> <bounds left="856" right="868" top="826" bottom="838" /> </bezel>
100      <bezel name="internal_led_3" element="internal_led"> <bounds left="894" right="906" top="826" bottom="838" /> </bezel>
101      <bezel name="internal_led_4" element="internal_led"> <bounds left="932" right="944" top="826" bottom="838" /> </bezel>
102
103      <screen index="0"> <bounds x="0" y="0" width="1024" height="800" />
104      </screen>
105   </view>
106
107   <view name="Apollo 15&quot; Monochrome old">
108      <bezel element="background"> <bounds left="0" right="1023" top="801" bottom="821" /> </bezel>
109
110      <bezel name="internal_led_1" element="internal_led"> <bounds left="5" right="17" top="805" bottom="817" /> </bezel>
111      <bezel name="internal_led_2" element="internal_led"> <bounds left="25" right="37" top="805" bottom="817" /> </bezel>
112      <bezel name="internal_led_3" element="internal_led"> <bounds left="45" right="57" top="805" bottom="817" /> </bezel>
113      <bezel name="internal_led_4" element="internal_led"> <bounds left="65" right="77" top="805" bottom="817" /> </bezel>
114
115      <bezel element="label_a"> <bounds left="812" right="826" top="803" bottom="819" /> </bezel>
116      <bezel name="external_led_a" element="external_led"> <bounds left="830" right="842" top="805" bottom="817" /> </bezel>
117
118      <bezel element="label_b"> <bounds left="850" right="862" top="803" bottom="819" /> </bezel>
119      <bezel name="external_led_b" element="external_led"> <bounds left="868" right="880" top="805" bottom="817" /> </bezel>
120
121      <bezel element="label_c"> <bounds left="888" right="900" top="803" bottom="819" /> </bezel>
122      <bezel name="external_led_c" element="external_led"> <bounds left="906" right="918" top="805" bottom="817" /> </bezel>
123
124      <bezel element="label_d"> <bounds left="926" right="938" top="803" bottom="819" /> </bezel>
125      <bezel name="external_led_d" element="external_led"> <bounds left="944" right="956" top="805" bottom="817" /> </bezel>
126
127      <bezel element="power_label"> <bounds left="964" right="996" top="803" bottom="819" /> </bezel>
128      <bezel name="power_led" element="power_led"> <bounds left="1002" right="1014" top="805" bottom="817" /> </bezel>
129
130      <bezel element="background"> <bounds left="0" right="340" top="823" bottom="865" /> </bezel>
131      <bezel element="f1s"> <bounds left="0" right="80" top="827" bottom="843" /> </bezel>
132      <bezel element="f1"> <bounds left="0" right="80" top="845" bottom="861" /> </bezel>
133      <bezel element="f2s"> <bounds left="82" right="162" top="827" bottom="843" /> </bezel>
134      <bezel element="f2"> <bounds left="82" right="162" top="845" bottom="861" /> </bezel>
135      <bezel element="f3s"> <bounds left="164" right="246" top="827" bottom="843" /> </bezel>
136      <bezel element="f3"> <bounds left="164" right="246" top="845" bottom="861" /> </bezel>
137      <bezel element="f4s"> <bounds left="248" right="328" top="827" bottom="843" /> </bezel>
138      <bezel element="f4"> <bounds left="248" right="328" top="845" bottom="861" /> </bezel>
139
140      <bezel element="background"> <bounds left="342" right="682" top="823" bottom="865" /> </bezel>
141      <bezel element="f5s"> <bounds left="350" right="430" top="827" bottom="843" /> </bezel>
142      <bezel element="f5"> <bounds left="350" right="430" top="845" bottom="861" /> </bezel>
143      <bezel element="f6s"> <bounds left="432" right="512" top="827" bottom="843" /> </bezel>
144      <bezel element="f6"> <bounds left="432" right="512" top="845" bottom="861" /> </bezel>
145      <bezel element="f7s"> <bounds left="514" right="594" top="827" bottom="843" /> </bezel>
146      <bezel element="f7"> <bounds left="514" right="594" top="845" bottom="861" /> </bezel>
147      <bezel element="f8s"> <bounds left="597" right="677" top="827" bottom="843" /> </bezel>
148      <bezel element="f8"> <bounds left="597" right="677" top="845" bottom="861" /> </bezel>
149
150      <bezel element="background"> <bounds left="684" right="1023" top="823" bottom="865" /> </bezel>
151      <bezel element="f9s"> <bounds left="697" right="777" top="827" bottom="843" /> </bezel>
152      <bezel element="f9"> <bounds left="697" right="777" top="845" bottom="861" /> </bezel>
153      <bezel element="f10s"> <bounds left="779" right="859" top="827" bottom="843" /> </bezel>
154      <bezel element="f10"> <bounds left="779" right="859" top="845" bottom="861" /> </bezel>
155      <bezel element="f11s"> <bounds left="861" right="941" top="827" bottom="843" /> </bezel>
156      <bezel element="f11"> <bounds left="861" right="941" top="845" bottom="861" /> </bezel>
157      <bezel element="f12s"> <bounds left="943" right="1023" top="827" bottom="843" /> </bezel>
158      <bezel element="f12"> <bounds left="943" right="1023" top="845" bottom="861" /> </bezel>
159
160      <screen index="0">
161         <bounds x="0" y="0" width="1024" height="800" />
162      </screen>
163   </view>
164
165</mamelayout>
src/mess/drivers/apollo.c
r0r14540
1/*
2 * apollo.c - APOLLO DN3500/DN3000 driver
3 *
4 *  Created on: May 12, 2010
5 *      Author: Hans Ostermeyer
6 *
7 *  Released for general non-commercial use under the MAME license
8 *  Visit http://mamedev.org for licensing and usage restrictions.
9 *
10 *  Adapted February 19, 2012 for general MAME/MESS standards by R. Belmont
11 *
12 *  TODO: use MESS ram device and MCFG_RAM_* to handle RAM sizing.
13 *        AT bus stuff indicates ISA compatibility?  If so, convert to use MESS ISA bus infrastructure, including 3c505?
14 *        Remove need for instruction hook.
15 *        Convert to modern address map.
16 *
17 *  see also:
18 *  - Domain Series 3000/Series 4000 Hardware Architecture Handbook (Order No. 007861 Rev. 02)
19 *  - Domain Personal Workstations and Servers Technical Reference (Apollo Order No. 008778-A01)
20 *  - Servicing the Domain Personal Workstations and Servers (Apollo Order No. 007859-A01)
21 *  - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf
22 *  - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
23 *  - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf
24 *  - http://www.bitsavers.org/pdf/apollo/019411-A00_Addendum_to_Domain_Personal_Workstations_and_Servers_Hardware_Architecture_Handbook_1991.pdf
25 *  - data sheets from Intel and Motorola
26 */
27
28#define VERBOSE 0
29
30#include "includes/apollo.h"
31#include "machine/apollo_kbd.h"
32#include "machine/omti8621.h"
33#include "machine/sc499.h"
34#include "machine/3c505.h"
35#include "machine/68681.h"
36
37#include "debugger.h"
38
39#include "cpu/m68000/m68000.h"
40#include "cpu/m68000/m68kcpu.h"
41
42#include "machine/terminal.h"
43#include "machine/ram.h"
44
45#include "sound/beep.h"
46
47#include "apollo_dsp.lh"
48
49// we use this to prevent excessive logging (if emulation runs amok)
50// error.log will be 10 MB for 100000 lines
51#define APOLLO_MAX_NO_OF_LOG_LINES 500000
52
53#define ATBUS_IO_BASE      0x040000
54#define ATBUS_IO_END      0x05ffff
55#define ATBUS_MEMORY_BASE   0x080000
56#define ATBUS_MEMORY_END   0xffffff
57
58#define DN3500_RAM_SIZE       16 // 8 or 16 MB
59
60#if DN3500_RAM_SIZE   == 8
61#define DN3500_RAM_BASE     0x1000000
62#define DN3500_RAM_END       0x17fffff
63#define DN3500_RAM_CONFIG_BYTE   0x64 // or 0xe8
64#else /* DN3500_RAM_SIZE == 16 */
65#define DN3500_RAM_BASE     0x1000000
66#define DN3500_RAM_END       0x1ffffff
67#define DN3500_RAM_CONFIG_BYTE 0x60 // 4-4-4-4
68//#define DN3500_RAM_CONFIG_BYTE 0x14 // 8-8-0-0
69#endif
70
71#define DN3000_RAM_BASE     0x100000
72#define DN3000_RAM_END       0x8fffff
73#define DN3000_RAM_CONFIG_8MB  0xA8
74
75#define DN5500_RAM_SIZE       32 // 16 or 32 MB
76
77#if DN5500_RAM_SIZE   == 16
78#define DN5500_RAM_BASE     0x1000000
79#define DN5500_RAM_END       0x1ffffff
80#define DN5500_RAM_CONFIG_BYTE  0x14 // 8-8-0-0
81#define DN5500_MEM_PRESENT_BYTE 0xAA // 8-8-0-0
82#else /* DN5500_RAM_SIZE == 32 */
83#define DN5500_RAM_BASE     0x1000000
84#define DN5500_RAM_END       0x2ffffff
85#define DN5500_RAM_CONFIG_BYTE  0x20 // 8-8-8-8
86#define DN5500_MEM_PRESENT_BYTE 0x00 // 8-8-8-8
87#endif
88
89#define NODE_TYPE_DN3000 3000
90#define NODE_TYPE_DN3500 3500
91#define NODE_TYPE_DN5500 5500
92#define NODE_TYPE_DSP3000 -3000
93#define NODE_TYPE_DSP3500 -3500
94#define NODE_TYPE_DSP5500 -5500
95
96#define DEFAULT_NODE_ID 0x12345
97
98static UINT8 cache_control_register = 0x00;
99static UINT8 cache_status_register = 0xff;
100static UINT8 task_alias_register = 0x00;
101
102static offs_t parity_error_offset = 0;
103static UINT16 parity_error_byte_mask = 0;
104static int parity_error_handler_is_installed = 0;
105static int parity_error_handler_install_counter = 0;
106
107static UINT16 latch_page_on_parity_error_register = 0x0000;
108static UINT16 master_req_register = 0x0000;
109
110// DN3000: Node Id 1D117 at 0x9600 - 0x961f
111// DN3500: Node Id 2616D at 0x11200 - 0x1121f
112
113static UINT32 node_id = DEFAULT_NODE_ID;
114
115static UINT32 ram_base_address;
116static UINT32 ram_end_address;
117
118static generic_ptr messram_ptr;
119static size_t messram_size = 0;
120
121static int node_type;
122
123// FIXME: value of ram_config_byte must match with default/selected RAM size
124static UINT8 ram_config_byte;
125
126static device_t *dsp_terminal = NULL;
127
128static UINT32 log_line_counter = 0;
129
130/***************************************************************************
131 cpu_context - return a string describing which CPU is currently executing and their PC
132 ***************************************************************************/
133
134const char *apollo_cpu_context(device_t *cpu) {
135   static char statebuf[64]; /* string buffer containing state description */
136
137   /* if we have an executing CPU, output data */
138   if (cpu != NULL) {
139      osd_ticks_t t = osd_ticks();
140      int s = t / osd_ticks_per_second();
141      int ms = (t % osd_ticks_per_second()) / 1000;
142
143      sprintf(statebuf, "%d.%03d %s pc=%08x", s, ms, cpu->tag(), cpu_get_previouspc(cpu));
144   } else {
145      strcpy(statebuf, "(no context)");
146   }
147   return statebuf;
148}
149
150/*-------------------------------------------------
151 apollo_set_cpu_has_fpu - enable/disable the FPU
152 -------------------------------------------------*/
153
154/*void apollo_set_cpu_has_fpu(device_t *device, int onoff)
155{
156   if (device == NULL || (device->type() != M68020PMMU && device->type() != M68030))
157   {
158      DLOG1(("set_cpu_has_fpu: unexpected CPU device"));
159   }
160   else
161   {
162      m68ki_cpu_core *cpu = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token();
163      cpu->has_fpu = onoff;
164      DLOG1(("set_cpu_has_fpu: FPU has been %s", onoff ? "enabled" : "disabled"));
165   }
166}*/
167
168/***************************************************************************
169 apollo_check_log - check for excessive logging
170 ***************************************************************************/
171
172void apollo_check_log() {
173   if (++log_line_counter >= APOLLO_MAX_NO_OF_LOG_LINES) {
174      fatalerror("apollo_check_log: maximum number of log lines exceeded.\n");
175   }
176}
177
178/***************************************************************************
179 apollo_is_dn3000 - return 1 if node is DN3000 or DSP3000, 0 otherwise
180 ***************************************************************************/
181
182int apollo_is_dn3000(void) {
183   return node_type == NODE_TYPE_DN3000 || node_type == NODE_TYPE_DSP3000;
184}
185
186/***************************************************************************
187 apollo_is_dn5500 - return 1 if node is DN5500 or DSP5500, 0 otherwise
188 ***************************************************************************/
189
190int apollo_is_dn5500(void) {
191   return node_type == NODE_TYPE_DN5500 || node_type == NODE_TYPE_DSP5500;
192}
193
194/***************************************************************************
195 apollo_is_dsp3x00 - return 1 if node is DSP3x00 or DSP5500, 0 otherwise
196 ***************************************************************************/
197
198int apollo_is_dsp3x00(void) {
199   switch (node_type)
200   {
201   case NODE_TYPE_DSP3000:
202   case NODE_TYPE_DSP3500:
203   case NODE_TYPE_DSP5500:
204      return 1;
205   }
206   return 0;
207}
208
209/***************************************************************************
210 apollo_get_ram_config_byte - get the ram configuration byte
211 ***************************************************************************/
212
213UINT8 apollo_get_ram_config_byte(void) {
214   return ram_config_byte;
215}
216
217/***************************************************************************
218 apollo_get_node_id - get the node id
219 ***************************************************************************/
220
221UINT32 apollo_get_node_id(void) {
222   return node_id;
223}
224
225/***************************************************************************
226  apollo_instruction_hook
227  must be called by the CPU core before executing each instruction
228***************************************************************************/
229int apollo_instruction_hook(device_t *device, offs_t curpc)
230{
231   m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token();
232
233   static UINT16 idle_counter = 0;
234
235   // m68k->ir still has previous instruction
236   UINT16 last_ir = m68k->ir;
237
238   // get next instruction (or 0 if unavailable)
239   UINT16 next_ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : 0;
240
241   // check for NULLPROC:
242   // 027C F8FF AND.W #F8FF,SR
243   // 60FA        BRA *-4
244
245   if ((next_ir == 0x60fa && last_ir == 0x027c) || (next_ir == 0x027c   && last_ir == 0x60fa))
246   {
247      // we are within the idle loop, slow down CPU to reduce power usage
248      m68k->remaining_cycles -= 500;
249
250      if (apollo_config(APOLLO_CONF_IDLE_SLEEP) && apollo_is_dsp3x00() && ++idle_counter >= 1000)
251      {
252         // slow down even more on DSP3x00
253         idle_counter -= 100;
254         // sleep 1 ms
255         osd_sleep(osd_ticks_per_second() / 1000);
256      }
257   }
258   else
259   {
260      // we are outside of the idle loop
261      idle_counter = 0;
262   }
263
264   if (!m68k->has_fpu && !m68k->pmmu_enabled && (m68k->ir & 0xff00) == 0xf200)
265   {
266      // set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test
267      apollo_csr_set_status_register(APOLLO_CSR_SR_FP_TRAP, APOLLO_CSR_SR_FP_TRAP);
268   }
269
270   if (m68k->t1_flag && !m68k->s_flag)
271   {
272      // FIXME: trace emulation is disabled in m68kcpu.h; why???
273      m68ki_exception_trace(m68k);
274   }
275
276   return apollo_debug_instruction_hook(device, curpc);
277}
278
279/***************************************************************************
280 apollo bus error
281 ***************************************************************************/
282
283static void apollo_bus_error(running_machine &machine)
284{
285    cputag_set_input_line(machine, MAINCPU, M68K_LINE_BUSERROR, ASSERT_LINE);
286    cputag_set_input_line(machine, MAINCPU, M68K_LINE_BUSERROR, CLEAR_LINE);
287
288    apollo_csr_set_status_register(APOLLO_CSR_SR_CPU_TIMEOUT, APOLLO_CSR_SR_CPU_TIMEOUT);
289}
290
291static IRQ_CALLBACK(apollo_irq_acknowledge) {
292   int result = M68K_INT_ACK_AUTOVECTOR;
293
294   cputag_set_input_line(device->machine(), MAINCPU, irqline, CLEAR_LINE);
295
296   DLOG2(("apollo_irq_acknowledge: interrupt level=%d", irqline));
297
298   if (irqline == 6) {
299      result = apollo_pic_acknowledge(device, irqline);
300   }
301   return result;
302}
303
304/***************************************************************************
305 DN3500 Cache Control/Status Register at 0x10200
306 ***************************************************************************/
307
308static WRITE8_HANDLER(cache_control_register_w ) {
309   if (apollo_is_dn5500())
310   {
311      SLOG1(("Error: writing DN5500 Cache Status Register at offset %02x = %02x", offset, data));
312   }
313   else
314   {
315      cache_control_register = data;
316      cache_status_register = (cache_status_register & 0x7f) | (cache_control_register & 0x80);
317      SLOG2(("writing Cache Control Register at offset %02x = %02x", offset, data));
318   }
319}
320
321static READ8_HANDLER( cache_status_register_r ) {
322   UINT8 data = cache_status_register;
323
324   if (apollo_is_dn5500()) {
325#define DN5500_CSR_NOT_HSI_PRESENT 8
326#define DN5500_CSR_MEM_TIME 1
327      data |= DN5500_CSR_NOT_HSI_PRESENT;
328   }
329
330   SLOG2(("reading Cache Status Register at offset %02x = %02x", offset, data));
331   return data;
332}
333
334void apollo_set_cache_status_register(UINT8 mask, UINT8 data) {
335   UINT16 new_value = (cache_status_register & ~mask) | (data & mask);
336   if (new_value != cache_status_register) {
337      cache_status_register = new_value;
338      LOG2(("setting Cache Status Register with data=%02x and mask=%02x to %02x",
339            data, mask, cache_status_register));
340   }
341}
342
343/***************************************************************************
344 DN3500 Task Alias Register at 0x10300
345 ***************************************************************************/
346
347static WRITE8_HANDLER(task_alias_register_w ) {
348   task_alias_register = data;
349   apollo_set_cache_status_register(0x07,  data);
350   SLOG(("writing Task Alias Register at offset %02x = %02x",offset, data));
351}
352
353static READ8_HANDLER( task_alias_register_r ) {
354   UINT8 data = 0xff;
355   SLOG(("reading Task Alias Register at offset %02x = %02x", offset, data));
356   return data;
357}
358
359/***************************************************************************
360 DN3000/DN3500 Node Id PROM at 0x9600/0x11200
361 ***************************************************************************/
362
363static WRITE16_HANDLER(apollo_node_id_w ) {
364   SLOG1(("Error: writing node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask));
365}
366
367static READ16_HANDLER( apollo_node_id_r ) {
368   UINT16 data;
369   switch (offset & 0x0f) {
370   case 1: // msb
371      data = (node_id >> 16) & 0xff;
372      break;
373   case 2:
374      data = (node_id >> 8) & 0xff;
375      break;
376   case 3: // lsb
377      data = node_id & 0xff;
378      break;
379   case 15: // checksum
380      data = ((node_id >> 16) + (node_id >> 8) + node_id) & 0xff;
381      break;
382   default:
383      data = 0;
384      break;
385   }
386   data <<= 8;
387   SLOG2(("reading node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask));
388   return data;
389}
390
391/***************************************************************************
392 DN3000/DN3500 Latch Page on Parity Error Register at 0x9300/0x11300
393 ***************************************************************************/
394
395static WRITE16_HANDLER(latch_page_on_parity_error_register_w ) {
396   latch_page_on_parity_error_register = data;
397   SLOG1(("writing Latch Page on Error Parity Register at offset %02x = %04x", offset*2, data));
398}
399
400static READ16_HANDLER( latch_page_on_parity_error_register_r ) {
401   UINT16 data = latch_page_on_parity_error_register;
402   SLOG2(("reading Latch Page on Error Parity Register at offset %02x = %04x", offset*2, data));
403   return data;
404}
405
406/***************************************************************************
407 DN3500 Master REQ Register at 0x11600
408 ***************************************************************************/
409
410static WRITE8_HANDLER(master_req_register_w ) {
411   master_req_register = data;
412   SLOG2(("writing Master REQ Register at offset %02x = %02x", offset, data));
413}
414
415static READ8_HANDLER( master_req_register_r ) {
416   UINT8 data = 0xff;
417   SLOG1(("reading Master REQ Register at offset %02x = %02x", offset, data));
418   return data;
419}
420
421/***************************************************************************
422 DN3500 Selective Clear Locations at 0x11600
423 ***************************************************************************/
424
425static WRITE16_HANDLER(selective_clear_locations_w ) {
426   SLOG2(("writing Selective Clear Locations at offset %02x = %02x", offset*2, data));
427   switch (offset * 2) {
428   case 0x00: // Clear All
429      apollo_csr_set_status_register(APOLLO_CSR_SR_CLEAR_ALL, 0);
430      break;
431   case 0x04: // clear floating-point trap
432      apollo_csr_set_status_register(APOLLO_CSR_SR_FP_TRAP, 0);
433      break;
434   case 0x06: // clear Parity error interrupt
435      apollo_csr_set_status_register(APOLLO_CSR_SR_PARITY_BYTE_MASK, 0);
436      break;
437   case 0x08: // clear Bus Error Status (CPU Timeout)
438      apollo_csr_set_status_register(APOLLO_CSR_SR_CPU_TIMEOUT, 0);
439      break;
440   case 0x0e: // Clear (Flush) Cache
441      break;
442   }
443}
444
445static READ16_HANDLER(selective_clear_locations_r ) {
446   UINT16 data = 0xffff;
447   SLOG1(("reading Selective Clear Locations at offset %02x = %02x", offset*2, data));
448   return data;
449}
450
451/***************************************************************************
452 DN3000/DN3500 RAM with parity (and null proc loop delay for DomainOS)
453 ***************************************************************************/
454
455static READ32_HANDLER( ram_with_parity_r ) {
456   UINT32 data = messram_ptr.u32[parity_error_offset+offset];
457
458   SLOG2(("memory dword read with parity error at %08x = %08x & %08x parity_byte=%04x",
459         ram_base_address + parity_error_offset*4 + offset*4,data, mem_mask, parity_error_byte_mask));
460
461   if (parity_error_byte_mask != 0) {
462      latch_page_on_parity_error_register = (ram_base_address + parity_error_offset * 4) >> 10;
463
464      apollo_csr_set_status_register(APOLLO_CSR_CR_PARITY_BYTE_MASK,   apollo_csr_get_status_register() |parity_error_byte_mask);
465
466      if (apollo_csr_get_control_register() & APOLLO_CSR_CR_INTERRUPT_ENABLE) {
467         // force parity error (if NMI is enabled)
468//         cpu_set_input_line_and_vector(&space->device(), 7, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
469         cputag_set_input_line_and_vector(space->machine(), MAINCPU, 7, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
470
471      }
472   }
473   return data;
474}
475
476static WRITE32_HANDLER( ram_with_parity_w ) {
477
478   COMBINE_DATA(messram_ptr.u32+offset);
479
480   if (apollo_csr_get_control_register() & APOLLO_CSR_CR_FORCE_BAD_PARITY) {
481      parity_error_byte_mask = (apollo_csr_get_control_register()
482            & APOLLO_CSR_CR_PARITY_BYTE_MASK);
483
484      if (!apollo_is_dn3000()) {
485         parity_error_byte_mask ^= APOLLO_CSR_CR_PARITY_BYTE_MASK;
486      }
487
488      parity_error_offset = offset;
489
490//      SLOG1(("memory dword write with parity to %08x = %08x & %08x parity_byte=%04x",
491//            ram_base_address +offset * 4, data, mem_mask, parity_error_byte_mask));
492
493      if (parity_error_handler_is_installed == 0) {
494         // no more than 192 read/write handlers may be used
495         // see table_assign_handler in memory.c
496         if (parity_error_handler_install_counter < 40) {
497            //memory_install_read32_handler(space, ram_base_address+offset*4, ram_base_address+offset*4+3, 0xffffffff, 0, ram_with_parity_r);
498            space->install_legacy_read_handler(ram_base_address+offset*4, ram_base_address+offset*4+3, 0xffffffff,0,FUNC(ram_with_parity_r));
499            parity_error_handler_is_installed = 1;
500            parity_error_handler_install_counter++;
501         }
502      }
503   } else if (parity_error_handler_is_installed && offset == parity_error_offset) {
504      SLOG1(("memory dword write with parity to %08x = %08x & %08x reset %d",
505            ram_base_address +parity_error_offset*4, data, mem_mask, parity_error_handler_install_counter));
506
507      // uninstall not supported, reinstall previous read handler instead
508
509      // memory_install_rom(space, ram_base_address, ram_end_address, 0xffffffff, 0, messram_ptr.v);
510      space->install_rom(ram_base_address,ram_end_address,0xffffffff,0,messram_ptr.v);
511
512      parity_error_handler_is_installed = 0;
513      parity_error_byte_mask = 0;
514   }
515}
516
517/***************************************************************************
518 DN3000/DN3500 unmapped memory
519 ***************************************************************************/
520
521static READ32_HANDLER( apollo_unmapped_r )
522{
523   offs_t address = offset * 4;
524
525   m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *>(&space->device())->token();
526
527   if ((address & 0xfff00000) == 0xfa800000 && VERBOSE < 2) {
528      // ?
529   } else if ((address & 0xfff00ff7) == 0xfd800000 && VERBOSE < 2) {
530      // omit logging for memory sizing in FPA address space
531      // strange: MD seems to search for the 3C505 Boot ROM
532      // note (6.10.2010): might be color7 address space (!?!)
533   } else if ((address & 0xfc03ffff) == 0x00000000 && VERBOSE < 2) {
534      // omit logging for memory sizing in standalone utilities
535   } else if (address == 0xfff90000 && VERBOSE < 2) {
536      // omit logging for FPA trial access
537   } else if (address == 0x00030000 && VERBOSE < 2) {
538      // omit logging for Bus error test address in DN3500 boot prom and self_test
539   } else if (address == 0x0000ac00 && VERBOSE < 2) {
540      // omit logging for Bus error test address in DN3000 boot prom
541   } else {
542      SLOG1(("unmapped memory dword read from %08x with mask %08x (ir=%04x)", address , mem_mask, m68k->ir));
543   }
544
545//   if (address == 0xfffffffc) {
546//      // temporary hack for disp7d.dex @ 010456D8
547//      return    0xffffffff;
548//   }
549   /* unmapped; access causes a bus error */
550   apollo_bus_error(space->machine());
551
552   return 0xffffffff;
553}
554
555static WRITE32_HANDLER( apollo_unmapped_w )
556{
557   SLOG(("unmapped memory dword write to %08x = %08x & %08x", offset * 4, data, mem_mask));
558
559   /* unmapped; access causes a bus error */
560   apollo_bus_error(space->machine());
561}
562
563/***************************************************************************
564 DN3000/DN3500 ROM write
565 ***************************************************************************/
566
567static WRITE32_HANDLER( apollo_rom_w )
568{
569   offs_t address =  offset * 4;
570   offs_t pc = cpu_get_previouspc(&space->device());
571
572   if (pc == 0x00002c1c && address == 0x00000004 && VERBOSE < 2) {
573      // don't log invalid code in 3500_boot_12191_7.bin
574   } else {
575      SLOG1(("ROM dword write to %08x = %08x & %08x", offset * 4, data, mem_mask));
576   }
577}
578
579/***************************************************************************
580 DN3000/DN3500 AT Bus I/O space
581 ***************************************************************************/
582
583static READ16_HANDLER( apollo_atbus_io_r ) {
584   UINT16 data = 0xffff;
585   offs_t address = ATBUS_IO_BASE + offset * 2;
586
587   switch (address & ~7) {
588   case 0x04d000: /* Fixed Disk Controller 1 */
589   case 0x04d400: /* Fixed Disk Controller 2 */
590   case 0x050000: /* Tape Controller */
591   case 0x054000: /* domain_os at 0x3C4BF15A ? */
592   case 0x054400: /* domain_os at 0x3C4BF1A8 ? */
593   case 0x054800: /* domain_os at 0x3C4BF15A ? */
594   case 0x054c00: /* domain_os at 0x3C4BF1A8 ? */
595   case 0x055808: /* domain_os at 0x3C4C4784 ? */
596   case 0x055c08: /* domain_os at 0x3C4C4784 ? */
597   case 0x058800: /* alternate 802.3 Network Controller */
598   case 0x059000: /* Apollo Token Ring Controller 0 */
599   case 0x05a000: /* alternate Network Controller */
600   case 0x05d800: /* alternate color or mono graphics */
601   case 0x05dc00: /* alternate color or mono graphics */
602   case 0x05e800: /* alternate mono or color graphics */
603   case 0x05ec00: /* alternate mono or color graphics */
604      // omit logging
605      break;
606   default:
607      SLOG1(("AT Bus I/O word read from %08x = %04x & %04x", address, data, mem_mask));
608   }
609
610   // set bit AT-Compatible I/O Timeout in CPU Status Register
611   // Note: should be set for broken hardware only
612   // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_IO_TIMEOUT,   APOLLO_CSR_SR_ATBUS_IO_TIMEOUT);
613   return data;
614}
615
616static WRITE16_HANDLER( apollo_atbus_io_w ) {
617   offs_t address = ATBUS_IO_BASE + offset * 2;
618
619   switch (address & ~7) {
620   case 0x04d000: /* Fixed Disk Controller 1 */
621   case 0x04d400: /* Fixed Disk Controller 2 */
622   case 0x050000: /* Tape Controller */
623   case 0x054000: /* domain_os at 0x3C4BF15A ? */
624   case 0x054400: /* domain_os at 0x3C4BF1A8 ? */
625   case 0x054800: /* domain_os at 0x3C4BF15A ? */
626   case 0x054c00: /* domain_os at 0x3C4BF1A8 ? */
627   case 0x058800: /* alternate 802.3 Network Controller */
628   case 0x059000: /* Apollo Token Ring Controller 0 */
629   case 0x05a000: /* alternate Network Controller */
630   case 0x05d800: /* alternate color or mono graphics */
631   case 0x05dc00: /* alternate color or mono graphics */
632   case 0x05e800: /* alternate mono or color graphics */
633   case 0x05ec00: /* alternate mono or color graphics */
634      // omit logging
635      break;
636   default:
637      SLOG1(("AT Bus I/O word write to %08x = %04x & %04x ",
638                  ATBUS_IO_BASE+ offset * 2, data, mem_mask))
639      ;
640   }
641
642   // set bit AT-Compatible I/O Timeout in CPU Status Register
643   // Note: should be set for broken hardware only
644   // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_IO_TIMEOUT,   APOLLO_CSR_SR_ATBUS_IO_TIMEOUT);
645}
646
647/***************************************************************************
648 DN3000/DN3500 AT Bus memory space
649 ***************************************************************************/
650
651static READ32_HANDLER( apollo_atbus_memory_r ) {
652   UINT32 data = 0xffffffff;
653   offs_t address = ATBUS_MEMORY_BASE +  offset * 4;
654   if (VERBOSE < 2 && (address & 0xfff) == 0 && address >= 0x80000 && address < 0x1000000) {
655      // omit logging for memory sizing the AT Bus memory
656   } else {
657      SLOG1(("AT Bus memory dword read from %08x = %08x & %08x",address, data, mem_mask));
658   }
659
660   // set bit AT-Compatible Memory Timeout in CPU Status Register
661   // Note: should be set for broken hardware only
662   // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT, APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT);
663
664   return data;
665}
666
667static WRITE32_HANDLER( apollo_atbus_memory_w ) {
668   SLOG1(("AT Bus memory dword write to %08x = %08x & %08x ",
669               ATBUS_MEMORY_BASE+offset * 4, data, mem_mask));
670
671   // set bit AT-Compatible Memory Timeout in CPU Status Register
672   // Note: should be set for broken hardware only
673   // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT, APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT);
674}
675
676/***************************************************************************
677 DN5500 Memory Present Register at 0x11400-0x114ff
678 Strange: documented but not used
679 ***************************************************************************/
680
681static WRITE8_HANDLER( dn5500_memory_present_register_w ) {
682   SLOG(("Error: writing DN5500 Memory Present Register at offset %02x = %02x", offset, data));
683}
684
685static READ8_HANDLER( dn5500_memory_present_register_r ) {
686   UINT8 data = DN5500_MEM_PRESENT_BYTE;
687   SLOG(("reading DN5500 Memory Present Register at offset %02x = %02x", offset, data));
688   return data;
689}
690
691/***************************************************************************
692 DN5500 11500 Registers at 0x11500-0x115ff (undocumented, what does it do?)
693 ***************************************************************************/
694
695static WRITE8_HANDLER( dn5500_11500_w ) {
696   SLOG1(("writing DN5500 11500 at offset %02x = %02x", offset, data));
697}
698
699static READ8_HANDLER( dn5500_11500_r ) {
700   UINT8 data = 0xff;
701   SLOG1(("reading DN5500 11500 at offset %02x = %02x", offset, data));
702   return data;
703}
704
705/***************************************************************************
706 DN5500 I/O Protection Map at 0x7000000-0x700FFFF
707 ***************************************************************************/
708
709static WRITE8_HANDLER(dn5500_io_protection_map_w ) {
710   // TODO
711   SLOG1(("writing DN5500 I/O Protection Map at offset %02x = %02x", offset, data));
712}
713
714static READ8_HANDLER( dn5500_io_protection_map_r ) {
715   UINT8 data = 0xff;
716   SLOG1(("reading DN5500 I/O Protection Map at offset %02x = %02x", offset, data));
717   return data;
718}
719
720#if 0
721/***************************************************************************
722 DN3000/DN3500 at f8000000 - ffffffff (used by fpa and/or color7?)
723 ***************************************************************************/
724
725static READ32_HANDLER( apollo_f8_r ) {
726   offs_t address = 0xf8000000 + offset * 4;
727   UINT32 data = 0xffffffff;
728   SLOG2(("unexpected memory dword read from %08x = %08x & %08x",
729               address, data, mem_mask));
730   return data;
731}
732
733static WRITE32_HANDLER( apollo_f8_w ) {
734   offs_t address = 0xf8000000 +offset * 4;
735
736   SLOG2(("unexpected memory dword write to %08x = %08x & %08x",
737               address, data, mem_mask));
738}
739#endif
740
741/***************************************************************************
742 ADDRESS MAPS
743 ***************************************************************************/
744
745static ADDRESS_MAP_START(dn3500_map, AS_PROGRAM, 32)
746      AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM  */
747        AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w)
748      AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
749      AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
750      AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff )
751      AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff )
752      AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
753      AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff )
754      AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
755      AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
756      AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
757      AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
758      AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
759      AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
760      AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff)
761      AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
762      AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff)
763
764      AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
765      AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
766
767      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
768      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
769      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
770      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
771
772      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
773      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
774
775      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
776
777      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
778
779      // FIXME: must match with RAM size in driver/apollo_sio.c
780      // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM  AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */
781      AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
782
783      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
784
785//      AM_RANGE(0x03020000, 0x0303ffff) Cache Tag Store (DN4500 only)
786//      AM_RANGE(0x04000000, 0x0400ffff) Cache Tag Data (DN4500 only)
787//      AM_RANGE(0x0e000000, 0x0fffffff) FPA address space
788
789//      AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w)
790      AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
791ADDRESS_MAP_END
792
793static ADDRESS_MAP_START(dsp3500_map, AS_PROGRAM, 32)
794      AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM  */
795        AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w)
796      AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
797      AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
798      AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff )
799      AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff )
800      AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
801      AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff )
802      AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
803      AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
804      AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
805      AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
806      AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
807      AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
808      AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff)
809      AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
810      AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff)
811
812      AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
813      AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
814
815      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
816      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
817      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
818      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
819
820//      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
821//      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
822
823      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
824
825      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
826
827      // FIXME: must match with RAM size in driver/apollo_sio.c
828      // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM  AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */
829      AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
830
831      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
832
833//      AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w)
834      AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
835ADDRESS_MAP_END
836
837static ADDRESS_MAP_START(dn3000_map, AS_PROGRAM, 32)
838      AM_RANGE(0x000000, 0x007fff) AM_ROM /* boot ROM  */
839      AM_RANGE(0x000000, 0x007fff) AM_WRITE(apollo_rom_w)
840      AM_RANGE(0x008000, 0x0080ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
841      AM_RANGE(0x008100, 0x0081ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
842      AM_RANGE(0x008400, 0x0087ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
843      AM_RANGE(0x008800, 0x0088ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
844      AM_RANGE(0x008900, 0x0089ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
845
846      AM_RANGE(0x009000, 0x0090ff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
847      AM_RANGE(0x009100, 0x0091ff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
848      AM_RANGE(0x009200, 0x0092ff) AM_READWRITE8( apollo_dma_page_register_r, apollo_dma_page_register_w, 0xffffffff )
849      AM_RANGE(0x009300, 0x0093ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
850      AM_RANGE(0x009400, 0x0094ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
851      AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
852      AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff)
853
854      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
855      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
856      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
857      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
858
859      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
860      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
861
862      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
863
864      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
865
866      // FIXME: must match with RAM size in driver/apollo_sio.c
867      // AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM  AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */
868      AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
869
870      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
871
872      AM_RANGE(0x000000, 0xffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
873ADDRESS_MAP_END
874
875static ADDRESS_MAP_START(dsp3000_map, AS_PROGRAM, 32)
876      AM_RANGE(0x000000, 0x007fff) AM_ROM /* boot ROM  */
877      AM_RANGE(0x000000, 0x007fff) AM_WRITE(apollo_rom_w)
878      AM_RANGE(0x008000, 0x0080ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
879      AM_RANGE(0x008100, 0x0081ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
880      AM_RANGE(0x008400, 0x0087ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
881      AM_RANGE(0x008800, 0x0088ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
882      AM_RANGE(0x008900, 0x0089ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
883
884      AM_RANGE(0x009000, 0x0090ff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
885      AM_RANGE(0x009100, 0x0091ff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
886      AM_RANGE(0x009200, 0x0092ff) AM_READWRITE8( apollo_dma_page_register_r, apollo_dma_page_register_w, 0xffffffff )
887      AM_RANGE(0x009300, 0x0093ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
888      AM_RANGE(0x009400, 0x0094ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
889      AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
890      AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff)
891
892      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
893      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
894      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
895      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
896
897//      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
898//      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
899
900      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
901
902      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
903
904      // FIXME: must match with RAM size in driver/apollo_sio.c
905      // AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM  AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */
906      AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
907
908      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
909
910      AM_RANGE(0x000000, 0xffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
911ADDRESS_MAP_END
912
913
914static ADDRESS_MAP_START(dn5500_map, AS_PROGRAM, 32)
915      AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM  */
916        AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w)
917      AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
918      AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
919      AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff )
920      AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff )
921      AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
922      AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff )
923      AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
924      AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
925      AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
926      AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
927      AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
928      AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
929      AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff)
930      AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
931      AM_RANGE(0x011400, 0x0114ff) AM_READWRITE8( dn5500_memory_present_register_r, dn5500_memory_present_register_w, 0xffffffff )
932      AM_RANGE(0x011500, 0x0115ff) AM_READWRITE8( dn5500_11500_r, dn5500_11500_w, 0xffffffff )
933      AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff)
934
935      AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
936      AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
937
938      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
939      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
940      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
941      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
942
943      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
944      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
945
946      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
947
948      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
949
950      // FIXME: must match with RAM size in driver/apollo_sio.c
951      // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM  AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */
952      AM_RANGE(DN5500_RAM_BASE, DN5500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
953
954      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
955
956//      AM_RANGE(0x03020000, 0x0303ffff) Cache Tag Store (DN4500 only)
957//      AM_RANGE(0x04000000, 0x0400ffff) Cache Tag Data (DN4500 only)
958      AM_RANGE(0x07000000, 0x0700FFFF) AM_READWRITE8( dn5500_io_protection_map_r, dn5500_io_protection_map_w, 0xffffffff )
959//      AM_RANGE(0x0e000000, 0x0fffffff) FPA address space
960
961//      AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w)
962      AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
963ADDRESS_MAP_END
964
965
966static ADDRESS_MAP_START(dsp5500_map, AS_PROGRAM, 32)
967      AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM  */
968        AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w)
969      AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff)
970      AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff)
971      AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff )
972      AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff )
973      AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff )
974      AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff )
975      AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff )
976      AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff )
977      AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff )
978      AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff )
979      AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff)
980      AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff)
981      AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff)
982      AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff )
983      AM_RANGE(0x011400, 0x0114ff) AM_READWRITE8( dn5500_memory_present_register_r, dn5500_memory_present_register_w, 0xffffffff )
984      AM_RANGE(0x011500, 0x0115ff) AM_READWRITE8( dn5500_11500_r, dn5500_11500_w, 0xffffffff )
985      AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff)
986
987      AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
988      AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
989
990      AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff)
991      AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff)
992      AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
993      AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff)
994
995//      AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
996//      AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
997
998      AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
999
1000      AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM  */
1001
1002      // FIXME: must match with RAM size in driver/apollo_sio.c
1003      AM_RANGE(DN5500_RAM_BASE, DN5500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size)
1004
1005      AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w)
1006
1007      AM_RANGE(0x07000000, 0x0700FFFF) AM_READWRITE8( dn5500_io_protection_map_r, dn5500_io_protection_map_w, 0xffffffff )
1008//      AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w)
1009      AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w)
1010ADDRESS_MAP_END
1011
1012/***************************************************************************
1013 Machine Reset
1014 ***************************************************************************/
1015
1016static MACHINE_RESET( dn3500 )
1017{
1018   device_t *cpu = machine.device(MAINCPU);
1019
1020   MLOG1(("machine_reset_dn3500"));
1021
1022   MACHINE_RESET_CALL(apollo);
1023
1024   // set configuration
1025   omti8621_set_verbose(apollo_config(APOLLO_CONF_DISK_TRACE));
1026   threecom3c505_set_verbose(apollo_config(APOLLO_CONF_NET_TRACE));
1027
1028   if (apollo_config(APOLLO_CONF_NODE_ID))
1029   {
1030      UINT8 db[0x50];
1031      UINT16 sector1 = apollo_is_dn5500() ? 4 : 1;
1032
1033      // check label of physical volume and get sector data of logical volume 1
1034      // Note: sector data starts with 32 byte block header
1035      if (omti8621_get_sector(machine.device(APOLLO_WDC_TAG), 0, db,   sizeof(db), 0) == sizeof(db) &&
1036         memcmp (db+0x22, "APOLLO", 6) == 0 &&
1037         omti8621_get_sector(machine.device(APOLLO_WDC_TAG), sector1, db,   sizeof(db), 0) == sizeof(db))
1038      {
1039         MLOG2(("machine_reset_dn3500: node ID is %06X (from ROM)", node_id));
1040
1041         // set node_id from UID of logical volume 1 of logical unit 0
1042         node_id = (((db[0x49] << 8) | db[0x4a]) << 8) | db[0x4b];
1043
1044         MLOG2(("machine_reset_dn3500: node ID is %06X (from disk)", node_id));
1045      }
1046   }
1047
1048    m68k_set_instruction_hook(cpu, apollo_instruction_hook);
1049}
1050
1051static void apollo_reset_instr_callback(device_t *device)
1052{
1053   DLOG1(("apollo_reset_instr_callback"));
1054   // FIXME: this will reset the CPU too
1055//   device->machine().schedule_soft_reset();    // needs to call reset on the devices other than the CPU
1056}
1057
1058/***************************************************************************
1059 Machine Start
1060 ***************************************************************************/
1061
1062static MACHINE_START( dn3500 ) {
1063   MLOG1(("machine_start_dn3500: ram size is %d MB", (int)messram_size/(1024*1024)));
1064
1065   // clear ram
1066   memset(messram_ptr.u8, 0x55, messram_size);
1067
1068   MACHINE_START_CALL(apollo);
1069}
1070
1071/***************************************************************************
1072 Driver Init
1073 ***************************************************************************/
1074
1075static DRIVER_INIT( dn3500 ) {
1076   MLOG1(("driver_init_dn3500"));
1077
1078   device_set_irq_callback(machine.device(MAINCPU), apollo_irq_acknowledge);
1079
1080   /* hook the RESET line, which resets a slew of other components */
1081   m68k_set_reset_callback(machine.device(MAINCPU), apollo_reset_instr_callback);
1082
1083   ram_base_address = DN3500_RAM_BASE;
1084   ram_end_address = DN3500_RAM_END;
1085
1086   node_type=  NODE_TYPE_DN3500;
1087   ram_config_byte= DN3500_RAM_CONFIG_BYTE;
1088
1089   DRIVER_INIT_CALL(apollo);
1090}
1091
1092static DRIVER_INIT( dsp3500 ) {
1093   DRIVER_INIT_CALL( dn3500 );
1094   MLOG1(("driver_init_dsp3500"));
1095   node_type = NODE_TYPE_DSP3500;
1096   dsp_terminal = machine.device(TERMINAL_TAG);
1097}
1098
1099static DRIVER_INIT( dn3000 ) {
1100   DRIVER_INIT_CALL( dn3500 );
1101   MLOG1(("driver_init_dn3000"));
1102
1103   ram_base_address = DN3000_RAM_BASE;
1104   ram_end_address = DN3000_RAM_END;
1105
1106   node_type = NODE_TYPE_DN3000;
1107   ram_config_byte= DN3000_RAM_CONFIG_8MB;
1108}
1109
1110static DRIVER_INIT( dsp3000 ) {
1111   DRIVER_INIT_CALL( dn3000 );
1112   MLOG1(("driver_init_dsp3000"));
1113   node_type = NODE_TYPE_DSP3000;
1114   dsp_terminal = machine.device(TERMINAL_TAG);
1115}
1116
1117static DRIVER_INIT( dn5500 ) {
1118   DRIVER_INIT_CALL( dn3500 );
1119   MLOG1(("driver_init_dn5500"));
1120
1121   ram_base_address = DN5500_RAM_BASE;
1122   ram_end_address = DN5500_RAM_END;
1123
1124   node_type = NODE_TYPE_DN5500;
1125   ram_config_byte= DN5500_RAM_CONFIG_BYTE;
1126}
1127
1128static DRIVER_INIT( dsp5500 ) {
1129   DRIVER_INIT_CALL( dn5500 );
1130   MLOG1(("driver_init_dsp5500"));
1131   node_type = NODE_TYPE_DSP5500;
1132   dsp_terminal = machine.device(TERMINAL_TAG);
1133}
1134
1135/***************************************************************************
1136 Input Ports
1137 ***************************************************************************/
1138
1139static INPUT_PORTS_START( dn3500 )
1140   PORT_INCLUDE(apollo_config)
1141   PORT_INCLUDE(apollo_kbd)
1142INPUT_PORTS_END
1143
1144static INPUT_PORTS_START( dsp3500 )
1145   PORT_INCLUDE(apollo_config)
1146INPUT_PORTS_END
1147
1148static WRITE8_DEVICE_HANDLER( apollo_kbd_putchar ) {
1149   // put keyboard character to the keyboard sio
1150//   DLOG1(("apollo_kbd_putchar: 0x%02x", data));
1151   apollo_sio_rx_data(device->machine().device(APOLLO_SIO_TAG), 0, data);
1152}
1153
1154static READ8_DEVICE_HANDLER( apollo_kbd_has_beeper ) {
1155   return 1; // apollo_config(APOLLO_CONF_KBD_BEEPER);
1156}
1157
1158static READ8_DEVICE_HANDLER( apollo_kbd_is_german ) {
1159   return apollo_config(APOLLO_CONF_GERMAN_KBD);
1160}
1161
1162static APOLLO_KBD_INTERFACE( apollo_kbd_config ) = {
1163   apollo_kbd_putchar,
1164   apollo_kbd_has_beeper,
1165   apollo_kbd_is_german
1166};
1167
1168static WRITE8_DEVICE_HANDLER( terminal_kbd_putchar ) {
1169   apollo_sio_rx_data(device->machine().device(APOLLO_SIO_TAG), 1, data);
1170}
1171
1172static GENERIC_TERMINAL_INTERFACE( apollo_terminal_config ) {
1173   DEVCB_HANDLER(terminal_kbd_putchar)
1174};
1175
1176void apollo_terminal_write(UINT8 data) {
1177   if (dsp_terminal != NULL) {
1178      // output data to the terminal emulator
1179      terminal_write(dsp_terminal, 0,   data);
1180   }
1181}
1182
1183/***************************************************************************
1184 MACHINE DRIVERS
1185 ***************************************************************************/
1186
1187static MACHINE_CONFIG_START( dn3500, apollo_state )
1188   /* basic machine hardware */
1189   MCFG_CPU_ADD(MAINCPU, M68030, 25000000) /* 25 MHz 68030 */
1190   MCFG_CPU_PROGRAM_MAP(dn3500_map)
1191   MCFG_QUANTUM_TIME(attotime::from_hz(60))
1192
1193   MCFG_MACHINE_START( dn3500 )
1194   MCFG_MACHINE_RESET( dn3500 )
1195
1196   MCFG_FRAGMENT_ADD( apollo )
1197
1198   /* keyboard beeper */
1199   MCFG_SPEAKER_STANDARD_MONO("mono")
1200   MCFG_SOUND_ADD("beep", BEEP, 0)
1201   MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
1202
1203   /* internal ram */
1204   MCFG_RAM_ADD("messram")
1205   MCFG_RAM_DEFAULT_SIZE("8M")
1206   MCFG_RAM_EXTRA_OPTIONS("4M,8M,16M,32M")
1207MACHINE_CONFIG_END
1208
1209static MACHINE_CONFIG_DERIVED( dsp3500, dn3500 )
1210   // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE
1211   MCFG_CPU_REPLACE(MAINCPU, M68030, 25000000) /* 25 MHz 68030 */
1212   MCFG_CPU_PROGRAM_MAP(dsp3500_map)
1213   /* terminal hardware */
1214   MCFG_DEFAULT_LAYOUT( layout_apollo_dsp )
1215//   MCFG_FRAGMENT_ADD( generic_terminal )
1216   MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config)
1217MACHINE_CONFIG_END
1218
1219static MACHINE_CONFIG_DERIVED( dn3500_19i, dn3500 )
1220   /* video hardware 19" monochrome */
1221   MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG)
1222   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1223MACHINE_CONFIG_END
1224
1225static MACHINE_CONFIG_DERIVED( dn3500_15i, dn3500 )
1226   /* video hardware 15" monochrome */
1227   MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG)
1228   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1229MACHINE_CONFIG_END
1230
1231static MACHINE_CONFIG_DERIVED( dn3000, dn3500 )
1232   MCFG_CPU_REPLACE(MAINCPU, M68020PMMU, 12000000) /* 12 MHz */
1233   MCFG_CPU_PROGRAM_MAP(dn3000_map)
1234   MCFG_DEVICE_REMOVE( APOLLO_SIO2_TAG )
1235
1236   MCFG_MACHINE_START( dn3500 )
1237   MCFG_MACHINE_RESET( dn3500 )
1238
1239   MCFG_RAM_MODIFY("messram")
1240   MCFG_RAM_DEFAULT_SIZE("8M")
1241   MCFG_RAM_EXTRA_OPTIONS("4M")
1242MACHINE_CONFIG_END
1243
1244static MACHINE_CONFIG_DERIVED( dsp3000, dn3000 )
1245   // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE
1246   MCFG_CPU_REPLACE(MAINCPU, M68020PMMU, 12000000) /* 12 MHz */
1247   MCFG_CPU_PROGRAM_MAP(dsp3000_map)
1248   /* terminal hardware */
1249   MCFG_DEFAULT_LAYOUT( layout_apollo_dsp )
1250//   MCFG_FRAGMENT_ADD( generic_terminal )
1251   MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config)
1252MACHINE_CONFIG_END
1253
1254static MACHINE_CONFIG_DERIVED( dn3000_19i, dn3000 )
1255   /* video hardware 19" monochrome */
1256   MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG)
1257   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1258MACHINE_CONFIG_END
1259
1260static MACHINE_CONFIG_DERIVED( dn3000_15i, dn3000 )
1261   /* video hardware 15" monochrome */
1262   MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG)
1263   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1264MACHINE_CONFIG_END
1265
1266static MACHINE_CONFIG_DERIVED( dn5500, dn3500 )
1267   MCFG_CPU_REPLACE(MAINCPU, M68040, 25000000) /* 25 MHz */
1268   MCFG_CPU_PROGRAM_MAP(dn5500_map)
1269
1270   MCFG_MACHINE_START( dn3500 )
1271   MCFG_MACHINE_RESET( dn3500 )
1272MACHINE_CONFIG_END
1273
1274static MACHINE_CONFIG_DERIVED( dsp5500, dn5500 )
1275   // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE
1276   MCFG_CPU_REPLACE(MAINCPU, M68040, 25000000) /* 25 MHz */
1277   MCFG_CPU_PROGRAM_MAP(dsp5500_map)
1278   /* terminal hardware */
1279   MCFG_DEFAULT_LAYOUT( layout_apollo_dsp )
1280//   MCFG_FRAGMENT_ADD( generic_terminal )
1281   MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config)
1282MACHINE_CONFIG_END
1283
1284static MACHINE_CONFIG_DERIVED( dn5500_19i, dn5500 )
1285   /* video hardware 19" monochrome */
1286   MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG)
1287   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1288MACHINE_CONFIG_END
1289
1290static MACHINE_CONFIG_DERIVED( dn5500_15i, dn5500 )
1291   /* video hardware 15" monochrome */
1292   MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG)
1293   MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config )
1294MACHINE_CONFIG_END
1295
1296/***************************************************************************
1297 ROM Definitions
1298 ***************************************************************************/
1299
1300ROM_START( dn3500 )
1301   // dn3500 boot ROM (Note: use sha1sum -b <rom file>)
1302   ROM_REGION( 0x0100000, MAINCPU, 0 ) /* 68000 code */
1303
1304   // http://www.bitsavers.org/bits/Apollo/firmware/3500_BOOT_12191_7.bin
1305   // Note: file name must be converted to lower case (i.e. 3500_boot_12191_7.bin)
1306   // Note: this duplicates boot rom md7c-rev-8.00-1989-08-16-17-23-52.bin
1307   ROM_SYSTEM_BIOS( 0, "md7c-rev-8.00", "MD7C REV 8.00, 1989/08/16.17:23:52" )
1308   ROMX_LOAD( "3500_boot_12191_7.bin", 0x00000, 0x10000, SHA1(36f3c83d9f2df42f2537b09ca2f051a8c9dfbfc2) , ROM_BIOS(1) )
1309
1310   ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) )
1311ROM_END
1312
1313ROM_START( dn5500 )
1314   // dn5500 boot ROM (Note: use sha1sum -b <rom file>)
1315   ROM_REGION( 0x0100000, MAINCPU, 0 ) /* 68000 code */
1316
1317   ROM_SYSTEM_BIOS( 0, "md7c-rev-8.00", "MD7C REV 8.00, 1989/08/16.17:23:52" )
1318   ROMX_LOAD( "5500_boot_a1631-80046_1-30-92.bin", 0x00000, 0x10000, SHA1(7315a884ec4551c44433c6079cc06509223cb02b) , ROM_BIOS(1) )
1319
1320   ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) )
1321ROM_END
1322
1323ROM_START( dn3000)
1324   ROM_REGION( 0x0090000, MAINCPU, 0 ) /* 68000 code */
1325
1326   ROM_SYSTEM_BIOS( 0, "md8-rev-7.0", "MD8 REV 7.0, 1988/08/16.15:14:39" )
1327   ROMX_LOAD( "3000_boot_8475_7.bin",  0x00000, 0x08000, SHA1(6c383d2266719a3d069b7bf015f6945179395e7a), ROM_BIOS(1) )
1328
1329   ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) )
1330ROM_END
1331
1332#define rom_dsp3500    rom_dn3500
1333#define rom_dn3500_15i rom_dn3500
1334#define rom_dn3500_19i rom_dn3500
1335
1336#define rom_dsp3000    rom_dn3000
1337#define rom_dn3000_15i rom_dn3000
1338
1339#define rom_dsp5500    rom_dn5500
1340#define rom_dn5500_15i rom_dn5500
1341#define rom_dn5500_19i rom_dn5500
1342
1343/***************************************************************************
1344    GAME DRIVERS
1345 ***************************************************************************/
1346
1347#define DN_FLAGS 0
1348#define DSP_FLAGS 0
1349//#define DSP_FLAGS GAME_NO_SOUND
1350
1351/*    YEAR  NAME        PARENT  COMPAT  MACHINE     INPUT   INIT    COMPANY     FULLNAME                         FLAGS */
1352COMP( 1989, dn3500,     0,      0,      dn3500_19i, dn3500, dn3500, "Apollo",   "Apollo DN3500 19\" Monochrome", DN_FLAGS )
1353COMP( 1989, dsp3500,    dn3500, 0,      dsp3500,    dsp3500,dsp3500,"Apollo",   "Apollo DSP3500",                DSP_FLAGS )
1354COMP( 1989, dn3500_15i, dn3500, 0,      dn3500_15i, dn3500, dn3500, "Apollo",   "Apollo DN3500 15\" Monochrome", DN_FLAGS )
1355
1356COMP( 1988, dn3000,     dn3500, 0,      dn3000_19i, dn3500, dn3000, "Apollo",   "Apollo DN3000 19\" Monochrome", DN_FLAGS )
1357COMP( 1988, dsp3000,    dn3500, 0,      dsp3000,    dsp3500,dsp3000,"Apollo",   "Apollo DSP3000",                DSP_FLAGS )
1358COMP( 1988, dn3000_15i, dn3500, 0,      dn3000_15i, dn3500, dn3000, "Apollo",   "Apollo DN3000 15\" Monochrome", DN_FLAGS )
1359
1360COMP( 1991, dn5500,     dn3500, 0,      dn5500_19i, dn3500, dn5500, "Apollo",   "Apollo DN5500 19\" Monochrome", GAME_NOT_WORKING )
1361COMP( 1991, dsp5500,    dn3500, 0,      dsp5500,    dsp3500,dsp5500,"Apollo",   "Apollo DSP5500",                GAME_NOT_WORKING )
1362COMP( 1991, dn5500_15i, dn3500, 0,      dn5500_15i, dn3500, dn5500, "Apollo",   "Apollo DN5500 15\" Monochrome", GAME_NOT_WORKING )

Previous 15994 Revisions Next


© 1998-2018 The MESS Team