// license:BSD-3-Clause // copyright-holders:Hans Ostermeyer, R. Belmont /* * apollo.c - Apollo DS3500 CPU Board * * Created on: Jan 20, 2011 * Author: Hans Ostermeyer * * Contains: * - apollo_config.c - APOLLO DS3500 configuration * - apollo_csr.c - APOLLO DS3500 CPU Control and Status registers * - apollo_dma.c - APOLLO DS3500 DMA controllers * - apollo_pic.c - APOLLO DS3500 PIC8259 controllers * - apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840 * - apollo_rtc.c - APOLLO DS3500 RTC MC146818 * - apollo_sio.c - APOLLO DS3500 SIO * - apollo_sio2.c - APOLLO DS3500 SIO2 * - apollo_stdio.c - stdio terminal for mess * - apollo_3c505.h - Apollo 3C505 Ethernet controller * * see also: * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf * - http://www.freescale.com/files/32bit/doc/inactive/MC68681UM.pdf * * SIO usage: * SIO: ch A keyboard, ch B serial console * SIO2: modem/printer? * */ #include "emu.h" #include "includes/apollo.h" #include "bus/isa/omti8621.h" #include "bus/isa/sc499.h" #include "bus/isa/3c505.h" #include "softlist.h" #define APOLLO_IRQ_VECTOR 0xa0 #define APOLLO_IRQ_PTM 0 #define APOLLO_IRQ_SIO1 1 #define APOLLO_IRQ_PIC_SLAVE 3 #define APOLLO_IRQ_CTAPE 5 #define APOLLO_IRQ_FDC 6 #define APOLLO_IRQ_RTC 8 // DN3000 only #define APOLLO_IRQ_SIO2 8 // DN3500 #define APOLLO_IRQ_ETH2 9 #define APOLLO_IRQ_ETH1 10 #define APOLLO_IRQ_DIAG 13 #define APOLLO_IRQ_WIN1 14 #define APOLLO_DMA_ETH1 6 #define APOLLO_DMA_ETH2 3 //########################################################################## // machine/apollo_config.c - APOLLO DS3500 configuration //########################################################################## #undef VERBOSE #define VERBOSE 0 static uint16_t config = 0; /*************************************************************************** apollo_config - check configuration setting ***************************************************************************/ int apollo_config(int mask) { return config & mask ? 1 : 0; } /*************************************************************************** Input Ports ***************************************************************************/ INPUT_PORTS_START( apollo_config ) PORT_START( "apollo_config" ) PORT_CONFNAME(APOLLO_CONF_SERVICE_MODE, 0x00, "Normal/Service" ) PORT_CONFSETTING(0x00, "Service" ) PORT_CONFSETTING(APOLLO_CONF_SERVICE_MODE, "Normal" ) PORT_CONFNAME(APOLLO_CONF_DISPLAY, APOLLO_CONF_8_PLANES, "Graphics Controller") PORT_CONFSETTING(APOLLO_CONF_8_PLANES, "8-Plane Color") PORT_CONFSETTING(APOLLO_CONF_4_PLANES, "4-Plane Color") PORT_CONFSETTING(APOLLO_CONF_MONO_15I, "15\" Monochrome") // PORT_CONFSETTING(APOLLO_CONF_MONO_19I, "19\" Monochrome") PORT_CONFNAME(APOLLO_CONF_GERMAN_KBD, 0x00, "German Keyboard") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_GERMAN_KBD, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_20_YEARS_AGO, APOLLO_CONF_20_YEARS_AGO, "20 Years Ago ...") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_20_YEARS_AGO, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_25_YEARS_AGO, APOLLO_CONF_25_YEARS_AGO, "25 Years Ago ...") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_25_YEARS_AGO, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_NODE_ID, APOLLO_CONF_NODE_ID, "Node ID from Disk") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_NODE_ID, DEF_STR ( On ) ) // PORT_CONFNAME(APOLLO_CONF_IDLE_SLEEP, 0x00, "Idle Sleep") // PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) // PORT_CONFSETTING(APOLLO_CONF_IDLE_SLEEP, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_TRAP_TRACE, 0x00, "Trap Trace") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_TRAP_TRACE, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_FPU_TRACE, 0x00, "FPU Trace") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_FPU_TRACE, DEF_STR ( On ) ) #ifdef APOLLO_XXL PORT_CONFNAME(APOLLO_CONF_DISK_TRACE, 0x00, "Disk Trace") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_DISK_TRACE, DEF_STR ( On ) ) PORT_CONFNAME(APOLLO_CONF_NET_TRACE, 0x00, "Network Trace") PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) PORT_CONFSETTING(APOLLO_CONF_NET_TRACE, DEF_STR ( On ) ) #endif INPUT_PORTS_END class apollo_config_device : public device_t { public: apollo_config_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; private: // internal state }; DEFINE_DEVICE_TYPE(APOLLO_CONF, apollo_config_device, "apollo_config", "Apollo Configuration") apollo_config_device::apollo_config_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, APOLLO_CONF, tag, owner, clock) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void apollo_config_device::device_start() { MLOG1(("start apollo_config")); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void apollo_config_device::device_reset() { MLOG1(("reset apollo_config")); // load configuration config = machine().root_device().ioport("apollo_config")->read(); } //########################################################################## // machine/apollo_csr.c - APOLLO DS3500 CPU Control and Status registers //########################################################################## #undef VERBOSE #define VERBOSE 0 #define CPU_CONTROL_REGISTER_ADDRESS 0x010100 static uint16_t cpu_status_register = APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_SERVICE; static uint16_t cpu_control_register = 0x0000; /*------------------------------------------------- apollo_csr_get/set_servicemode -------------------------------------------------*/ /*static int apollo_csr_get_servicemode() { return cpu_status_register & APOLLO_CSR_SR_SERVICE ? 0 : 1; }*/ static void apollo_csr_set_servicemode(int mode) { apollo_csr_set_status_register(1, mode ? APOLLO_CSR_SR_SERVICE : 0); } uint16_t apollo_csr_get_control_register(void) { return cpu_control_register; } uint16_t apollo_csr_get_status_register(void) { return cpu_status_register; } void apollo_csr_set_status_register(uint16_t mask, uint16_t data) { uint16_t new_value = (cpu_status_register & ~mask) | (data & mask); if (new_value != cpu_status_register) { cpu_status_register = new_value; //LOG1(("#### setting CPU Status Register with data=%04x & %04x to %04x", data, mask, cpu_status_register)); } } /*------------------------------------------------- DN3000/DN3500 CPU Status Register at 0x8000/0x10000 -------------------------------------------------*/ WRITE16_MEMBER(apollo_state::apollo_csr_status_register_w){ // To clear bus timeouts or parity conditions from status register, // write to the status register. This register is readonly. // in DN3500 bit 15 is always set (undocumented !?) cpu_status_register &= (APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_FP_TRAP | APOLLO_CSR_SR_SERVICE); SLOG1(("writing CPU Status Register at offset %X = %04x & %04x (%04x)", offset, data, mem_mask, cpu_status_register)); } READ16_MEMBER(apollo_state::apollo_csr_status_register_r){ SLOG2(("reading CPU Status Register at offset %X = %04x & %04x", offset, cpu_status_register, mem_mask)); return cpu_status_register & mem_mask; } /*------------------------------------------------- DN3000/DN3500 CPU Control Register at 0x8100/0x10100 -------------------------------------------------*/ WRITE16_MEMBER(apollo_state::apollo_csr_control_register_w) { int leds; if ((mem_mask & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) { // FPU Trap enable not involved } else if (((data ^ cpu_control_register) & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) { // FPU Trap enable remains unchanged } else if ((data & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) { // enable FPU (i.e. FPU opcodes in CPU) apollo_set_cpu_has_fpu(m_maincpu, 1); } else { // disable FPU (i.e. FPU opcodes in CPU) apollo_set_cpu_has_fpu(m_maincpu, 0); if (!apollo_is_dn3000()) { // hack: set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test // APOLLO_CSR_SR_FP_TRAP in status register should be set by next fmove instruction // cpu_status_register |= APOLLO_CSR_SR_FP_TRAP; } } COMBINE_DATA(&cpu_control_register); output().set_value("internal_led_1", (cpu_control_register >> 15) & 1); output().set_value("internal_led_2", (cpu_control_register >> 14) & 1); output().set_value("internal_led_3", (cpu_control_register >> 13) & 1); output().set_value("internal_led_4", (cpu_control_register >> 12) & 1); output().set_value("external_led_a", (cpu_control_register >> 11) & 1); output().set_value("external_led_b", (cpu_control_register >> 10) & 1); output().set_value("external_led_c", (cpu_control_register >> 9) & 1); output().set_value("external_led_d", (cpu_control_register >> 8) & 1); leds = ((cpu_control_register >> 8) & 0xff) ^ 0xff; SLOG1(("writing CPU Control Register at offset %X = %04x & %04x (%04x - %d%d%d%d %d%d%d%d)", offset, data, mem_mask, cpu_control_register, (leds >> 3) & 1,(leds >> 2) & 1, (leds >> 1) & 1, (leds >> 0) & 1, (leds >> 7) & 1,(leds >> 6) & 1, (leds >> 5) & 1, (leds >> 4) & 1 )); if (data & APOLLO_CSR_CR_RESET_DEVICES) { // FIXME: reset all devices (but not SIO lines!) } } READ16_MEMBER(apollo_state::apollo_csr_control_register_r) { SLOG1(("reading CPU Control Register at offset %X = %04x & %04x", offset, cpu_control_register, mem_mask)); return cpu_control_register & mem_mask; } //########################################################################## // machine/apollo_dma.c - APOLLO DS3500 DMA //########################################################################## #undef VERBOSE #define VERBOSE 0 static uint16_t address_translation_map[0x400]; static uint16_t dma_page_register[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const uint8_t channel2page_register[8] = { 7, 3, 1, 2, 0, 11, 9, 10}; static uint8_t dn3000_dma_channel1 = 1; // 1 = memory/ctape, 2 = floppy dma channel static uint8_t dn3000_dma_channel2 = 5; // 5 = memory dma channel /*------------------------------------------------- DN3000/DN3500 DMA Controller 1 at 0x9000/0x10c00 -------------------------------------------------*/ WRITE8_MEMBER(apollo_state::apollo_dma_1_w){ SLOG1(("apollo_dma_1_w: writing DMA Controller 1 at offset %02x = %02x", offset, data)); m_dma8237_1->write(space, offset, data); } READ8_MEMBER(apollo_state::apollo_dma_1_r){ uint8_t data = m_dma8237_1->read(space, offset); SLOG1(("apollo_dma_1_r: reading DMA Controller 1 at offset %02x = %02x", offset, data)); return data; } /*------------------------------------------------- DN3000/DN3500 DMA Controller 2 at 0x9100/0x10d00 -------------------------------------------------*/ WRITE8_MEMBER(apollo_state::apollo_dma_2_w){ SLOG1(("apollo_dma_2_w: writing DMA Controller 2 at offset %02x = %02x", offset/2, data)); m_dma8237_2->write(space, offset / 2, data); } READ8_MEMBER(apollo_state::apollo_dma_2_r){ // Nasty hack (13-06-15 - ost): // MD self_test will test wrong DMA register and // mem-to-mem DMA in am9517a.c is often starting much too late (for MD self_test) // (8237dma.c was always fast enough to omit these problems) if (offset == 8) { switch (m_maincpu->pcbase()) { case 0x00102e22: // DN3000 case 0x01002f3c: // DN3500 case 0x010029a6: // DN5500 offset = 16; break; } } uint8_t data = m_dma8237_2->read(space, offset / 2); SLOG1(("apollo_dma_2_r: reading DMA Controller 2 at offset %02x = %02x", offset/2, data)); return data; } /*************************************************************************** DN3000 DMA Page Register at 0x9200 ***************************************************************************/ WRITE8_MEMBER(apollo_state::apollo_dma_page_register_w){ dma_page_register[offset & 0x0f] = data; SLOG1(("writing DMA Page Register at offset %02x = %02x", offset, data)); } READ8_MEMBER(apollo_state::apollo_dma_page_register_r){ uint8_t data = dma_page_register[offset & 0x0f]; SLOG1(("reading DMA Page Register at offset %02x = %02x", offset, data)); return data; } /*------------------------------------------------- DN3500 Address Translation Map at 0x017000 -------------------------------------------------*/ WRITE16_MEMBER(apollo_state::apollo_address_translation_map_w){ address_translation_map[offset & 0x3ff] = data; SLOG2(("writing Address Translation Map at offset %02x = %04x", offset, data)); } READ16_MEMBER(apollo_state::apollo_address_translation_map_r){ uint16_t data = address_translation_map[offset & 0x3ff]; SLOG2(("reading Address Translation Map at offset %02x = %04x", offset, data)); return data; } READ8_MEMBER(apollo_state::apollo_dma_read_byte){ uint8_t data; offs_t page_offset; if (apollo_is_dn3000()) { page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16; } else { // FIXME: address_translation_map[0x200] ? page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00; offset &= 0x3ff; } data = m_maincpu->space(AS_PROGRAM).read_byte(page_offset + offset); if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff) { SLOG1(("dma read byte at offset %x+%03x = %02x", page_offset, offset, data)); } // logerror(" %02x", data); return data; } WRITE8_MEMBER(apollo_state::apollo_dma_write_byte){ offs_t page_offset; if (apollo_is_dn3000()) { page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16; } else { // FIXME: address_translation_map[0x200] ? page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00; offset &= 0x3ff; } // FIXME: MSB not available, writing only LSB m_maincpu->space(AS_PROGRAM).write_byte(page_offset + offset, data); if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff) { SLOG1(("dma write byte at offset %x+%03x = %02x", page_offset, offset , data)); } // logerror(" %02x", data); } READ8_MEMBER(apollo_state::apollo_dma_read_word){ uint16_t data; offs_t page_offset; if (apollo_is_dn3000()) { page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16; page_offset &= 0xfffe0000; offset <<= 1; } else { // FIXME: address_translation_map[0x200] ? page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) << 10) & 0x7FFFFC00; offset = (offset << 1) & 0x3ff; } data = m_maincpu->space(AS_PROGRAM).read_byte(page_offset + offset); SLOG1(("dma read word at offset %x+%03x = %04x", page_offset, offset , data)); // FIXME: MSB will get lost return data; } WRITE8_MEMBER(apollo_state::apollo_dma_write_word){ offs_t page_offset; SLOG1(("dma write word at offset %x = %02x", offset, data)); if (apollo_is_dn3000()) { page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16; page_offset &= 0xfffe0000; offset <<= 1; } else { // FIXME: address_translation_map[0x200] ? page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) << 10) & 0x7FFFFC00; offset = (offset << 1) & 0x3ff; } m_maincpu->space(AS_PROGRAM).write_byte(page_offset + offset, data); SLOG1(("dma write word at offset %x+%03x = %02x", page_offset, offset, data)); } WRITE_LINE_MEMBER(apollo_state::apollo_dma8237_out_eop ) { CLOG1(("dma out eop state %02x", state)); m_cur_eop = state == ASSERT_LINE; if(m_dma_channel != -1) m_isa->eop_w(m_dma_channel, m_cur_eop ? ASSERT_LINE : CLEAR_LINE ); } WRITE_LINE_MEMBER(apollo_state::apollo_dma_1_hrq_changed ) { CLOG2(("dma 1 hrq changed state %02x", state)); m_dma8237_1->dreq0_w(state); /* Assert HLDA */ m_dma8237_1->hack_w(state); // cascade mode? // i8237_hlda_w(get_device_dma8237_2(device), state); } WRITE_LINE_MEMBER(apollo_state::apollo_dma_2_hrq_changed ) { CLOG2(("dma 2 hrq changed state %02x", state)); m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); /* Assert HLDA */ m_dma8237_2->hack_w(state); } READ8_MEMBER( apollo_state::pc_dma8237_0_dack_r ) { return m_isa->dack_r(0); } READ8_MEMBER( apollo_state::pc_dma8237_1_dack_r ) { return m_isa->dack_r(1); } READ8_MEMBER( apollo_state::pc_dma8237_2_dack_r ) { return m_isa->dack_r(2); } READ8_MEMBER( apollo_state::pc_dma8237_3_dack_r ) { return m_isa->dack_r(3); } READ8_MEMBER( apollo_state::pc_dma8237_5_dack_r ) { return m_isa->dack_r(5); } READ8_MEMBER( apollo_state::pc_dma8237_6_dack_r ) { return m_isa->dack_r(6); } READ8_MEMBER( apollo_state::pc_dma8237_7_dack_r ) { return m_isa->dack_r(7); } WRITE8_MEMBER( apollo_state::pc_dma8237_0_dack_w ){ m_isa->dack_w(0, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_1_dack_w ){ m_isa->dack_w(1, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_2_dack_w ){ m_isa->dack_w(2, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_3_dack_w ){ m_isa->dack_w(3, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_5_dack_w ){ m_isa->dack_w(5, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_6_dack_w ){ m_isa->dack_w(6, data); } WRITE8_MEMBER( apollo_state::pc_dma8237_7_dack_w ){ m_isa->dack_w(7, data); } WRITE_LINE_MEMBER( apollo_state::pc_dack0_w ) { select_dma_channel(0, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack1_w ) { select_dma_channel(1, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack2_w ) { select_dma_channel(2, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack3_w ) { select_dma_channel(3, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack4_w ) { m_dma8237_1->hack_w( state ? 0 : 1); } // it's inverted WRITE_LINE_MEMBER( apollo_state::pc_dack5_w ) { select_dma_channel(5, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack6_w ) { select_dma_channel(6, state); } WRITE_LINE_MEMBER( apollo_state::pc_dack7_w ) { select_dma_channel(7, state); } void apollo_state::select_dma_channel(int channel, bool state) { if(!state) { m_dma_channel = channel; if(m_cur_eop) m_isa->eop_w(channel, ASSERT_LINE ); } else if(m_dma_channel == channel) { m_dma_channel = -1; if(m_cur_eop) m_isa->eop_w(channel, CLEAR_LINE ); } } //########################################################################## // machine/apollo_pic.c - APOLLO DS3500 PIC 8259 controllers //########################################################################## #undef VERBOSE #define VERBOSE 0 void apollo_state::apollo_pic_set_irq_line(int irq, int state) { switch (irq) { case 0: m_pic8259_master->ir0_w(state); break; case 1: m_pic8259_master->ir1_w(state); break; case 2: m_pic8259_master->ir2_w(state); break; case 3: m_pic8259_master->ir3_w(state); break; case 4: m_pic8259_master->ir4_w(state); break; case 5: m_pic8259_master->ir5_w(state); break; case 6: m_pic8259_master->ir6_w(state); break; case 7: m_pic8259_master->ir7_w(state); break; case 8: m_pic8259_slave->ir0_w(state); break; case 9: m_pic8259_slave->ir1_w(state); break; case 10: m_pic8259_slave->ir2_w(state); break; case 11: m_pic8259_slave->ir3_w(state); break; case 12: m_pic8259_slave->ir4_w(state); break; case 13: m_pic8259_slave->ir5_w(state); break; case 14: m_pic8259_slave->ir6_w(state); break; case 15: m_pic8259_slave->ir7_w(state); break; } } IRQ_CALLBACK_MEMBER(apollo_state::apollo_pic_acknowledge) { uint32_t vector = m_pic8259_master->acknowledge(); if ((vector & 0x0f) == APOLLO_IRQ_PIC_SLAVE) { vector = m_pic8259_slave->acknowledge(); } // don't log ptm interrupts if (vector != APOLLO_IRQ_VECTOR+APOLLO_IRQ_PTM) { MLOG1(("apollo_pic_acknowledge: irq=%d vector=%x", vector & 0x0f, vector)); } if (apollo_is_dn3000()) { apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, 0); } else { // clear bit Interrupt Pending in Cache Status Register apollo_set_cache_status_register(this,0x10, 0x00); } return vector; } /************************************************************* * pic8259 configuration *************************************************************/ READ8_MEMBER( apollo_state::apollo_pic8259_get_slave_ack ) { MLOG1(("apollo_pic8259_get_slave_ack: offset=%x", offset)); return offset == 3 ? m_pic8259_slave->acknowledge() : 0; } WRITE_LINE_MEMBER( apollo_state::apollo_pic8259_master_set_int_line ) { static int interrupt_line = -1; if (state != interrupt_line) { device_t *device = m_pic8259_master; DLOG1(("apollo_pic8259_master_set_int_line: %x", state)); } interrupt_line = state; if (apollo_is_dn3000()) { apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, state ? APOLLO_CSR_SR_INTERRUPT_PENDING : 0); } else { // set bit Interrupt Pending in Cache Status Register apollo_set_cache_status_register(this,0x10, state ? 0x10 : 0x00); } m_maincpu->set_input_line_and_vector(M68K_IRQ_6,state ? ASSERT_LINE : CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR); } WRITE_LINE_MEMBER( apollo_state::apollo_pic8259_slave_set_int_line ) { static int interrupt_line = -1; if (state != interrupt_line) { device_t *device = m_pic8259_slave; DLOG1(("apollo_pic8259_slave_set_int_line: %x", state)); interrupt_line = state; apollo_pic_set_irq_line(3, state); } } //########################################################################## // machine/apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840 //########################################################################## #undef VERBOSE #define VERBOSE 0 WRITE_LINE_MEMBER(apollo_state::apollo_ptm_timer_tick) { if ((state) && (m_ptm->started())) { ptm_counter++; m_ptm->set_c1( 1); m_ptm->set_c1( 0); m_ptm->set_c2(ptm_counter & 1); if ((ptm_counter & 1) == 0) { m_ptm->set_c3((ptm_counter >> 1) & 1); } } } WRITE_LINE_MEMBER(apollo_state::apollo_ptm_irq_function) { apollo_pic_set_irq_line(APOLLO_IRQ_PTM, state); } // Timer 1's input is a 250-kHz (4-microsecond period) signal. // Timer 2's input is a 125-kHz (8-microsecond period) signal. // Timer 3's input is a 62.5-kHz (16-microsecond period) signal. // The Timer 3 input may be prescaled to make the effective input signal have a 128-microsecond period. //########################################################################## // machine/apollo_rtc.c - APOLLO DS3500 RTC MC146818 //########################################################################## #undef VERBOSE #define VERBOSE 0 /*************************************************************************** DN3000/DN3500 Realtime Calendar MC146818 at 0x8900/0x10900 ***************************************************************************/ WRITE8_MEMBER(apollo_state::apollo_rtc_w) { m_rtc->write(space, 0, offset); m_rtc->write(space, 1, data); if (offset >= 0x0b && offset <= 0x0c) { SLOG2(("writing MC146818 at offset %02x = %02x", offset, data)); } } READ8_MEMBER(apollo_state::apollo_rtc_r) { uint8_t data; m_rtc->write(space, 0, offset); data = m_rtc->read(space, 1); if (offset >= 0x0b && offset <= 0x0c) { SLOG2(("reading MC146818 at offset %02x = %02x", offset, data)); } return data; } // TODO: this is covering for missing mc146818 functionality TIMER_CALLBACK_MEMBER( apollo_state::apollo_rtc_timer ) { address_space &space = m_maincpu->space(AS_PROGRAM); // FIXME: reading register 0x0c will clear all interrupt flags if ((apollo_rtc_r(space, 0x0c) & 0x80)) { //SLOG2(("apollo_rtc_timer - set_irq_line %d", APOLLO_IRQ_RTC)); apollo_pic_set_irq_line(APOLLO_IRQ_RTC, 1); } } //########################################################################## // machine/apollo_sio.c - DN3000/DS3500 SIO at 0x8400/0x10400 //########################################################################## #undef VERBOSE #define VERBOSE 0 apollo_sio::apollo_sio(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : duart_base_device(mconfig, APOLLO_SIO, tag, owner, clock), m_csrb(0) { } void apollo_sio::device_reset() { uint8_t input_data = apollo_get_ram_config_byte(); ip0_w((input_data & 0x01) ? ASSERT_LINE : CLEAR_LINE); ip1_w((input_data & 0x02) ? ASSERT_LINE : CLEAR_LINE); ip2_w((input_data & 0x04) ? ASSERT_LINE : CLEAR_LINE); ip3_w((input_data & 0x08) ? ASSERT_LINE : CLEAR_LINE); ip4_w((input_data & 0x10) ? ASSERT_LINE : CLEAR_LINE); ip5_w((input_data & 0x20) ? ASSERT_LINE : CLEAR_LINE); ip6_w((input_data & 0x40) ? ASSERT_LINE : CLEAR_LINE); } READ8_MEMBER( apollo_sio::read ) { static int last_read8_offset[2] = { -1, -1 }; static int last_read8_value[2] = { -1, -1 }; static const char * const duart68681_reg_read_names[0x10] = { "MRA", "SRA", "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB", "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter", "Stop Counter" }; int data = duart_base_device::read(space, offset/2, mem_mask); switch (offset / 2) { case 0x0b: /* RHRB */ if (m_csrb == 0x77 && data == 0xfe) { // special fix for the MD ROM baudrate recognition // fix data only if CR is entered while baudrate is set to 2000 Baud // Receive and transmit clock in diserial.c are not precise enough // to support the baudrate recognition done in the Apollo MD ROM // use 0xff instead of 0xfe to set the baudrate recognition for 9600 Bd // (to prevent that the MD selftest or SK command will hang in Service mode) data = 0xff; } break; } // omit logging if sio is being polled from the boot rom if ((offset != last_read8_offset[1] || data != last_read8_value[1]) && \ (offset != last_read8_offset[0] || data != last_read8_value[0])) { last_read8_offset[0] = last_read8_offset[1]; last_read8_value[0] = last_read8_value[1]; last_read8_offset[1] = offset; last_read8_value[1] = data; CLOG2(("reading MC2681 reg %02x (%s) returned %02x", offset, duart68681_reg_read_names[(offset/2) & 15], data)); } return data; } WRITE8_MEMBER( apollo_sio::write ) { static const char * const duart68681_reg_write_names[0x10] = { "MRA", "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" }; CLOG2(("writing MC2681 reg %02x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data)); switch (offset / 2) { case 0x09: /* CSRB */ // remember CSRB to handle MD selftest or SK command m_csrb = data; break; #if 1 case 0x0b: /* THRB */ // tee output of SIO1 to stdout // sad: ceterm will get confused from '\r' if (apollo_is_dsp3x00() && data != '\r') ::putchar(data); break; #endif } duart_base_device::write(space, offset/2, data, mem_mask); } // device type definition DEFINE_DEVICE_TYPE(APOLLO_SIO, apollo_sio, "apollo_sio", "DN3000/DS3500 SIO (MC2681)") WRITE_LINE_MEMBER(apollo_state::sio_irq_handler) { apollo_pic_set_irq_line(APOLLO_IRQ_SIO1, state); } WRITE8_MEMBER(apollo_state::sio_output) { // CLOG2(("apollo_sio - sio_output %02x", data)); if ((data & 0x80) != (sio_output_data & 0x80)) { apollo_pic_set_irq_line(APOLLO_IRQ_DIAG, (data & 0x80) ? 1 : 0); } // The counter/timer on the SIO chip is used for the RAM refresh count. // This is set up in the timer mode to produce a square wave output on output OP3. // The period of the output is 15 microseconds. if ((data & 0x08) != (sio_output_data & 0x08)) { m_sio->ip0_w((data & 0x08) ? ASSERT_LINE : CLEAR_LINE); } sio_output_data = data; } //########################################################################## // machine/apollo_sio2.c - APOLLO DS3500 SIO2 //########################################################################## WRITE_LINE_MEMBER(apollo_state::sio2_irq_handler) { apollo_pic_set_irq_line(APOLLO_IRQ_SIO2, state); } //########################################################################## // machine/apollo_ni.c - APOLLO DS3500 node ID //########################################################################## #undef VERBOSE #define VERBOSE 0 #define DEFAULT_NODE_ID 0x12345 /*************************************************************************** IMPLEMENTATION ***************************************************************************/ /*** Apollo Node ID device ***/ // device type definition DEFINE_DEVICE_TYPE(APOLLO_NI, apollo_ni, "node_id", "Apollo Node ID") //------------------------------------------------- // apollo_ni - constructor //------------------------------------------------- apollo_ni::apollo_ni(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, APOLLO_NI, tag, owner, clock), device_image_interface(mconfig, *this) { } //------------------------------------------------- // apollo_ni - destructor //------------------------------------------------- apollo_ni::~apollo_ni() { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void apollo_ni::device_start() { CLOG1(("apollo_ni::device_start")); set_node_id(DEFAULT_NODE_ID); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void apollo_ni::device_reset() { CLOG1(("apollo_ni::device_reset")); } //------------------------------------------------- // set node ID //------------------------------------------------- void apollo_ni::set_node_id(uint32_t node_id) { m_node_id = node_id; CLOG1(("apollo_ni::set_node_id: node ID is %x", node_id)); } //------------------------------------------------- // read/write //------------------------------------------------- WRITE16_MEMBER(apollo_ni::write) { CLOG1(("Error: writing node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask)); } READ16_MEMBER(apollo_ni::read) { uint16_t data = 0; switch (offset & 0x0f) { case 1: // msb data = (m_node_id >> 16) & 0xff; break; case 2: data = (m_node_id >> 8) & 0xff; break; case 3: // lsb data = m_node_id & 0xff; break; case 15: // checksum data = ((m_node_id >> 16) + (m_node_id >> 8) + m_node_id) & 0xff; break; default: data = 0; break; } data <<= 8; CLOG2(("reading node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask)); return data; } /*------------------------------------------------- DEVICE_IMAGE_LOAD( rom ) -------------------------------------------------*/ image_init_result apollo_ni::call_load() { CLOG1(("apollo_ni::call_load: %s", filename())); uint64_t size = length(); if (size != 32) { CLOG(("apollo_ni::call_load: %s has unexpected file size %d", filename(), size)); } else { uint8_t data[32]; fread(data, sizeof(data)); uint8_t checksum = data[2] + data[4] + data[6]; if (checksum != data[30]) { CLOG(("apollo_ni::call_load: checksum is %02x - should be %02x", checksum, data[30])); } else { m_node_id = (((data[2] << 8) | data[4]) << 8) | (data[6]); CLOG1(("apollo_ni::call_load: node ID is %x", m_node_id)); return image_init_result::PASS; } } return image_init_result::FAIL; } /*------------------------------------------------- DEVICE_IMAGE_CREATE( rom ) -------------------------------------------------*/ image_init_result apollo_ni::call_create(int format_type, util::option_resolution *format_options) { CLOG1(("apollo_ni::call_create:")); if (length() > 0) { CLOG(("apollo_ni::call_create: %s already exists", filename())); } else { uint32_t node_id = 0; sscanf(basename_noext(), "%x", &node_id); if (node_id == 0 || node_id > 0xfffff) { CLOG(("apollo_ni::call_create: filename %s is no valid node ID", basename())); } else { uint8_t data[32]; memset(data, 0, sizeof(data)); data[2] = node_id >> 16; data[4] = node_id >> 8; data[6] = node_id; data[30] = data[2] + data[4] + data[6]; fwrite(data, sizeof(data)); CLOG(("apollo_ni::call_create: created %s with node ID %x", filename(), node_id)); set_node_id(node_id); return image_init_result::PASS; } } return image_init_result::FAIL; } /*------------------------------------------------- DEVICE_IMAGE_UNLOAD( rom ) -------------------------------------------------*/ void apollo_ni::call_unload() { CLOG1(("apollo_ni::call_unload:")); } //------------------------------------------------- // set node ID from disk //------------------------------------------------- void apollo_ni::set_node_id_from_disk() { omti8621_apollo_device *omti8621 = machine().device("isa1:wdc"); uint8_t db[0x50]; // check label of physical volume and get sector data of logical volume 1 // Note: sector data starts with 32 byte block header // set node ID from UID of logical volume 1 of logical unit 0 if (omti8621 && omti8621->get_sector(0, db, sizeof(db), 0) == sizeof(db) && memcmp(db + 0x22, "APOLLO", 6) == 0) { uint16_t sector1 = apollo_is_dn5500() ? 4 : 1; if (omti8621->get_sector(sector1, db, sizeof(db), 0) == sizeof(db)) { // set node_id from UID of logical volume 1 of logical unit 0 m_node_id = (((db[0x49] << 8) | db[0x4a]) << 8) | db[0x4b]; CLOG1(("apollo_ni::set_node_id_from_disk: node ID is %x", m_node_id)); } } } //########################################################################## // machine/apollo.c - APOLLO DS3500 CPU Board //########################################################################## #undef VERBOSE #define VERBOSE 0 static void apollo_isa_cards(device_slot_interface &device) { device.option_add("wdc", ISA16_OMTI8621_APOLLO); // Combo ESDI/AT floppy controller device.option_add("ctape", ISA8_SC499); // Archive SC499 cartridge tape device.option_add("3c505", ISA16_3C505); // 3Com 3C505 Ethernet card } MACHINE_CONFIG_START(apollo_state::common) // configuration MUST be reset first ! MCFG_DEVICE_ADD(APOLLO_CONF_TAG, APOLLO_CONF, 0) MCFG_DEVICE_ADD( APOLLO_DMA1_TAG, AM9517A, XTAL(14'318'181)/3 ) MCFG_I8237_OUT_HREQ_CB(WRITELINE(*this, apollo_state, apollo_dma_1_hrq_changed)) MCFG_I8237_OUT_EOP_CB(WRITELINE(*this, apollo_state, apollo_dma8237_out_eop)) MCFG_I8237_IN_MEMR_CB(READ8(*this, apollo_state, apollo_dma_read_byte)) MCFG_I8237_OUT_MEMW_CB(WRITE8(*this, apollo_state, apollo_dma_write_byte)) MCFG_I8237_IN_IOR_0_CB(READ8(*this, apollo_state, pc_dma8237_0_dack_r)) MCFG_I8237_IN_IOR_1_CB(READ8(*this, apollo_state, pc_dma8237_1_dack_r)) MCFG_I8237_IN_IOR_2_CB(READ8(*this, apollo_state, pc_dma8237_2_dack_r)) MCFG_I8237_IN_IOR_3_CB(READ8(*this, apollo_state, pc_dma8237_3_dack_r)) MCFG_I8237_OUT_IOW_0_CB(WRITE8(*this, apollo_state, pc_dma8237_0_dack_w)) MCFG_I8237_OUT_IOW_1_CB(WRITE8(*this, apollo_state, pc_dma8237_1_dack_w)) MCFG_I8237_OUT_IOW_2_CB(WRITE8(*this, apollo_state, pc_dma8237_2_dack_w)) MCFG_I8237_OUT_IOW_3_CB(WRITE8(*this, apollo_state, pc_dma8237_3_dack_w)) MCFG_I8237_OUT_DACK_0_CB(WRITELINE(*this, apollo_state, pc_dack0_w)) MCFG_I8237_OUT_DACK_1_CB(WRITELINE(*this, apollo_state, pc_dack1_w)) MCFG_I8237_OUT_DACK_2_CB(WRITELINE(*this, apollo_state, pc_dack2_w)) MCFG_I8237_OUT_DACK_3_CB(WRITELINE(*this, apollo_state, pc_dack3_w)) MCFG_DEVICE_ADD( APOLLO_DMA2_TAG, AM9517A, XTAL(14'318'181)/3 ) MCFG_I8237_OUT_HREQ_CB(WRITELINE(*this, apollo_state, apollo_dma_2_hrq_changed)) MCFG_I8237_IN_MEMR_CB(READ8(*this, apollo_state, apollo_dma_read_word)) MCFG_I8237_OUT_MEMW_CB(WRITE8(*this, apollo_state, apollo_dma_write_word)) MCFG_I8237_IN_IOR_1_CB(READ8(*this, apollo_state, pc_dma8237_5_dack_r)) MCFG_I8237_IN_IOR_2_CB(READ8(*this, apollo_state, pc_dma8237_6_dack_r)) MCFG_I8237_IN_IOR_3_CB(READ8(*this, apollo_state, pc_dma8237_7_dack_r)) MCFG_I8237_OUT_IOW_1_CB(WRITE8(*this, apollo_state, pc_dma8237_5_dack_w)) MCFG_I8237_OUT_IOW_2_CB(WRITE8(*this, apollo_state, pc_dma8237_6_dack_w)) MCFG_I8237_OUT_IOW_3_CB(WRITE8(*this, apollo_state, pc_dma8237_7_dack_w)) MCFG_I8237_OUT_DACK_0_CB(WRITELINE(*this, apollo_state, pc_dack4_w)) MCFG_I8237_OUT_DACK_1_CB(WRITELINE(*this, apollo_state, pc_dack5_w)) MCFG_I8237_OUT_DACK_2_CB(WRITELINE(*this, apollo_state, pc_dack6_w)) MCFG_I8237_OUT_DACK_3_CB(WRITELINE(*this, apollo_state, pc_dack7_w)) MCFG_DEVICE_ADD(APOLLO_PIC1_TAG, PIC8259, 0) MCFG_PIC8259_OUT_INT_CB(WRITELINE(*this, apollo_state, apollo_pic8259_master_set_int_line)) MCFG_PIC8259_IN_SP_CB(VCC) MCFG_PIC8259_CASCADE_ACK_CB(READ8(*this, apollo_state, apollo_pic8259_get_slave_ack)) MCFG_DEVICE_ADD(APOLLO_PIC2_TAG, PIC8259, 0) MCFG_PIC8259_OUT_INT_CB(WRITELINE(*this, apollo_state, apollo_pic8259_slave_set_int_line)) MCFG_PIC8259_IN_SP_CB(GND) MCFG_DEVICE_ADD(APOLLO_PTM_TAG, PTM6840, 0) MCFG_PTM6840_EXTERNAL_CLOCKS(250000, 125000, 62500) MCFG_PTM6840_IRQ_CB(WRITELINE(*this, apollo_state, apollo_ptm_irq_function)) MCFG_DEVICE_ADD("ptmclock", CLOCK, 250000) MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(*this, apollo_state, apollo_ptm_timer_tick)) MCFG_MC146818_ADD( APOLLO_RTC_TAG, XTAL(32'768) ) MCFG_MC146818_UTC( true ) MCFG_MC146818_BINARY( false ) MCFG_MC146818_24_12( false ) MCFG_MC146818_EPOCH( 0 ) MCFG_APOLLO_NI_ADD( APOLLO_NI_TAG, 0 ) MCFG_APOLLO_SIO_ADD( APOLLO_SIO2_TAG, XTAL(3'686'400) ) MCFG_APOLLO_SIO_IRQ_CALLBACK(WRITELINE(*this, apollo_state, sio2_irq_handler)) MCFG_DEVICE_ADD(APOLLO_ISA_TAG, ISA16, 0) MCFG_ISA16_CPU(MAINCPU) MCFG_ISA16_BUS_CUSTOM_SPACES() MCFG_ISA_OUT_IRQ2_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir2_w)) // in place of irq 2 on at irq 9 is used MCFG_ISA_OUT_IRQ3_CB(WRITELINE(APOLLO_PIC1_TAG, pic8259_device, ir3_w)) MCFG_ISA_OUT_IRQ4_CB(WRITELINE(APOLLO_PIC1_TAG, pic8259_device, ir4_w)) MCFG_ISA_OUT_IRQ5_CB(WRITELINE(APOLLO_PIC1_TAG, pic8259_device, ir5_w)) MCFG_ISA_OUT_IRQ6_CB(WRITELINE(APOLLO_PIC1_TAG, pic8259_device, ir6_w)) MCFG_ISA_OUT_IRQ7_CB(WRITELINE(APOLLO_PIC1_TAG, pic8259_device, ir7_w)) MCFG_ISA_OUT_IRQ10_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir2_w)) MCFG_ISA_OUT_IRQ11_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir3_w)) MCFG_ISA_OUT_IRQ12_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir4_w)) MCFG_ISA_OUT_IRQ14_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir6_w)) MCFG_ISA_OUT_IRQ15_CB(WRITELINE(APOLLO_PIC2_TAG, pic8259_device, ir7_w)) MCFG_ISA_OUT_DRQ0_CB(WRITELINE(APOLLO_DMA1_TAG, am9517a_device, dreq0_w)) MCFG_ISA_OUT_DRQ1_CB(WRITELINE(APOLLO_DMA1_TAG, am9517a_device, dreq1_w)) MCFG_ISA_OUT_DRQ2_CB(WRITELINE(APOLLO_DMA1_TAG, am9517a_device, dreq2_w)) MCFG_ISA_OUT_DRQ3_CB(WRITELINE(APOLLO_DMA1_TAG, am9517a_device, dreq3_w)) MCFG_ISA_OUT_DRQ5_CB(WRITELINE(APOLLO_DMA2_TAG, am9517a_device, dreq1_w)) MCFG_ISA_OUT_DRQ6_CB(WRITELINE(APOLLO_DMA2_TAG, am9517a_device, dreq2_w)) MCFG_ISA_OUT_DRQ7_CB(WRITELINE(APOLLO_DMA2_TAG, am9517a_device, dreq3_w)) MCFG_DEVICE_ADD("isa1", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, "wdc", false) // FIXME: determine ISA bus clock MCFG_DEVICE_ADD("isa2", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, "ctape", false) MCFG_DEVICE_ADD("isa3", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, "3c505", false) MCFG_DEVICE_ADD("isa4", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, nullptr, false) MCFG_DEVICE_ADD("isa5", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, nullptr, false) MCFG_DEVICE_ADD("isa6", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, nullptr, false) MCFG_DEVICE_ADD("isa7", ISA16_SLOT, 0, APOLLO_ISA_TAG, apollo_isa_cards, nullptr, false) MCFG_SOFTWARE_LIST_ADD("ctape_list", "apollo_ctape") MACHINE_CONFIG_END // for machines with the keyboard and a graphics head MACHINE_CONFIG_START(apollo_state::apollo) common(config); MCFG_APOLLO_SIO_ADD( APOLLO_SIO_TAG, XTAL(3'686'400) ) MCFG_APOLLO_SIO_IRQ_CALLBACK(WRITELINE(*this, apollo_state, sio_irq_handler)) MCFG_APOLLO_SIO_OUTPORT_CALLBACK(WRITE8(*this, apollo_state, sio_output)) MCFG_APOLLO_SIO_A_TX_CALLBACK(WRITELINE(APOLLO_KBD_TAG, apollo_kbd_device, rx_w)) #ifdef APOLLO_XXL MCFG_APOLLO_SIO_B_TX_CALLBACK(WRITELINE(APOLLO_STDIO_TAG, apollo_stdio_device, rx_w)) #endif MACHINE_CONFIG_END static DEVICE_INPUT_DEFAULTS_START( apollo_terminal ) DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 ) DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 ) DEVICE_INPUT_DEFAULTS( "RS232_STARTBITS", 0xff, RS232_STARTBITS_1 ) DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) DEVICE_INPUT_DEFAULTS_END // for headless machines using a serial console MACHINE_CONFIG_START(apollo_state::apollo_terminal) common(config); MCFG_APOLLO_SIO_ADD( APOLLO_SIO_TAG, XTAL(3'686'400) ) MCFG_APOLLO_SIO_IRQ_CALLBACK(WRITELINE(*this, apollo_state, sio_irq_handler)) MCFG_APOLLO_SIO_OUTPORT_CALLBACK(WRITE8(*this, apollo_state, sio_output)) MCFG_APOLLO_SIO_B_TX_CALLBACK(WRITELINE("rs232", rs232_port_device, write_txd)) MCFG_DEVICE_ADD("rs232", RS232_PORT, default_rs232_devices, "terminal") MCFG_RS232_RXD_HANDLER(WRITELINE(APOLLO_SIO_TAG, apollo_sio, rx_b_w)) MCFG_SLOT_OPTION_DEVICE_INPUT_DEFAULTS("terminal", apollo_terminal) MACHINE_CONFIG_END void apollo_state::init_apollo() { MLOG1(("driver_init_apollo")); } MACHINE_START_MEMBER(apollo_state,apollo) { MLOG1(("machine_start_apollo")); if (apollo_is_dn3000()) { //MLOG1(("faking mc146818 interrupts (DN3000 only)")); // fake mc146818 interrupts (DN3000 only) m_dn3000_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(apollo_state::apollo_rtc_timer),this)); } m_dma_channel = -1; m_cur_eop = false; } MACHINE_RESET_MEMBER(apollo_state,apollo) { address_space &space = m_maincpu->space(AS_PROGRAM); uint8_t year = apollo_rtc_r(space, 9); MLOG1(("machine_reset_apollo")); // set configuration apollo_csr_set_servicemode(apollo_config(APOLLO_CONF_SERVICE_MODE)); // change year according to configuration settings if (year < 25 && apollo_config(APOLLO_CONF_25_YEARS_AGO)) { year += 75; apollo_rtc_w(space, 9, year); } else if (year < 20 && apollo_config(APOLLO_CONF_20_YEARS_AGO)) { year += 80; apollo_rtc_w(space, 9, year); } else if (year >= 80 && !apollo_config(APOLLO_CONF_20_YEARS_AGO) && !apollo_config(APOLLO_CONF_25_YEARS_AGO)) { year -= 80; apollo_rtc_w(space, 9, year); } ptm_counter = 0; sio_output_data = 0xff; if (apollo_is_dn3000()) { m_dn3000_timer->adjust(attotime::from_hz(2), 0, attotime::from_hz(2)); } } #ifdef APOLLO_XXL //########################################################################## // machine/apollo_stdio.c - stdio terminal for mess //########################################################################## #undef VERBOSE #define VERBOSE 0 #if defined(__linux__) #include #include #endif /*************************************************************************** IMPLEMENTATION ***************************************************************************/ // device type definition DEFINE_DEVICE_TYPE(APOLLO_STDIO, apollo_stdio_device, "apollo_stdio", "Apollo STDIO") //------------------------------------------------- // apollo_stdio_device - constructor //------------------------------------------------- apollo_stdio_device::apollo_stdio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, APOLLO_STDIO, tag, owner, clock), device_serial_interface(mconfig, *this), m_tx_w(*this) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void apollo_stdio_device::device_start() { CLOG1(("device_start")); m_tx_w.resolve_safe(); m_poll_timer = machine().scheduler().timer_alloc(timer_expired_delegate( FUNC(apollo_stdio_device::poll_timer), this)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void apollo_stdio_device::device_reset() { CLOG1(("device_reset")); // comms is at 8N1, 9600 baud set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1); set_rcv_rate(9600); set_tra_rate(9600); m_tx_busy = false; m_xmit_read = m_xmit_write = 0; #if defined(__linux__) // FIXME: unavailable in mingw // set stdin to nonblocking to allow polling fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); #endif // start timer m_poll_timer->adjust(attotime::zero, 0, attotime::from_msec(1)); // every 1ms } void apollo_stdio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { // FIXME? // device_serial_interface::device_timer(timer, id, param, ptr); } void apollo_stdio_device::rcv_complete() // Rx completed receiving byte { receive_register_extract(); uint8_t data = get_received_char(); // output data to stdout (FIXME: '\r' may confuse ceterm) if (data != '\r') { ::putchar(data); ::fflush(stdout); } CLOG1(("rcv_complete %02x - %c", data, data)); } void apollo_stdio_device::tra_complete() // Tx completed sending byte { // is there more waiting to send? if (m_xmit_read != m_xmit_write) { transmit_register_setup(m_xmitring[m_xmit_read++]); if (m_xmit_read >= XMIT_RING_SIZE) { m_xmit_read = 0; } } else { m_tx_busy = false; } } void apollo_stdio_device::tra_callback() // Tx send bit { int bit = transmit_register_get_data_bit(); m_tx_w(bit); CLOG2(("tra_callback %02x", bit)); } TIMER_CALLBACK_MEMBER(apollo_stdio_device::poll_timer) { #if defined(__linux__) uint8_t data; while (::read(STDIN_FILENO, &data, 1) == 1) { xmit_char(data == '\n' ? '\r' : data); } #endif } void apollo_stdio_device::xmit_char(uint8_t data) { CLOG1(("xmit_char %02x - %c", data, data)); // if tx is busy it'll pick this up automatically when it completes if (!m_tx_busy) { m_tx_busy = true; transmit_register_setup(data); } else { // tx is busy, it'll pick this up next time m_xmitring[m_xmit_write++] = data; if (m_xmit_write >= XMIT_RING_SIZE) { m_xmit_write = 0; } } } #endif