New working clones

------------------
Acorn Electron (Stop Press 64i) [Nigel Barnes]
This commit is contained in:
Nigel Barnes 2019-12-20 19:08:14 +00:00
parent ef97edfddb
commit 71ae6112dd
5 changed files with 304 additions and 27 deletions

View File

@ -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 )

View File

@ -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<cpu_device> m_maincpu;
required_device<input_merger_device> m_irqs;
required_device<screen_device> m_screen;
required_device<cassette_image_device> m_cassette;
required_device<beep_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<via6522_device> m_via;
required_device<bbc_userport_slot_device> m_userport;
required_device_array<generic_slot_device, 2> m_romi;
required_ioport m_rompages;
uint8_t m_sp64_bank;
std::unique_ptr<uint8_t[]> 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

View File

@ -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<uint8_t[]>(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;
}

View File

@ -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 //

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
// copyright-holders:Wilbert Pol, Nigel Barnes
/******************************************************************************
Acorn Electron driver