/*************************************************************************** machine.c Functions to emulate general aspects of the machine (RAM, ROM, interrupts, I/O ports) ***************************************************************************/ #include "emu.h" #include "cpu/z80/z80.h" #include "includes/cgenie.h" #include "machine/wd17xx.h" #include "imagedev/cartslot.h" #include "imagedev/cassette.h" #include "sound/dac.h" #include "imagedev/flopdrv.h" #include "machine/ram.h" #define AYWriteReg(chip,port,value) \ m_ay8910->address_w(space, 0,port); \ m_ay8910->data_w(space, 0,value) #define TAPE_HEADER "Colour Genie - Virtual Tape File" #define IRQ_TIMER 0x80 #define IRQ_FDC 0x40 TIMER_CALLBACK_MEMBER(cgenie_state::handle_cassette_input) { UINT8 new_level = ( (m_cassette->input()) > 0.0 ) ? 1 : 0; if ( new_level != m_cass_level ) { m_cass_level = new_level; m_cass_bit ^= 1; } } void cgenie_state::machine_reset() { address_space &space = m_maincpu->space(AS_PROGRAM); UINT8 *ROM = memregion("maincpu")->base(); /* reset the AY8910 to be quiet, since the cgenie BIOS doesn't */ AYWriteReg(0, 0, 0); AYWriteReg(0, 1, 0); AYWriteReg(0, 2, 0); AYWriteReg(0, 3, 0); AYWriteReg(0, 4, 0); AYWriteReg(0, 5, 0); AYWriteReg(0, 6, 0); AYWriteReg(0, 7, 0x3f); AYWriteReg(0, 8, 0); AYWriteReg(0, 9, 0); AYWriteReg(0, 10, 0); /* wipe out color RAM */ memset(&ROM[0x0f000], 0x00, 0x0400); /* wipe out font RAM */ memset(&ROM[0x0f400], 0xff, 0x0400); if( ioport("DSW0")->read() & 0x80 ) { logerror("cgenie floppy discs enabled\n"); } else { logerror("cgenie floppy discs disabled\n"); } /* copy DOS ROM, if enabled or wipe out that memory area */ if( ioport("DSW0")->read() & 0x40 ) { if ( ioport("DSW0")->read() & 0x80 ) { space.install_read_bank(0xc000, 0xdfff, "bank10"); space.nop_write(0xc000, 0xdfff); membank("bank10")->set_base(&ROM[0x0c000]); logerror("cgenie DOS enabled\n"); memcpy(&ROM[0x0c000],&ROM[0x10000], 0x2000); } else { space.nop_readwrite(0xc000, 0xdfff); logerror("cgenie DOS disabled (no floppy image given)\n"); } } else { space.nop_readwrite(0xc000, 0xdfff); logerror("cgenie DOS disabled\n"); memset(&memregion("maincpu")->base()[0x0c000], 0x00, 0x2000); } /* copy EXT ROM, if enabled or wipe out that memory area */ if( ioport("DSW0")->read() & 0x20 ) { space.install_rom(0xe000, 0xefff, 0); // mess 0135u3 need to check logerror("cgenie EXT enabled\n"); memcpy(&memregion("maincpu")->base()[0x0e000], &memregion("maincpu")->base()[0x12000], 0x1000); } else { space.nop_readwrite(0xe000, 0xefff); logerror("cgenie EXT disabled\n"); memset(&memregion("maincpu")->base()[0x0e000], 0x00, 0x1000); } m_cass_level = 0; m_cass_bit = 1; } void cgenie_state::machine_start() { address_space &space = m_maincpu->space(AS_PROGRAM); UINT8 *gfx = memregion("gfx2")->base(); int i; /* initialize static variables */ m_irq_status = 0; m_motor_drive = 0; m_head = 0; m_tv_mode = -1; m_port_ff = 0xff; /* * Every fifth cycle is a wait cycle, so I reduced * the overlocking by one fitfth * Underclocking causes the tape loading to not work. */ // cpunum_set_clockscale(machine(), 0, 0.80); /* Initialize some patterns to be displayed in graphics mode */ for( i = 0; i < 256; i++ ) memset(gfx + i * 8, i, 8); /* set up RAM */ space.install_read_bank(0x4000, 0x4000 + m_ram->size() - 1, "bank1"); space.install_write_handler(0x4000, 0x4000 + m_ram->size() - 1, write8_delegate(FUNC(cgenie_state::cgenie_videoram_w),this)); m_videoram = m_ram->pointer(); membank("bank1")->set_base(m_ram->pointer()); machine().scheduler().timer_pulse(attotime::from_hz(11025), timer_expired_delegate(FUNC(cgenie_state::handle_cassette_input),this)); } /************************************* * * Port handlers. * *************************************/ /* used bits on port FF */ #define FF_CAS 0x01 /* tape output signal */ #define FF_BGD0 0x04 /* background color enable */ #define FF_CHR1 0x08 /* charset 0xc0 - 0xff 1:fixed 0:defined */ #define FF_CHR0 0x10 /* charset 0x80 - 0xbf 1:fixed 0:defined */ #define FF_CHR (FF_CHR0 | FF_CHR1) #define FF_FGR 0x20 /* 1: "hi" resolution graphics, 0: text mode */ #define FF_BGD1 0x40 /* background color select 1 */ #define FF_BGD2 0x80 /* background color select 2 */ #define FF_BGD (FF_BGD0 | FF_BGD1 | FF_BGD2) WRITE8_MEMBER( cgenie_state::cgenie_port_ff_w ) { int port_ff_changed = m_port_ff ^ data; m_cassette->output(data & 0x01 ? -1.0 : 1.0 ); /* background bits changed ? */ if( port_ff_changed & FF_BGD ) { unsigned char r, g, b; if( data & FF_BGD0 ) { r = 112; g = 0; b = 112; } else { if( m_tv_mode == 0 ) { switch( data & (FF_BGD1 + FF_BGD2) ) { case FF_BGD1: r = 112; g = 40; b = 32; break; case FF_BGD2: r = 40; g = 112; b = 32; break; case FF_BGD1 + FF_BGD2: r = 72; g = 72; b = 72; break; default: r = 0; g = 0; b = 0; break; } } else { r = 15; g = 15; b = 15; } } m_palette->set_pen_color(0, r, g, b); } /* character mode changed ? */ if( port_ff_changed & FF_CHR ) { m_font_offset[2] = (data & FF_CHR0) ? 0x00 : 0x80; m_font_offset[3] = (data & FF_CHR1) ? 0x00 : 0x80; } /* graphics mode changed ? */ if( port_ff_changed & FF_FGR ) { cgenie_mode_select(data & FF_FGR); } m_port_ff = data; } READ8_MEMBER( cgenie_state::cgenie_port_ff_r ) { UINT8 data = m_port_ff & ~0x01; data |= m_cass_bit; return data; } int cgenie_state::cgenie_port_xx_r( int offset ) { return 0xff; } /************************************* * * * Memory handlers * * * *************************************/ READ8_MEMBER( cgenie_state::cgenie_psg_port_a_r ) { return m_psg_a_inp; } READ8_MEMBER( cgenie_state::cgenie_psg_port_b_r ) { if( m_psg_a_out < 0xd0 ) { /* comparator value */ m_psg_b_inp = 0x00; if( ioport("JOY0")->read() > m_psg_a_out ) m_psg_b_inp |= 0x80; if( ioport("JOY1")->read() > m_psg_a_out ) m_psg_b_inp |= 0x40; if( ioport("JOY2")->read() > m_psg_a_out ) m_psg_b_inp |= 0x20; if( ioport("JOY3")->read() > m_psg_a_out ) m_psg_b_inp |= 0x10; } else { /* read keypad matrix */ m_psg_b_inp = 0xFF; if( !(m_psg_a_out & 0x01) ) m_psg_b_inp &= ~ioport("KP0")->read(); if( !(m_psg_a_out & 0x02) ) m_psg_b_inp &= ~ioport("KP1")->read(); if( !(m_psg_a_out & 0x04) ) m_psg_b_inp &= ~ioport("KP2")->read(); if( !(m_psg_a_out & 0x08) ) m_psg_b_inp &= ~ioport("KP3")->read(); if( !(m_psg_a_out & 0x10) ) m_psg_b_inp &= ~ioport("KP4")->read(); if( !(m_psg_a_out & 0x20) ) m_psg_b_inp &= ~ioport("KP5")->read(); } return m_psg_b_inp; } WRITE8_MEMBER( cgenie_state::cgenie_psg_port_a_w ) { m_psg_a_out = data; } WRITE8_MEMBER( cgenie_state::cgenie_psg_port_b_w ) { m_psg_b_out = data; } READ8_MEMBER( cgenie_state::cgenie_status_r ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, return 0 */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return 0; return fdc->status_r(space, offset); } READ8_MEMBER( cgenie_state::cgenie_track_r ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, return 0xff */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return 0xff; return fdc->track_r(space, offset); } READ8_MEMBER( cgenie_state::cgenie_sector_r ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, return 0xff */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return 0xff; return fdc->sector_r(space, offset); } READ8_MEMBER( cgenie_state::cgenie_data_r ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, return 0xff */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return 0xff; return fdc->data_r(space, offset); } WRITE8_MEMBER( cgenie_state::cgenie_command_w ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, return immediately */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return; fdc->command_w(space, offset, data); } WRITE8_MEMBER( cgenie_state::cgenie_track_w ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, ignore the write */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return; fdc->track_w(space, offset, data); } WRITE8_MEMBER( cgenie_state::cgenie_sector_w ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, ignore the write */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return; fdc->sector_w(space, offset, data); } WRITE8_MEMBER( cgenie_state::cgenie_data_w ) { fd1793_device *fdc = machine().device("wd179x"); /* If the floppy isn't emulated, ignore the write */ if( (ioport("DSW0")->read() & 0x80) == 0 ) return; fdc->data_w(space, offset, data); } READ8_MEMBER( cgenie_state::cgenie_irq_status_r ) { int result = m_irq_status; m_irq_status &= ~(IRQ_TIMER | IRQ_FDC); return result; } INTERRUPT_GEN_MEMBER(cgenie_state::cgenie_timer_interrupt) { if( (m_irq_status & IRQ_TIMER) == 0 ) { m_irq_status |= IRQ_TIMER; m_maincpu->set_input_line(0, HOLD_LINE); } } WRITE_LINE_MEMBER(cgenie_state::cgenie_fdc_intrq_w) { /* if disc hardware is not enabled, do not cause an int */ if (!( ioport("DSW0")->read() & 0x80 )) return; if (state) { if( (m_irq_status & IRQ_FDC) == 0 ) { m_irq_status |= IRQ_FDC; m_maincpu->set_input_line(0, HOLD_LINE); } } else { m_irq_status &= ~IRQ_FDC; } } const wd17xx_interface cgenie_wd17xx_interface = { DEVCB_NULL, DEVCB_DRIVER_LINE_MEMBER(cgenie_state,cgenie_fdc_intrq_w), DEVCB_NULL, {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} }; WRITE8_MEMBER( cgenie_state::cgenie_motor_w ) { fd1793_device *fdc = machine().device("wd179x"); UINT8 drive = 255; logerror("cgenie motor_w $%02X\n", data); if( data & 1 ) drive = 0; if( data & 2 ) drive = 1; if( data & 4 ) drive = 2; if( data & 8 ) drive = 3; if( drive > 3 ) return; /* mask head select bit */ m_head = (data >> 4) & 1; /* currently selected drive */ m_motor_drive = drive; fdc->set_drive(drive); fdc->set_side(m_head); } /************************************* * Keyboard * *************************************/ READ8_MEMBER( cgenie_state::cgenie_keyboard_r ) { int result = 0; if( offset & 0x01 ) result |= ioport("ROW0")->read(); if( offset & 0x02 ) result |= ioport("ROW1")->read(); if( offset & 0x04 ) result |= ioport("ROW2")->read(); if( offset & 0x08 ) result |= ioport("ROW3")->read(); if( offset & 0x10 ) result |= ioport("ROW4")->read(); if( offset & 0x20 ) result |= ioport("ROW5")->read(); if( offset & 0x40 ) result |= ioport("ROW6")->read(); if( offset & 0x80 ) result |= ioport("ROW7")->read(); return result; } /************************************* * Video RAM * *************************************/ int cgenie_state::cgenie_videoram_r( int offset ) { UINT8 *videoram = m_videoram; return videoram[offset]; } WRITE8_MEMBER( cgenie_state::cgenie_videoram_w ) { UINT8 *videoram = m_videoram; /* write to video RAM */ if( data == videoram[offset] ) return; /* no change */ videoram[offset] = data; } READ8_MEMBER( cgenie_state::cgenie_colorram_r ) { return m_colorram[offset] | 0xf0; } WRITE8_MEMBER( cgenie_state::cgenie_colorram_w ) { /* only bits 0 to 3 */ data &= 15; /* nothing changed ? */ if( data == m_colorram[offset] ) return; /* set new value */ m_colorram[offset] = data; /* make offset relative to video frame buffer offset */ offset = (offset + (cgenie_get_register(12) << 8) + cgenie_get_register(13)) & 0x3ff; } READ8_MEMBER( cgenie_state::cgenie_fontram_r ) { return m_fontram[offset]; } WRITE8_MEMBER( cgenie_state::cgenie_fontram_w ) { UINT8 *dp; if( data == m_fontram[offset] ) return; /* no change */ /* store data */ m_fontram[offset] = data; /* convert eight pixels */ dp = const_cast(m_gfxdecode->gfx(0)->get_data(256 + offset/8) + (offset % 8) * m_gfxdecode->gfx(0)->width()); dp[0] = (data & 0x80) ? 1 : 0; dp[1] = (data & 0x40) ? 1 : 0; dp[2] = (data & 0x20) ? 1 : 0; dp[3] = (data & 0x10) ? 1 : 0; dp[4] = (data & 0x08) ? 1 : 0; dp[5] = (data & 0x04) ? 1 : 0; dp[6] = (data & 0x02) ? 1 : 0; dp[7] = (data & 0x01) ? 1 : 0; } /************************************* * * Interrupt handlers. * *************************************/ INTERRUPT_GEN_MEMBER(cgenie_state::cgenie_frame_interrupt) { if( m_tv_mode != (ioport("DSW0")->read() & 0x10) ) { m_tv_mode = ioport("DSW0")->read() & 0x10; /* force setting of background color */ m_port_ff ^= FF_BGD0; cgenie_port_ff_w(m_maincpu->space(AS_PROGRAM), 0, m_port_ff ^ FF_BGD0); } } READ8_MEMBER(cgenie_state::cgenie_sh_control_port_r) { return m_control_port; } WRITE8_MEMBER(cgenie_state::cgenie_sh_control_port_w) { m_control_port = data; m_ay8910->address_w(space, offset, data); }