From 71ae6112dd08b18948a584a0849f34d66cb72047 Mon Sep 17 00:00:00 2001 From: Nigel Barnes Date: Fri, 20 Dec 2019 19:08:14 +0000 Subject: New working clones ------------------ Acorn Electron (Stop Press 64i) [Nigel Barnes] --- src/mame/drivers/electron.cpp | 102 ++++++++++++++++++++++--- src/mame/includes/electron.h | 58 +++++++++++++-- src/mame/machine/electron.cpp | 168 +++++++++++++++++++++++++++++++++++++++--- src/mame/mame.lst | 1 + src/mame/video/electron.cpp | 2 +- 5 files changed, 304 insertions(+), 27 deletions(-) diff --git a/src/mame/drivers/electron.cpp b/src/mame/drivers/electron.cpp index cc799facb50..218477d20ea 100644 --- a/src/mame/drivers/electron.cpp +++ b/src/mame/drivers/electron.cpp @@ -1,8 +1,6 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, Nigel Barnes /****************************************************************************** - Acorn Electron driver - By Wilbert Pol Hardware Overview ----------------- @@ -46,6 +44,26 @@ Notes: (all IC's shown. Only 16 ICs are used) KBD_CONN - 22-pin keyboard connector SPKR - 2-pin internal speaker connector + +Master RAM Board +---------------- +The Master RAM Board (MRB) is an internal expansion board from Slogger, and could +also be purchased pre-fitted in the form of the Electron 64. +The MRB comes with a new MOS which provides three modes of operation, selected by a +switch, which are Normal, Turbo, and 64K. The 64K mode was the first to provide a +'shadow mode' on the Electron. + + +Stop Press 64i +-------------- +The Stop Press 64i (SP64i) is another internal expansion board from Slogger, which +also requires the MRB to fitted. Being released in the early 90's there are no known +working examples, but bare prototype boards and ROMs were discovered during a Slogger +workshop clearout. +It provides a re-written AMX Stop Press (Desktop Publishing) for the Electron to take +advantage of the extra memory provided by the Master RAM Board, and also offers +ROM/RAM sockets and User Port for a mouse. + ****************************************************************************** Emulation notes: @@ -58,6 +76,11 @@ Incomplete: - 1 MHz bus is not emulated - Bus claiming by ULA is not implemented +Other internal boards to emulate: + - Slogger Turbo Driver + - Jafa Mode7 Mk2 Display Unit + - move MRB and SP64i to an internal slot device? + ******************************************************************************/ #include "emu.h" @@ -211,11 +234,29 @@ static INPUT_PORTS_START( electron64 ) PORT_CONFSETTING(0x02, "64K") INPUT_PORTS_END +static INPUT_PORTS_START(electronsp) + PORT_INCLUDE(electron64) + + PORT_START("ROMPAGES") + /* TODO: Actual 4bit dip settings are unknown, require a manual */ + PORT_DIPNAME(0x0f, 0x06, "SP64i ROM Pages") + PORT_DIPSETTING(0x00, "0&1") + PORT_DIPSETTING(0x02, "2&3") + PORT_DIPSETTING(0x04, "4&5") + PORT_DIPSETTING(0x06, "6&7") + PORT_DIPSETTING(0x08, "8&9 (reserved)") + PORT_DIPSETTING(0x0a, "10&11 (reserved)") + PORT_DIPSETTING(0x0c, "12&13") + PORT_DIPSETTING(0x0e, "14&15") +INPUT_PORTS_END + void electron_state::electron(machine_config &config) { M6502(config, m_maincpu, 16_MHz_XTAL / 8); m_maincpu->set_addrmap(AS_PROGRAM, &electron_state::electron_mem); + INPUT_MERGER_ANY_HIGH(config, m_irqs).output_handler().set_inputline(m_maincpu, M6502_IRQ_LINE); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(16_MHz_XTAL, 1024, 0, 640, 312, 0, 256); //m_screen->set_raw(16_MHz_XTAL, 1024, 264, 264 + 640, 312, 31, 31 + 256) @@ -237,7 +278,7 @@ void electron_state::electron(machine_config &config) /* expansion port */ ELECTRON_EXPANSION_SLOT(config, m_exp, 16_MHz_XTAL, electron_expansion_devices, "plus3"); - m_exp->irq_handler().set_inputline(m_maincpu, M6502_IRQ_LINE); + m_exp->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<1>)); m_exp->nmi_handler().set_inputline(m_maincpu, M6502_NMI_LINE); /* software lists */ @@ -277,6 +318,30 @@ void electron_state::electron64(machine_config &config) } +void electronsp_state::electronsp(machine_config &config) +{ + /* install mrb board */ + electron64(config); + + /* rom sockets */ + GENERIC_SOCKET(config, m_romi[0], generic_plain_slot, "electron_rom", "bin,rom"); + m_romi[0]->set_device_load(FUNC(electronsp_state::rom1_load)); + GENERIC_SOCKET(config, m_romi[1], generic_plain_slot, "electron_rom", "bin,rom"); + m_romi[1]->set_device_load(FUNC(electronsp_state::rom2_load)); + + /* via */ + VIA6522(config, m_via, 16_MHz_XTAL / 16); + m_via->readpb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_r)); + m_via->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w)); + m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<2>)); + + /* user port */ + BBC_USERPORT_SLOT(config, m_userport, bbc_userport_devices, "amxmouse"); + m_userport->cb1_handler().set(m_via, FUNC(via6522_device::write_cb1)); + m_userport->cb2_handler().set(m_via, FUNC(via6522_device::write_cb2)); +} + + ROM_START(electron) ROM_REGION( 0x4000, "mos", 0 ) ROM_LOAD( "b02_acornos-1.rom", 0x0000, 0x4000, CRC(a0c2cf43) SHA1(a27ce645472cc5497690e4bfab43710efbb0792d) ) @@ -295,15 +360,32 @@ ROM_END ROM_START(electron64) ROM_REGION( 0x4000, "mos", 0 ) ROM_LOAD( "os_300.rom", 0x0000, 0x4000, CRC(f80a0cea) SHA1(165e42ff4164a842e56f08ebd420d5027af99fdd) ) - ROM_REGION(0x4000, "basic", 0) + ROM_REGION( 0x4000, "basic", 0 ) + ROM_LOAD( "basic.rom", 0x0000, 0x4000, CRC(79434781) SHA1(4a7393f3a45ea309f744441c16723e2ef447a281) ) +ROM_END + +ROM_START(electronsp) + ROM_REGION( 0x4000, "mos", 0 ) + ROM_LOAD( "os_310.rom", 0x0000, 0x4000, CRC(8b7a9003) SHA1(6d4e2f8ddc1d829b14206d2747749c4c24789568) ) + ROM_REGION( 0x4000, "basic", 0 ) ROM_LOAD( "basic.rom", 0x0000, 0x4000, CRC(79434781) SHA1(4a7393f3a45ea309f744441c16723e2ef447a281) ) + ROM_REGION( 0x8000, "sp64", 0 ) + ROM_SYSTEM_BIOS( 0, "101_2", "v1.01 (2x16K)" ) + ROMX_LOAD( "sp64_101_1.rom", 0x0000, 0x4000, CRC(07e2c5d6) SHA1(837e3382c376e3cc1ae42f1ca51158657ef2fd73), ROM_BIOS(0) ) + ROMX_LOAD( "sp64_101_2.rom", 0x4000, 0x4000, CRC(3d0e5dc1) SHA1(89743c43b24950d481c150fd4b4de985600cca2d), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "100", "v1.00 (32K)" ) + ROMX_LOAD( "sp64_100.rom", 0x0000, 0x8000, CRC(4918221c) SHA1(f185873106e7e7225b2e0c718803dc1ec4ebc685), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 2, "100_2", "v1.00 (2x16K)" ) + ROMX_LOAD( "sp64_100_1.rom", 0x0000, 0x4000, CRC(6053e5a0) SHA1(6d79e5494349f157672e7c59949f3941e5a3dbdb), ROM_BIOS(2) ) + ROMX_LOAD( "sp64_100_2.rom", 0x4000, 0x4000, CRC(25d11d8e) SHA1(c1bceeb50fee1e11de7505a3b664b844cfb56289), ROM_BIOS(2) ) ROM_END #define rom_btm2105 rom_electron -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP ( 1983, electron, 0, 0, electron, electron, electron_state, empty_init, "Acorn", "Acorn Electron", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) -COMP ( 1983, electront, electron, 0, electron, electron, electron_state, empty_init, "Acorn", "Acorn Electron (Trial)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) -COMP ( 1985, btm2105, electron, 0, btm2105, electron, electron_state, empty_init, "British Telecom Business Systems", "BT Merlin M2105", MACHINE_NOT_WORKING ) -COMP ( 1987, electron64, electron, 0, electron64, electron64, electron_state, empty_init, "Acorn/Slogger", "Acorn Electron (64K Master RAM Board)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP ( 1983, electron, 0, 0, electron, electron, electron_state, empty_init, "Acorn Computers", "Acorn Electron", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +COMP ( 1983, electront, electron, 0, electron, electron, electron_state, empty_init, "Acorn Computers", "Acorn Electron (Trial)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +COMP ( 1985, btm2105, electron, 0, btm2105, electron, electron_state, empty_init, "British Telecom Business Systems", "BT Merlin M2105", MACHINE_NOT_WORKING ) +COMP ( 1987, electron64, electron, 0, electron64, electron64, electron_state, empty_init, "Acorn Computers / Slogger", "Acorn Electron (64K Master RAM Board)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) +COMP ( 1991, electronsp, electron, 0, electronsp, electronsp, electronsp_state, empty_init, "Acorn Computers / Slogger", "Acorn Electron (Stop Press 64i)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/includes/electron.h b/src/mame/includes/electron.h index 9dd9bb30eca..1bf29e0440c 100644 --- a/src/mame/includes/electron.h +++ b/src/mame/includes/electron.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, Nigel Barnes /***************************************************************************** * * includes/electron.h @@ -15,11 +15,16 @@ #pragma once #include "machine/ram.h" +#include "machine/6522via.h" +#include "machine/input_merger.h" #include "imagedev/cassette.h" #include "sound/beep.h" #include "emupal.h" #include "bus/electron/exp.h" +#include "bus/bbc/userport/userport.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" /* Interrupts */ #define INT_HIGH_TONE 0x40 @@ -36,6 +41,7 @@ public: electron_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_irqs(*this, "irqs") , m_screen(*this, "screen") , m_cassette(*this, "cassette") , m_beeper(*this, "beeper") @@ -54,7 +60,7 @@ public: DECLARE_INPUT_CHANGED_MEMBER( trigger_reset ); -private: +protected: enum { TIMER_TAPE_HANDLER, @@ -69,12 +75,12 @@ private: DECLARE_READ8_MEMBER(electron64_fetch_r); DECLARE_READ8_MEMBER(electron_mem_r); DECLARE_WRITE8_MEMBER(electron_mem_w); - DECLARE_READ8_MEMBER(electron_paged_r); - DECLARE_WRITE8_MEMBER(electron_paged_w); + virtual DECLARE_READ8_MEMBER(electron_paged_r); + virtual DECLARE_WRITE8_MEMBER(electron_paged_w); DECLARE_READ8_MEMBER(electron_mos_r); DECLARE_WRITE8_MEMBER(electron_mos_w); - DECLARE_READ8_MEMBER(electron_fred_r); - DECLARE_WRITE8_MEMBER(electron_fred_w); + virtual DECLARE_READ8_MEMBER(electron_fred_r); + virtual DECLARE_WRITE8_MEMBER(electron_fred_w); DECLARE_READ8_MEMBER(electron_jim_r); DECLARE_WRITE8_MEMBER(electron_jim_w); DECLARE_READ8_MEMBER(electron_sheila_r); @@ -101,6 +107,7 @@ private: virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; required_device m_maincpu; + required_device m_irqs; required_device m_screen; required_device m_cassette; required_device m_beeper; @@ -147,4 +154,43 @@ private: bool m_vdu_drivers; }; + +class electronsp_state : public electron_state +{ +public: + electronsp_state(const machine_config &mconfig, device_type type, const char *tag) + : electron_state(mconfig, type, tag) + , m_region_sp64(*this, "sp64") + , m_via(*this, "via6522") + , m_userport(*this, "userport") + , m_romi(*this, "romi%u", 1) + , m_rompages(*this, "ROMPAGES") + { } + + void electronsp(machine_config &config); + +protected: + virtual DECLARE_READ8_MEMBER(electron_paged_r) override; + virtual DECLARE_WRITE8_MEMBER(electron_paged_w) override; + virtual DECLARE_READ8_MEMBER(electron_fred_r) override; + virtual DECLARE_WRITE8_MEMBER(electron_fred_w) override; + + virtual void machine_start() override; + +private: + required_memory_region m_region_sp64; + required_device m_via; + required_device m_userport; + required_device_array m_romi; + required_ioport m_rompages; + + uint8_t m_sp64_bank; + std::unique_ptr m_sp64_ram; + + image_init_result load_rom(device_image_interface &image, generic_slot_device *slot); + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(rom1_load) { return load_rom(image, m_romi[0]); } + DECLARE_DEVICE_IMAGE_LOAD_MEMBER(rom2_load) { return load_rom(image, m_romi[1]); } +}; + + #endif // MAME_INCLUDES_ELECTRON_H diff --git a/src/mame/machine/electron.cpp b/src/mame/machine/electron.cpp index 19862d17e72..ce62fe7aad3 100644 --- a/src/mame/machine/electron.cpp +++ b/src/mame/machine/electron.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, Nigel Barnes /****************************************************************************** Acorn Electron driver @@ -121,12 +121,12 @@ TIMER_CALLBACK_MEMBER(electron_state::electron_tape_timer_handler) case 9: /* stop bit */ m_ula.stop_bit = ( ( m_ula.tape_value == 0x0000FFFF ) ? 0 : 1 ); //logerror( "++ Read stop bit: %d\n", m_ula.stop_bit ); - if ( m_ula.start_bit && m_ula.stop_bit && m_ula.tape_byte == 0xFF && ! m_ula.high_tone_set ) + if ( m_ula.start_bit && m_ula.stop_bit && m_ula.tape_byte == 0xFF && !m_ula.high_tone_set ) { electron_interrupt_handler( INT_SET, INT_HIGH_TONE ); m_ula.high_tone_set = 1; } - else if ( ! m_ula.start_bit && m_ula.stop_bit ) + else if ( !m_ula.start_bit && m_ula.stop_bit ) { //logerror( "-- Byte read from tape: %02x\n", m_ula.tape_byte ); electron_interrupt_handler( INT_SET, INT_RECEIVE_FULL ); @@ -251,6 +251,69 @@ WRITE8_MEMBER(electron_state::electron_paged_w) m_exp->expbus_w(0x8000 + offset, data); } +READ8_MEMBER(electronsp_state::electron_paged_r) +{ + uint8_t data = 0; + + /* The processor will run at 2MHz during an access cycle to the ROM */ + m_maincpu->set_clock_scale(1.0f); + + if ((m_ula.rompage & 0x0e) == m_rompages->read()) + { + data = m_romi[m_ula.rompage & 0x01]->read_rom(offset); + } + else + { + switch (m_ula.rompage) + { + case 10: + /* SP64 ROM utilises the spare BASIC ROM page */ + if (BIT(m_sp64_bank, 7) && (offset & 0x2000)) + { + data = m_sp64_ram[offset & 0x1fff]; + } + else + { + data = m_region_sp64->base()[(!BIT(m_sp64_bank, 0) << 14) | offset]; + } + break; + + default: + data = electron_state::electron_paged_r(space, offset, mem_mask); + break; + } + } + return data; +} + +WRITE8_MEMBER(electronsp_state::electron_paged_w) +{ + /* The processor will run at 2MHz during an access cycle to the ROM */ + m_maincpu->set_clock_scale(1.0f); + + if ((m_ula.rompage & 0x0e) == m_rompages->read()) + { + /* TODO: sockets are writeable if RAM */ + } + else + { + switch (m_ula.rompage) + { + case 10: + /* SP64 ROM utilises the spare BASIC ROM page */ + if (BIT(m_sp64_bank, 7) && (offset & 0x2000)) + { + m_sp64_ram[offset & 0x1fff] = data; + } + break; + + default: + electronsp_state::electron_paged_w(space, offset, data, mem_mask); + break; + } + } +} + READ8_MEMBER(electron_state::electron_mos_r) { /* The processor will run at 2MHz during an access cycle to the ROM */ @@ -290,6 +353,41 @@ WRITE8_MEMBER(electron_state::electron_fred_w) m_exp->expbus_w(0xfc00 + offset, data); } +READ8_MEMBER(electronsp_state::electron_fred_r) +{ + uint8_t data = 0; + + /* The processor will run at 2MHz during an access cycle to the ROM */ + m_maincpu->set_clock_scale(1.0f); + + if ((offset & 0xf0) == 0xb0) + { + data = m_via->read(offset & 0x0f); + } + else + { + data = electron_state::electron_fred_r(space, offset, mem_mask); + } + return data;; +} + +WRITE8_MEMBER(electronsp_state::electron_fred_w) +{ + /* The processor will run at 2MHz during an access cycle to the ROM */ + m_maincpu->set_clock_scale(1.0f); + + electron_state::electron_fred_w(space, offset, data, mem_mask); + + if ((offset & 0xf0) == 0xb0) + { + m_via->write(offset & 0x0f, data); + } + else if (offset == 0xfa) + { + m_sp64_bank = data; + } +} + READ8_MEMBER(electron_state::electron_jim_r) { /* The processor will run at 2MHz during an access cycle to the ROM */ @@ -467,12 +565,12 @@ void electron_state::electron_interrupt_handler(int mode, int interrupt) if ( m_ula.interrupt_status & m_ula.interrupt_control & ~0x83 ) { m_ula.interrupt_status |= 0x01; - m_maincpu->set_input_line(0, ASSERT_LINE ); + m_irqs->in_w<0>(ASSERT_LINE); } else { m_ula.interrupt_status &= ~0x01; - m_maincpu->set_input_line(0, CLEAR_LINE ); + m_irqs->in_w<0>(CLEAR_LINE); } } @@ -486,6 +584,31 @@ TIMER_CALLBACK_MEMBER(electron_state::setup_beep) m_beeper->set_clock( 300 ); } +void electron_state::machine_start() +{ + m_ula.interrupt_status = 0x82; + m_ula.interrupt_control = 0x00; + timer_set(attotime::zero, TIMER_SETUP_BEEP); + m_tape_timer = timer_alloc(TIMER_TAPE_HANDLER); + + /* register save states */ + save_item(STRUCT_MEMBER(m_ula, interrupt_status)); + save_item(STRUCT_MEMBER(m_ula, interrupt_control)); + save_item(STRUCT_MEMBER(m_ula, rompage)); + save_item(STRUCT_MEMBER(m_ula, screen_start)); + save_item(STRUCT_MEMBER(m_ula, screen_base)); + save_item(STRUCT_MEMBER(m_ula, screen_size)); + save_item(STRUCT_MEMBER(m_ula, screen_addr)); + save_item(STRUCT_MEMBER(m_ula, screen_dispend)); + save_item(STRUCT_MEMBER(m_ula, current_pal)); + save_item(STRUCT_MEMBER(m_ula, communication_mode)); + save_item(STRUCT_MEMBER(m_ula, screen_mode)); + save_item(STRUCT_MEMBER(m_ula, cassette_motor_mode)); + save_item(STRUCT_MEMBER(m_ula, capslock_mode)); + save_item(NAME(m_mrb_mapped)); + save_item(NAME(m_vdu_drivers)); +} + void electron_state::machine_reset() { m_ula.communication_mode = 0x04; @@ -502,10 +625,35 @@ void electron_state::machine_reset() m_vdu_drivers = false; } -void electron_state::machine_start() +void electronsp_state::machine_start() { - m_ula.interrupt_status = 0x82; - m_ula.interrupt_control = 0x00; - timer_set(attotime::zero, TIMER_SETUP_BEEP); - m_tape_timer = timer_alloc(TIMER_TAPE_HANDLER); + electron_state::machine_start(); + + m_sp64_ram = std::make_unique(0x2000); + + /* register save states */ + save_item(NAME(m_sp64_bank)); + save_pointer(NAME(m_sp64_ram), 0x2000); +} + + +image_init_result electronsp_state::load_rom(device_image_interface &image, generic_slot_device *slot) +{ + uint32_t size = slot->common_get_size("rom"); + + // socket accepts 8K and 16K ROM only + if (size != 0x2000 && size != 0x4000) + { + image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid size: Only 8K/16K is supported"); + return image_init_result::FAIL; + } + + slot->rom_alloc(0x4000, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE); + slot->common_load_rom(slot->get_rom_base(), size, "rom"); + + // mirror 8K ROMs + uint8_t *crt = slot->get_rom_base(); + if (size <= 0x2000) memcpy(crt + 0x2000, crt, 0x2000); + + return image_init_result::PASS; } diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 50d35af670d..0b348be7c7a 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -12819,6 +12819,7 @@ electron // 1983 Acorn Electron electront // 1983 Acorn Electron (Trial) btm2105 // 1985 BT Merlin M2105 electron64 // 1987 Acorn Electron (64K Master RAM Board) +electronsp // 1991 Acorn Electron (Stop Press 64i) @source:elekscmp.cpp elekscmp // diff --git a/src/mame/video/electron.cpp b/src/mame/video/electron.cpp index a5050c3bcf4..e506a4e930c 100644 --- a/src/mame/video/electron.cpp +++ b/src/mame/video/electron.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, Nigel Barnes /****************************************************************************** Acorn Electron driver -- cgit v1.2.3