summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/kc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/kc.c')
-rw-r--r--src/mame/machine/kc.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/src/mame/machine/kc.c b/src/mame/machine/kc.c
new file mode 100644
index 00000000000..ad707f9dbc6
--- /dev/null
+++ b/src/mame/machine/kc.c
@@ -0,0 +1,788 @@
+// license:GPL-2.0+
+// copyright-holders:Kevin Thacker,Sandro Ronco
+/* Core includes */
+#include "emu.h"
+#include "includes/kc.h"
+
+#define KC_DEBUG 0
+#define LOG(x) do { if (KC_DEBUG) logerror x; } while (0)
+
+struct kcc_header
+{
+ UINT8 name[10];
+ UINT8 reserved[6];
+ UINT8 number_addresses;
+ UINT8 load_address_l;
+ UINT8 load_address_h;
+ UINT8 end_address_l;
+ UINT8 end_address_h;
+ UINT8 execution_address_l;
+ UINT8 execution_address_h;
+ UINT8 pad[128-2-2-2-1-16];
+};
+
+/* appears to work a bit.. */
+/* load file, then type: MENU and it should now be displayed. */
+/* now type name that has appeared! */
+
+/* load snapshot */
+QUICKLOAD_LOAD_MEMBER( kc_state,kc)
+{
+ struct kcc_header *header;
+ UINT16 addr;
+ UINT16 datasize;
+ UINT16 execution_address;
+ UINT16 i;
+
+ /* get file size */
+ UINT64 size = image.length();
+
+ if (size == 0)
+ return IMAGE_INIT_FAIL;
+
+ dynamic_buffer data(size);
+ image.fread( &data[0], size);
+
+ header = (struct kcc_header *) &data[0];
+ addr = (header->load_address_l & 0x0ff) | ((header->load_address_h & 0x0ff)<<8);
+ datasize = ((header->end_address_l & 0x0ff) | ((header->end_address_h & 0x0ff)<<8)) - addr;
+ execution_address = (header->execution_address_l & 0x0ff) | ((header->execution_address_h & 0x0ff)<<8);
+
+ if (datasize > size - 128)
+ {
+ osd_printf_info("Invalid snapshot size: expected 0x%04x, found 0x%04x\n", datasize, (UINT32)size - 128);
+ datasize = size - 128;
+ }
+
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ for (i=0; i<datasize; i++)
+ space.write_byte((addr+i) & 0xffff, data[i+128]);
+
+ if (execution_address != 0 && header->number_addresses >= 3 )
+ {
+ // if specified, jumps to the quickload start address
+ m_maincpu->set_pc(execution_address);
+ }
+
+ logerror("Snapshot loaded at: 0x%04x-0x%04x, execution address: 0x%04x\n", addr, addr + datasize - 1, execution_address);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//**************************************************************************
+// MODULE SYSTEM EMULATION
+//**************************************************************************
+
+// The KC85/4 and KC85/3 are "modular systems". These computers can be expanded with modules.
+
+READ8_MEMBER( kc_state::expansion_read )
+{
+ UINT8 result = 0xff;
+
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ for (int i=0; i<3; i++)
+ m_expansions[i]->read(offset, result);
+
+ return result;
+}
+
+WRITE8_MEMBER( kc_state::expansion_write )
+{
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ for (int i=0; i<3; i++)
+ m_expansions[i]->write(offset, data);
+}
+
+/*
+ port xx80
+
+ - xx is module id.
+
+ Only addressess divisible by 4 are checked.
+ If module does not exist, 0x0ff is returned.
+
+ When xx80 is read, if a module exists a id will be returned.
+ Id's for known modules are listed above.
+*/
+
+READ8_MEMBER( kc_state::expansion_io_read )
+{
+ UINT8 result = 0xff;
+
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ if ((offset & 0xff) == 0x80)
+ {
+ UINT8 slot_id = (offset>>8) & 0xff;
+
+ if (slot_id == 0x08 || slot_id == 0x0c)
+ result = m_expansions[(slot_id - 8) >> 2]->module_id_r();
+ else
+ m_expansions[2]->io_read(offset, result);
+ }
+ else
+ {
+ for (int i=0; i<3; i++)
+ m_expansions[i]->io_read(offset, result);
+ }
+
+ return result;
+}
+
+WRITE8_MEMBER( kc_state::expansion_io_write )
+{
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ if ((offset & 0xff) == 0x80)
+ {
+ UINT8 slot_id = (offset>>8) & 0xff;
+
+ if (slot_id == 0x08 || slot_id == 0x0c)
+ m_expansions[(slot_id - 8) >> 2]->control_w(data);
+ else
+ m_expansions[2]->io_write(offset, data);
+ }
+ else
+ {
+ for (int i=0; i<3; i++)
+ m_expansions[i]->io_write(offset, data);
+ }
+}
+
+// module read/write handlers
+READ8_MEMBER ( kc_state::expansion_4000_r ){ return expansion_read(space, offset + 0x4000); }
+WRITE8_MEMBER( kc_state::expansion_4000_w ){ expansion_write(space, offset + 0x4000, data); }
+READ8_MEMBER ( kc_state::expansion_8000_r ){ return expansion_read(space, offset + 0x8000); }
+WRITE8_MEMBER( kc_state::expansion_8000_w ){ expansion_write(space, offset + 0x8000, data); }
+READ8_MEMBER ( kc_state::expansion_c000_r ){ return expansion_read(space, offset + 0xc000); }
+WRITE8_MEMBER( kc_state::expansion_c000_w ){ expansion_write(space, offset + 0xc000, data); }
+READ8_MEMBER ( kc_state::expansion_e000_r ){ return expansion_read(space, offset + 0xe000); }
+WRITE8_MEMBER( kc_state::expansion_e000_w ){ expansion_write(space, offset + 0xe000, data); }
+
+
+//**************************************************************************
+// CASSETTE EMULATION
+//**************************************************************************
+
+/*
+ The cassette motor is controlled by bit 6 of PIO port A.
+ The cassette read data is connected to /ASTB input of the PIO.
+ A edge from the cassette therefore will trigger a interrupt
+ from the PIO.
+ The duration between two edges can be timed and the data-bit
+ identified.
+
+ I have used a timer to feed data into /ASTB. The timer is only
+ active when the cassette motor is on.
+*/
+
+void kc_state::update_cassette(int state)
+{
+ int astb = (state & m_ardy) ? 0 : 1;
+
+ // if state is changed updates the /ASTB line
+ if (m_astb ^ astb)
+ {
+ m_z80pio->strobe_a(astb);
+
+ m_astb = astb;
+
+ // FIXME: temporary for allow kc85_2-3 to load cassette
+ if ((m_cassette->get_state() & 0x03) == CASSETTE_PLAY)
+ m_z80pio->data_write(0, m_pio_data[0]);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(kc_state::kc_cassette_oneshot_timer)
+{
+ update_cassette(0);
+
+ m_cassette_oneshot_timer->reset();
+}
+
+// timer used for polling data from cassette input
+// enabled only when cassette motor is on
+TIMER_CALLBACK_MEMBER(kc_state::kc_cassette_timer_callback)
+{
+ // read cassette data
+ int bit = (m_cassette->input() > 0.0038) ? 1 : 0;
+
+ // generates a pulse when the cassette input changes state
+ if (bit ^ m_cassette_in)
+ {
+ update_cassette(1);
+ m_cassette_in = bit;
+ m_cassette_oneshot_timer->adjust(attotime::from_double(TIME_OF_74LS123(RES_K(10), CAP_N(1))));
+ }
+}
+
+void kc_state::cassette_set_motor(int motor_state)
+{
+ /* set new motor state in cassette device */
+ m_cassette->change_state(motor_state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ if (motor_state)
+ {
+ /* start timer */
+ m_cassette_timer->adjust(attotime::zero, 0, KC_CASSETTE_TIMER_FREQUENCY);
+ }
+ else
+ {
+ /* stop timer */
+ m_cassette_timer->reset();
+ }
+}
+
+/*
+ pin 2 = gnd
+ pin 3 = read
+ pin 1 = k1 ?? modulating signal
+ pin 4 = k0 ?? signal??
+ pin 5 = motor on
+
+
+ Tape signals:
+ K0, K1 ??
+ MOTON motor control
+ ASTB read?
+
+ T1-T4 give 4 bit a/d tone sound?
+ K1, K0 are mixed with tone.
+
+ Cassette read goes into ASTB of PIO.
+ From this, KC must be able to detect the length
+ of the pulses and can read the data.
+
+
+ Tape write: clock comes from CTC?
+ truck signal resets, 5v signal for set.
+ output gives k0 and k1.
+
+*/
+
+
+
+//**************************************************************************
+// KC85 bankswitch
+//**************************************************************************
+
+/* update status of memory area 0x0000-0x03fff */
+void kc_state::update_0x00000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ /* access ram? */
+ if (m_pio_data[0] & (1<<1))
+ {
+ LOG(("ram0 enabled\n"));
+
+ /* yes; set address of bank */
+ space.install_read_bank(0x0000, 0x3fff, "bank1");
+ membank("bank1")->set_base(m_ram_base);
+
+ /* write protect ram? */
+ if ((m_pio_data[0] & (1<<3)) == 0)
+ {
+ /* yes */
+ LOG(("ram0 write protected\n"));
+
+ /* ram is enabled and write protected */
+ space.unmap_write(0x0000, 0x3fff);
+ }
+ else
+ {
+ LOG(("ram0 write enabled\n"));
+
+ /* ram is enabled and write enabled */
+ space.install_write_bank(0x0000, 0x3fff, "bank1");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x0000\n"));
+
+ space.install_read_handler (0x0000, 0x3fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_read), this), 0);
+ space.install_write_handler(0x0000, 0x3fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_write), this), 0);
+ }
+}
+
+/* update status of memory area 0x4000-0x07fff */
+void kc_state::update_0x04000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ LOG(("Module at 0x4000\n"));
+
+ space.install_read_handler (0x4000, 0x7fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_4000_r), this), 0);
+ space.install_write_handler(0x4000, 0x7fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_4000_w), this), 0);
+
+}
+
+
+/* update memory address 0x0c000-0x0e000 */
+void kc_state::update_0x0c000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ if ((m_pio_data[0] & (1<<7)) && memregion("basic")->base() != NULL)
+ {
+ /* BASIC takes next priority */
+ LOG(("BASIC rom 0x0c000\n"));
+
+ membank("bank4")->set_base(memregion("basic")->base());
+ space.install_read_bank(0xc000, 0xdfff, "bank4");
+ space.unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ LOG(("Module at 0x0c000\n"));
+
+ space.install_read_handler (0xc000, 0xdfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_c000_r), this), 0);
+ space.install_write_handler(0xc000, 0xdfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_c000_w), this), 0);
+ }
+}
+
+/* update memory address 0x0e000-0x0ffff */
+void kc_state::update_0x0e000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<0))
+ {
+ /* enable CAOS rom in memory range 0x0e000-0x0ffff */
+ LOG(("CAOS rom 0x0e000\n"));
+ /* read will access the rom */
+ membank("bank5")->set_base(memregion("caos")->base() + 0x2000);
+ space.install_read_bank(0xe000, 0xffff, "bank5");
+ space.unmap_write(0xe000, 0xffff);
+ }
+ else
+ {
+ LOG(("Module at 0x0e000\n"));
+
+ space.install_read_handler (0xe000, 0xffff, 0, 0, read8_delegate(FUNC(kc_state::expansion_e000_r), this), 0);
+ space.install_write_handler(0xe000, 0xffff, 0, 0, write8_delegate(FUNC(kc_state::expansion_e000_w), this), 0);
+ }
+}
+
+
+/* update status of memory area 0x08000-0x0ffff */
+void kc_state::update_0x08000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<2))
+ {
+ /* IRM enabled */
+ LOG(("IRM enabled\n"));
+
+ membank("bank3")->set_base(m_video_ram);
+ space.install_readwrite_bank(0x8000, 0xbfff, "bank3");
+ }
+ else
+ {
+ LOG(("Module at 0x8000!\n"));
+
+ space.install_read_handler(0x8000, 0xbfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_8000_r), this), 0);
+ space.install_write_handler(0x8000, 0xbfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_8000_w), this), 0);
+ }
+}
+
+
+/* update status of memory area 0x4000-0x07fff */
+void kc85_4_state::update_0x04000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ /* access ram? */
+ if (m_port_86_data & (1<<0))
+ {
+ LOG(("RAM4 enabled\n"));
+
+ /* yes */
+ space.install_read_bank(0x4000, 0x7fff, "bank2");
+ /* set address of bank */
+ membank("bank2")->set_base(m_ram_base + 0x4000);
+
+ /* write protect ram? */
+ if ((m_port_86_data & (1<<1)) == 0)
+ {
+ /* yes */
+ LOG(("ram4 write protected\n"));
+
+ /* ram is enabled and write protected */
+ space.nop_write(0x4000, 0x7fff);
+ }
+ else
+ {
+ LOG(("ram4 write enabled\n"));
+
+ /* ram is enabled and write enabled */
+ space.install_write_bank(0x4000, 0x7fff, "bank2");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x4000\n"));
+
+ space.install_read_handler (0x4000, 0x7fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_4000_r), this), 0);
+ space.install_write_handler(0x4000, 0x7fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_4000_w), this), 0);
+ }
+
+}
+
+/* update memory address 0x0c000-0x0e000 */
+void kc85_4_state::update_0x0c000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ if (m_port_86_data & (1<<7))
+ {
+ /* CAOS rom takes priority */
+ LOG(("CAOS rom 0x0c000\n"));
+
+ membank("bank4")->set_base(memregion("caos")->base());
+ space.install_read_bank(0xc000, 0xdfff, "bank4");
+ space.unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ if (m_pio_data[0] & (1<<7))
+ {
+ /* BASIC takes next priority */
+ LOG(("BASIC rom 0x0c000\n"));
+
+ int bank = memregion("basic")->bytes() == 0x8000 ? (m_port_86_data>>5) & 0x03 : 0;
+
+ membank("bank4")->set_base(memregion("basic")->base() + (bank << 13));
+ space.install_read_bank(0xc000, 0xdfff, "bank4");
+ space.unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ LOG(("Module at 0x0c000\n"));
+
+ space.install_read_handler (0xc000, 0xdfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_c000_r), this), 0);
+ space.install_write_handler(0xc000, 0xdfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_c000_w), this), 0);
+ }
+ }
+}
+
+void kc85_4_state::update_0x08000()
+{
+ address_space &space = m_maincpu->space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<2))
+ {
+ /* IRM enabled - has priority over RAM8 enabled */
+ LOG(("IRM enabled\n"));
+
+ UINT8* ram_page = m_video_ram + ((BIT(m_port_84_data, 2)<<15) | (BIT(m_port_84_data, 1)<<14));
+
+ membank("bank3")->set_base(ram_page);
+ space.install_readwrite_bank(0x8000, 0xa7ff, "bank3");
+
+ membank("bank6")->set_base(m_video_ram + 0x2800);
+ space.install_readwrite_bank(0xa800, 0xbfff, "bank6");
+ }
+ else if (m_pio_data[1] & (1<<5))
+ {
+ LOG(("RAM8 enabled\n"));
+
+ int ram8_block;
+ UINT8 *mem_ptr;
+
+ /* ram8 block chosen */
+
+ if (m_ram->size() == 64 * 1024)
+ {
+ // kc85_4 64K RAM
+ ram8_block = ((m_port_84_data)>>4) & 0x01;
+ mem_ptr = m_ram_base + 0x8000 + (ram8_block<<14);
+ }
+ else
+ {
+ // kc85_5 256K RAM
+ ram8_block = ((m_port_84_data)>>4) & 0x0f;
+ mem_ptr = m_ram_base + (ram8_block<<14);
+ }
+
+ membank("bank3")->set_base(mem_ptr);
+ membank("bank6")->set_base(mem_ptr + 0x2800);
+ space.install_read_bank(0x8000, 0xa7ff, "bank3");
+ space.install_read_bank(0xa800, 0xbfff, "bank6");
+
+ /* write protect RAM8 ? */
+ if ((m_pio_data[1] & (1<<6)) == 0)
+ {
+ /* ram8 is enabled and write protected */
+ LOG(("RAM8 write protected\n"));
+
+ space.nop_write(0x8000, 0xa7ff);
+ space.nop_write(0xa800, 0xbfff);
+ }
+ else
+ {
+ LOG(("RAM8 write enabled\n"));
+
+ /* ram8 is enabled and write enabled */
+ space.install_write_bank(0x8000, 0xa7ff, "bank3");
+ space.install_write_bank(0xa800, 0xbfff, "bank6");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x8000\n"));
+
+ space.install_read_handler(0x8000, 0xbfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_8000_r), this), 0);
+ space.install_write_handler(0x8000, 0xbfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_8000_w), this), 0);
+ }
+}
+
+//**************************************************************************
+// KC85 Z80PIO Interface
+//**************************************************************************
+
+
+/* PIO PORT A: port 0x088:
+
+bit 7: ROM C (BASIC)
+bit 6: Tape Motor on
+bit 5: LED
+bit 4: K OUT
+bit 3: WRITE PROTECT RAM 0
+bit 2: IRM
+bit 1: ACCESS RAM 0
+bit 0: CAOS ROM E
+*/
+
+READ8_MEMBER( kc_state::pio_porta_r )
+{
+ return m_pio_data[0];
+}
+
+WRITE8_MEMBER( kc_state::pio_porta_w )
+{
+ if (m_pio_data[0] != data) // to avoid a severe slowdown during cassette loading
+ {
+ m_pio_data[0] = data;
+
+ update_0x00000();
+ update_0x08000();
+ update_0x0c000();
+ update_0x0e000();
+
+ cassette_set_motor(BIT(data, 6));
+ }
+}
+
+
+/* PIO PORT B: port 0x089:
+bit 7: BLINK ENABLE
+bit 6: WRITE PROTECT RAM 8
+bit 5: ACCESS RAM 8
+bit 4: TONE 4
+bit 3: TONE 3
+bit 2: TONE 2
+bit 1: TONE 1
+bit 0: TRUCK */
+
+READ8_MEMBER( kc_state::pio_portb_r )
+{
+ return m_pio_data[1];
+}
+
+WRITE8_MEMBER( kc_state::pio_portb_w )
+{
+ m_pio_data[1] = data;
+
+ update_0x08000();
+
+ /* 16 speaker levels */
+ m_speaker_level = (data>>1) & 0x0f;
+
+ speaker_update();
+}
+
+/* port 0x84/0x85:
+
+bit 7: RAF3
+bit 6: RAF2
+bit 5: RAF1
+bit 4: RAF0
+bit 3: FPIX. high resolution
+bit 2: BLA1 .access screen
+bit 1: BLA0 .pixel/color
+bit 0: BILD .display screen 0 or 1
+*/
+
+WRITE8_MEMBER( kc85_4_state::kc85_4_84_w )
+{
+ LOG(("0x84 W: %02x\n", data));
+
+ m_port_84_data = data;
+
+ video_control_w(data);
+
+ update_0x08000();
+}
+
+READ8_MEMBER( kc85_4_state::kc85_4_84_r )
+{
+ return m_port_84_data;
+}
+
+
+/* port 0x86/0x87:
+
+bit 7: ROCC
+bit 6: ROF1
+bit 5: ROF0
+bit 4-2 are not connected
+bit 1: WRITE PROTECT RAM 4
+bit 0: ACCESS RAM 4
+*/
+
+WRITE8_MEMBER( kc85_4_state::kc85_4_86_w )
+{
+ LOG(("0x86 W: %02x\n", data));
+
+ m_port_86_data = data;
+
+ update_0x0c000();
+ update_0x04000();
+}
+
+READ8_MEMBER( kc85_4_state::kc85_4_86_r )
+{
+ return m_port_86_data;
+}
+
+/*****************************************************************/
+
+
+/* callback for ardy output from PIO */
+/* used in KC85/4 & KC85/3 cassette interface */
+WRITE_LINE_MEMBER( kc_state::pio_ardy_cb)
+{
+ m_ardy = state & 0x01;
+}
+
+/* callback for brdy output from PIO */
+/* used in KC85/4 & KC85/3 keyboard interface */
+WRITE_LINE_MEMBER( kc_state::pio_brdy_cb)
+{
+ m_brdy = state & 0x01;
+}
+
+/* used in cassette write -> K0 */
+WRITE_LINE_MEMBER( kc_state::ctc_zc0_callback )
+{
+ if (state)
+ {
+ m_k0_line^=1;
+ speaker_update();
+ }
+}
+
+/* used in cassette write -> K1 */
+WRITE_LINE_MEMBER( kc_state::ctc_zc1_callback)
+{
+ if (state)
+ {
+ m_k1_line^=1;
+ speaker_update();
+
+ // K1 line is also cassette output
+ m_cassette->output((m_k1_line & 1) ? +1 : -1);
+ }
+
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(kc_state::kc_scanline)
+{
+ int scanline = (int)param;
+
+ /* set clock input for channel 0 and 1 to ctc */
+ m_z80ctc->trg0(1);
+ m_z80ctc->trg0(0);
+ m_z80ctc->trg1(1);
+ m_z80ctc->trg1(0);
+
+ if (scanline == 256)
+ {
+ /* set clock input for channel 2 and 3 to ctc */
+ m_z80ctc->trg2(1);
+ m_z80ctc->trg2(0);
+ m_z80ctc->trg3(1);
+ m_z80ctc->trg3(0);
+ }
+}
+
+void kc_state::speaker_update()
+{
+ /* this might not be correct, the range might be logarithmic and not linear! */
+ m_speaker->level_w(m_k0_line ? (m_speaker_level | (m_k1_line ? 0x01 : 0)) : 0);
+}
+
+/* keyboard callback */
+WRITE_LINE_MEMBER( kc_state::keyboard_cb )
+{
+ m_z80pio->strobe_b(state & m_brdy);
+
+ // FIXME: understand why the PIO fail to acknowledge the irq on kc85_2/3
+ m_z80pio->data_write(1, m_pio_data[1]);
+}
+
+
+void kc_state::machine_start()
+{
+ m_cassette_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kc_state::kc_cassette_timer_callback),this));
+ m_cassette_oneshot_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kc_state::kc_cassette_oneshot_timer),this));
+
+ m_ram_base = m_ram->pointer();
+
+ m_expansions[0] = machine().device<kcexp_slot_device>("m8");
+ m_expansions[1] = machine().device<kcexp_slot_device>("mc");
+ m_expansions[2] = machine().device<kcexp_slot_device>("exp");
+}
+
+void kc_state::machine_reset()
+{
+ m_pio_data[0] = 0x0f;
+ m_pio_data[1] = 0xf1;
+
+ update_0x00000();
+ update_0x04000();
+ update_0x08000();
+ update_0x0c000();
+ update_0x0e000();
+
+ // set low resolution at reset
+ m_high_resolution = 0;
+
+ cassette_set_motor(0);
+
+ /* this is temporary. Normally when a Z80 is reset, it will
+ execute address 0. It appears the KC85 series pages the rom
+ at address 0x0000-0x01000 which has a single jump in it,
+ can't see yet where it disables it later!!!! so for now
+ here will be a override */
+ m_maincpu->set_pc(0x0f000);
+}
+
+void kc85_4_state::machine_reset()
+{
+ kc_state::machine_reset();
+
+ m_port_84_data = 0x00;
+ m_port_86_data = 0x00;
+}