diff options
Diffstat (limited to 'src/mess/drivers/vic10.c')
-rw-r--r-- | src/mess/drivers/vic10.c | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/src/mess/drivers/vic10.c b/src/mess/drivers/vic10.c new file mode 100644 index 00000000000..6365cfa2ded --- /dev/null +++ b/src/mess/drivers/vic10.c @@ -0,0 +1,664 @@ +/* + + TODO: + + - memory mapping with PLA + - PLA dump + +*/ + + + +#include "includes/vic10.h" + + + +//************************************************************************** +// INTERRUPTS +//************************************************************************** + +//------------------------------------------------- +// check_interrupts - +//------------------------------------------------- + +void vic10_state::check_interrupts() +{ + m_maincpu->set_input_line(INPUT_LINE_IRQ0, m_cia_irq | m_vic_irq | m_exp_irq); +} + + +//************************************************************************** +// MEMORY MANAGEMENT +//************************************************************************** + +//------------------------------------------------- +// read - +//------------------------------------------------- + +READ8_MEMBER( vic10_state::read ) +{ + // TODO this is really handled by the PLA + + UINT8 data = 0; + int lorom = 1, uprom = 1, exram = 1; + + if (offset < 0x800) + { + data = m_ram->pointer()[offset]; + } + else if (offset < 0x1000) + { + exram = 0; + } + else if (offset >= 0x8000 && offset < 0xa000) + { + lorom = 0; + } + else if (offset >= 0xd000 && offset < 0xd400) + { + data = m_vic->read(space, offset & 0x3f); + } + else if (offset >= 0xd400 && offset < 0xd800) + { + data = sid6581_r(m_sid, offset & 0x1f); + } + else if (offset >= 0xd800 && offset < 0xdc00) + { + data = m_color_ram[offset & 0x3ff]; + } + else if (offset >= 0xdc00 && offset < 0xe000) + { + data = mos6526_r(m_cia, offset & 0x0f); + } + else if (offset >= 0xe000) + { + uprom = 0; + } + + data |= m_exp->cd_r(space, offset, lorom, uprom, exram); + + return data; +} + + +//------------------------------------------------- +// write - +//------------------------------------------------- + +WRITE8_MEMBER( vic10_state::write ) +{ + // TODO this is really handled by the PLA + + int lorom = 1, uprom = 1, exram = 1; + + if (offset < 0x800) + { + m_ram->pointer()[offset] = data; + } + else if (offset < 0x1000) + { + exram = 0; + } + else if (offset >= 0xd000 && offset < 0xd400) + { + m_vic->write(space, offset & 0x3f, data); + } + else if (offset >= 0xd400 && offset < 0xd800) + { + sid6581_w(m_sid, offset & 0x1f, data); + } + else if (offset >= 0xd800 && offset < 0xdc00) + { + m_color_ram[offset & 0x3ff] = data & 0x0f; + } + else if (offset >= 0xdc00 && offset < 0xe000) + { + mos6526_w(m_cia, offset & 0x0f, data); + } + + m_exp->cd_w(space, offset, data, lorom, uprom, exram); +} + + +//------------------------------------------------- +// vic_videoram_r - +//------------------------------------------------- + +READ8_MEMBER( vic10_state::vic_videoram_r ) +{ + address_space *program = m_maincpu->memory().space(AS_PROGRAM); + + if (offset < 0x3000) + return program->read_byte(offset); + + return program->read_byte(0xe000 + (offset & 0x1fff)); +} + + +//------------------------------------------------- +// vic_colorram_r - +//------------------------------------------------- + +READ8_MEMBER( vic10_state::vic_colorram_r ) +{ + return m_color_ram[offset]; +} + + + +//************************************************************************** +// ADDRESS MAPS +//************************************************************************** + +//------------------------------------------------- +// ADDRESS_MAP( vic10_mem ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic10_mem, AS_PROGRAM, 8, vic10_state ) + AM_RANGE(0x0000, 0xffff) AM_READWRITE(read, write) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( vic_videoram_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic_videoram_map, AS_0, 8, vic10_state ) + AM_RANGE(0x0000, 0x3fff) AM_READ(vic_videoram_r) +ADDRESS_MAP_END + + +//------------------------------------------------- +// ADDRESS_MAP( vic_colorram_map ) +//------------------------------------------------- + +static ADDRESS_MAP_START( vic_colorram_map, AS_1, 8, vic10_state ) + AM_RANGE(0x000, 0x3ff) AM_READ(vic_colorram_r) +ADDRESS_MAP_END + + + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +//------------------------------------------------- +// INPUT_PORTS( vic10 ) +//------------------------------------------------- + +static INPUT_PORTS_START( vic10 ) + PORT_INCLUDE( common_cbm_keyboard ) // ROW0 -> ROW7 + + PORT_INCLUDE( c64_special ) // SPECIAL + + PORT_INCLUDE( c64_controls ) // CTRLSEL, JOY0, JOY1, PADDLE0 -> PADDLE3, TRACKX, TRACKY, LIGHTX, LIGHTY, OTHER +INPUT_PORTS_END + + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +//------------------------------------------------- +// vic2_interface vic_intf +//------------------------------------------------- + +static INTERRUPT_GEN( vic10_frame_interrupt ) +{ + cbm_common_interrupt(device); +} + +READ8_MEMBER( vic10_state::vic_lightpen_x_cb ) +{ + return ioport("LIGHTX")->read() & ~0x01; +} + +READ8_MEMBER( vic10_state::vic_lightpen_y_cb ) +{ + return ioport("LIGHTY")->read() & ~0x01; +} + +READ8_MEMBER( vic10_state::vic_lightpen_button_cb ) +{ + return ioport("OTHER")->read() & 0x04; +} + +WRITE_LINE_MEMBER( vic10_state::vic_irq_w ) +{ + m_vic_irq = state; + + check_interrupts(); +} + +READ8_MEMBER( vic10_state::vic_rdy_cb ) +{ + return ioport("CYCLES")->read() & 0x07; +} + +static MOS6566_INTERFACE( vic_intf ) +{ + SCREEN_TAG, + M6510_TAG, + DEVCB_DRIVER_LINE_MEMBER(vic10_state, vic_irq_w), + DEVCB_NULL, + DEVCB_DRIVER_MEMBER(vic10_state, vic_lightpen_x_cb), + DEVCB_DRIVER_MEMBER(vic10_state, vic_lightpen_y_cb), + DEVCB_DRIVER_MEMBER(vic10_state, vic_lightpen_button_cb), + DEVCB_DRIVER_MEMBER(vic10_state, vic_rdy_cb) +}; + + +//------------------------------------------------- +// sid6581_interface sid_intf +//------------------------------------------------- + +static int vic10_paddle_read( device_t *device, int which ) +{ + running_machine &machine = device->machine(); + vic10_state *state = device->machine().driver_data<vic10_state>(); + + int pot1 = 0xff, pot2 = 0xff, pot3 = 0xff, pot4 = 0xff, temp; + UINT8 cia0porta = mos6526_pa_r(state->m_cia, 0); + int controller1 = machine.root_device().ioport("CTRLSEL")->read() & 0x07; + int controller2 = machine.root_device().ioport("CTRLSEL")->read() & 0x70; + // Notice that only a single input is defined for Mouse & Lightpen in both ports + switch (controller1) + { + case 0x01: + if (which) + pot2 = machine.root_device().ioport("PADDLE2")->read(); + else + pot1 = machine.root_device().ioport("PADDLE1")->read(); + break; + + case 0x02: + if (which) + pot2 = machine.root_device().ioport("TRACKY")->read(); + else + pot1 = machine.root_device().ioport("TRACKX")->read(); + break; + + case 0x03: + if (which && (machine.root_device().ioport("JOY1_2B")->read() & 0x20)) // Joy1 Button 2 + pot1 = 0x00; + break; + + case 0x04: + if (which) + pot2 = machine.root_device().ioport("LIGHTY")->read(); + else + pot1 = machine.root_device().ioport("LIGHTX")->read(); + break; + + case 0x06: + if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) // Lightpen Signal + pot2 = 0x00; + break; + + case 0x00: + case 0x07: + break; + + default: + logerror("Invalid Controller Setting %d\n", controller1); + break; + } + + switch (controller2) + { + case 0x10: + if (which) + pot4 = machine.root_device().ioport("PADDLE4")->read(); + else + pot3 = machine.root_device().ioport("PADDLE3")->read(); + break; + + case 0x20: + if (which) + pot4 = machine.root_device().ioport("TRACKY")->read(); + else + pot3 = machine.root_device().ioport("TRACKX")->read(); + break; + + case 0x30: + if (which && (machine.root_device().ioport("JOY2_2B")->read() & 0x20)) // Joy2 Button 2 + pot4 = 0x00; + break; + + case 0x40: + if (which) + pot4 = machine.root_device().ioport("LIGHTY")->read(); + else + pot3 = machine.root_device().ioport("LIGHTX")->read(); + break; + + case 0x60: + if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) // Lightpen Signal + pot4 = 0x00; + break; + + case 0x00: + case 0x70: + break; + + default: + logerror("Invalid Controller Setting %d\n", controller1); + break; + } + + if (machine.root_device().ioport("CTRLSEL")->read() & 0x80) // Swap + { + temp = pot1; pot1 = pot3; pot3 = temp; + temp = pot2; pot2 = pot4; pot4 = temp; + } + + switch (cia0porta & 0xc0) + { + case 0x40: + return which ? pot2 : pot1; + + case 0x80: + return which ? pot4 : pot3; + + case 0xc0: + return which ? pot2 : pot1; + + default: + return 0; + } +} + +static const sid6581_interface sid_intf = +{ + vic10_paddle_read +}; + + +//------------------------------------------------- +// mos6526_interface cia_intf +//------------------------------------------------- + +WRITE_LINE_MEMBER( vic10_state::cia_irq_w ) +{ + m_cia_irq = state; + + check_interrupts(); +} + +READ8_MEMBER( vic10_state::cia_pa_r ) +{ + /* + + bit description + + PA0 COL0, JOY B0 + PA1 COL1, JOY B1 + PA2 COL2, JOY B2 + PA3 COL3, JOY B3 + PA4 COL4, BTNB + PA5 COL5 + PA6 COL6 + PA7 COL7 + + */ + + UINT8 cia0portb = mos6526_pb_r(m_cia, 0); + + return cbm_common_cia0_port_a_r(m_cia, cia0portb); +} + +READ8_MEMBER( vic10_state::cia_pb_r ) +{ + /* + + bit description + + PB0 JOY A0 + PB1 JOY A1 + PB2 JOY A2 + PB3 JOY A3 + PB4 BTNA/_LP + PB5 + PB6 + PB7 + + */ + + UINT8 cia0porta = mos6526_pa_r(m_cia, 0); + + return cbm_common_cia0_port_b_r(m_cia, cia0porta); +} + +WRITE8_MEMBER( vic10_state::cia_pb_w ) +{ + /* + + bit description + + PB0 ROW0 + PB1 ROW1 + PB2 ROW2 + PB3 ROW3 + PB4 ROW4 + PB5 ROW5 + PB6 ROW6 + PB7 ROW7 + + */ + + m_vic->lp_w(BIT(data, 4)); +} + +static const mos6526_interface cia_intf = +{ + 10, + DEVCB_DRIVER_LINE_MEMBER(vic10_state, cia_irq_w), + DEVCB_NULL, + DEVCB_DEVICE_LINE_MEMBER(VIC10_EXPANSION_SLOT_TAG, vic10_expansion_slot_device, sp_w), + DEVCB_DEVICE_LINE_MEMBER(VIC10_EXPANSION_SLOT_TAG, vic10_expansion_slot_device, cnt_w), + DEVCB_DRIVER_MEMBER(vic10_state, cia_pa_r), + DEVCB_NULL, + DEVCB_DRIVER_MEMBER(vic10_state, cia_pb_r), + DEVCB_DRIVER_MEMBER(vic10_state, cia_pb_w) +}; + + +//------------------------------------------------- +// m6502_interface cpu_intf +//------------------------------------------------- + +READ8_MEMBER( vic10_state::cpu_r ) +{ + /* + + bit description + + P0 EXPANSION PORT + P1 1 + P2 1 + P3 + P4 CASS SENS + P5 + + */ + + UINT8 data = 0x06; + + data |= m_exp->p0_r(); + + data |= ((m_cassette->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED) << 4; + + return data; +} + +WRITE8_MEMBER( vic10_state::cpu_w ) +{ + /* + + bit description + + P0 EXPANSION PORT + P1 + P2 + P3 CASS WRT + P4 + P5 CASS MOTOR + + */ + + if (BIT(offset, 0)) + { + m_exp->p0_w(BIT(data, 0)); + } + + // cassette write + m_cassette->output(BIT(data, 3) ? -(0x5a9e >> 1) : +(0x5a9e >> 1)); + + // cassette motor + if (!BIT(data, 5)) + { + m_cassette->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR); + m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(44100)); + } + else + { + m_cassette->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); + m_cassette_timer->reset(); + } +} + +static const m6502_interface cpu_intf = +{ + NULL, + NULL, + DEVCB_DRIVER_MEMBER(vic10_state, cpu_r), + DEVCB_DRIVER_MEMBER(vic10_state, cpu_w) +}; + + +//------------------------------------------------- +// TIMER_DEVICE_CALLBACK( cassette_tick ) +//------------------------------------------------- + +static TIMER_DEVICE_CALLBACK( cassette_tick ) +{ + vic10_state *state = timer.machine().driver_data<vic10_state>(); + + mos6526_flag_w(state->m_cia, state->m_cassette->input() > +0.0); +} + + +//------------------------------------------------- +// C64_EXPANSION_INTERFACE( expansion_intf ) +//------------------------------------------------- + +WRITE_LINE_MEMBER( vic10_state::exp_irq_w ) +{ + m_exp_irq = state; + + check_interrupts(); +} + +static VIC10_EXPANSION_INTERFACE( expansion_intf ) +{ + DEVCB_DRIVER_LINE_MEMBER(vic10_state, exp_irq_w), + DEVCB_DEVICE_LINE(MOS6526_TAG, mos6526_sp_w), + DEVCB_DEVICE_LINE(MOS6526_TAG, mos6526_cnt_w), + DEVCB_CPU_INPUT_LINE(M6510_TAG, INPUT_LINE_RESET) +}; + + + +//************************************************************************** +// MACHINE INITIALIZATION +//************************************************************************** + +//------------------------------------------------- +// MACHINE_START( vic10 ) +//------------------------------------------------- + +void vic10_state::machine_start() +{ + // allocate memory + m_color_ram = auto_alloc_array(machine(), UINT8, 0x400); + + // state saving + save_item(NAME(m_cia_irq)); + save_item(NAME(m_vic_irq)); + save_item(NAME(m_exp_irq)); +} + + +//------------------------------------------------- +// MACHINE_RESET( vic10 ) +//------------------------------------------------- + +void vic10_state::machine_reset() +{ + m_maincpu->reset(); + + m_exp->reset(); +} + + + +//************************************************************************** +// MACHINE DRIVERS +//************************************************************************** + +//------------------------------------------------- +// MACHINE_CONFIG( vic10 ) +//------------------------------------------------- + +static MACHINE_CONFIG_START( vic10, vic10_state ) + // basic hardware + MCFG_CPU_ADD(M6510_TAG, M6510, VIC6566_CLOCK) + MCFG_CPU_PROGRAM_MAP(vic10_mem) + MCFG_CPU_CONFIG(cpu_intf) + MCFG_CPU_VBLANK_INT(SCREEN_TAG, vic10_frame_interrupt) + MCFG_QUANTUM_PERFECT_CPU(M6510_TAG) + + // video hardware + MCFG_MOS6566_ADD(MOS6566_TAG, SCREEN_TAG, VIC6566_CLOCK, vic_intf, vic_videoram_map, vic_colorram_map) + + // sound hardware + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_ADD(MOS6581_TAG, SID6581, VIC6566_CLOCK) + MCFG_SOUND_CONFIG(sid_intf) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + // devices + MCFG_MOS6526R1_ADD(MOS6526_TAG, VIC6566_CLOCK, cia_intf) + MCFG_CASSETTE_ADD(CASSETTE_TAG, cbm_cassette_interface) + MCFG_TIMER_ADD(TIMER_C1531_TAG, cassette_tick) + MCFG_VIC10_EXPANSION_SLOT_ADD(VIC10_EXPANSION_SLOT_TAG, expansion_intf, vic10_expansion_cards, NULL, NULL) + + // software list + MCFG_SOFTWARE_LIST_ADD("cart_list", "vic10") + + // internal ram + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("4K") +MACHINE_CONFIG_END + + + +//************************************************************************** +// ROM DEFINITIONS +//************************************************************************** + +ROM_START( vic10 ) + ROM_REGION( 0x100, "pla", 0 ) + ROM_LOAD( "6703.u4", 0x000, 0x100, NO_DUMP ) +ROM_END + + + +//************************************************************************** +// GAME DRIVERS +//************************************************************************** + +COMP( 1982, vic10, 0, 0, vic10, vic10, driver_device, 0, "Commodore Business Machines", "VIC-10 / Max Machine / UltiMax (NTSC)", GAME_NOT_WORKING ) |