diff options
Diffstat (limited to 'src/mame/drivers/a6809.c')
-rw-r--r-- | src/mame/drivers/a6809.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/mame/drivers/a6809.c b/src/mame/drivers/a6809.c new file mode 100644 index 00000000000..38a455614ca --- /dev/null +++ b/src/mame/drivers/a6809.c @@ -0,0 +1,277 @@ +// license:BSD-3-Clause +// copyright-holders:Robbbert and unknown others +/*************************************************************************** + + Acorn 6809 + + 2009-05-12 Skeleton driver. + 2013-12-16 Fixed video [Robbbert] + + Acorn System 3 update? + http://acorn.chriswhy.co.uk/8bit_Upgrades/Acorn_6809_CPU.html + + This is a few boards emulated together: + - 6809 main board + - 80x25 video board + - FDC board (to come) + +The video board has a mc6845, and the characters do not go to a character +generator, instead they go to a SAA5050, which has its own CG inbuilt, plus +many other features. + +ToDo: + - FDC (address A00) + - Centronics Printer (VIA port A) + +Commands: +C - Echo to printer ( C '+' turns it on) +D - boot from disk +G - Go +L - Load tape +P - Run from pc reg +R - Display regs +S - Save tape +T - Trace +V - Set breakpoint + +M - Modify memory +MV - Modify memory at breakpoint address +MG - Modify memory from Go address +MP - Modify memory from pc-reg address +MR - Modify regs + +While modifying memory: +, show next address +- show previous address +enter show next address +; exit + + +****************************************************************************/ + +#include "emu.h" +#include "cpu/m6809/m6809.h" +#include "machine/6522via.h" +#include "machine/keyboard.h" +#include "video/saa5050.h" +#include "video/mc6845.h" +#include "imagedev/cassette.h" +#include "sound/wave.h" + + +class a6809_state : public driver_device +{ +public: + a6809_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_p_videoram(*this, "videoram") + , m_via(*this, "via") + , m_cass(*this, "cassette") + , m_maincpu(*this, "maincpu") + , m_crtc(*this, "mc6845") + { } + + DECLARE_WRITE8_MEMBER(kbd_put); + DECLARE_READ8_MEMBER(videoram_r); + DECLARE_WRITE8_MEMBER(a6809_address_w); + DECLARE_WRITE8_MEMBER(a6809_register_w); + DECLARE_WRITE_LINE_MEMBER(cass_w); + DECLARE_MACHINE_RESET(a6809); + TIMER_DEVICE_CALLBACK_MEMBER(a6809_c); + TIMER_DEVICE_CALLBACK_MEMBER(a6809_p); + required_shared_ptr<UINT8> m_p_videoram; + UINT16 m_start_address; + UINT16 m_cursor_address; +private: + UINT8 m_cass_data[4]; + bool m_cass_state; + bool m_cassold; + UINT8 m_video_index; + required_device<via6522_device> m_via; + required_device<cassette_image_device> m_cass; + required_device<cpu_device> m_maincpu; + required_device<mc6845_device> m_crtc; +}; + + +static ADDRESS_MAP_START(a6809_mem, AS_PROGRAM, 8, a6809_state) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE(0x0000,0x03ff) AM_RAM + AM_RANGE(0x0400,0x07ff) AM_RAM AM_SHARE("videoram") + AM_RANGE(0x0800,0x0800) AM_DEVREAD("mc6845", mc6845_device, status_r) AM_WRITE(a6809_address_w) + AM_RANGE(0x0801,0x0801) AM_DEVREAD("mc6845", mc6845_device, register_r) AM_WRITE(a6809_register_w) + AM_RANGE(0x0900,0x090f) AM_MIRROR(0xf0) AM_DEVREADWRITE("via", via6522_device, read, write) + AM_RANGE(0xf000,0xf7ff) // optional ROM + AM_RANGE(0xf800,0xffff) AM_ROM AM_REGION("maincpu", 0) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( a6809_io, AS_IO, 8, a6809_state) + ADDRESS_MAP_UNMAP_HIGH +ADDRESS_MAP_END + +/* Input ports */ +static INPUT_PORTS_START( a6809 ) +INPUT_PORTS_END + + +MACHINE_RESET_MEMBER( a6809_state, a6809) +{ + m_via->write_pb0(0); + m_via->write_pb1(0); + m_via->write_pb2(0); + m_via->write_pb3(0); + m_via->write_pb4(0); + m_via->write_pb5(0); + m_via->write_pb6(0); + m_via->write_pb7(0); +} + +READ8_MEMBER( a6809_state::videoram_r ) +{ + offset += m_start_address; + + if (m_cursor_address == offset) + return 0x7f; // cheap cursor + else + return m_p_videoram[offset&0x3ff]; +} + +WRITE8_MEMBER( a6809_state::a6809_address_w ) +{ + m_crtc->address_w( space, 0, data ); + + m_video_index = data & 0x1f; +} + +WRITE8_MEMBER( a6809_state::a6809_register_w ) +{ + UINT16 temp = m_start_address; + UINT16 temq = m_cursor_address; + + // data is 18, but we need 19, to give the 20 rows needed by the SAA5050 + if (m_video_index == 9) + data++; + + m_crtc->register_w( space, 0, data ); + + // Get start address + if (m_video_index == 12) + m_start_address = ((data & 7) << 8 ) | (temp & 0xff); + else + if (m_video_index == 13) + m_start_address = data | (temp & 0x3f00); + + else + // Get cursor address + if (m_video_index == 14) + m_cursor_address = ((data & 7) << 8 ) | (temq & 0xff); + else + if (m_video_index == 15) + m_cursor_address = data | (temq & 0x3f00); +} + +WRITE_LINE_MEMBER( a6809_state::cass_w ) +{ + m_cass_state = state; +} + +TIMER_DEVICE_CALLBACK_MEMBER(a6809_state::a6809_c) +{ + m_cass_data[3]++; + + if (m_cass_state != m_cassold) + { + m_cass_data[3] = 0; + m_cassold = m_cass_state; + } + + if (m_cass_state) + m_cass->output(BIT(m_cass_data[3], 0) ? -1.0 : +1.0); // 2400Hz + else + m_cass->output(BIT(m_cass_data[3], 1) ? -1.0 : +1.0); // 1200Hz +} + +TIMER_DEVICE_CALLBACK_MEMBER(a6809_state::a6809_p) +{ + /* cassette - turn 1200/2400Hz to a bit */ + m_cass_data[1]++; + UINT8 cass_ws = (m_cass->input() > +0.03) ? 1 : 0; + + if (cass_ws != m_cass_data[0]) + { + m_cass_data[0] = cass_ws; + m_via->write_pb7(m_cass_data[1] < 12); + m_cass_data[1] = 0; + } +} + +WRITE8_MEMBER( a6809_state::kbd_put ) +{ + UINT8 d = data & 0x7f; + if (d == 8) d = 0x7f; // allow backspace to work + + m_via->write_pb0((d>>0)&1); + m_via->write_pb1((d>>1)&1); + m_via->write_pb2((d>>2)&1); + m_via->write_pb3((d>>3)&1); + m_via->write_pb4((d>>4)&1); + m_via->write_pb5((d>>5)&1); + m_via->write_pb6((d>>6)&1); + m_via->write_cb1(1); + m_via->write_cb1(0); +} + +static MACHINE_CONFIG_START( a6809, a6809_state ) + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu",M6809E, XTAL_4MHz) + MCFG_CPU_PROGRAM_MAP(a6809_mem) + MCFG_CPU_IO_MAP(a6809_io) + MCFG_MACHINE_RESET_OVERRIDE(a6809_state, a6809) + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_REFRESH_RATE(50) + MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) + MCFG_SCREEN_SIZE(40 * 12, 25 * 20) + MCFG_SCREEN_VISIBLE_AREA(0, 40 * 12 - 1, 0, 25 * 20 - 1) + MCFG_SCREEN_UPDATE_DEVICE("saa5050", saa5050_device, screen_update) + MCFG_PALETTE_ADD("palette", 8) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_MONO("mono") + MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) + + /* Devices */ + MCFG_DEVICE_ADD("via", VIA6522, XTAL_4MHz / 4) + MCFG_VIA6522_CB2_HANDLER(WRITELINE(a6809_state, cass_w)) + MCFG_VIA6522_IRQ_HANDLER(DEVWRITELINE("maincpu", m6809e_device, irq_line)) + + MCFG_MC6845_ADD("mc6845", MC6845, "screen", XTAL_4MHz / 2) + MCFG_MC6845_SHOW_BORDER_AREA(false) + MCFG_MC6845_CHAR_WIDTH(12) + + MCFG_DEVICE_ADD("saa5050", SAA5050, 6000000) + MCFG_SAA5050_D_CALLBACK(READ8(a6809_state, videoram_r)) + MCFG_SAA5050_SCREEN_SIZE(40, 25, 40) + + MCFG_DEVICE_ADD("keyboard", GENERIC_KEYBOARD, 0) + MCFG_GENERIC_KEYBOARD_CB(WRITE8(a6809_state, kbd_put)) + MCFG_CASSETTE_ADD( "cassette" ) + MCFG_TIMER_DRIVER_ADD_PERIODIC("a6809_c", a6809_state, a6809_c, attotime::from_hz(4800)) + MCFG_TIMER_DRIVER_ADD_PERIODIC("a6809_p", a6809_state, a6809_p, attotime::from_hz(40000)) +MACHINE_CONFIG_END + +/* ROM definition */ +ROM_START( a6809 ) + ROM_REGION( 0x800, "maincpu", 0 ) + ROM_LOAD( "acorn6809.bin", 0x000, 0x800, CRC(5fa5b632) SHA1(b14a884bf82a7a8c23bc03c2e112728dd1a74896) ) + + ROM_REGION( 0x100, "proms", 0 ) + ROM_LOAD( "acorn6809.ic11", 0x0000, 0x0100, CRC(7908317d) SHA1(e0f1e5bd3a8598d3b62bc432dd1f3892ed7e66d8) ) // address decoder +ROM_END + +/* Driver */ + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1980, a6809, 0, 0, a6809, a6809, driver_device, 0, "Acorn", "System 3 (6809 CPU)", 0 ) |