llc2: cleanup, added cassette

This commit is contained in:
Robbbert 2020-07-10 02:41:24 +10:00
parent be6924832d
commit 700d95e88f

View File

@ -2,24 +2,21 @@
// copyright-holders:Miodrag Milanovic, Robbbert
/******************************************************************************
LLC driver by Miodrag Milanovic
LLC2 driver by Miodrag Milanovic
17/04/2009 Preliminary driver.
2009-04-17 Preliminary driver.
July 2012, updates by Robbbert
2012-07-?? Updates by Robbbert
Very little info available on these computers.
The BEL character plays a short tune.
In the monitor, it is case sensitive, most commands are uppercase,
but some are lowercase.
To start Basic, the command is b. To quit basic, use BYE.
Inside Basic, it is not case-sensitive.
LLC2:
The BEL character plays a short tune.
In the monitor, it is case sensitive, most commands are uppercase,
but some are lowercase.
To start Basic, the command is b. To quit basic, use BYE.
Inside Basic, it is not case-sensitive.
ToDo:
- LLC2: Keyboard is incomplete
- Lots of other things
ToDo:
- Unofficial expansions
- Need software
*******************************************************************************/
@ -31,6 +28,7 @@
#include "machine/ram.h"
#include "machine/z80ctc.h"
#include "machine/z80pio.h"
#include "imagedev/cassette.h"
#include "sound/spkrdev.h"
#include "emupal.h"
#include "screen.h"
@ -47,6 +45,10 @@ public:
, m_maincpu(*this, "maincpu")
, m_ram(*this, RAM_TAG)
, m_p_chargen(*this, "chargen")
, m_cass(*this, "cassette")
, m_ctc(*this, "ctc")
, m_bankr(*this, "bankr%u", 0U)
, m_bankw(*this, "bankw%u", 0U)
{ }
void llc2(machine_config &config);
@ -56,42 +58,46 @@ public:
private:
void machine_start() override;
void machine_reset() override;
void llc2_rom_disable_w(u8 data);
void llc2_basic_enable_w(u8 data);
u8 llc2_port1_b_r();
u8 llc2_port2_a_r();
void llc2_port1_b_w(u8 data);
u32 screen_update_llc2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void rom_disable_w(u8 data);
void basic_enable_w(u8 data);
u8 port1b_r();
u8 port2a_r();
void port1b_w(u8 data);
u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void io_map(address_map &map);
void mem_map(address_map &map);
bool m_rv;
required_device<speaker_sound_device> m_speaker;
optional_shared_ptr<u8> m_vram;
required_shared_ptr<u8> m_vram;
required_device<z80_device> m_maincpu;
required_device<ram_device> m_ram;
required_region_ptr<u8> m_p_chargen;
required_device<cassette_image_device> m_cass;
required_device<z80ctc_device> m_ctc;
required_memory_bank_array<2> m_bankr;
required_memory_bank_array<2> m_bankw;
};
/* Address maps */
void llc2_state::mem_map(address_map &map)
{
map(0x0000, 0x3fff).bankrw("bank1");
map(0x4000, 0x5fff).bankrw("bank2");
map(0x6000, 0xbfff).bankrw("bank3");
map(0xc000, 0xffff).bankrw("bank4");
map(0x0000, 0x3fff).bankr("bankr0").bankw("bankw0");
map(0x4000, 0x5fff).bankr("bankr1").bankw("bankw1");
map(0x6000, 0xbfff).ram();
map(0xc000, 0xffff).ram().share("videoram");
}
void llc2_state::io_map(address_map &map)
{
map.global_mask(0xff);
map.unmap_value_high();
map(0xE0, 0xE3).w(FUNC(llc2_state::llc2_rom_disable_w));
map(0xE4, 0xE7).rw("z80pio2", FUNC(z80pio_device::read), FUNC(z80pio_device::write));
map(0xE8, 0xEB).rw("z80pio1", FUNC(z80pio_device::read), FUNC(z80pio_device::write));
map(0xEC, 0xEC).w(FUNC(llc2_state::llc2_basic_enable_w));
map(0xF8, 0xFB).rw("z80ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
map(0xE0, 0xE3).w(FUNC(llc2_state::rom_disable_w));
map(0xE4, 0xE7).rw("pio2", FUNC(z80pio_device::read), FUNC(z80pio_device::write));
map(0xE8, 0xEB).rw("pio1", FUNC(z80pio_device::read), FUNC(z80pio_device::write));
map(0xEC, 0xEC).w(FUNC(llc2_state::basic_enable_w));
map(0xF8, 0xFB).rw("ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
}
/* Input ports */
@ -102,74 +108,53 @@ INPUT_PORTS_END
/* Driver initialization */
void llc2_state::init_llc2()
{
m_vram.set_target( m_ram->pointer() + 0xc000,m_vram.bytes());
u8 *r = m_ram->pointer();
u8 *m = memregion("maincpu")->base();
m_bankr[0]->configure_entry(0, r);
m_bankr[0]->configure_entry(1, m);
m_bankw[0]->configure_entry(0, r);
m_bankr[1]->configure_entry(0, r+0x4000);
m_bankr[1]->configure_entry(1, m+0x4000);
m_bankw[1]->configure_entry(0, r+0x4000);
}
void llc2_state::machine_reset()
{
address_space &space = m_maincpu->space(AS_PROGRAM);
u8 *ram = m_ram->pointer();
space.unmap_write(0x0000, 0x3fff);
membank("bank1")->set_base(memregion("maincpu")->base());
space.unmap_write(0x4000, 0x5fff);
membank("bank2")->set_base(ram + 0x4000);
space.unmap_write(0x6000, 0xbfff);
membank("bank3")->set_base(ram + 0x6000);
space.install_write_bank(0xc000, 0xffff, "bank4");
membank("bank4")->set_base(ram + 0xc000);
m_bankr[0]->set_entry(1);
m_bankw[0]->set_entry(0);
m_bankr[1]->set_entry(0);
m_bankw[1]->set_entry(0);
}
void llc2_state::llc2_rom_disable_w(u8 data)
void llc2_state::rom_disable_w(u8 data)
{
address_space &mem_space = m_maincpu->space(AS_PROGRAM);
u8 *ram = m_ram->pointer();
mem_space.install_write_bank(0x0000, 0xbfff, "bank1");
membank("bank1")->set_base(ram);
mem_space.install_write_bank(0x4000, 0x5fff, "bank2");
membank("bank2")->set_base(ram + 0x4000);
mem_space.install_write_bank(0x6000, 0xbfff, "bank3");
membank("bank3")->set_base(ram + 0x6000);
mem_space.install_write_bank(0xc000, 0xffff, "bank4");
membank("bank4")->set_base(ram + 0xc000);
m_bankr[0]->set_entry(0);
}
void llc2_state::llc2_basic_enable_w(u8 data)
void llc2_state::basic_enable_w(u8 data)
{
address_space &mem_space = m_maincpu->space(AS_PROGRAM);
if (BIT(data, 1))
{
mem_space.unmap_write(0x4000, 0x5fff);
membank("bank2")->set_base(memregion("maincpu")->base() + 0x4000);
}
else
{
mem_space.install_write_bank(0x4000, 0x5fff, "bank2");
membank("bank2")->set_base(m_ram->pointer() + 0x4000);
}
m_bankr[1]->set_entry(BIT(data, 1));
}
u8 llc2_state::llc2_port1_b_r()
u8 llc2_state::port1b_r()
{
return 0;
u8 data = 0xfd;
if (m_cass->input() > 0.03)
data |= 0x02;
return data;
}
void llc2_state::llc2_port1_b_w(u8 data)
void llc2_state::port1b_w(u8 data)
{
m_cass->output(BIT(data, 0) ? -1.0 : +1.0);
m_speaker->level_w(BIT(data, 6));
m_rv = BIT(data, 5);
}
u8 llc2_state::llc2_port2_a_r()
u8 llc2_state::port2a_r()
{
return 0; // bit 2 low or hangs on ^Z^X^C sequence
}
@ -179,7 +164,7 @@ void llc2_state::machine_start()
save_item(NAME(m_rv));
}
u32 llc2_state::screen_update_llc2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
u32 llc2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
u8 y,ra,chr,gfx,inv, inv1=m_rv ? 0xff : 0;
u16 sy=0,ma=0,x;
@ -222,15 +207,16 @@ u32 llc2_state::screen_update_llc2(screen_device &screen, bitmap_ind16 &bitmap,
return 0;
}
static const z80_daisy_config llc2_daisy_chain[] =
static const z80_daisy_config daisy_chain[] =
{
{ "z80pio1" },
{ "z80ctc" },
{ "ctc" },
{ "pio1" },
{ "pio2" },
{ nullptr }
};
/* F4 Character Displayer */
static const gfx_layout llc2_charlayout =
static const gfx_layout charlayout =
{
8, 8, /* 8 x 8 characters */
256, /* 256 characters */
@ -244,15 +230,15 @@ static const gfx_layout llc2_charlayout =
};
static GFXDECODE_START( gfx_llc2 )
GFXDECODE_ENTRY( "chargen", 0x0000, llc2_charlayout, 0, 1 )
GFXDECODE_ENTRY( "chargen", 0x0000, charlayout, 0, 1 )
GFXDECODE_END
/* Machine driver */
void llc2_state::llc2(machine_config &config)
{
/* basic machine hardware */
Z80(config, m_maincpu, XTAL(3'000'000));
m_maincpu->set_daisy_config(llc2_daisy_chain);
Z80(config, m_maincpu, 12_MHz_XTAL / 4);
m_maincpu->set_daisy_config(daisy_chain);
m_maincpu->set_addrmap(AS_PROGRAM, &llc2_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &llc2_state::io_map);
@ -262,7 +248,7 @@ void llc2_state::llc2(machine_config &config)
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */
screen.set_size(64*8, 32*8);
screen.set_visarea(0, 64*8-1, 0, 32*8-1);
screen.set_screen_update(FUNC(llc2_state::screen_update_llc2));
screen.set_screen_update(FUNC(llc2_state::screen_update));
screen.set_palette("palette");
GFXDECODE(config, "gfxdecode", "palette", gfx_llc2);
@ -270,17 +256,28 @@ void llc2_state::llc2(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.15);
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
z80pio_device& pio1(Z80PIO(config, "z80pio1", XTAL(3'000'000)));
z80pio_device& pio1(Z80PIO(config, "pio1", 12_MHz_XTAL / 4));
pio1.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
pio1.in_pa_callback().set(K7659_KEYBOARD_TAG, FUNC(k7659_keyboard_device::read));
pio1.in_pb_callback().set(FUNC(llc2_state::llc2_port1_b_r));
pio1.out_pb_callback().set(FUNC(llc2_state::llc2_port1_b_w));
pio1.in_pb_callback().set(FUNC(llc2_state::port1b_r));
pio1.out_pb_callback().set(FUNC(llc2_state::port1b_w));
z80pio_device& pio2(Z80PIO(config, "z80pio2", XTAL(3'000'000)));
pio2.in_pa_callback().set(FUNC(llc2_state::llc2_port2_a_r));
z80pio_device& pio2(Z80PIO(config, "pio2", 12_MHz_XTAL / 4));
pio2.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
pio2.in_pa_callback().set(FUNC(llc2_state::port2a_r));
Z80CTC(config, "z80ctc", XTAL(3'000'000));
Z80CTC(config, m_ctc, 12_MHz_XTAL / 4);
m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_ctc->set_clk<0>(12_MHz_XTAL / 8);
m_ctc->set_clk<1>(12_MHz_XTAL / 8);
m_ctc->set_clk<2>(50); // comes from deep in the video section, assumed to be 50Hz
m_ctc->zc_callback<2>().set(m_ctc, FUNC(z80ctc_device::trg3));
CASSETTE(config, m_cass);
m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
m_cass->add_route(ALL_OUTPUTS, "mono", 0.05);
K7659_KEYBOARD(config, K7659_KEYBOARD_TAG, 0);
@ -291,11 +288,11 @@ void llc2_state::llc2(machine_config &config)
/* ROM definition */
ROM_START( llc2 )
ROM_REGION( 0x6000, "maincpu", ROMREGION_ERASEFF )
ROM_LOAD( "scchmon_91.bin", 0x0000, 0x1000, CRC(218d8236) SHA1(b8297272cc79751afc2eb8688d99b40691346dcb) )
ROM_LOAD( "scchmon_91.d35", 0x0000, 0x1000, CRC(218d8236) SHA1(b8297272cc79751afc2eb8688d99b40691346dcb) )
ROM_LOAD( "gsbasic.bin", 0x4000, 0x2000, CRC(78a5f388) SHA1(e7b475b98dce36b24540ad11eb89046ddb4f02af) )
ROM_REGION( 0x0800, "chargen", 0 )
ROM_LOAD ("llc2font.bin", 0x0000, 0x0800, CRC(ce53e55d) SHA1(da23d93f14a8a1f8d82bb72470a96b0bfd81ed1b) )
ROM_LOAD ("llc2font.d17", 0x0000, 0x0800, CRC(ce53e55d) SHA1(da23d93f14a8a1f8d82bb72470a96b0bfd81ed1b) )
ROM_END