summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/concept.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/concept.c')
-rw-r--r--src/mess/machine/concept.c728
1 files changed, 728 insertions, 0 deletions
diff --git a/src/mess/machine/concept.c b/src/mess/machine/concept.c
new file mode 100644
index 00000000000..42812eee9df
--- /dev/null
+++ b/src/mess/machine/concept.c
@@ -0,0 +1,728 @@
+/*
+ Corvus Concept driver
+
+ Raphael Nabet, Brett Wyer, 2003-2005
+*/
+
+#include "emu.h"
+#include "includes/concept.h"
+#include "machine/6522via.h"
+#include "machine/mm58274c.h" /* mm58274 seems to be compatible with mm58174 */
+//#include "machine/6551acia.h"
+#include "machine/wd17xx.h"
+#include "cpu/m68000/m68000.h"
+#include "includes/corvushd.h"
+#include "imagedev/flopdrv.h"
+
+
+#define VERBOSE 1
+
+#define LOG(x) do { if (VERBOSE > 0) logerror x; } while (0)
+#define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0)
+
+
+/* interrupt priority encoder */
+enum
+{
+ IOCINT_level = 1, /* serial lines (CTS, DSR & DCD) and I/O ports */
+ SR1INT_level, /* serial port 1 acia */
+ OMINT_level, /* omninet */
+ SR0INT_level, /* serial port 0 acia */
+ TIMINT_level, /* via */
+ KEYINT_level, /* keyboard acia */
+ NMIINT_level /* reserved */
+};
+
+/* Clock interface */
+
+/* Omninet */
+/*static int ready;*/ /* ready line from monochip, role unknown */
+
+/* Via */
+static READ8_DEVICE_HANDLER(via_in_a);
+static WRITE8_DEVICE_HANDLER(via_out_a);
+static READ8_DEVICE_HANDLER(via_in_b);
+static WRITE8_DEVICE_HANDLER(via_out_b);
+static WRITE8_DEVICE_HANDLER(via_out_cb2);
+static void via_irq_func(device_t *device, int state);
+
+
+const via6522_interface concept_via6522_intf =
+{ /* main via */
+ DEVCB_HANDLER(via_in_a), DEVCB_HANDLER(via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(via_out_a), DEVCB_HANDLER(via_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(via_out_cb2),
+ DEVCB_LINE(via_irq_func)
+};
+
+/* keyboard interface */
+
+/* Expansion slots */
+
+static void concept_fdc_init(running_machine &machine, int slot);
+static void concept_hdc_init(running_machine &machine, int slot);
+
+MACHINE_START(concept)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ /* initialize int state */
+ state->m_pending_interrupts = 0;
+
+ /* initialize clock interface */
+ state->m_clock_enable = 0/*1*/;
+
+ /* clear keyboard interface state */
+ state->m_KeyQueueHead = state->m_KeyQueueLen = 0;
+ memset(state->m_KeyStateSave, 0, sizeof(state->m_KeyStateSave));
+
+ /* initialize expansion slots */
+ memset(state->m_expansion_slots, 0, sizeof(state->m_expansion_slots));
+
+ concept_hdc_init(machine, 1); /* Flat cable Hard Disk Controller in Slot 2 */
+ concept_fdc_init(machine, 2); /* Floppy Disk Controller in Slot 3 */
+}
+
+static void install_expansion_slot(running_machine &machine, int slot,
+ read8_space_func reg_read, write8_space_func reg_write,
+ read8_space_func rom_read, write8_space_func rom_write)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ state->m_expansion_slots[slot].reg_read = reg_read;
+ state->m_expansion_slots[slot].reg_write = reg_write;
+ state->m_expansion_slots[slot].rom_read = rom_read;
+ state->m_expansion_slots[slot].rom_write = rom_write;
+}
+
+VIDEO_START(concept)
+{
+}
+
+SCREEN_UPDATE_IND16(concept)
+{
+ /* resolution is 720*560 */
+ concept_state *state = screen.machine().driver_data<concept_state>();
+ UINT16 *videoram = state->m_videoram;
+ int x, y;
+ UINT16 *line;
+
+ for (y = 0; y < 560; y++)
+ {
+ line = &bitmap.pix16(560-1-y);
+ for (x = 0; x < 720; x++)
+ line[720-1-x] = (videoram[(x+48+y*768)>>4] & (0x8000 >> ((x+48+y*768) & 0xf))) ? 0 : 1;
+ }
+ return 0;
+}
+
+static void concept_set_interrupt(running_machine &machine, int level, int state)
+{
+ concept_state *drvstate = machine.driver_data<concept_state>();
+ int interrupt_mask;
+ int final_level;
+
+ if (state)
+ drvstate->m_pending_interrupts |= 1 << level;
+ else
+ drvstate->m_pending_interrupts &= ~ (1 << level);
+
+ for (final_level = 7, interrupt_mask = drvstate->m_pending_interrupts; (final_level > 0) && ! (interrupt_mask & 0x80); final_level--, interrupt_mask <<= 1)
+ ;
+
+ if (final_level)
+ /* assert interrupt */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1 + final_level - 1, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else
+ /* clear all interrupts */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1, CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR);
+}
+
+INLINE void post_in_KeyQueue(concept_state *state, int keycode)
+{
+ state->m_KeyQueue[(state->m_KeyQueueHead+state->m_KeyQueueLen) % KeyQueueSize] = keycode;
+ state->m_KeyQueueLen++;
+}
+
+static void poll_keyboard(running_machine &machine)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ UINT32 keystate;
+ UINT32 key_transitions;
+ int i, j;
+ int keycode;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ for(i = 0; (i < /*4*/3) && (state->m_KeyQueueLen <= (KeyQueueSize-MaxKeyMessageLen)); i++)
+ {
+ keystate = machine.root_device().ioport(keynames[2*i])->read() | (machine.root_device().ioport(keynames[2*i + 1])->read() << 16);
+ key_transitions = keystate ^ state->m_KeyStateSave[i];
+ if(key_transitions)
+ {
+ for(j = 0; (j < 32) && (state->m_KeyQueueLen <= (KeyQueueSize-MaxKeyMessageLen)); j++)
+ {
+ if((key_transitions >> j) & 1)
+ {
+ keycode = (i << 5) | j;
+
+ if (((keystate >> j) & 1))
+ {
+ /* key is pressed */
+ state->m_KeyStateSave[i] |= (1 << j);
+ keycode |= 0x80;
+ }
+ else
+ /* key is released */
+ state->m_KeyStateSave[i] &= ~ (1 << j);
+
+ post_in_KeyQueue(state, keycode);
+ concept_set_interrupt(machine, KEYINT_level, 1);
+ }
+ }
+ }
+ }
+}
+
+INTERRUPT_GEN( concept_interrupt )
+{
+ poll_keyboard(device->machine());
+}
+
+/*
+ VIA port A
+
+ 0: omninet ready (I)
+ 1: CTS0 (I)
+ 2: CTS1 (I)
+ 3: DSR0 (I)
+ 4: DSR1 (I)
+ 5: DCD0 (I)
+ 6: DCD1 (I)
+ 7: IOX (O)
+*/
+static READ8_DEVICE_HANDLER(via_in_a)
+{
+ LOG(("via_in_a: VIA port A (Omninet and COMM port status) read\n"));
+ return 1; /* omninet ready always 1 */
+}
+
+static WRITE8_DEVICE_HANDLER(via_out_a)
+{
+ LOG(("via_out_a: VIA port A status written: data=0x%2.2x\n", data));
+ /*iox = (data & 0x80) != 0;*/
+}
+
+/*
+ VIA port B
+
+ 0: video off (O)
+ 1: video address 17 (O)
+ 2: video address 18 (O)
+ 3: monitor orientation (I)
+ 4: CH rate select DC0 (serial port line) (O)
+ 5: CH rate select DC1 (serial port line) (O)
+ 6: boot switch 0 (I)
+ 7: boot switch 1 (I)
+*/
+static READ8_DEVICE_HANDLER(via_in_b)
+{
+ UINT8 status;
+
+ status = ((device->machine().root_device().ioport("DSW0")->read() & 0x80) >> 1) | ((device->machine().root_device().ioport("DSW0")->read() & 0x40) << 1);
+ LOG(("via_in_b: VIA port B (DIP switches, Video, Comm Rate) - status: 0x%2.2x\n", status));
+ return status;
+}
+
+static WRITE8_DEVICE_HANDLER(via_out_b)
+{
+ VLOG(("via_out_b: VIA port B (Video Control and COMM rate select) written: data=0x%2.2x\n", data));
+}
+
+/*
+ VIA CB2: used as sound output
+*/
+static WRITE8_DEVICE_HANDLER(via_out_cb2)
+{
+ LOG(("via_out_cb2: Sound control written: data=0x%2.2x\n", data));
+}
+
+/*
+ VIA irq -> 68k level 5
+*/
+static void via_irq_func(device_t *device, int state)
+{
+ concept_set_interrupt(device->machine(), TIMINT_level, state);
+}
+
+READ16_MEMBER(concept_state::concept_io_r)
+{
+ if (! ACCESSING_BITS_0_7)
+ return 0;
+
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1:
+ /* IO1 registers */
+ case 2:
+ /* IO2 registers */
+ case 3:
+ /* IO3 registers */
+ case 4:
+ /* IO4 registers */
+ {
+ int slot = ((offset >> 4) & 7) - 1;
+ if (m_expansion_slots[slot].reg_read)
+ return m_expansion_slots[slot].reg_read(&space, offset & 0xf);
+ }
+ break;
+
+ default:
+ /* ??? */
+ logerror("concept_io_r: Slot I/O memory accessed for unknown purpose at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+
+ case 1:
+ /* IO1 ROM */
+ case 2:
+ /* IO2 ROM */
+ case 3:
+ /* IO3 ROM */
+ case 4:
+ /* IO4 ROM */
+ {
+ int slot = ((offset >> 8) & 7) - 1;
+ LOG(("concept_io_r: Slot ROM memory accessed for slot %d at address 0x03%4.4x\n", slot, offset << 1));
+ if (m_expansion_slots[slot].rom_read)
+ return m_expansion_slots[slot].rom_read(&space, offset & 0xff);
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ LOG(("concept_io_r: Slot status read at address 0x03%4.4x\n", offset << 1));
+ break;
+
+ case 6:
+ /* calendar R/W */
+ VLOG(("concept_io_r: Calendar read at address 0x03%4.4x\n", offset << 1));
+ if (!m_clock_enable)
+ return mm58274c_r(machine().device("mm58274c"), m_clock_address);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ switch (offset & 0xf)
+ {
+ int reply;
+
+ case 0:
+ /* data */
+ reply = 0;
+
+ if (m_KeyQueueLen)
+ {
+ reply = m_KeyQueue[m_KeyQueueHead];
+ m_KeyQueueHead = (m_KeyQueueHead + 1) % KeyQueueSize;
+ m_KeyQueueLen--;
+ }
+
+ if (!m_KeyQueueLen)
+ concept_set_interrupt(machine(), KEYINT_level, 0);
+
+ return reply;
+
+ case 1:
+ /* always tell transmit is empty */
+ reply = m_KeyQueueLen ? 0x98 : 0x10;
+ break;
+ }
+ break;
+ case 1:
+ /* NSR0 data comm port 0 */
+ case 2:
+ /* NSR1 data comm port 1 */
+ LOG(("concept_io_r: Data comm port read at address 0x03%4.4x\n", offset << 1));
+ if ((offset & 0xf) == 1)
+ return 0x10;
+ break;
+
+ case 3:
+ /* NVIA versatile system interface */
+ LOG(("concept_io_r: VIA read at address 0x03%4.4x\n", offset << 1));
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ return via_0->read(space, offset & 0xf);
+ }
+ break;
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ /* write-only? */
+ LOG(("concept_io_r: NCALM clock/calendar read at address 0x03%4.4x\n", offset << 1));
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_r: NOMNI Omninet Transporter register read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_r: NOMOFF Omninet interrupt flip-flop read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe (disables interface RAM) */
+ logerror("concept_io_r: NIOSTRB External I/O ROM strobe read at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+WRITE16_MEMBER(concept_state::concept_io_w)
+{
+ if (! ACCESSING_BITS_0_7)
+ return;
+
+ data &= 0xff;
+
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1:
+ /* IO1 registers */
+ case 2:
+ /* IO2 registers */
+ case 3:
+ /* IO3 registers */
+ case 4:
+ /* IO4 registers */
+ {
+ int slot = ((offset >> 4) & 7) - 1;
+ LOG(("concept_io_w: Slot I/O register written for slot %d at address 0x03%4.4x, data: 0x%4.4x\n",
+ slot, offset << 1, data));
+ if (m_expansion_slots[slot].reg_write)
+ m_expansion_slots[slot].reg_write(&space, offset & 0xf, data);
+ }
+ break;
+
+ default:
+ /* ??? */
+ logerror("concept_io_w: Slot I/O memory written for unknown purpose at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+
+ case 1:
+ /* IO1 ROM */
+ case 2:
+ /* IO2 ROM */
+ case 3:
+ /* IO3 ROM */
+ case 4:
+ /* IO4 ROM */
+ {
+ int slot = ((offset >> 8) & 7) - 1;
+ LOG(("concept_io_w: Slot ROM memory written to for slot %d at address 0x03%4.4x, data: 0x%4.4x\n", slot, offset << 1, data));
+ if (m_expansion_slots[slot].rom_write)
+ m_expansion_slots[slot].rom_write(&space, offset & 0xff, data);
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ logerror("concept_io_w: Slot status written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* calendar R/W */
+ LOG(("concept_io_w: Calendar written to at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data));
+ if (!m_clock_enable)
+ mm58274c_w(machine().device("mm58274c"), m_clock_address, data & 0xf);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ case 1:
+ /* NSR0 data comm port 0 */
+ case 2:
+ /* NSR1 data comm port 1 */
+ /*acia_6551_w((offset >> 4) & 7, offset & 0x3, data);*/
+ break;
+
+ case 3:
+ /* NVIA versatile system interface */
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via_0->write(space, offset & 0xf, data);
+ }
+ break;
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ if (m_clock_enable != ((data & 0x10) != 0))
+ {
+ m_clock_enable = (data & 0x10) != 0;
+ if (! m_clock_enable)
+ /* latch address when enable goes low */
+ m_clock_address = data & 0x0f;
+ }
+ /*volume_control = (data & 0x20) != 0;*/
+ /*alt_map = (data & 0x40) != 0;*/
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_w: NOMNI Omninet Transporter register written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_w: NOMOFF Omninet flip-flop reset at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe */
+ logerror("concept_io_w: NIOSTRB External I/O ROM strobe written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+ }
+}
+
+/*
+ Concept fdc controller
+*/
+
+enum
+{
+ LS_DRQ_bit = 0, // DRQ
+ LS_INT_bit = 1, // INT
+ LS_SS_bit = 4, // 1 if single-sided (floppy or drive?)
+ LS_8IN_bit = 5, // 1 if 8" floppy drive?
+ LS_DSKCHG_bit = 6, // 0 if disk changed, 1 if not
+ LS_SD_bit = 7, // 1 if single density
+
+ LS_DRQ_mask = (1 << LS_DRQ_bit),
+ LS_INT_mask = (1 << LS_INT_bit),
+ LS_SS_mask = (1 << LS_SS_bit),
+ LS_8IN_mask = (1 << LS_8IN_bit),
+ LS_DSKCHG_mask = (1 << LS_DSKCHG_bit),
+ LS_SD_mask = (1 << LS_SD_bit)
+};
+enum
+{
+ LC_FLPSD1_bit = 0, // 0 if side 0 , 1 if side 1
+ LC_DE0_bit = 1, // drive select bit 0
+ LC_DE1_bit = 4, // drive select bit 1
+ LC_MOTOROF_bit = 5, // 1 if motor to be turned off
+ LC_FLP8IN_bit = 6, // 1 to select 8", 0 for 5"1/4 (which I knew what it means)
+ LC_FMMFM_bit = 7, // 1 to select single density, 0 for double
+
+ LC_FLPSD1_mask = (1 << LC_FLPSD1_bit),
+ LC_DE0_mask = (1 << LC_DE0_bit),
+ LC_DE1_mask = (1 << LC_DE1_bit),
+ LC_MOTOROF_mask = (1 << LC_MOTOROF_bit),
+ LC_FLP8IN_mask = (1 << LC_FLP8IN_bit),
+ LC_FMMFM_mask = (1 << LC_FMMFM_bit)
+};
+
+
+static READ8_HANDLER(concept_fdc_reg_r);
+static WRITE8_HANDLER(concept_fdc_reg_w);
+static READ8_HANDLER(concept_fdc_rom_r);
+
+static void concept_fdc_init(running_machine &machine, int slot)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ state->m_fdc_local_status = 0;
+ state->m_fdc_local_command = 0;
+
+ install_expansion_slot(machine, slot, concept_fdc_reg_r, concept_fdc_reg_w, concept_fdc_rom_r, NULL);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( concept_fdc_intrq_w )
+{
+ concept_state *drvstate = device->machine().driver_data<concept_state>();
+ if (state)
+ drvstate->m_fdc_local_status |= LS_INT_mask;
+ else
+ drvstate->m_fdc_local_status &= ~LS_INT_mask;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( concept_fdc_drq_w )
+{
+ concept_state *drvstate = device->machine().driver_data<concept_state>();
+ if (state)
+ drvstate->m_fdc_local_status |= LS_DRQ_mask;
+ else
+ drvstate->m_fdc_local_status &= ~LS_DRQ_mask;
+}
+
+const wd17xx_interface concept_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(concept_fdc_intrq_w),
+ DEVCB_LINE(concept_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+static READ8_HANDLER(concept_fdc_reg_r)
+{
+ concept_state *state = space->machine().driver_data<concept_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0:
+ /* local Status reg */
+ return state->m_fdc_local_status;
+
+ case 8:
+ /* FDC STATUS REG */
+ return wd17xx_status_r(fdc, offset);
+
+ case 9:
+ /* FDC TRACK REG */
+ return wd17xx_track_r(fdc, offset);
+
+ case 10:
+ /* FDC SECTOR REG */
+ return wd17xx_sector_r(fdc, offset);
+
+ case 11:
+ /* FDC DATA REG */
+ return wd17xx_data_r(fdc, offset);
+ }
+
+ return 0;
+}
+
+static WRITE8_HANDLER(concept_fdc_reg_w)
+{
+ concept_state *state = space->machine().driver_data<concept_state>();
+ int current_drive;
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0:
+ /* local command reg */
+ state->m_fdc_local_command = data;
+
+ wd17xx_set_side(fdc,(data & LC_FLPSD1_mask) != 0);
+ current_drive = ((data >> LC_DE0_bit) & 1) | ((data >> (LC_DE1_bit-1)) & 2);
+ wd17xx_set_drive(fdc, current_drive);
+ /*motor_on = (data & LC_MOTOROF_mask) == 0;*/
+ // floppy_drive_set_motor_state(floppy_get_device(machine, current_drive), (data & LC_MOTOROF_mask) == 0 ? 1 : 0);
+ /*flp_8in = (data & LC_FLP8IN_mask) != 0;*/
+ wd17xx_dden_w(fdc, BIT(data, 7));
+ floppy_drive_set_ready_state(floppy_get_device(space->machine(), current_drive), 1, 0);
+ break;
+
+ case 8:
+ /* FDC COMMAMD REG */
+ wd17xx_command_w(fdc, offset, data);
+ break;
+
+ case 9:
+ /* FDC TRACK REG */
+ wd17xx_track_w(fdc, offset, data);
+ break;
+
+ case 10:
+ /* FDC SECTOR REG */
+ wd17xx_sector_w(fdc, offset, data);
+ break;
+
+ case 11:
+ /* FDC DATA REG */
+ wd17xx_data_w(fdc, offset, data);
+ break;
+ }
+}
+
+static READ8_HANDLER(concept_fdc_rom_r)
+{
+ static const UINT8 data[] = "CORVUS01";
+ return (offset < 8) ? data[offset] : 0;
+}
+
+/*
+ * Concept Hard Disk Controller (hdc)
+ */
+
+static READ8_HANDLER(concept_hdc_reg_r);
+static WRITE8_HANDLER(concept_hdc_reg_w);
+static READ8_HANDLER(concept_hdc_rom_r);
+
+/*
+ * Hook up the Register and ROM R/W routines into the Slot I/O Space
+ */
+
+static void concept_hdc_init(running_machine &machine, int slot)
+{
+ if(corvus_hdc_init(machine))
+ install_expansion_slot(machine, slot, concept_hdc_reg_r, concept_hdc_reg_w, concept_hdc_rom_r, NULL);
+}
+
+/*
+ * Handle reads against the Hard Disk Controller's onboard registers
+ */
+static READ8_HANDLER(concept_hdc_reg_r)
+{
+ switch (offset)
+ {
+ case 0:
+ /* HDC Data Register */
+ return corvus_hdc_data_r(space, offset);
+
+ case 1:
+ /* HDC Status Register */
+ return corvus_hdc_status_r(space, offset);
+ }
+
+ return 0;
+}
+
+/*
+ * Handle writes against the Hard Disk Controller's onboard registers
+ */
+static WRITE8_HANDLER(concept_hdc_reg_w)
+{
+ switch (offset)
+ {
+ case 0:
+ /* HDC Data Register */
+ corvus_hdc_data_w(space, offset, data);
+ break;
+ }
+}
+
+/*
+ * Handle reads agsint the Hard Disk Controller's onboard ROM
+ */
+static READ8_HANDLER(concept_hdc_rom_r)
+{
+ static const UINT8 data[8] = { 0xa9, 0x20, 0xa9, 0x00, 0xa9, 0x03, 0xa9, 0x3c }; /* Same as Apple II */
+ return (offset < 8) ? data[offset] : 0;
+}