mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
Z88: added serial port and NVRAM support. [Sandro Ronco]
This commit is contained in:
parent
a9f4cae377
commit
b2aa336249
@ -1705,6 +1705,8 @@ files {
|
||||
MAME_DIR .. "src/mame/includes/z88.h",
|
||||
MAME_DIR .. "src/mame/machine/upd65031.cpp",
|
||||
MAME_DIR .. "src/mame/machine/upd65031.h",
|
||||
MAME_DIR .. "src/mame/machine/z88_impexp.cpp",
|
||||
MAME_DIR .. "src/mame/machine/z88_impexp.h",
|
||||
MAME_DIR .. "src/mame/video/z88.cpp",
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,26 @@ z88_1024k_flash_device::z88_1024k_flash_device(const machine_config &mconfig, co
|
||||
: device_t(mconfig, Z88_1024K_FLASH, tag, owner, clock)
|
||||
, device_z88cart_interface(mconfig, *this)
|
||||
, m_flash(*this, FLASH_TAG)
|
||||
, m_region(*this, FLASH_TAG)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_region - device-specific ROM region
|
||||
//-------------------------------------------------
|
||||
|
||||
ROM_START( z88_1024k_flash )
|
||||
ROM_REGION( 0x100000, FLASH_TAG, ROMREGION_ERASEFF )
|
||||
// this region is required to initialize the flash device with the data loaded from the cartridge interface
|
||||
ROM_END
|
||||
|
||||
|
||||
const tiny_rom_entry *z88_1024k_flash_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( z88_1024k_flash );
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
@ -64,7 +81,7 @@ void z88_1024k_flash_device::device_add_mconfig(machine_config &config)
|
||||
|
||||
uint8_t* z88_1024k_flash_device::get_cart_base()
|
||||
{
|
||||
return m_flash->base();
|
||||
return m_region->base();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
|
@ -26,6 +26,9 @@ protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
|
||||
// optional information overrides
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
|
||||
// z88cart_interface overrides
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
@ -34,6 +37,7 @@ protected:
|
||||
|
||||
private:
|
||||
required_device<intelfsh8_device> m_flash;
|
||||
required_memory_region m_region;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
|
@ -38,7 +38,10 @@ z88_32k_ram_device::z88_32k_ram_device(const machine_config &mconfig, const char
|
||||
}
|
||||
|
||||
z88_32k_ram_device::z88_32k_ram_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock), device_z88cart_interface(mconfig, *this), m_ram(nullptr)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_nvram_interface(mconfig, *this)
|
||||
, device_z88cart_interface(mconfig, *this)
|
||||
, m_ram(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
// ======================> z88_32k_ram_device
|
||||
|
||||
class z88_32k_ram_device : public device_t,
|
||||
public device_nvram_interface,
|
||||
public device_z88cart_interface
|
||||
{
|
||||
public:
|
||||
@ -26,6 +27,11 @@ protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
|
||||
// device_nvram_interface overrides
|
||||
virtual void nvram_default() override { }
|
||||
virtual bool nvram_read(util::read_stream &file) override { size_t actual; return !file.read (get_cart_base(), get_cart_size(), actual) && actual == get_cart_size(); }
|
||||
virtual bool nvram_write(util::write_stream &file) override { size_t actual; return !file.write(get_cart_base(), get_cart_size(), actual) && actual == get_cart_size(); }
|
||||
|
||||
// z88cart_interface overrides
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
|
@ -37,7 +37,12 @@ z88_32k_rom_device::z88_32k_rom_device(const machine_config &mconfig, const char
|
||||
}
|
||||
|
||||
z88_32k_rom_device::z88_32k_rom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock), device_z88cart_interface(mconfig, *this), m_rom(nullptr)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_nvram_interface(mconfig, *this)
|
||||
, device_z88cart_interface(mconfig, *this)
|
||||
, m_rom(nullptr)
|
||||
, m_vpp_state(0)
|
||||
, m_modified(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -66,6 +71,10 @@ z88_256k_rom_device::z88_256k_rom_device(const machine_config &mconfig, const ch
|
||||
void z88_32k_rom_device::device_start()
|
||||
{
|
||||
m_rom = machine().memory().region_alloc(tag(), get_cart_size(), 1, ENDIANNESS_LITTLE)->base();
|
||||
std::fill_n(m_rom, get_cart_size(), 0xff);
|
||||
|
||||
save_item(NAME(m_vpp_state));
|
||||
save_item(NAME(m_modified));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
@ -85,3 +94,20 @@ uint8_t z88_32k_rom_device::read(offs_t offset)
|
||||
{
|
||||
return m_rom[offset & (get_cart_size() - 1)];
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
write
|
||||
-------------------------------------------------*/
|
||||
|
||||
void z88_32k_rom_device::write(offs_t offset, uint8_t data)
|
||||
{
|
||||
if (m_vpp_state)
|
||||
{
|
||||
const uint32_t offset_mask = get_cart_size() - 1;
|
||||
if (m_rom[offset & offset_mask] & ~data)
|
||||
m_modified = true;
|
||||
|
||||
m_rom[offset & offset_mask] &= data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
// ======================> z88_32k_rom_device
|
||||
|
||||
class z88_32k_rom_device : public device_t,
|
||||
public device_nvram_interface,
|
||||
public device_z88cart_interface
|
||||
{
|
||||
public:
|
||||
@ -26,14 +27,24 @@ protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
|
||||
// device_nvram_interface overrides
|
||||
virtual void nvram_default() override { }
|
||||
virtual bool nvram_read(util::read_stream &file) override { size_t actual; return !file.read (get_cart_base(), get_cart_size(), actual) && actual == get_cart_size(); }
|
||||
virtual bool nvram_write(util::write_stream &file) override { size_t actual; return !file.write(get_cart_base(), get_cart_size(), actual) && actual == get_cart_size(); }
|
||||
virtual bool nvram_can_write() override { return m_modified; } // Save only if the EPROM has been programmed
|
||||
|
||||
// z88cart_interface overrides
|
||||
virtual uint8_t read(offs_t offset) override;
|
||||
virtual void write(offs_t offset, uint8_t data) override;
|
||||
virtual void vpp_w(int state) override { m_vpp_state = state; }
|
||||
virtual uint8_t* get_cart_base() override;
|
||||
virtual uint32_t get_cart_size() override { return 0x8000; }
|
||||
|
||||
protected:
|
||||
// internal state
|
||||
uint8_t * m_rom;
|
||||
int m_vpp_state;
|
||||
bool m_modified;
|
||||
};
|
||||
|
||||
// ======================> z88_128k_rom_device
|
||||
@ -59,7 +70,7 @@ public:
|
||||
|
||||
protected:
|
||||
// z88cart_interface overrides
|
||||
virtual uint32_t get_cart_size() override { return 0x200000; }
|
||||
virtual uint32_t get_cart_size() override { return 0x40000; }
|
||||
};
|
||||
|
||||
// device type definition
|
||||
|
@ -162,6 +162,24 @@ void z88cart_slot_device::call_unload()
|
||||
|
||||
std::string z88cart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
|
||||
{
|
||||
// select the correct slot device for the ROM size
|
||||
if (hook.image_file())
|
||||
{
|
||||
uint64_t size;
|
||||
std::error_condition err = hook.image_file()->length(size);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
if (size <= 0x8000) return std::string("32krom");
|
||||
if (size <= 0x20000) return std::string("128krom");
|
||||
if (size <= 0x40000) return std::string("256krom");
|
||||
if (size <= 0x100000) return std::string("1024kflash");
|
||||
fatalerror("%s: unsupported ROM size 0x%06x", tag(), size);
|
||||
}
|
||||
else
|
||||
fatalerror("%s: %s:%d %s\n", tag(), err.category().name(), err.value(), err.message());
|
||||
}
|
||||
|
||||
return software_get_default_slot("128krom");
|
||||
}
|
||||
|
||||
@ -189,6 +207,16 @@ void z88cart_slot_device::write(offs_t offset, uint8_t data)
|
||||
m_cart->write(offset, data);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
set EPROM programming voltage to slot 3
|
||||
-------------------------------------------------*/
|
||||
|
||||
void z88cart_slot_device::vpp_w(int state)
|
||||
{
|
||||
if (m_cart)
|
||||
m_cart->vpp_w(state);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_cart_base
|
||||
|
@ -74,6 +74,7 @@ public:
|
||||
// reading and writing
|
||||
virtual uint8_t read(offs_t offset) { return 0xff; }
|
||||
virtual void write(offs_t offset, uint8_t data) { }
|
||||
virtual void vpp_w(int state) { }
|
||||
virtual uint8_t* get_cart_base() { return nullptr; }
|
||||
virtual uint32_t get_cart_size() { return 0; }
|
||||
|
||||
@ -117,6 +118,7 @@ public:
|
||||
// reading and writing
|
||||
uint8_t read(offs_t offset);
|
||||
void write(offs_t offset, uint8_t data);
|
||||
void vpp_w(int state);
|
||||
uint8_t* get_cart_base();
|
||||
|
||||
protected:
|
||||
|
@ -2,17 +2,15 @@
|
||||
// copyright-holders:Kevin Thacker,Sandro Ronco
|
||||
/******************************************************************************
|
||||
|
||||
z88.c
|
||||
z88.cpp
|
||||
|
||||
z88 Notepad computer
|
||||
|
||||
system driver
|
||||
|
||||
TODO:
|
||||
- speaker controlled by txd
|
||||
- cartridges should be hot swappable
|
||||
- expansion interface
|
||||
- serial port
|
||||
|
||||
Kevin Thacker [MESS driver]
|
||||
|
||||
@ -46,110 +44,37 @@ explains why the extra checks are done
|
||||
|
||||
*/
|
||||
|
||||
// cartridges read
|
||||
uint8_t z88_state::bank0_cart_r(offs_t offset) { return m_carts[m_bank[0].slot]->read((m_bank[0].page<<14) + offset); }
|
||||
uint8_t z88_state::bank1_cart_r(offs_t offset) { return m_carts[m_bank[1].slot]->read((m_bank[1].page<<14) + offset); }
|
||||
uint8_t z88_state::bank2_cart_r(offs_t offset) { return m_carts[m_bank[2].slot]->read((m_bank[2].page<<14) + offset); }
|
||||
uint8_t z88_state::bank3_cart_r(offs_t offset) { return m_carts[m_bank[3].slot]->read((m_bank[3].page<<14) + offset); }
|
||||
|
||||
// cartridges write
|
||||
void z88_state::bank0_cart_w(offs_t offset, uint8_t data) { m_carts[m_bank[0].slot]->write((m_bank[0].page<<14) + offset, data); }
|
||||
void z88_state::bank1_cart_w(offs_t offset, uint8_t data) { m_carts[m_bank[1].slot]->write((m_bank[1].page<<14) + offset, data); }
|
||||
void z88_state::bank2_cart_w(offs_t offset, uint8_t data) { m_carts[m_bank[2].slot]->write((m_bank[2].page<<14) + offset, data); }
|
||||
void z88_state::bank3_cart_w(offs_t offset, uint8_t data) { m_carts[m_bank[3].slot]->write((m_bank[3].page<<14) + offset, data); }
|
||||
|
||||
|
||||
UPD65031_MEMORY_UPDATE(z88_state::bankswitch_update)
|
||||
{
|
||||
// bank 0 is always even
|
||||
if (bank == 0) page &= 0xfe;
|
||||
|
||||
if (page < 0x20) // internal ROM
|
||||
{
|
||||
// install read bank
|
||||
if (m_bank_type[bank] != Z88_BANK_ROM)
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_bank(bank<<14, (bank<<14) + 0x3fff, m_banks[bank + 1]);
|
||||
m_maincpu->space(AS_PROGRAM).unmap_write(bank<<14, (bank<<14) + 0x3fff);
|
||||
m_bank_type[bank] = Z88_BANK_ROM;
|
||||
}
|
||||
|
||||
m_banks[bank + 1]->set_entry(page);
|
||||
}
|
||||
else if (page < 0x40) // internal RAM
|
||||
{
|
||||
if((page & 0x1f) < (m_ram->size()>>14))
|
||||
{
|
||||
// install readwrite bank
|
||||
if (m_bank_type[bank] != Z88_BANK_RAM)
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_bank(bank<<14, (bank<<14) + 0x3fff, m_banks[bank + 1]);
|
||||
m_bank_type[bank] = Z88_BANK_RAM;
|
||||
}
|
||||
|
||||
// set the bank
|
||||
m_banks[bank + 1]->set_entry(page);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bank_type[bank] != Z88_BANK_UNMAP)
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).unmap_readwrite(bank<<14, (bank<<14) + 0x3fff);
|
||||
m_bank_type[bank] = Z88_BANK_UNMAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // cartridges
|
||||
{
|
||||
m_bank[bank].slot = (page >> 6) & 3;
|
||||
m_bank[bank].page = page & 0x3f;
|
||||
|
||||
if (m_bank_type[bank] != Z88_BANK_CART)
|
||||
{
|
||||
switch (bank)
|
||||
{
|
||||
case 0:
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x0000, 0x3fff, read8sm_delegate(*this, FUNC(z88_state::bank0_cart_r)), write8sm_delegate(*this, FUNC(z88_state::bank0_cart_w)));
|
||||
break;
|
||||
case 1:
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x4000, 0x7fff, read8sm_delegate(*this, FUNC(z88_state::bank1_cart_r)), write8sm_delegate(*this, FUNC(z88_state::bank1_cart_w)));
|
||||
break;
|
||||
case 2:
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x8000, 0xbfff, read8sm_delegate(*this, FUNC(z88_state::bank2_cart_r)), write8sm_delegate(*this, FUNC(z88_state::bank2_cart_w)));
|
||||
break;
|
||||
case 3:
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xc000, 0xffff, read8sm_delegate(*this, FUNC(z88_state::bank3_cart_r)), write8sm_delegate(*this, FUNC(z88_state::bank3_cart_w)));
|
||||
break;
|
||||
}
|
||||
|
||||
m_bank_type[bank] = Z88_BANK_CART;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// override setting for lower 8k of bank 0
|
||||
if (bank == 0)
|
||||
{
|
||||
m_maincpu->space(AS_PROGRAM).install_read_bank(0, 0x1fff, m_banks[0]);
|
||||
|
||||
// enable RAM
|
||||
if (rams)
|
||||
m_maincpu->space(AS_PROGRAM).install_write_bank(0, 0x1fff, m_banks[0]);
|
||||
else
|
||||
m_maincpu->space(AS_PROGRAM).unmap_write(0, 0x1fff);
|
||||
|
||||
m_banks[0]->set_entry(rams & 1);
|
||||
// bank 0 is only 8k (0x2000 - 0x3fff) and bit 0 is used to select the upper/lower
|
||||
// part of a 16k page, for this reason only even pages can be mapped in this bank.
|
||||
m_banks[bank]->set_bank(((page & 0xfe) << 1) | (page & 1));
|
||||
m_boot_view.select(rams ? 1 : 0);
|
||||
}
|
||||
else
|
||||
m_banks[bank]->set_bank(page);
|
||||
}
|
||||
|
||||
void z88_state::z88_map(address_map &map)
|
||||
{
|
||||
map(0x000000, 0x07ffff).rom().region("bios", 0);
|
||||
map(0x080000, 0x0fffff).rw(m_ram, FUNC(ram_device::read), FUNC(ram_device::write));
|
||||
map(0x100000, 0x1fffff).rw(m_carts[1], FUNC(z88cart_slot_device::read), FUNC(z88cart_slot_device::write));
|
||||
map(0x200000, 0x2fffff).rw(m_carts[2], FUNC(z88cart_slot_device::read), FUNC(z88cart_slot_device::write));
|
||||
map(0x300000, 0x3fffff).rw(m_carts[3], FUNC(z88cart_slot_device::read), FUNC(z88cart_slot_device::write));
|
||||
}
|
||||
|
||||
void z88_state::z88_mem(address_map &map)
|
||||
{
|
||||
map(0x0000, 0x1fff).bankrw(m_banks[0]);
|
||||
map(0x2000, 0x3fff).bankrw(m_banks[1]);
|
||||
map(0x4000, 0x7fff).bankrw(m_banks[2]);
|
||||
map(0x8000, 0xbfff).bankrw(m_banks[3]);
|
||||
map(0xc000, 0xffff).bankrw(m_banks[4]);
|
||||
map(0x0000, 0x1fff).view(m_boot_view);
|
||||
m_boot_view[0](0x0000, 0x1fff).rom().region("bios", 0);
|
||||
m_boot_view[1](0x0000, 0x1fff).rw(m_ram, FUNC(ram_device::read), FUNC(ram_device::write));
|
||||
map(0x2000, 0x3fff).rw(m_banks[0], FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
|
||||
map(0x4000, 0x7fff).rw(m_banks[1], FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
|
||||
map(0x8000, 0xbfff).rw(m_banks[2], FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
|
||||
map(0xc000, 0xffff).rw(m_banks[3], FUNC(address_map_bank_device::read8), FUNC(address_map_bank_device::write8));
|
||||
}
|
||||
|
||||
void z88_state::z88_io(address_map &map)
|
||||
@ -183,6 +108,11 @@ Small note about natural keyboard: currently,
|
||||
*/
|
||||
|
||||
static INPUT_PORTS_START( z88 )
|
||||
PORT_START("BATTERY")
|
||||
PORT_CONFNAME( 0x01, 0x00, "Battery Status" ) PORT_WRITE_LINE_DEVICE_MEMBER("blink", upd65031_device, btl_w)
|
||||
PORT_CONFSETTING( 0x00, DEF_STR( Normal ) )
|
||||
PORT_CONFSETTING( 0x01, "Low" )
|
||||
|
||||
PORT_START("LINE0")
|
||||
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Del") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
|
||||
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
|
||||
@ -551,26 +481,16 @@ INPUT_PORTS_END
|
||||
|
||||
void z88_state::machine_start()
|
||||
{
|
||||
m_bios = (uint8_t*)m_bios_region->base();
|
||||
m_ram_base = (uint8_t*)m_ram->pointer();
|
||||
|
||||
// configure the memory banks
|
||||
|
||||
m_banks[0]->configure_entry(0, m_bios);
|
||||
m_banks[0]->configure_entry(1, m_ram_base);
|
||||
m_banks[1]->configure_entries(0, 32, m_bios, 0x4000);
|
||||
m_banks[2]->configure_entries(0, 32, m_bios, 0x4000);
|
||||
m_banks[3]->configure_entries(0, 32, m_bios, 0x4000);
|
||||
m_banks[4]->configure_entries(0, 32, m_bios, 0x4000);
|
||||
m_banks[1]->configure_entries(32, m_ram->size()>>14, m_ram_base, 0x4000);
|
||||
m_banks[2]->configure_entries(32, m_ram->size()>>14, m_ram_base, 0x4000);
|
||||
m_banks[3]->configure_entries(32, m_ram->size()>>14, m_ram_base, 0x4000);
|
||||
m_banks[4]->configure_entries(32, m_ram->size()>>14, m_ram_base, 0x4000);
|
||||
m_nvram->set_base(m_ram->pointer(), m_ram->size());
|
||||
}
|
||||
|
||||
void z88_state::machine_reset()
|
||||
{
|
||||
m_bank_type[0] = m_bank_type[1] = m_bank_type[2] = m_bank_type[3] = 0;
|
||||
m_boot_view.select(0);
|
||||
m_banks[0]->set_bank(0);
|
||||
m_banks[1]->set_bank(0);
|
||||
m_banks[2]->set_bank(0);
|
||||
m_banks[3]->set_bank(0);
|
||||
}
|
||||
|
||||
uint8_t z88_state::kb_r(offs_t offset)
|
||||
@ -598,6 +518,23 @@ static void z88_cart(device_slot_interface &device)
|
||||
device.option_add("1024kflash", Z88_1024K_FLASH); // 1024KB Flash cart
|
||||
}
|
||||
|
||||
static DEVICE_INPUT_DEFAULTS_START( z88_rs232_defaults )
|
||||
DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 )
|
||||
DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 )
|
||||
DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 )
|
||||
DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE )
|
||||
DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 )
|
||||
DEVICE_INPUT_DEFAULTS( "FLOW_CONTROL", 0x07, 0x01 ) // Flow Control: RTS
|
||||
DEVICE_INPUT_DEFAULTS_END
|
||||
|
||||
|
||||
static void z88_rs232_devices(device_slot_interface &device)
|
||||
{
|
||||
default_rs232_devices(device);
|
||||
device.option_add("z88_impexp", Z88_IMPEXP);
|
||||
}
|
||||
|
||||
|
||||
void z88_state::z88(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
@ -605,12 +542,17 @@ void z88_state::z88(machine_config &config)
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &z88_state::z88_mem);
|
||||
m_maincpu->set_addrmap(AS_IO, &z88_state::z88_io);
|
||||
|
||||
ADDRESS_MAP_BANK(config, m_banks[0]).set_map(&z88_state::z88_map).set_options(ENDIANNESS_LITTLE, 8, 22, 0x2000);
|
||||
ADDRESS_MAP_BANK(config, m_banks[1]).set_map(&z88_state::z88_map).set_options(ENDIANNESS_LITTLE, 8, 22, 0x4000);
|
||||
ADDRESS_MAP_BANK(config, m_banks[2]).set_map(&z88_state::z88_map).set_options(ENDIANNESS_LITTLE, 8, 22, 0x4000);
|
||||
ADDRESS_MAP_BANK(config, m_banks[3]).set_map(&z88_state::z88_map).set_options(ENDIANNESS_LITTLE, 8, 22, 0x4000);
|
||||
|
||||
/* video hardware */
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_LCD);
|
||||
m_screen->set_refresh_hz(50);
|
||||
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0));
|
||||
m_screen->set_size(Z88_SCREEN_WIDTH, Z88_SCREEN_HEIGHT);
|
||||
m_screen->set_visarea(0, (Z88_SCREEN_WIDTH - 1), 0, (Z88_SCREEN_HEIGHT - 1));
|
||||
m_screen->set_visarea_full();
|
||||
m_screen->set_palette(m_palette);
|
||||
m_screen->set_screen_update("blink", FUNC(upd65031_device::screen_update));
|
||||
|
||||
@ -623,13 +565,24 @@ void z88_state::z88(machine_config &config)
|
||||
m_blink->spkr_wr_callback().set("speaker", FUNC(speaker_sound_device::level_w));
|
||||
m_blink->set_screen_update_callback(FUNC(z88_state::lcd_update));
|
||||
m_blink->set_memory_update_callback(FUNC(z88_state::bankswitch_update));
|
||||
m_blink->txd_wr_callback().set("rs232", FUNC(rs232_port_device::write_txd));
|
||||
m_blink->rts_wr_callback().set("rs232", FUNC(rs232_port_device::write_rts));
|
||||
m_blink->dtr_wr_callback().set("rs232", FUNC(rs232_port_device::write_dtr));
|
||||
m_blink->vpp_wr_callback().set(m_carts[3], FUNC(z88cart_slot_device::vpp_w)); // Only on Slot 3
|
||||
|
||||
rs232_port_device &rs232(RS232_PORT(config, "rs232", z88_rs232_devices, "z88_impexp"));
|
||||
rs232.rxd_handler().set(m_blink, FUNC(upd65031_device::rxd_w));
|
||||
rs232.cts_handler().set(m_blink, FUNC(upd65031_device::cts_w));
|
||||
rs232.dcd_handler().set(m_blink, FUNC(upd65031_device::dcd_w));
|
||||
rs232.set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(z88_rs232_defaults));
|
||||
|
||||
/* sound hardware */
|
||||
SPEAKER(config, "mono").front_center();
|
||||
SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 0.50);
|
||||
|
||||
/* internal ram */
|
||||
RAM(config, RAM_TAG).set_default_size("128K").set_extra_options("32K,64K,256K,512K");
|
||||
RAM(config, m_ram).set_default_size("128K").set_extra_options("32K,64K,256K,512K");
|
||||
NVRAM(config, m_nvram, nvram_device::DEFAULT_NONE);
|
||||
|
||||
/* cartridges */
|
||||
Z88CART_SLOT(config, m_carts[1], z88_cart, nullptr);
|
||||
|
@ -12,10 +12,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "machine/bankdev.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/upd65031.h"
|
||||
#include "machine/z88_impexp.h"
|
||||
#include "sound/spkrdev.h"
|
||||
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "bus/z88/flash.h"
|
||||
#include "bus/z88/ram.h"
|
||||
#include "bus/z88/rom.h"
|
||||
@ -44,7 +48,7 @@ public:
|
||||
z88_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag)
|
||||
, m_maincpu(*this, "maincpu")
|
||||
, m_bios_region(*this, "bios")
|
||||
, m_nvram(*this, "nvram")
|
||||
, m_ram(*this, RAM_TAG)
|
||||
, m_screen(*this, "screen")
|
||||
, m_palette(*this, "palette")
|
||||
@ -52,66 +56,40 @@ public:
|
||||
, m_lines(*this, "LINE%u", 0U)
|
||||
, m_banks(*this, "bank%u", 1U)
|
||||
, m_carts(*this, "slot%u", 0U)
|
||||
, m_boot_view(*this, "boot_view")
|
||||
{ }
|
||||
|
||||
void z88(machine_config &config);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
Z88_BANK_ROM = 1,
|
||||
Z88_BANK_RAM,
|
||||
Z88_BANK_CART,
|
||||
Z88_BANK_UNMAP
|
||||
};
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
uint8_t kb_r(offs_t offset);
|
||||
UPD65031_MEMORY_UPDATE(bankswitch_update);
|
||||
UPD65031_SCREEN_UPDATE(lcd_update);
|
||||
|
||||
// cartridges read/write
|
||||
uint8_t bank0_cart_r(offs_t offset);
|
||||
uint8_t bank1_cart_r(offs_t offset);
|
||||
uint8_t bank2_cart_r(offs_t offset);
|
||||
uint8_t bank3_cart_r(offs_t offset);
|
||||
void bank0_cart_w(offs_t offset, uint8_t data);
|
||||
void bank1_cart_w(offs_t offset, uint8_t data);
|
||||
void bank2_cart_w(offs_t offset, uint8_t data);
|
||||
void bank3_cart_w(offs_t offset, uint8_t data);
|
||||
|
||||
// defined in video/z88.c
|
||||
// defined in video/z88.cpp
|
||||
inline void plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint16_t color);
|
||||
inline uint8_t* convert_address(uint32_t offset);
|
||||
void vh_render_8x8(bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint8_t *gfx);
|
||||
void vh_render_6x8(bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint8_t *gfx);
|
||||
void vh_render_8x8(address_space &space, bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint32_t offset);
|
||||
void vh_render_6x8(address_space &space, bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint32_t offset);
|
||||
void vh_render_line(bitmap_ind16 &bitmap, int x, int y, uint16_t pen);
|
||||
|
||||
void z88_palette(palette_device &palette) const;
|
||||
|
||||
void z88_io(address_map &map);
|
||||
void z88_mem(address_map &map);
|
||||
void z88_map(address_map &map);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_memory_region m_bios_region;
|
||||
required_device<nvram_device> m_nvram;
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<upd65031_device> m_blink;
|
||||
required_ioport_array<8> m_lines;
|
||||
required_memory_bank_array<5> m_banks;
|
||||
required_device_array<address_map_bank_device, 4> m_banks;
|
||||
optional_device_array<z88cart_slot_device, 4> m_carts;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t slot = 0;
|
||||
uint8_t page = 0;
|
||||
} m_bank[4];
|
||||
|
||||
int m_bank_type[4] = {};
|
||||
uint8_t * m_bios = 0;
|
||||
uint8_t * m_ram_base = 0;
|
||||
memory_view m_boot_view;
|
||||
};
|
||||
|
||||
#endif // MAME_INCLUDES_Z88_H
|
||||
|
@ -15,9 +15,7 @@
|
||||
|
||||
TODO:
|
||||
- coma and snooze mode
|
||||
- speaker controlled by txd
|
||||
- EPROM programming
|
||||
- UART
|
||||
- UART Loopback mode
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
@ -25,6 +23,9 @@
|
||||
#include "emu.h"
|
||||
#include "upd65031.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(UPD65031, upd65031_device, "upd65031", "NEC uPD65031")
|
||||
@ -34,9 +35,9 @@ DEFINE_DEVICE_TYPE(UPD65031, upd65031_device, "upd65031", "NEC uPD65031")
|
||||
// MACROS / CONSTANTS
|
||||
//**************************************************************************
|
||||
|
||||
#define LOG 0
|
||||
namespace {
|
||||
|
||||
#define SPEAKER_ALARM_FREQ attotime::from_hz(3200)
|
||||
static constexpr uint32_t SPEAKER_ALARM_FREQ = 3200;
|
||||
|
||||
// internal registers
|
||||
enum
|
||||
@ -92,48 +93,98 @@ enum
|
||||
};
|
||||
|
||||
// interrupt status
|
||||
#define STA_FLAPOPEN 0x80
|
||||
#define STA_A19 0x40
|
||||
#define STA_FLAP 0x20
|
||||
#define STA_UART 0x10
|
||||
#define STA_BTL 0x08
|
||||
#define STA_KEY 0x04
|
||||
#define STA_TIME 0x01
|
||||
static constexpr uint8_t STA_FLAPOPEN = 0x80; // Flap status
|
||||
static constexpr uint8_t STA_A19 = 0x40; // High level on A19 occurred during Coma
|
||||
static constexpr uint8_t STA_FLAP = 0x20; // Flap interrupt
|
||||
static constexpr uint8_t STA_UART = 0x10; // UART interrupt
|
||||
static constexpr uint8_t STA_BTL = 0x08; // Battery low interrupt
|
||||
static constexpr uint8_t STA_KEY = 0x04; // Keyboard interrupt
|
||||
static constexpr uint8_t STA_TIME = 0x01; // RTC interrupt
|
||||
|
||||
// interrupt control
|
||||
#define INT_KWAIT 0x80
|
||||
#define INT_A19 0x40
|
||||
#define INT_FLAP 0x20
|
||||
#define INT_UART 0x10
|
||||
#define INT_BTL 0x08
|
||||
#define INT_KEY 0x04
|
||||
#define INT_TIME 0x02
|
||||
#define INT_GINT 0x01
|
||||
static constexpr uint8_t INT_KWAIT = 0x80; // Reading the keyboard will Snooze
|
||||
static constexpr uint8_t INT_A19 = 0x40; // A19 high will exit Coma mode
|
||||
static constexpr uint8_t INT_FLAP = 0x20; // Enable Flap open interrupt
|
||||
static constexpr uint8_t INT_UART = 0x10; // Enable UART interrupt
|
||||
static constexpr uint8_t INT_BTL = 0x08; // Enable Battery low interrupt
|
||||
static constexpr uint8_t INT_KEY = 0x04; // Enable Keyboard interrupt
|
||||
static constexpr uint8_t INT_TIME = 0x02; // Enable RTC interrupt
|
||||
static constexpr uint8_t INT_GINT = 0x01; // Global interrupts mask
|
||||
|
||||
// acknowledge interrupts
|
||||
static constexpr uint8_t ACK_A19 = 0x40; // Acknowledge A19 interrupt
|
||||
static constexpr uint8_t ACK_FLAP = 0x20; // Acknowledge Flap interrupt
|
||||
static constexpr uint8_t ACK_BTL = 0x08; // Acknowledge battery low interrupt
|
||||
static constexpr uint8_t ACK_KEY = 0x04; // Acknowledge keyboard interrupt
|
||||
|
||||
// command register
|
||||
#define COM_SRUN 0x80
|
||||
#define COM_SBIT 0x40
|
||||
#define COM_OVERP 0x20
|
||||
#define COM_RESTIM 0x10
|
||||
#define COM_PROGRAM 0x08
|
||||
#define COM_RAMS 0x04
|
||||
#define COM_VPPON 0x02
|
||||
#define COM_LCDON 0x01
|
||||
static constexpr uint8_t COM_SRUN = 0x80; // Speaker source (0: manual, 1: auto)
|
||||
static constexpr uint8_t COM_SBIT = 0x40; // Speaker source for SRUN=1 (0: 3200Hz, 1: TxD)
|
||||
static constexpr uint8_t COM_OVERP = 0x20; // Overprogram EPROMs
|
||||
static constexpr uint8_t COM_RESTIM = 0x10; // RTC reset
|
||||
static constexpr uint8_t COM_PROGRAM = 0x08; // EPROM programming
|
||||
static constexpr uint8_t COM_RAMS = 0x04; // Enable boot ROM bank
|
||||
static constexpr uint8_t COM_VPPON = 0x02; // Programming voltage ON
|
||||
static constexpr uint8_t COM_LCDON = 0x01; // LCD ON
|
||||
|
||||
// EPROM programming register
|
||||
#define EPR_PD1 0x80
|
||||
#define EPR_PD0 0x40
|
||||
#define EPR_PGMD 0x20
|
||||
#define EPR_EOED 0x10
|
||||
#define EPR_SE3D 0x08
|
||||
#define EPR_PGMP 0x04
|
||||
#define EPR_EOEP 0x02
|
||||
#define EPR_SE3P 0x01
|
||||
static constexpr uint8_t EPR_PD = 0xc0; // Two bits representing the length of delay period
|
||||
static constexpr uint8_t EPR_PGMD = 0x20; // State of program pulse during delay period
|
||||
static constexpr uint8_t EPR_EOED = 0x10; // State of EOE during delay period
|
||||
static constexpr uint8_t EPR_SE3D = 0x08; // State of slot 3 select during delay period
|
||||
static constexpr uint8_t EPR_PGMP = 0x04; // State of program pulse during porch period
|
||||
static constexpr uint8_t EPR_EOEP = 0x02; // State of EOE during porch period
|
||||
static constexpr uint8_t EPR_SE3P = 0x01; // State of slot 3 select during porch period
|
||||
|
||||
// RTC interrupt status
|
||||
#define TSTA_MIN 0x04
|
||||
#define TSTA_SEC 0x02
|
||||
#define TSTA_TICK 0x01
|
||||
static constexpr uint8_t TSTA_MIN = 0x04; // Minute interrupt has occurred
|
||||
static constexpr uint8_t TSTA_SEC = 0x02; // Second interrupt has occurred
|
||||
static constexpr uint8_t TSTA_TICK = 0x01; // Tick interrupt has occurred
|
||||
|
||||
// UART extended receive data
|
||||
static constexpr uint8_t RXE_FE = 0x20; // Frame error
|
||||
static constexpr uint8_t RXE_RXDB = 0x10; // RXD line state
|
||||
static constexpr uint8_t RXE_TCLK = 0x08; // Transmit clock
|
||||
static constexpr uint8_t RXE_RCLK = 0x04; // Receive clock
|
||||
static constexpr uint8_t RXE_PAR = 0x02; // Parity bit
|
||||
static constexpr uint8_t RXE_START = 0x01; // Start bit (should be zero)
|
||||
|
||||
// UART receive control
|
||||
static constexpr uint8_t RXC_SHTW = 0x80; // Short word mode
|
||||
static constexpr uint8_t RXC_LOOP = 0x40; // Loopback mode
|
||||
static constexpr uint8_t RXC_UART = 0x20; // Reset
|
||||
static constexpr uint8_t RXC_ARTS = 0x10; // Auto RTS mode
|
||||
static constexpr uint8_t RXC_IRTS = 0x08; // Invert RTS
|
||||
static constexpr uint8_t RXC_BAUD = 0x07; // Baud rate
|
||||
|
||||
// UART transmit control
|
||||
static constexpr uint8_t TXC_UTEST = 0x80; // Fast baud rate
|
||||
static constexpr uint8_t TXC_IDCD = 0x40; // DCD interrupt when low (0 for when high)
|
||||
static constexpr uint8_t TXC_ICTS = 0x20; // CTD interrupt when low (0 for when high)
|
||||
static constexpr uint8_t TXC_ATX = 0x10; // Auto transmit mode
|
||||
static constexpr uint8_t TXC_ITX = 0x08; // Invert Tx
|
||||
static constexpr uint8_t TXC_BAUD = 0x07; // Baud rate
|
||||
|
||||
// UART interrupt status
|
||||
static constexpr uint8_t UIT_RSRD = 0x80; // Receive shift register full
|
||||
static constexpr uint8_t UIT_DCDI = 0x40; // DCD interrupt
|
||||
static constexpr uint8_t UIT_CTSI = 0x20; // CTS interrupt
|
||||
static constexpr uint8_t UIT_TDRE = 0x10; // Transmit register empty
|
||||
static constexpr uint8_t UIT_RDRF = 0x04; // Receive register full
|
||||
static constexpr uint8_t UIT_DCD = 0x02; // Inverse of the DCD line level
|
||||
static constexpr uint8_t UIT_CTS = 0x01; // Inverse of the CTS line level
|
||||
|
||||
// UART interrupt mask
|
||||
static constexpr uint8_t UMK_DCD = 0x40; // DCD interrupts are enabled
|
||||
static constexpr uint8_t UMK_CTS = 0x20; // CTS interrupts are enabled
|
||||
static constexpr uint8_t UMK_TDRE = 0x10; // Transmit data register empty interrupt enabled
|
||||
static constexpr uint8_t UMK_RDRF = 0x04; // Receive data register full interrupt enabled
|
||||
|
||||
// UART interrupt acknowledge register
|
||||
static constexpr uint8_t UAK_DCD = 0x40; // Acknowledge DCD interrupt
|
||||
static constexpr uint8_t UAK_CTS = 0x20; // Acknowledge CTS interrupt
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//**************************************************************************
|
||||
// INLINE HELPERS
|
||||
@ -143,13 +194,13 @@ inline void upd65031_device::interrupt_refresh()
|
||||
{
|
||||
if ((m_int & INT_GINT) && ((m_int & m_sta & 0x7c) || ((m_int & INT_TIME) && (m_sta & STA_TIME))))
|
||||
{
|
||||
if (LOG) logerror("uPD65031 '%s': set int\n", tag());
|
||||
LOG("%s: set int\n", machine().describe_context());
|
||||
|
||||
m_write_int(ASSERT_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG) logerror("uPD65031 '%s': clear int\n", tag());
|
||||
LOG("%s: clear int\n", machine().describe_context());
|
||||
|
||||
m_write_int(CLEAR_LINE);
|
||||
}
|
||||
@ -165,6 +216,24 @@ inline void upd65031_device::update_rtc_interrupt()
|
||||
m_sta &= ~STA_TIME;
|
||||
}
|
||||
|
||||
inline void upd65031_device::update_uart_interrupt()
|
||||
{
|
||||
if ((m_int & INT_UART) && (m_uit & m_umk))
|
||||
m_sta |= STA_UART;
|
||||
else
|
||||
m_sta &= ~STA_UART;
|
||||
|
||||
interrupt_refresh();
|
||||
}
|
||||
|
||||
inline void upd65031_device::update_tx(int state)
|
||||
{
|
||||
m_txd_line = state;
|
||||
m_write_txd(m_txd_line);
|
||||
|
||||
if ((m_com & COM_SRUN) && (m_com & COM_SBIT))
|
||||
m_write_spkr(m_txd_line);
|
||||
}
|
||||
|
||||
inline void upd65031_device::set_mode(int mode)
|
||||
{
|
||||
@ -198,12 +267,19 @@ inline void upd65031_device::set_mode(int mode)
|
||||
|
||||
upd65031_device::upd65031_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, UPD65031, tag, owner, clock),
|
||||
device_serial_interface(mconfig, *this),
|
||||
m_read_kb(*this),
|
||||
m_write_int(*this),
|
||||
m_write_nmi(*this),
|
||||
m_write_spkr(*this),
|
||||
m_write_txd(*this),
|
||||
m_write_rts(*this),
|
||||
m_write_dtr(*this),
|
||||
m_write_vpp(*this),
|
||||
m_screen_update_cb(*this),
|
||||
m_out_mem_cb(*this)
|
||||
m_out_mem_cb(*this),
|
||||
m_sta(0),
|
||||
m_int(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -219,6 +295,10 @@ void upd65031_device::device_start()
|
||||
m_write_int.resolve_safe();
|
||||
m_write_nmi.resolve_safe();
|
||||
m_write_spkr.resolve_safe();
|
||||
m_write_txd.resolve_safe();
|
||||
m_write_rts.resolve_safe();
|
||||
m_write_dtr.resolve_safe();
|
||||
m_write_vpp.resolve_safe();
|
||||
|
||||
// bind delegates
|
||||
m_screen_update_cb.resolve();
|
||||
@ -244,6 +324,12 @@ void upd65031_device::device_start()
|
||||
save_item(NAME(m_tmk));
|
||||
save_item(NAME(m_tack));
|
||||
save_item(NAME(m_com));
|
||||
save_item(NAME(m_uit));
|
||||
save_item(NAME(m_umk));
|
||||
save_item(NAME(m_txc));
|
||||
save_item(NAME(m_rxe));
|
||||
save_item(NAME(m_rxc));
|
||||
save_item(NAME(m_txd_line));
|
||||
save_item(NAME(m_flash));
|
||||
}
|
||||
|
||||
@ -266,6 +352,12 @@ void upd65031_device::device_reset()
|
||||
m_com = 0;
|
||||
m_flash = 0;
|
||||
m_mode = 0;
|
||||
m_uit = UIT_TDRE; // Transmit register empty
|
||||
m_umk = 0x00;
|
||||
m_rxe = 0x00;
|
||||
m_rxc = RXC_SHTW | 0x05; // 9600 baud, 1 Stop Bit
|
||||
m_txc = TXC_IDCD | TXC_ICTS | 0x05; // 9600 baud
|
||||
m_txd_line = 0;
|
||||
set_mode(STATE_AWAKE);
|
||||
|
||||
if (!m_out_mem_cb.isnull())
|
||||
@ -276,6 +368,14 @@ void upd65031_device::device_reset()
|
||||
m_out_mem_cb(2, 0, 0);
|
||||
m_out_mem_cb(3, 0, 0);
|
||||
}
|
||||
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
||||
set_rate(9600);
|
||||
transmit_register_reset();
|
||||
receive_register_reset();
|
||||
m_write_rts(1);
|
||||
m_write_dtr(1);
|
||||
m_write_vpp(0);
|
||||
}
|
||||
|
||||
|
||||
@ -292,7 +392,7 @@ void upd65031_device::device_timer(emu_timer &timer, device_timer_id id, int par
|
||||
// if a key is pressed sets the interrupt
|
||||
if ((m_int & INT_GINT) && (m_int & INT_KEY) && m_read_kb(0) != 0xff)
|
||||
{
|
||||
if (LOG) logerror("uPD65031 '%s': Keyboard interrupt!\n", tag());
|
||||
LOG("%s: Keyboard interrupt!\n", machine().describe_context());
|
||||
|
||||
// awakes CPU from snooze on key down
|
||||
if (m_mode == STATE_SNOOZE)
|
||||
@ -324,20 +424,22 @@ void upd65031_device::device_timer(emu_timer &timer, device_timer_id id, int par
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tim[0] == 200)
|
||||
if (m_tim[0] == 128) // on the rising edge of TIM0 bit 7
|
||||
{
|
||||
m_tim[0] = 0;
|
||||
|
||||
// set seconds int has occurred
|
||||
if (m_tmk & TSTA_SEC)
|
||||
{
|
||||
m_tsta |= TSTA_SEC;
|
||||
irq_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tim[0] == 200)
|
||||
{
|
||||
m_tim[0] = 0;
|
||||
m_tim[1]++;
|
||||
|
||||
if (m_tim[1] == 60)
|
||||
if (m_tim[1] == 32) // on the rising edge of TIM1 bit 5
|
||||
{
|
||||
// set minutes int has occurred
|
||||
if (m_tmk & TSTA_MIN)
|
||||
@ -345,6 +447,10 @@ void upd65031_device::device_timer(emu_timer &timer, device_timer_id id, int par
|
||||
m_tsta |= TSTA_MIN;
|
||||
irq_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tim[1] == 60)
|
||||
{
|
||||
m_tim[1] = 0;
|
||||
m_tim[2]++;
|
||||
|
||||
@ -419,47 +525,54 @@ uint8_t upd65031_device::read(offs_t offset)
|
||||
{
|
||||
set_mode(STATE_SNOOZE);
|
||||
|
||||
if (LOG) logerror("uPD65031 '%s': entering snooze!\n", tag());
|
||||
LOG("%s: entering snooze!\n", machine().describe_context());
|
||||
}
|
||||
|
||||
uint8_t data = m_read_kb(offset>>8);
|
||||
|
||||
if (LOG) logerror("uPD65031 '%s': key r %02x: %02x\n", tag(), offset>>8, data);
|
||||
LOG("%s: key r %02x %02x\n", machine().describe_context(), offset>>8, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// read real time clock status
|
||||
case REG_TSTA:
|
||||
if (LOG) logerror("uPD65031 '%s': tsta r: %02x\n", tag(), m_tsta);
|
||||
LOG("%s: tsta r %02x\n", machine().describe_context(), m_tsta);
|
||||
return m_tsta & 0x07;
|
||||
|
||||
// read real time clock counters
|
||||
case REG_TIM0:
|
||||
if (LOG) logerror("uPD65031 '%s': TIM0 r: %02x\n", tag(), m_tim[0]);
|
||||
LOG("%s: TIM0 r %02x\n", machine().describe_context(), m_tim[0]);
|
||||
return m_tim[0];
|
||||
case REG_TIM1:
|
||||
if (LOG) logerror("uPD65031 '%s': TIM1 r: %02x\n", tag(), m_tim[1]);
|
||||
LOG("%s: TIM1 r %02x\n", machine().describe_context(), m_tim[1]);
|
||||
return m_tim[1];
|
||||
case REG_TIM2:
|
||||
if (LOG) logerror("uPD65031 '%s': TIM2 r: %02x\n", tag(), m_tim[2]);
|
||||
LOG("%s: TIM2 r %02x\n", machine().describe_context(), m_tim[2]);
|
||||
return m_tim[2];
|
||||
case REG_TIM3:
|
||||
if (LOG) logerror("uPD65031 '%s': TIM3 r: %02x\n", tag(), m_tim[3]);
|
||||
LOG("%s: TIM3 r %02x\n", machine().describe_context(), m_tim[3]);
|
||||
return m_tim[3];
|
||||
case REG_TIM4:
|
||||
if (LOG) logerror("uPD65031 '%s': TIM4 r: %02x\n", tag(), m_tim[4]);
|
||||
LOG("%s: TIM4 r %02x\n", machine().describe_context(), m_tim[4]);
|
||||
return m_tim[4];
|
||||
|
||||
// UART
|
||||
case REG_RXD:
|
||||
case REG_RXE:
|
||||
case REG_UIT:
|
||||
// TODO
|
||||
return 0;
|
||||
case REG_RXD: // UART receive data register
|
||||
m_uit &= ~UIT_RDRF;
|
||||
update_uart_interrupt();
|
||||
if (m_rxc & RXC_ARTS) // Auto RTS mode
|
||||
m_write_rts(1);
|
||||
return get_received_char();
|
||||
|
||||
case REG_RXE: // UART extended receive data
|
||||
return m_rxe;
|
||||
|
||||
case REG_UIT: // UART interrupt status
|
||||
return m_uit;
|
||||
|
||||
default:
|
||||
logerror("uPD65031 '%s': blink r: %04x\n", tag(), offset);
|
||||
logerror("%s: blink r %04x\n", machine().describe_context(), offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -471,6 +584,7 @@ uint8_t upd65031_device::read(offs_t offset)
|
||||
|
||||
void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
{
|
||||
static const int uart_div[] = { 1 << 17, 1 << 15, 1 << 14, 1 << 13, 1 << 12, 1 << 10, 1 << 9, 1 << 8 };
|
||||
uint8_t port = offset & 0xff;
|
||||
|
||||
switch (port)
|
||||
@ -485,7 +599,7 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
break;
|
||||
|
||||
case REG_COM: // command register
|
||||
if (LOG) logerror("uPD65031 '%s': com w: %02x\n", tag(), data);
|
||||
LOG("%s: com w %02x\n", machine().describe_context(), data);
|
||||
|
||||
// reset clock?
|
||||
if (data & COM_RESTIM)
|
||||
@ -494,7 +608,7 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
if ((data & COM_SRUN) && !(data & COM_SBIT))
|
||||
{
|
||||
// constant tone used for keyclick and alarm
|
||||
m_speaker_timer->adjust(SPEAKER_ALARM_FREQ, 0, SPEAKER_ALARM_FREQ);
|
||||
m_speaker_timer->adjust(attotime::from_hz(SPEAKER_ALARM_FREQ), 0, attotime::from_hz(SPEAKER_ALARM_FREQ));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -507,7 +621,7 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
else
|
||||
{
|
||||
// speaker controlled by txd line
|
||||
// TODO
|
||||
m_write_spkr(m_txd_line);
|
||||
}
|
||||
|
||||
m_speaker_timer->reset();
|
||||
@ -517,11 +631,13 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
if (BIT(m_com^data, 2) && !m_out_mem_cb.isnull())
|
||||
m_out_mem_cb(0, m_sr[0], BIT(data, 2));
|
||||
|
||||
m_write_vpp(BIT(data, 1));
|
||||
|
||||
m_com = data;
|
||||
break;
|
||||
|
||||
case REG_INT: // interrupt control
|
||||
if (LOG) logerror("uPD65031 '%s': int w: %02x\n", tag(), data);
|
||||
LOG("%s: int w %02x\n", machine().describe_context(), data);
|
||||
|
||||
m_int = data;
|
||||
|
||||
@ -531,12 +647,11 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
break;
|
||||
|
||||
case REG_EPR: // EPROM programming register
|
||||
if (LOG) logerror("uPD65031 '%s': epr w: %02x\n", tag(), data);
|
||||
// TODO
|
||||
LOG("%s: epr w %02x\n", machine().describe_context(), data);
|
||||
break;
|
||||
|
||||
case REG_TACK: // rtc interrupt acknowledge
|
||||
if (LOG) logerror("uPD65031 '%s': tack w: %02x\n", tag(), data);
|
||||
LOG("%s: tack w %02x\n", machine().describe_context(), data);
|
||||
|
||||
// clear ints that have occurred
|
||||
m_tsta &= ~(data & 0x07);
|
||||
@ -548,13 +663,13 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
break;
|
||||
|
||||
case REG_TMK: // write rtc interrupt mask
|
||||
if (LOG) logerror("uPD65031 '%s': tmk w: %02x\n", tag(), data);
|
||||
LOG("%s: tmk w %02x\n", machine().describe_context(), data);
|
||||
|
||||
m_tmk = data & 0x07;
|
||||
break;
|
||||
|
||||
case REG_ACK: // acknowledge ints
|
||||
if (LOG) logerror("uPD65031 '%s': ack w: %02x\n", tag(), data);
|
||||
LOG("%s: ack w %02x\n", machine().describe_context(), data);
|
||||
|
||||
m_ack = data;
|
||||
m_sta &= ~(data & 0x7f);
|
||||
@ -575,21 +690,116 @@ void upd65031_device::write(offs_t offset, uint8_t data)
|
||||
break;
|
||||
|
||||
// UART
|
||||
case REG_RXC:
|
||||
case REG_TXD:
|
||||
case REG_TXC:
|
||||
case REG_UMK:
|
||||
case REG_UAK:
|
||||
if (LOG) logerror("uPD65031 '%s': UART w: %02x %02x\n", tag(), port & 7 , data);
|
||||
// TODO
|
||||
case REG_RXC: // UART receive control
|
||||
LOG("%s: UART receive control %02x\n", machine().describe_context(), data);
|
||||
|
||||
if ((m_rxc & RXC_BAUD) != (data & RXC_BAUD))
|
||||
set_rcv_rate(clock() / uart_div[data & RXC_BAUD]);
|
||||
|
||||
if ((m_rxc ^ data) & RXC_SHTW)
|
||||
set_data_frame(1, 8, PARITY_NONE, (data & RXC_SHTW) ? STOP_BITS_1 : STOP_BITS_2);
|
||||
|
||||
if (data & RXC_LOOP)
|
||||
logerror("%s: Unsupported UART Loopback mode\n", machine().describe_context());
|
||||
|
||||
if (!(data & RXC_ARTS))
|
||||
m_write_rts((data & RXC_IRTS) ? 0 : 1);
|
||||
|
||||
m_rxc = data;
|
||||
break;
|
||||
|
||||
case REG_TXD: // UART transmit data
|
||||
transmit_register_setup(data);
|
||||
m_uit &= ~UIT_TDRE;
|
||||
update_uart_interrupt();
|
||||
break;
|
||||
|
||||
case REG_TXC: // UART transmit control
|
||||
LOG("%s: UART transmit control %02x\n", machine().describe_context(), data);
|
||||
|
||||
if ((m_txc & TXC_BAUD) != (data & TXC_BAUD))
|
||||
set_tra_rate(clock() / uart_div[data & TXC_BAUD]);
|
||||
|
||||
if (!(data & TXC_ATX) && ((m_txc ^ data) & TXC_ITX))
|
||||
update_tx((data & TXC_ITX) ? 0 : 1);
|
||||
|
||||
m_txc = data;
|
||||
break;
|
||||
|
||||
case REG_UMK: // UART interrupt mask
|
||||
LOG("%s: UART interrupt mask %02x\n", machine().describe_context(), data);
|
||||
|
||||
m_umk = data;
|
||||
update_uart_interrupt();
|
||||
break;
|
||||
|
||||
case REG_UAK: // UART interrupt acknowledge
|
||||
LOG("%s: UART interrupt acknowledge %02x\n", machine().describe_context(), data);
|
||||
|
||||
m_uit &= ~(data & m_umk & (UAK_CTS | UAK_DCD));
|
||||
update_uart_interrupt();
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("uPD65031 '%s': blink w: %04x %02x\n", tag(), offset, data);
|
||||
logerror("%s: blink w %04x = %02x\n", machine().describe_context(), offset, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void upd65031_device::tra_callback()
|
||||
{
|
||||
update_tx(transmit_register_get_data_bit() ^ BIT(m_txc, 3));
|
||||
}
|
||||
|
||||
void upd65031_device::tra_complete()
|
||||
{
|
||||
m_uit |= UIT_TDRE;
|
||||
update_uart_interrupt();
|
||||
}
|
||||
|
||||
void upd65031_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
|
||||
m_uit |= UIT_RDRF;
|
||||
|
||||
if (m_rxc & RXC_ARTS) // Auto RTS mode
|
||||
m_write_rts(0);
|
||||
|
||||
// Frame error
|
||||
if (is_receive_framing_error())
|
||||
m_rxe |= RXE_FE;
|
||||
else
|
||||
m_rxe &= ~RXE_FE;
|
||||
|
||||
update_uart_interrupt();
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( upd65031_device::cts_w )
|
||||
{
|
||||
if (state == BIT(m_uit, 0))
|
||||
{
|
||||
m_uit = (m_uit & ~UIT_CTS) | (state ? 0 : UIT_CTS);
|
||||
if (state != BIT(m_txc, 5))
|
||||
{
|
||||
m_uit |= UIT_CTSI;
|
||||
update_uart_interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( upd65031_device::dcd_w )
|
||||
{
|
||||
if (state == BIT(m_uit, 1))
|
||||
{
|
||||
m_uit = (m_uit & ~UIT_DCD) | (state ? 0 : UIT_DCD);
|
||||
if (state != BIT(m_txc, 6))
|
||||
{
|
||||
m_uit |= UIT_DCDI;
|
||||
update_uart_interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// flp line
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "diserial.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
@ -22,7 +23,8 @@
|
||||
|
||||
// ======================> upd65031_device
|
||||
|
||||
class upd65031_device : public device_t
|
||||
class upd65031_device : public device_t,
|
||||
public device_serial_interface
|
||||
{
|
||||
public:
|
||||
typedef device_delegate<void (bitmap_ind16 &bitmap, uint16_t sbf, uint16_t hires0, uint16_t hires1, uint16_t lores0, uint16_t lores1, int flash)> screen_update_delegate;
|
||||
@ -35,6 +37,10 @@ public:
|
||||
auto int_wr_callback() { return m_write_int.bind(); }
|
||||
auto nmi_wr_callback() { return m_write_nmi.bind(); }
|
||||
auto spkr_wr_callback() { return m_write_spkr.bind(); }
|
||||
auto txd_wr_callback() { return m_write_txd.bind(); }
|
||||
auto rts_wr_callback() { return m_write_rts.bind(); }
|
||||
auto dtr_wr_callback() { return m_write_dtr.bind(); }
|
||||
auto vpp_wr_callback() { return m_write_vpp.bind(); }
|
||||
|
||||
template <typename... T> void set_screen_update_callback(T &&... args) { m_screen_update_cb.set(std::forward<T>(args)...); }
|
||||
template <typename... T> void set_memory_update_callback(T &&... args) { m_out_mem_cb.set(std::forward<T>(args)...); }
|
||||
@ -43,6 +49,9 @@ public:
|
||||
void write(offs_t offset, uint8_t data);
|
||||
DECLARE_WRITE_LINE_MEMBER( flp_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( btl_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( rxd_w ) { rx_w(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( cts_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( dcd_w );
|
||||
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
|
||||
|
||||
protected:
|
||||
@ -51,9 +60,15 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override;
|
||||
|
||||
virtual void tra_callback() override;
|
||||
virtual void tra_complete() override;
|
||||
virtual void rcv_complete() override;
|
||||
|
||||
private:
|
||||
inline void interrupt_refresh();
|
||||
inline void update_rtc_interrupt();
|
||||
inline void update_uart_interrupt();
|
||||
inline void update_tx(int state);
|
||||
inline void set_mode(int mode);
|
||||
static const device_timer_id TIMER_RTC = 0;
|
||||
static const device_timer_id TIMER_FLASH = 1;
|
||||
@ -63,6 +78,10 @@ private:
|
||||
devcb_write_line m_write_int;
|
||||
devcb_write_line m_write_nmi;
|
||||
devcb_write_line m_write_spkr;
|
||||
devcb_write_line m_write_txd;
|
||||
devcb_write_line m_write_rts;
|
||||
devcb_write_line m_write_dtr;
|
||||
devcb_write_line m_write_vpp;
|
||||
|
||||
screen_update_delegate m_screen_update_cb; // callback for update the LCD
|
||||
memory_update_delegate m_out_mem_cb; // callback for update bankswitch
|
||||
@ -78,6 +97,12 @@ private:
|
||||
uint8_t m_tmk; // timer interrupt mask
|
||||
uint8_t m_tack; // timer interrupts acknowledge
|
||||
uint8_t m_com; // command register
|
||||
uint8_t m_uit; // UART interrupt status
|
||||
uint8_t m_umk; // UART interrupt mask
|
||||
uint8_t m_txc; // UART transmit control register
|
||||
uint8_t m_rxc; // UART receive control register
|
||||
uint8_t m_rxe; // UART extended receive data register
|
||||
int m_txd_line; // TXD line
|
||||
int m_flash; // cursor flash
|
||||
int m_speaker_state; // spkr line
|
||||
|
||||
|
273
src/mame/machine/z88_impexp.cpp
Normal file
273
src/mame/machine/z88_impexp.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Sandro Ronco
|
||||
/**********************************************************************
|
||||
|
||||
Z88 Imp-Export protocol
|
||||
|
||||
Send to Z88:
|
||||
- Launch Imp-Export popdown on Z88.
|
||||
- On Z88, select batch receive by pressing b and then the Enter key.
|
||||
- Go in the MAME file manager and load the file to import in the serial device.
|
||||
|
||||
Receive from Z88:
|
||||
- Launch Imp-Export popdown on Z88.
|
||||
- Go in the MAME file manager and create a new file in the serial device.
|
||||
- On Z88, select send by pressing s and then the Enter key.
|
||||
- Enter the filename to transfer, and then the Enter key.
|
||||
- When transfer is complete go in the MAME file manager and unload the image.
|
||||
|
||||
Protocol:
|
||||
- ESC + N: start of file name
|
||||
- ESC + F: start of file data
|
||||
- ESC + E: end of file
|
||||
- ESC + Z: end of batch
|
||||
- ESC + BXX: escaped byte, where XX is the uppercase hexadecimal
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "z88_impexp.h"
|
||||
|
||||
static constexpr uint32_t Z88_RS232_BAUD = 9600;
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(Z88_IMPEXP, z88_impexp_device, "z88_impexp", "Z88 Imp-Export protocol");
|
||||
|
||||
z88_impexp_device::z88_impexp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, Z88_IMPEXP, tag, owner, clock)
|
||||
, device_serial_interface(mconfig, *this)
|
||||
, device_rs232_port_interface(mconfig, *this)
|
||||
, device_image_interface(mconfig, *this)
|
||||
, m_timer_poll(nullptr)
|
||||
, m_mode(MODE_IDLE)
|
||||
, m_rts(1)
|
||||
, m_dtr(1)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void z88_impexp_device::device_start()
|
||||
{
|
||||
m_timer_poll = timer_alloc();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - reset up the device
|
||||
//-------------------------------------------------
|
||||
|
||||
void z88_impexp_device::device_reset()
|
||||
{
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
||||
set_rate(Z88_RS232_BAUD);
|
||||
|
||||
output_rxd(1);
|
||||
output_dcd(0);
|
||||
output_dsr(0);
|
||||
output_cts(0);
|
||||
|
||||
m_rts = 1;
|
||||
m_dtr = 1;
|
||||
m_queue = std::queue<uint8_t>();
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_timer - handler timer events
|
||||
//-------------------------------------------------
|
||||
|
||||
void z88_impexp_device::device_timer(emu_timer &timer, device_timer_id id, int param)
|
||||
{
|
||||
queue();
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( z88_impexp_device::input_rts )
|
||||
{
|
||||
if (!state && m_rts)
|
||||
{
|
||||
m_rts = state;
|
||||
queue();
|
||||
}
|
||||
else
|
||||
m_rts = state;
|
||||
}
|
||||
|
||||
void z88_impexp_device::queue()
|
||||
{
|
||||
if (is_transmit_register_empty())
|
||||
{
|
||||
if (!m_queue.empty() && m_rts == 0)
|
||||
{
|
||||
transmit_register_setup(m_queue.front());
|
||||
m_queue.pop();
|
||||
m_timer_poll->adjust(attotime::never);
|
||||
return;
|
||||
}
|
||||
|
||||
m_timer_poll->adjust(attotime::from_hz(Z88_RS232_BAUD));
|
||||
}
|
||||
}
|
||||
|
||||
void z88_impexp_device::tra_callback()
|
||||
{
|
||||
output_rxd(transmit_register_get_data_bit());
|
||||
}
|
||||
|
||||
void z88_impexp_device::tra_complete()
|
||||
{
|
||||
if (m_mode == MODE_SEND)
|
||||
queue();
|
||||
}
|
||||
|
||||
void z88_impexp_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
if (m_mode == MODE_RECV)
|
||||
m_queue.push(get_received_char());
|
||||
}
|
||||
|
||||
|
||||
void z88_impexp_device::check_filename(std::string &filename)
|
||||
{
|
||||
for (auto &c : filename)
|
||||
if (c != '-' && !std::isalnum(c))
|
||||
c = '-';
|
||||
}
|
||||
|
||||
|
||||
image_init_result z88_impexp_device::call_load()
|
||||
{
|
||||
m_mode = MODE_SEND;
|
||||
m_queue = std::queue<uint8_t>();
|
||||
|
||||
std::string name;
|
||||
if (basename())
|
||||
{
|
||||
if (basename_noext())
|
||||
name = basename_noext();
|
||||
else
|
||||
name = basename();
|
||||
|
||||
if (name.length() > 12)
|
||||
name.resize(12);
|
||||
|
||||
check_filename(name);
|
||||
|
||||
if (filetype().length())
|
||||
{
|
||||
std::string ext = filetype();
|
||||
if (ext.length() > 3)
|
||||
ext.resize(3);
|
||||
|
||||
check_filename(ext);
|
||||
name += "." + ext;
|
||||
}
|
||||
}
|
||||
else
|
||||
name = "UNKNOWN";
|
||||
|
||||
// file name
|
||||
m_queue.push(0x1b);
|
||||
m_queue.push('N');
|
||||
for (char const &c: name)
|
||||
m_queue.push(c);
|
||||
|
||||
// file data
|
||||
m_queue.push(0x1b);
|
||||
m_queue.push('F');
|
||||
while (!image_feof())
|
||||
{
|
||||
uint8_t b;
|
||||
if (fread(&b, 1) != 1)
|
||||
return image_init_result::FAIL;
|
||||
|
||||
// Escape non printable characters
|
||||
if ((b < 0x20 || b >= 0x7f) && b != 0x0a && b != 0x0d && b != 0x09)
|
||||
{
|
||||
m_queue.push(0x1b);
|
||||
m_queue.push('B');
|
||||
for (int i = 4; i >= 0; i -= 4)
|
||||
{
|
||||
uint8_t n = (b >> i) & 0x0f;
|
||||
if (n < 10)
|
||||
m_queue.push('0' + n);
|
||||
else
|
||||
m_queue.push('A' + n - 10);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_queue.push(b);
|
||||
}
|
||||
|
||||
// end of file
|
||||
m_queue.push(0x1b);
|
||||
m_queue.push('E');
|
||||
queue();
|
||||
|
||||
return image_init_result::PASS;
|
||||
}
|
||||
|
||||
|
||||
image_init_result z88_impexp_device::call_create(int format_type, util::option_resolution *format_options)
|
||||
{
|
||||
m_queue = std::queue<uint8_t>();
|
||||
m_mode = MODE_RECV;
|
||||
return image_init_result::PASS;
|
||||
}
|
||||
|
||||
|
||||
void z88_impexp_device::call_unload()
|
||||
{
|
||||
if (m_mode == MODE_RECV && !m_queue.empty())
|
||||
{
|
||||
std::string name;
|
||||
char mode = 0;
|
||||
while (!m_queue.empty())
|
||||
{
|
||||
uint8_t b = m_queue.front();
|
||||
m_queue.pop();
|
||||
if (b != 0x1b)
|
||||
{
|
||||
if (mode == 'F')
|
||||
fwrite(&b, 1);
|
||||
else if (mode == 'N')
|
||||
name.push_back(b);
|
||||
}
|
||||
else if (!m_queue.empty())
|
||||
{
|
||||
b = m_queue.front();
|
||||
m_queue.pop();
|
||||
if (b == 'N') mode = 'N'; // File name
|
||||
else if (b == 'F') mode = 'F'; // File data
|
||||
else if (b == 'E') break; // End of file
|
||||
else if (b == 'Z') break; // End of Batch
|
||||
else if (b == 'B') // Escaped byte
|
||||
{
|
||||
uint8_t val = 0;
|
||||
for (int i = 4; !m_queue.empty() && i >= 0; i -= 4)
|
||||
{
|
||||
b = m_queue.front();
|
||||
m_queue.pop();
|
||||
if (b >= '0' && b <= '9')
|
||||
val |= (b - '0') << i;
|
||||
else if (b >= 'A' && b <= 'F')
|
||||
val |= (b - 'A' + 10) << i;
|
||||
else
|
||||
logerror("Invalid escaped byte 0x%02x", b);
|
||||
}
|
||||
|
||||
if (mode == 'F')
|
||||
fwrite(&val, 1);
|
||||
}
|
||||
else
|
||||
logerror("Unknown escape 0x%02x\n", b);
|
||||
}
|
||||
}
|
||||
|
||||
logerror("Received file '%s'\n", name);
|
||||
}
|
||||
|
||||
m_queue = std::queue<uint8_t>();
|
||||
m_mode = MODE_IDLE;
|
||||
}
|
70
src/mame/machine/z88_impexp.h
Normal file
70
src/mame/machine/z88_impexp.h
Normal file
@ -0,0 +1,70 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Sandro Ronco
|
||||
|
||||
#ifndef MAME_MACHINE_Z88_IMPEXP_H
|
||||
#define MAME_MACHINE_Z88_IMPEXP_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "diserial.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
|
||||
class z88_impexp_device : public device_t,
|
||||
public device_serial_interface,
|
||||
public device_rs232_port_interface,
|
||||
public device_image_interface
|
||||
{
|
||||
public:
|
||||
z88_impexp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual WRITE_LINE_MEMBER( input_txd ) override { device_serial_interface::rx_w(state); }
|
||||
virtual WRITE_LINE_MEMBER( input_rts ) override;
|
||||
virtual WRITE_LINE_MEMBER( input_dtr ) override { m_dtr = state; }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override;
|
||||
|
||||
// device_serial_interface overrides
|
||||
virtual void tra_callback() override;
|
||||
virtual void tra_complete() override;
|
||||
virtual void rcv_complete() override;
|
||||
|
||||
// image-level overrides
|
||||
virtual image_init_result call_load() override;
|
||||
virtual void call_unload() override;
|
||||
virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
|
||||
|
||||
virtual bool is_readable() const noexcept override { return true; }
|
||||
virtual bool is_writeable() const noexcept override { return true; }
|
||||
virtual bool is_creatable() const noexcept override { return true; }
|
||||
virtual bool is_reset_on_load() const noexcept override { return false; }
|
||||
virtual const char *file_extensions() const noexcept override { return ""; }
|
||||
virtual const char *image_type_name() const noexcept override { return "serial"; }
|
||||
virtual const char *image_brief_type_name() const noexcept override { return "serl"; }
|
||||
|
||||
private:
|
||||
void check_filename(std::string &filename);
|
||||
void queue();
|
||||
|
||||
enum op_mode_t : uint8_t
|
||||
{
|
||||
MODE_IDLE,
|
||||
MODE_SEND,
|
||||
MODE_RECV,
|
||||
};
|
||||
|
||||
emu_timer * m_timer_poll;
|
||||
op_mode_t m_mode;
|
||||
int m_rts;
|
||||
int m_dtr;
|
||||
std::queue<uint8_t> m_queue;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(Z88_IMPEXP, z88_impexp_device)
|
||||
|
||||
#endif // MAME_MACHINE_Z88_IMPEXP_H
|
@ -2,7 +2,7 @@
|
||||
// copyright-holders:Kevin Thacker,Sandro Ronco
|
||||
/***************************************************************************
|
||||
|
||||
z88.c
|
||||
z88.cpp
|
||||
|
||||
Functions to emulate the video hardware of the Cambridge Z88
|
||||
|
||||
@ -18,23 +18,6 @@ inline void z88_state::plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint16_t c
|
||||
bitmap.pix(y, x) = color;
|
||||
}
|
||||
|
||||
// convert absolute offset into correct address to get data from
|
||||
inline uint8_t* z88_state::convert_address(uint32_t offset)
|
||||
{
|
||||
if (offset < 0x080000) // rom
|
||||
return m_bios + (offset & 0x7ffff);
|
||||
else if (offset < 0x100000) // slot0
|
||||
return m_ram_base + (offset & 0x7ffff);
|
||||
else if (offset < 0x200000) // slot1
|
||||
return m_carts[1]->get_cart_base() + (offset & 0xfffff);
|
||||
else if (offset < 0x300000) // slot2
|
||||
return m_carts[2]->get_cart_base() + (offset & 0xfffff);
|
||||
else if (offset < 0x400000) // slot3
|
||||
return m_carts[3]->get_cart_base() + (offset & 0xfffff);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Start the video hardware emulation.
|
||||
***************************************************************************/
|
||||
@ -49,11 +32,11 @@ void z88_state::z88_palette(palette_device &palette) const
|
||||
|
||||
/* temp - change to gfxelement structure */
|
||||
|
||||
void z88_state::vh_render_8x8(bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint8_t *gfx)
|
||||
void z88_state::vh_render_8x8(address_space &space, bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint32_t offset)
|
||||
{
|
||||
for (int h = 0; h < 8; h++)
|
||||
{
|
||||
uint8_t data = gfx[h];
|
||||
const uint8_t data = space.read_byte(offset + h);
|
||||
|
||||
for (int b = 0; b < 8; b++)
|
||||
{
|
||||
@ -62,11 +45,11 @@ void z88_state::vh_render_8x8(bitmap_ind16 &bitmap, int x, int y, uint16_t pen0,
|
||||
}
|
||||
}
|
||||
|
||||
void z88_state::vh_render_6x8(bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint8_t *gfx)
|
||||
void z88_state::vh_render_6x8(address_space &space, bitmap_ind16 &bitmap, int x, int y, uint16_t pen0, uint16_t pen1, uint32_t offset)
|
||||
{
|
||||
for (int h = 0; h < 8; h++)
|
||||
{
|
||||
uint8_t data = gfx[h] << 2;
|
||||
const uint8_t data = space.read_byte(offset + h) << 2;
|
||||
|
||||
for (int b = 0; b < 6; b++)
|
||||
{
|
||||
@ -92,7 +75,8 @@ UPD65031_SCREEN_UPDATE(z88_state::lcd_update)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *vram = convert_address(sbf << 11);
|
||||
address_space &space = m_banks[0]->space();
|
||||
const uint32_t vram = sbf << 11;
|
||||
|
||||
for (int y = 0; y < (Z88_SCREEN_HEIGHT >> 3); y++)
|
||||
{
|
||||
@ -100,8 +84,8 @@ UPD65031_SCREEN_UPDATE(z88_state::lcd_update)
|
||||
|
||||
while (x < Z88_SCREEN_WIDTH)
|
||||
{
|
||||
uint8_t byte0 = vram[(y * 0x100) + c];
|
||||
uint8_t byte1 = vram[(y * 0x100) + c + 1];
|
||||
const uint8_t byte0 = space.read_byte(vram + (y * 0x100) + c);
|
||||
const uint8_t byte1 = space.read_byte(vram + (y * 0x100) + c + 1);
|
||||
|
||||
// inverted graphics?
|
||||
uint16_t pen0 = 0;
|
||||
@ -120,17 +104,17 @@ UPD65031_SCREEN_UPDATE(z88_state::lcd_update)
|
||||
// low-res 6x8
|
||||
const uint16_t ch = (byte0 | (byte1 << 8)) & 0x1ff;
|
||||
|
||||
uint8_t *char_gfx;
|
||||
uint32_t char_offset;
|
||||
if ((ch & 0x01c0) == 0x01c0)
|
||||
char_gfx = convert_address(lores0 << 9) + ((ch & 0x3f) << 3);
|
||||
char_offset = (lores0 << 9) + ((ch & 0x3f) << 3);
|
||||
else
|
||||
char_gfx = convert_address(lores1 << 12) + (ch << 3);
|
||||
char_offset = (lores1 << 12) + (ch << 3);
|
||||
|
||||
// cursor flash
|
||||
if (flash && (byte1 & Z88_SCR_HW_CURS) == Z88_SCR_HW_CURS)
|
||||
vh_render_6x8(bitmap, x, y << 3, pen1, pen0, char_gfx);
|
||||
vh_render_6x8(space, bitmap, x, y << 3, pen1, pen0, char_offset);
|
||||
else
|
||||
vh_render_6x8(bitmap, x, y << 3, pen0, pen1, char_gfx);
|
||||
vh_render_6x8(space, bitmap, x, y << 3, pen0, pen1, char_offset);
|
||||
|
||||
// underline?
|
||||
if (byte1 & Z88_SCR_HW_UND)
|
||||
@ -143,17 +127,17 @@ UPD65031_SCREEN_UPDATE(z88_state::lcd_update)
|
||||
// high-res 8x8
|
||||
const uint16_t ch = (byte0 | (byte1 << 8)) & 0x3ff;
|
||||
|
||||
uint8_t *char_gfx;
|
||||
uint32_t char_offset;
|
||||
if (BIT(ch, 8))
|
||||
char_gfx = convert_address(hires1 << 11) + ((ch & 0xff) << 3);
|
||||
char_offset = (hires1 << 11) + ((ch & 0xff) << 3);
|
||||
else
|
||||
char_gfx = convert_address(hires0 << 13) + ((ch & 0xff) << 3);
|
||||
char_offset = (hires0 << 13) + ((ch & 0xff) << 3);
|
||||
|
||||
// flash
|
||||
if ((byte1 & Z88_SCR_HW_FLS) && flash)
|
||||
pen0 = pen1 = 0;
|
||||
|
||||
vh_render_8x8(bitmap, x, y << 3, pen0, pen1, char_gfx);
|
||||
vh_render_8x8(space, bitmap, x, y << 3, pen0, pen1, char_offset);
|
||||
|
||||
x += 8;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user