// license:BSD-3-Clause
// copyright-holders:Krzysztof Strzecha, Nathan Woods
/***************************************************************************
machine/dai.c
Functions to emulate general aspects of DAI (RAM, ROM, interrupts, I/O ports)
Krzysztof Strzecha
Nathan Woods
***************************************************************************/
#include "emu.h"
#include "includes/dai.h"
#define DEBUG_DAI_PORTS 0
#define LOG_DAI_PORT_R(_port, _data, _comment) do { if (DEBUG_DAI_PORTS) logerror ("DAI port read : %04x, Data: %02x (%s)\n", _port, _data, _comment); } while (0)
#define LOG_DAI_PORT_W(_port, _data, _comment) do { if (DEBUG_DAI_PORTS) logerror ("DAI port write: %04x, Data: %02x (%s)\n", _port, _data, _comment); } while (0)
void dai_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_TMS5501:
m_tms5501->xi7_w(BIT(m_io_keyboard[8]->read(), 2));
timer_set(attotime::from_hz(100), TIMER_TMS5501);
break;
default:
throw emu_fatalerror("Unknown id in dai_state::device_timer");
}
}
/* Discrete I/O devices */
/* Memory */
void dai_state::stack_interrupt_circuit_w(uint8_t data)
{
m_tms5501->sens_w(1);
m_tms5501->sens_w(0);
}
uint8_t dai_state::keyboard_r()
{
uint8_t data = 0x00;
for (u8 i = 0; i < 8; i++)
if (m_keyboard_scan_mask & (1 << i))
data |= m_io_keyboard[i]->read();
return data;
}
void dai_state::keyboard_w(uint8_t data)
{
m_keyboard_scan_mask = data;
}
IRQ_CALLBACK_MEMBER(dai_state::int_ack)
{
return m_tms5501->get_vector();
}
void dai_state::machine_start()
{
membank("bank2")->configure_entries(0, 4, m_rom + 0x2000, 0x1000);
timer_set(attotime::from_hz(100), TIMER_TMS5501);
save_item(NAME(m_paddle_select));
save_item(NAME(m_paddle_enable));
save_item(NAME(m_cassette_motor));
save_item(NAME(m_keyboard_scan_mask));
save_item(NAME(m_4_colours_palette));
}
void dai_state::machine_reset()
{
address_space &program = m_maincpu->space(AS_PROGRAM);
program.install_rom(0x0000, 0x07ff, m_rom); // do it here for F3
m_rom_shadow_tap = program.install_read_tap(0xc000, 0xc7ff, "rom_shadow_r",[this](offs_t offset, u8 &data, u8 mem_mask)
{
if (!machine().side_effects_disabled())
{
// delete this tap
m_rom_shadow_tap->remove();
// reinstall ram over the rom shadow
m_maincpu->space(AS_PROGRAM).install_ram(0x0000, 0x07ff, m_ram);
}
// return the original data
return data;
});
}
/***************************************************************************
Discrete Devices IO
FD00 POR1: IN bit 0 -
bit 1 -
bit 2 PIPGE: Page signal
bit 3 PIDTR: Serial output ready
bit 4 PIBU1: Button on paddle 1 (1 = closed)
bit 5 PIBU1: Button on paddle 2 (1 = closed)
bit 6 PIRPI: Random data
bit 7 PICAI: Cassette input data
FD01 PDLST: IN Single pulse used to trigger paddle timer circuit
FD04 POR1: OUT bit 0-3 Volume oscillator channel 0
bit 4-7 Volume oscillator channel 1
FD05 POR1: OUT bit 0-3 Volume oscillator channel 2
bit 4-7 Volume random noise generator
FD06 POR0: OUT bit 0 POCAS: Cassette data output
bit 1-2 PDLMSK: Paddle select
bit 3 PDPNA: Paddle enable
bit 4 POCM1: Cassette 1 motor control (0 = run)
bit 5 POCM2: Cassette 2 motor control (0 = run)
bit 6-7 ROM bank switching
***************************************************************************/
uint8_t dai_state::io_discrete_devices_r(offs_t offset)
{
uint8_t data = 0xff;
switch(offset & 0x0f) {
case 0:
data = m_io_keyboard[8]->read();
data |= 0x08; // serial ready
if (machine().rand()&0x01)
data |= 0x40; // random number generator
if (m_cassette->input() > 0.01)
data |= 0x80; // tape input
break;
default:
LOG_DAI_PORT_R (offset, data, "discrete devices - unmapped");
break;
}
return data;
}
void dai_state::io_discrete_devices_w(offs_t offset, uint8_t data)
{
switch(offset & 0x000f) {
case 0x04:
m_sound->set_volume(offset, data);
LOG_DAI_PORT_W (offset, data&0x0f, "discrete devices - osc. 0 volume");
LOG_DAI_PORT_W (offset, BIT(data, 4, 4), "discrete devices - osc. 1 volume");
break;
case 0x05:
m_sound->set_volume(offset, data);
LOG_DAI_PORT_W (offset, data&0x0f, "discrete devices - osc. 2 volume");
LOG_DAI_PORT_W (offset, BIT(data, 4, 4), "discrete devices - noise volume");
break;
case 0x06:
m_paddle_select = BIT(data, 1, 2);
m_paddle_enable = BIT(data, 3);
m_cassette_motor[0] = BIT(data, 4);
m_cassette_motor[1] = BIT(data, 5);
m_cassette->change_state(m_cassette_motor[0]?CASSETTE_MOTOR_DISABLED:CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
m_cassette->output(BIT(data, 0) ? -1.0 : 1.0);
membank("bank2")->set_entry(BIT(data, 6, 2));
LOG_DAI_PORT_W (offset, BIT(data, 1, 2), "discrete devices - paddle select");
LOG_DAI_PORT_W (offset, BIT(data, 3), "discrete devices - paddle enable");
LOG_DAI_PORT_W (offset, BIT(data, 4), "discrete devices - cassette motor 1");
LOG_DAI_PORT_W (offset, BIT(data, 5), "discrete devices - cassette motor 2");
LOG_DAI_PORT_W (offset, BIT(data, 6, 2), "discrete devices - ROM bank");
break;
default:
LOG_DAI_PORT_W (offset, data, "discrete devices - unmapped");
break;
}
}
/***************************************************************************
PIT8253
Offset need to be shifted by 1 to right, because the PIT is
connected to A1 and A2
***************************************************************************/
uint8_t dai_state::pit_r(offs_t offset)
{
return m_pit->read(BIT(offset, 1, 2));
}
void dai_state::pit_w(offs_t offset, uint8_t data)
{
m_pit->write(BIT(offset, 1, 2), data);
}
/***************************************************************************
AMD 9911 mathematical coprocesor
***************************************************************************/
uint8_t dai_state::amd9511_r()
{
/* optional and not present at this moment */
return 0xff;
}
void dai_state::amd9511_w(offs_t offset, uint8_t data)
{
logerror ("Writing to AMD9511 math chip, %04x, %02x\n", offset, data);
}