diff options
Diffstat (limited to 'src')
86 files changed, 3956 insertions, 1850 deletions
diff --git a/src/devices/bus/a2bus/a2sd.cpp b/src/devices/bus/a2bus/a2sd.cpp index 7a5208e473f..3f9bd439bc6 100644 --- a/src/devices/bus/a2bus/a2sd.cpp +++ b/src/devices/bus/a2bus/a2sd.cpp @@ -9,7 +9,7 @@ AppleIISD has a Xilinx FPGA which implements a minimally hardware assisted SPI interface, and the SD card is thus driven in SPI - mode rather than SD. + mode rather than SD. The SPI controller is fixed to SPI Mode 3 only. (shift on falling CLK edges, shift-then-latch). diff --git a/src/devices/bus/a2bus/laser128.cpp b/src/devices/bus/a2bus/laser128.cpp index e0c7626aa93..bf0319751db 100644 --- a/src/devices/bus/a2bus/laser128.cpp +++ b/src/devices/bus/a2bus/laser128.cpp @@ -23,6 +23,7 @@ //************************************************************************** DEFINE_DEVICE_TYPE(A2BUS_LASER128, a2bus_laser128_device, "a2laser128", "VTech Laser 128 Internal Device") +DEFINE_DEVICE_TYPE(A2BUS_LASER128_ORIG, a2bus_laser128_orig_device, "a2laser128o", "VTech Laser 128 Internal Device (original hardware)") /*************************************************************************** FUNCTION PROTOTYPES @@ -52,6 +53,11 @@ a2bus_laser128_device::a2bus_laser128_device(const machine_config &mconfig, cons { } +a2bus_laser128_orig_device::a2bus_laser128_orig_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + a2bus_laser128_device(mconfig, A2BUS_LASER128_ORIG, tag, owner, clock) +{ +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -142,3 +148,29 @@ bool a2bus_laser128_device::take_c800() return false; } } + +uint8_t a2bus_laser128_orig_device::read_c800(uint16_t offset) +{ + switch (slotno()) + { + case 1: + return m_rom[(offset & 0x7ff) + 0x4800]; + + case 2: + return m_rom[(offset & 0x7ff) + 0x5800]; + + case 5: + return m_rom[(offset & 0x7ff) + 0x5000]; + + case 6: + return m_rom[(offset & 0x7ff) + 0x6800]; + + case 7: + if (offset < 0x400) + return m_slot7_ram[offset]; + else + return m_rom[(offset & 0x3ff) + 0x6000 + m_slot7_bank]; + } + + return 0xff; +} diff --git a/src/devices/bus/a2bus/laser128.h b/src/devices/bus/a2bus/laser128.h index a71f88e0c3d..3ea016ad983 100644 --- a/src/devices/bus/a2bus/laser128.h +++ b/src/devices/bus/a2bus/laser128.h @@ -42,13 +42,25 @@ protected: virtual void write_c800(uint16_t offset, uint8_t data) override; virtual bool take_c800() override; -private: uint8_t *m_rom; uint8_t m_slot7_ram[0x800]; - int m_slot7_bank, m_slot7_ram_bank; + int m_slot7_bank; + +private: + int m_slot7_ram_bank; +}; + +class a2bus_laser128_orig_device: public a2bus_laser128_device +{ +public: + a2bus_laser128_orig_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual uint8_t read_c800(uint16_t offset) override; }; // device type definition DECLARE_DEVICE_TYPE(A2BUS_LASER128, a2bus_laser128_device) +DECLARE_DEVICE_TYPE(A2BUS_LASER128_ORIG, a2bus_laser128_orig_device) #endif // MAME_BUS_A2BUS_LASER128_H diff --git a/src/devices/bus/nes/batlab.cpp b/src/devices/bus/nes/batlab.cpp index cc39fb95466..7f11696134d 100644 --- a/src/devices/bus/nes/batlab.cpp +++ b/src/devices/bus/nes/batlab.cpp @@ -188,7 +188,7 @@ u8 nes_batmap_srrx_device::read_dpcm() u8 nes_batmap_srrx_device::read_l(offs_t offset) { -// LOG_MMC(("batmap_srrx read_l, offset: %04x", offset)); +// LOG_MMC(("batmap_srrx read_l, offset: %04x", offset)); offset += 0x100; switch (offset & 0x1800) @@ -204,7 +204,7 @@ u8 nes_batmap_srrx_device::read_l(offs_t offset) u8 nes_batmap_srrx_device::read_m(offs_t offset) { -// LOG_MMC(("batmap_srrx read_m, offset: %04x", offset)); +// LOG_MMC(("batmap_srrx read_m, offset: %04x", offset)); return m_prg[(m_reg * 0x2000 + offset) & (m_prg_size - 1)]; } diff --git a/src/devices/bus/nes/bootleg.cpp b/src/devices/bus/nes/bootleg.cpp index 4382bf7ec43..842b932869f 100644 --- a/src/devices/bus/nes/bootleg.cpp +++ b/src/devices/bus/nes/bootleg.cpp @@ -53,6 +53,7 @@ DEFINE_DEVICE_TYPE(NES_SMB2JB, nes_smb2jb_device, "nes_smb2jb", "N DEFINE_DEVICE_TYPE(NES_N32_4IN1, nes_n32_4in1_device, "nes_n32_4in1", "NES Cart N-32 4 in 1 PCB") DEFINE_DEVICE_TYPE(NES_0353, nes_0353_device, "nes_0353", "NES Cart 0353 PCB") DEFINE_DEVICE_TYPE(NES_09034A, nes_09034a_device, "nes_09034a", "NES Cart 09-034A PCB") +DEFINE_DEVICE_TYPE(NES_L001, nes_l001_device, "nes_l001", "NES Cart L-001 PCB") DEFINE_DEVICE_TYPE(NES_BATMANFS, nes_batmanfs_device, "nes_batmanfs", "NES Cart Batman Pirate PCB") DEFINE_DEVICE_TYPE(NES_PALTHENA, nes_palthena_device, "nes_palthena", "NES Cart Palthena no Kagami Pirate PCB") DEFINE_DEVICE_TYPE(NES_TOBIDASE, nes_tobidase_device, "nes_tobidase", "NES Cart Tobidase Daisakusen Pirate PCB") @@ -144,6 +145,11 @@ nes_09034a_device::nes_09034a_device(const machine_config &mconfig, const char * { } +nes_l001_device::nes_l001_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_nrom_device(mconfig, NES_L001, tag, owner, clock), m_irq_count(0), irq_timer(nullptr) +{ +} + nes_batmanfs_device::nes_batmanfs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : nes_nrom_device(mconfig, NES_BATMANFS, tag, owner, clock), m_irq_count(0), m_irq_enable(0), irq_timer(nullptr) { @@ -499,6 +505,23 @@ void nes_09034a_device::pcb_reset() m_reg = 0; } +void nes_l001_device::device_start() +{ + common_start(); + irq_timer = timer_alloc(TIMER_IRQ); + irq_timer->adjust(attotime::zero, 0, clocks_to_attotime(1)); + + save_item(NAME(m_irq_count)); +} + +void nes_l001_device::pcb_reset() +{ + prg32((m_prg_chunks >> 1) - 1); + chr8(0, CHRROM); + + m_irq_count = 0; +} + void nes_palthena_device::device_start() { common_start(); @@ -1550,6 +1573,64 @@ u8 nes_09034a_device::read_m(offs_t offset) /*------------------------------------------------- + Board L-001 + + Games: Sangokushi III (Sangokushi II bootleg) + + This board has swappable 8K PRG banks at 0x8000, 0xa000, + and 0xc000, while 0xe000 is fixed to the final bank. + CHRROM and CIRAM are also swappable in 1K banks. + The board has a 16-bit IRQ counter with the enable bit + acting as the MSB. The enhanced audio of the original + Namco 163 board is not retained. + + NES 2.0: mapper 330 + + In MAME: Supported. + + -------------------------------------------------*/ + +void nes_l001_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_IRQ) + { + if (BIT(m_irq_count, 15)) + { + if (++m_irq_count == 0) + set_irq_line(ASSERT_LINE); + } + } +} + +void nes_l001_device::write_h(offs_t offset, u8 data) +{ + LOG_MMC(("l-001 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6400) + { + case 0x0000: + case 0x2000: + chr1_x((offset >> 11) & 0x07, data, CHRROM); + break; + case 0x0400: + m_irq_count = (m_irq_count & 0xff00) | data; + break; + case 0x2400: + m_irq_count = (m_irq_count & 0x00ff) | data << 8; + set_irq_line(CLEAR_LINE); + break; + case 0x4000: + set_nt_page((offset >> 11) & 0x03, CIRAM, data & 1, 1); + break; + case 0x6000: + if (offset < 0x7800) + prg8_x((offset >> 11) & 0x03, data & 0x1f); + break; + } +} + +/*------------------------------------------------- + BTL-BATMANFS Games: Batman "Fine Studio" pirate @@ -2207,7 +2288,7 @@ void nes_shuiguan_device::write_h(offs_t offset, uint8_t data) { case 0x00: m_irq_count = (m_irq_count & 0xf0) | ((data & 0x0f) << 0); break; case 0x04: m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); break; - case 0x08: m_irq_enable= data; break; + case 0x08: m_irq_enable = data; break; case 0x0c: break; } break; diff --git a/src/devices/bus/nes/bootleg.h b/src/devices/bus/nes/bootleg.h index 7eeaaaf2ff9..081173d3e2e 100644 --- a/src/devices/bus/nes/bootleg.h +++ b/src/devices/bus/nes/bootleg.h @@ -320,6 +320,31 @@ private: }; +// ======================> nes_l001_device + +class nes_l001_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_l001_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + virtual void write_h(offs_t offset, u8 data) override; + + virtual void pcb_reset() override; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + u16 m_irq_count; + + static const device_timer_id TIMER_IRQ = 0; + emu_timer *irq_timer; +}; + + // ======================> nes_batmanfs_device class nes_batmanfs_device : public nes_nrom_device @@ -327,6 +352,7 @@ class nes_batmanfs_device : public nes_nrom_device public: // construction/destruction nes_batmanfs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + virtual void write_h(offs_t offset, u8 data) override; virtual void pcb_reset() override; @@ -751,6 +777,7 @@ DECLARE_DEVICE_TYPE(NES_SMB2JB, nes_smb2jb_device) DECLARE_DEVICE_TYPE(NES_N32_4IN1, nes_n32_4in1_device) DECLARE_DEVICE_TYPE(NES_0353, nes_0353_device) DECLARE_DEVICE_TYPE(NES_09034A, nes_09034a_device) +DECLARE_DEVICE_TYPE(NES_L001, nes_l001_device) DECLARE_DEVICE_TYPE(NES_BATMANFS, nes_batmanfs_device) DECLARE_DEVICE_TYPE(NES_PALTHENA, nes_palthena_device) DECLARE_DEVICE_TYPE(NES_TOBIDASE, nes_tobidase_device) diff --git a/src/devices/bus/nes/event.h b/src/devices/bus/nes/event.h index b4b67614b50..c1ba24d179d 100644 --- a/src/devices/bus/nes/event.h +++ b/src/devices/bus/nes/event.h @@ -1,7 +1,7 @@ // license:BSD-3-Clause // copyright-holders:Fabio Priuli -#ifndef MAEM_BUS_NES_EVENT_H -#define MAEM_BUS_NES_EVENT_H +#ifndef MAME_BUS_NES_EVENT_H +#define MAME_BUS_NES_EVENT_H #pragma once @@ -46,4 +46,4 @@ protected: // device type definition DECLARE_DEVICE_TYPE(NES_EVENT, nes_event_device) -#endif // MAEM_BUS_NES_EVENT_H +#endif // MAME_BUS_NES_EVENT_H diff --git a/src/devices/bus/nes/mmc1.cpp b/src/devices/bus/nes/mmc1.cpp index cb752cb0754..8c8e7bc31bd 100644 --- a/src/devices/bus/nes/mmc1.cpp +++ b/src/devices/bus/nes/mmc1.cpp @@ -16,6 +16,9 @@ TODO: - Combine 2 versions of set_prg in SxROM base class. This means dealing with variant boards SNROM, SUROM, etc which repurpose bits in the MMC1 regs. + - Determine if "MMC1" marked chips, the earliest version, ignores WRAM + enable/disable bit like its first revision, MMC1A. Also determine if MMC1C + really exists. It's described by kevtris, but it's not in BootGod's DB. ***********************************************************************************************************/ @@ -36,10 +39,8 @@ // constructor //------------------------------------------------- -DEFINE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device, "nes_sxrom", "NES Cart SxROM (MMC-1) PCB") -DEFINE_DEVICE_TYPE(NES_SOROM, nes_sorom_device, "nes_sorom", "NES Cart SOROM (MMC-1) PCB") -DEFINE_DEVICE_TYPE(NES_SXROM_A, nes_sxrom_a_device, "nes_sxrom_a", "NES Cart SxROM (MMC-1A) PCB") -DEFINE_DEVICE_TYPE(NES_SOROM_A, nes_sorom_a_device, "nes_sorom_a", "NES Cart SOROM (MMC-1A) PCB") +DEFINE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device, "nes_sxrom", "NES Cart SxROM (MMC-1) PCB") +DEFINE_DEVICE_TYPE(NES_SOROM, nes_sorom_device, "nes_sorom", "NES Cart SOROM (MMC-1) PCB") @@ -58,16 +59,6 @@ nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *ta { } -nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_sxrom_device(mconfig, NES_SXROM_A, tag, owner, clock) -{ -} - -nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_sxrom_device(mconfig, NES_SOROM_A, tag, owner, clock) -{ -} - void nes_sxrom_device::device_start() @@ -86,7 +77,8 @@ void nes_sxrom_device::pcb_reset() m_latch = 0; m_count = 0; m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; + m_reg[1] = m_reg[2] = 0; + m_reg[3] = m_mmc1_type == mmc1_type::MMC1C ? 0x10 : 0x00; // WRAM disabled by default on MMC1C m_reg_write_enable = 1; set_nt_mirroring(PPU_MIRROR_HORZ); @@ -94,35 +86,6 @@ void nes_sxrom_device::pcb_reset() set_prg(); } -void nes_sorom_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - - set_nt_mirroring(PPU_MIRROR_HORZ); - set_chr(); - set_prg(); -} - -void nes_sorom_a_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_latch = 0; - m_count = 0; - m_reg[0] = 0x0f; - m_reg[1] = m_reg[2] = m_reg[3] = 0; - m_reg_write_enable = 1; - - set_nt_mirroring(PPU_MIRROR_HORZ); - set_chr(); - set_prg(); -} @@ -295,7 +258,7 @@ void nes_sxrom_device::write_m(offs_t offset, uint8_t data) uint8_t bank = (m_reg[1] >> 2) & 3; LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data)); - if (!BIT(m_reg[3], 4)) // WRAM enabled + if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled { if (!m_battery.empty()) m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; @@ -309,7 +272,7 @@ uint8_t nes_sxrom_device::read_m(offs_t offset) uint8_t bank = (m_reg[1] >> 2) & 3; LOG_MMC(("sxrom read_m, offset: %04x\n", offset)); - if (!BIT(m_reg[3], 4)) // WRAM enabled + if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled { if (!m_battery.empty()) return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; @@ -317,7 +280,7 @@ uint8_t nes_sxrom_device::read_m(offs_t offset) return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; } - return get_open_bus(); // open bus + return get_open_bus(); } // SOROM has two RAM banks, the first is not battery backed up, the second is. @@ -326,7 +289,7 @@ void nes_sorom_device::write_m(offs_t offset, uint8_t data) uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data)); - if (!BIT(m_reg[3], 4)) // WRAM enabled + if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled { if (type) m_battery[offset & (m_battery.size() - 1)] = data; @@ -340,7 +303,7 @@ uint8_t nes_sorom_device::read_m(offs_t offset) uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); LOG_MMC(("sorom read_m, offset: %04x\n", offset)); - if (!BIT(m_reg[3], 4)) // WRAM enabled + if (!BIT(m_reg[3], 4) || m_mmc1_type == mmc1_type::MMC1A) // WRAM enabled { if (type) return m_battery[offset & (m_battery.size() - 1)]; @@ -348,52 +311,5 @@ uint8_t nes_sorom_device::read_m(offs_t offset) return m_prgram[offset & (m_prgram.size() - 1)]; } - return get_open_bus(); // open bus -} - -// MMC1A boards have no wram enable/disable bit -void nes_sxrom_a_device::write_m(offs_t offset, uint8_t data) -{ - uint8_t bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data)); - - if (!m_battery.empty()) - m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)] = data; - if (!m_prgram.empty()) - m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)] = data; -} - -uint8_t nes_sxrom_a_device::read_m(offs_t offset) -{ - uint8_t bank = (m_reg[1] >> 2) & 3; - LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset)); - - if (!m_battery.empty()) - return m_battery[((bank * 0x2000) + offset) & (m_battery.size() - 1)]; - if (!m_prgram.empty()) - return m_prgram[((bank * 0x2000) + offset) & (m_prgram.size() - 1)]; - - return get_open_bus(); // open bus -} - -void nes_sorom_a_device::write_m(offs_t offset, uint8_t data) -{ - uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data)); - - if (type) - m_battery[offset & (m_battery.size() - 1)] = data; - else - m_prgram[offset & (m_prgram.size() - 1)] = data; -} - -uint8_t nes_sorom_a_device::read_m(offs_t offset) -{ - uint8_t type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3); - LOG_MMC(("sorom_a read_m, offset: %04x\n", offset)); - - if (type) - return m_battery[offset & (m_battery.size() - 1)]; - else - return m_prgram[offset & (m_prgram.size() - 1)]; + return get_open_bus(); } diff --git a/src/devices/bus/nes/mmc1.h b/src/devices/bus/nes/mmc1.h index bc2198c33aa..dbf234f734f 100644 --- a/src/devices/bus/nes/mmc1.h +++ b/src/devices/bus/nes/mmc1.h @@ -34,7 +34,7 @@ protected: void set_prg(int prg_base, int prg_mask); void set_chr(int chr_base, int chr_mask); virtual void set_prg(); -// virtual void set_prg() { set_prg(0x00, 0x0f); } +// virtual void set_prg() { set_prg(0x00, 0x0f); } virtual void set_chr() { set_chr(0x00, 0x1f); } uint8_t m_reg[4]; @@ -51,37 +51,11 @@ public: virtual uint8_t read_m(offs_t offset) override; virtual void write_m(offs_t offset, uint8_t data) override; - - virtual void pcb_reset() override; -}; - -class nes_sxrom_a_device : public nes_sxrom_device -{ -public: - // construction/destruction - nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t read_m(offs_t offset) override; - virtual void write_m(offs_t offset, uint8_t data) override; -}; - -class nes_sorom_a_device : public nes_sxrom_device -{ -public: - // construction/destruction - nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t read_m(offs_t offset) override; - virtual void write_m(offs_t offset, uint8_t data) override; - - virtual void pcb_reset() override; }; // device type definition -DECLARE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device) -DECLARE_DEVICE_TYPE(NES_SOROM, nes_sorom_device) -DECLARE_DEVICE_TYPE(NES_SXROM_A, nes_sxrom_a_device) -DECLARE_DEVICE_TYPE(NES_SOROM_A, nes_sorom_a_device) +DECLARE_DEVICE_TYPE(NES_SXROM, nes_sxrom_device) +DECLARE_DEVICE_TYPE(NES_SOROM, nes_sorom_device) #endif // MAME_BUS_NES_MMC1_H diff --git a/src/devices/bus/nes/mmc3.cpp b/src/devices/bus/nes/mmc3.cpp index d6f7f37dc4a..dfc57f59b71 100644 --- a/src/devices/bus/nes/mmc3.cpp +++ b/src/devices/bus/nes/mmc3.cpp @@ -283,7 +283,8 @@ void nes_txrom_device::txrom_write(offs_t offset, uint8_t data) break; case 0x2000: - set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + if (m_mirroring != PPU_MIRROR_4SCREEN) + set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; case 0x2001: diff --git a/src/devices/bus/nes/mmc3_clones.cpp b/src/devices/bus/nes/mmc3_clones.cpp index 322d35bdacd..82e3d0abfaf 100644 --- a/src/devices/bus/nes/mmc3_clones.cpp +++ b/src/devices/bus/nes/mmc3_clones.cpp @@ -50,7 +50,7 @@ DEFINE_DEVICE_TYPE(NES_SF3, nes_sf3_device, "nes_sf3", DEFINE_DEVICE_TYPE(NES_GOUDER, nes_gouder_device, "nes_gouder", "NES Cart Gouder PCB") DEFINE_DEVICE_TYPE(NES_SA9602B, nes_sa9602b_device, "nes_sa9602b", "NES Cart SA-9602B PCB") DEFINE_DEVICE_TYPE(NES_SACHEN_SHERO, nes_sachen_shero_device, "nes_shero", "NES Cart Street Hero PCB") -//DEFINE_DEVICE_TYPE(NES_A9746, nes_a9746_device, "nes_bmc_a9746", "NES Cart A-9746 PCB") +DEFINE_DEVICE_TYPE(NES_A9746, nes_a9746_device, "nes_bmc_a9746", "NES Cart A-9746 PCB") DEFINE_DEVICE_TYPE(NES_A88S1, nes_a88s1_device, "nes_a88s1", "NES Cart BMC A88S-1 PCB") DEFINE_DEVICE_TYPE(NES_FCGJ8IN1, nes_fcgj8in1_device, "nes_fcgj8in1", "NES Cart BMC FC Genjin 8 in 1 PCB") @@ -83,6 +83,29 @@ DEFINE_DEVICE_TYPE(NES_PJOY84, nes_pjoy84_device, "nes_pjoy84", DEFINE_DEVICE_TYPE(NES_COOLBOY, nes_coolboy_device, "nes_coolboy", "NES Cart CoolBoy PCB") +INPUT_PORTS_START( sachen_shero ) + PORT_START("JUMPER") + PORT_CONFNAME( 0x80, 0x00, "Title Screen" ) + PORT_CONFSETTING( 0x00, "Street Heroes" ) + PORT_CONFSETTING( 0x80, u8"\u4f8d\u9b42 (Shìhún)" ) // 侍魂 +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_sachen_shero_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sachen_shero ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + nes_nitra_device::nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : nes_txrom_device(mconfig, NES_NITRA, tag, owner, clock) { @@ -203,15 +226,17 @@ nes_sa9602b_device::nes_sa9602b_device(const machine_config &mconfig, const char { } -nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_txrom_device(mconfig, NES_SACHEN_SHERO, tag, owner, clock), m_reg(0) +nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_txrom_device(mconfig, NES_SACHEN_SHERO, tag, owner, clock) + , m_jumper(*this, "JUMPER") + , m_reg(0) { } -//nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) -// : nes_txrom_device(mconfig, NES_A9746, tag, owner, clock) -//{ -//} +nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : nes_txrom_device(mconfig, NES_A9746, tag, owner, clock) +{ +} nes_a88s1_device::nes_a88s1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : nes_txrom_device(mconfig, NES_A88S1, tag, owner, clock) @@ -278,8 +303,8 @@ nes_bmc_8in1_device::nes_bmc_8in1_device(const machine_config &mconfig, const ch { } -nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_txrom_device(mconfig, NES_BMC_15IN1, tag, owner, clock) +nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_txrom_device(mconfig, NES_BMC_15IN1, tag, owner, clock), m_jumper(0) { } @@ -533,7 +558,23 @@ void nes_sachen_shero_device::pcb_reset() m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; m_reg = 0; - mmc3_common_initialize(0xff, 0x1ff, 0); + mmc3_common_initialize(0xff, 0xff, 0); +} + +void nes_a9746_device::device_start() +{ + mmc3_start(); + save_item(NAME(m_reg)); +} + +void nes_a9746_device::pcb_reset() +{ + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + + m_reg[0] = 0; + m_reg[1] = 0; + m_reg[2] = 0; + mmc3_common_initialize(0x7f, 0xff, 0); } void nes_a88s1_device::device_start() @@ -657,10 +698,7 @@ void nes_bmc_8in1_device::pcb_reset() void nes_bmc_15in1_device::pcb_reset() { m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - mmc3_common_initialize(0x1f, 0xff, 0); - m_prg_base = 0x10; // this board has a diff prg_base - set_prg(m_prg_base, m_prg_mask); } void nes_bmc_sbig7_device::pcb_reset() @@ -1874,22 +1912,21 @@ void nes_sa9602b_device::write_h(offs_t offset, uint8_t data) Sachen boards used for Street Heroes - in MESS: Very Preliminary support + NES 2.0: mapper 262 - -------------------------------------------------*/ + In MAME: Supported. + -------------------------------------------------*/ -void nes_sachen_shero_device::chr_cb( int start, int bank, int source ) +void nes_sachen_shero_device::chr_cb(int start, int bank, int source) { - int shift = start < 2 ? 5 : - start < 4 ? 6 : - start < 6 ? 8 : 7; + static constexpr u8 shift[4] = {5, 6, 8, 7}; + if (!BIT(m_reg, 6)) - chr1_x(start, ((m_reg << shift) & 0x100) | bank, source); + chr1_x(start, ((m_reg << shift[start >> 1]) & 0x100) | bank, source); } - -void nes_sachen_shero_device::write_l(offs_t offset, uint8_t data) +void nes_sachen_shero_device::write_l(offs_t offset, u8 data) { LOG_MMC(("shero write_l, offset: %04x, data: %02x\n", offset, data)); offset += 0x4100; @@ -1904,16 +1941,90 @@ void nes_sachen_shero_device::write_l(offs_t offset, uint8_t data) } } -uint8_t nes_sachen_shero_device::read_l(offs_t offset) +u8 nes_sachen_shero_device::read_l(offs_t offset) { LOG_MMC(("shero read_l, offset: %04x\n", offset)); offset += 0x4100; if (offset == 0x4100) + return m_jumper->read(); + else + return get_open_bus(); +} + +/*------------------------------------------------- + + UNL-A9746 + + Games: Toy Story, Super 1997 4 in 1 (NT-8029) + + MMC3 clone + + iNES: mapper 219 + + Preliminary emulation based on Cah4e3's code + + -------------------------------------------------*/ + +void nes_a9746_device::update_banks(uint8_t value) +{ + uint8_t bank = bitswap<8>(value & 0x3c,7,6,0,1,2,3,4,5); + + switch (m_reg[0]) { - // DSW read! + case 0x26: prg8_89(bank); break; + case 0x25: prg8_ab(bank); break; + case 0x24: prg8_cd(bank); break; + case 0x23: prg8_ef(bank); break; + } + + switch (m_reg[1]) + { + case 0x08: case 0x0a: case 0x0c: case 0x0e: + case 0x10: case 0x12: case 0x14: case 0x16: + case 0x18: case 0x1a: case 0x1c: case 0x1e: + m_reg[2] = (value << 4); + break; + case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break; + case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break; + case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break; + } +} + +void nes_a9746_device::write_h(offs_t offset, uint8_t data) +{ + LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data)); + + switch (offset & 0x6003) + { + case 0x0000: + m_reg[1] = data; + m_reg[0] = 0; + break; + case 0x0001: + update_banks(data); + break; + case 0x0002: + m_reg[0] = data; + m_reg[1] = 0; + break; + + case 0x0003: + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + break; + + default: + txrom_write(offset, data); + break; } - return get_open_bus(); // open bus } @@ -1924,16 +2035,16 @@ uint8_t nes_sachen_shero_device::read_l(offs_t offset) -------------------------------------------------*/ - /*------------------------------------------------- +/*------------------------------------------------- - Board BMC-FK23C + Board BMC-FK23C - MMC3 clone + MMC3 clone - In MESS: partially supported (still to sort initial banking - for many games) + In MAME: partially supported (still to sort initial banking + for many games) - -------------------------------------------------*/ + -------------------------------------------------*/ #if 0 // alt version... @@ -2235,30 +2346,32 @@ void nes_bmc_8in1_device::write_h(offs_t offset, u8 data) /*------------------------------------------------- - BMC-15IN1 + BMC-15IN1 (PCB JC-016-2?) - Unknown Bootleg Multigame Board Games: 3 in 1, 15 in 1 - iNES: mapper 205, MMC3 clone + MMC3 clone with banking for multigame menu. - In MESS: Supported. + iNES: mapper 205 + + In MAME: Supported. -------------------------------------------------*/ -void nes_bmc_15in1_device::write_m(offs_t offset, uint8_t data) +void nes_bmc_15in1_device::write_m(offs_t offset, u8 data) { LOG_MMC(("bmc_15in1 write_m, offset: %04x, data: %02x\n", offset, data)); - if (offset & 0x0800) - { - m_prg_base = (data & 0x03) << 4; - m_prg_mask = (data & 0x02) ? 0x0f : 0x1f; - m_chr_base = (data & 0x03) << 7; - m_chr_mask = (data & 0x02) ? 0x7f : 0xff; - set_prg(m_prg_base, m_prg_mask); - set_chr(m_chr_source, m_chr_base, m_chr_mask); - } + if (data & 1) + data |= m_jumper; // TODO: add jumper settings, m_jumper is 0 for now + + m_prg_base = (data & 0x03) << 4; + m_prg_mask = 0x1f >> BIT(data, 1); + set_prg(m_prg_base, m_prg_mask); + + m_chr_base = m_prg_base << 3; + m_chr_mask = 0xff >> BIT(data, 1); + set_chr(m_chr_source, m_chr_base, m_chr_mask); } /*------------------------------------------------- @@ -3052,95 +3165,3 @@ void nes_coolboy_device::write_m(offs_t offset, uint8_t data) set_chr(m_chr_source, m_chr_base, m_chr_mask); set_prg(m_prg_base, m_prg_mask); } - -#ifdef UNUSED_FUNCTION -/*------------------------------------------------- - - UNL-A9746 - - - MMC3 clone - - - Preliminary emulation based on Cah4e3's code - No dump is available (yet) for this. - - -------------------------------------------------*/ - -void nes_a9746_device::device_start() -{ - mmc3_start(); - save_item(NAME(m_reg)); -} - -void nes_a9746_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - - m_reg[0] = 0; - m_reg[1] = 0; - m_reg[2] = 0; - mmc3_common_initialize(0x7f, 0xff, 0); -} - -void nes_a9746_device::update_banks(uint8_t value) -{ - uint8_t bank = bitswap<8>(value & 0x3c,7,6,0,1,2,3,4,5); - - switch (m_reg[0]) - { - case 0x26: prg8_89(bank); break; - case 0x25: prg8_ab(bank); break; - case 0x24: prg8_cd(bank); break; - case 0x23: prg8_ef(bank); break; - } - - switch (m_reg[1]) - { - case 0x08: case 0x0a: case 0x0c: case 0x0e: - case 0x10: case 0x12: case 0x14: case 0x16: - case 0x18: case 0x1a: case 0x1c: case 0x1e: - m_reg[2] = (value << 4); - break; - case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break; - case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break; - case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break; - case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break; - } -} - -void nes_a9746_device::write_h(offs_t offset, uint8_t data) -{ - LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data)); - - switch (offset & 0x6003) - { - case 0x0000: - m_reg[1] = data; - m_reg[0] = 0; - break; - case 0x0001: - update_banks(data); - break; - case 0x0002: - m_reg[0] = data; - m_reg[1] = 0; - break; - - case 0x0003: - case 0x2000: - case 0x2001: - case 0x2002: - case 0x2003: - break; - - default: - txrom_write(offset, data); - break; - } -} -#endif diff --git a/src/devices/bus/nes/mmc3_clones.h b/src/devices/bus/nes/mmc3_clones.h index 201c82efca7..08822d6a7f2 100644 --- a/src/devices/bus/nes/mmc3_clones.h +++ b/src/devices/bus/nes/mmc3_clones.h @@ -412,23 +412,24 @@ class nes_sachen_shero_device : public nes_txrom_device { public: // construction/destruction - nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - virtual uint8_t read_l(offs_t offset) override; - virtual void write_l(offs_t offset, uint8_t data) override; + virtual u8 read_l(offs_t offset) override; + virtual void write_l(offs_t offset, u8 data) override; virtual void chr_cb(int start, int bank, int source) override; virtual void pcb_reset() override; protected: // device-level overrides + virtual ioport_constructor device_input_ports() const override; virtual void device_start() override; private: - uint8_t m_reg; + required_ioport m_jumper; + u8 m_reg; }; -#ifdef UNUSED_FUNCTION // ======================> nes_a9746_device class nes_a9746_device : public nes_txrom_device @@ -439,7 +440,7 @@ public: virtual void write_h(offs_t offset, uint8_t data) override; - virtual void pcb_reset(); + virtual void pcb_reset() override; protected: // device-level overrides @@ -449,7 +450,6 @@ private: void update_banks(uint8_t value); uint8_t m_reg[3]; }; -#endif // ======================> nes_a88s1_device @@ -651,12 +651,15 @@ class nes_bmc_15in1_device : public nes_txrom_device { public: // construction/destruction - nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); // device-level overrides - virtual void write_m(offs_t offset, uint8_t data) override; + virtual void write_m(offs_t offset, u8 data) override; virtual void pcb_reset() override; + +private: + u8 m_jumper; }; @@ -1018,9 +1021,7 @@ DECLARE_DEVICE_TYPE(NES_SF3, nes_sf3_device) DECLARE_DEVICE_TYPE(NES_GOUDER, nes_gouder_device) DECLARE_DEVICE_TYPE(NES_SA9602B, nes_sa9602b_device) DECLARE_DEVICE_TYPE(NES_SACHEN_SHERO, nes_sachen_shero_device) -#ifdef UNUSED_FUNCTION DECLARE_DEVICE_TYPE(NES_A9746, nes_a9746_device) -#endif DECLARE_DEVICE_TYPE(NES_A88S1, nes_a88s1_device) DECLARE_DEVICE_TYPE(NES_FCGJ8IN1, nes_fcgj8in1_device) diff --git a/src/devices/bus/nes/multigame.cpp b/src/devices/bus/nes/multigame.cpp index 58679f5ea1e..71793333747 100644 --- a/src/devices/bus/nes/multigame.cpp +++ b/src/devices/bus/nes/multigame.cpp @@ -66,7 +66,8 @@ DEFINE_DEVICE_TYPE(NES_BMC_HIK300, nes_bmc_hik300_device, "nes_bmc_hik30 DEFINE_DEVICE_TYPE(NES_BMC_S700, nes_bmc_s700_device, "nes_bmc_s700", "NES Cart BMC Super 700 in 1 PCB") DEFINE_DEVICE_TYPE(NES_BMC_BALL11, nes_bmc_ball11_device, "nes_bmc_ball11", "NES Cart BMC Ball 11 in 1 PCB") DEFINE_DEVICE_TYPE(NES_BMC_22GAMES, nes_bmc_22games_device, "nes_bmc_22games", "NES Cart BMC 22 Games PCB") -DEFINE_DEVICE_TYPE(NES_BMC_64Y2K, nes_bmc_64y2k_device, "nes_bmc_64y2k", "NES Cart BMC 64 in 1 Y2K PCB") +DEFINE_DEVICE_TYPE(NES_BMC_64Y2K, nes_bmc_64y2k_device, "nes_bmc_64y2k", "NES Cart BMC Y2K 64 in 1 PCB") +DEFINE_DEVICE_TYPE(NES_BMC_420Y2K, nes_bmc_420y2k_device, "nes_bmc_420y2k", "NES Cart BMC Y2K 420 in 1 PCB") DEFINE_DEVICE_TYPE(NES_BMC_12IN1, nes_bmc_12in1_device, "nes_bmc_12in1", "NES Cart BMC 12 in 1 PCB") DEFINE_DEVICE_TYPE(NES_BMC_20IN1, nes_bmc_20in1_device, "nes_bmc_20in1", "NES Cart BMC 20 in 1 PCB") DEFINE_DEVICE_TYPE(NES_BMC_21IN1, nes_bmc_21in1_device, "nes_bmc_21in1", "NES Cart BMC 21 in 1 PCB") @@ -305,6 +306,11 @@ nes_bmc_64y2k_device::nes_bmc_64y2k_device(const machine_config &mconfig, const { } +nes_bmc_420y2k_device::nes_bmc_420y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_nrom_device(mconfig, NES_BMC_420Y2K, tag, owner, clock), m_latch(0), m_reg(0) +{ +} + nes_bmc_12in1_device::nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : nes_nrom_device(mconfig, NES_BMC_12IN1, tag, owner, clock) { @@ -340,8 +346,18 @@ nes_bmc_64in1_device::nes_bmc_64in1_device(const machine_config &mconfig, const { } -nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_nrom_device(mconfig, NES_BMC_70IN1, tag, owner, clock), m_mode(0) +nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : nes_nrom_device(mconfig, type, tag, owner, clock), m_jumper(type == NES_BMC_70IN1 ? 0x0d : 0x06) +{ +} + +nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_bmc_70in1_device(mconfig, NES_BMC_70IN1, tag, owner, clock) +{ +} + +nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_bmc_70in1_device(mconfig, NES_BMC_800IN1, tag, owner, clock) { } @@ -365,11 +381,6 @@ nes_bmc_500in1_device::nes_bmc_500in1_device(const machine_config &mconfig, cons { } -nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_nrom_device(mconfig, NES_BMC_800IN1, tag, owner, clock), m_mode(0) -{ -} - nes_bmc_1200in1_device::nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : nes_nrom_device(mconfig, NES_BMC_1200IN1, tag, owner, clock), m_vram_protect(0) { @@ -819,6 +830,23 @@ void nes_bmc_64y2k_device::pcb_reset() set_nt_mirroring(PPU_MIRROR_VERT); } +void nes_bmc_420y2k_device::device_start() +{ + common_start(); + save_item(NAME(m_latch)); + save_item(NAME(m_reg)); +} + +void nes_bmc_420y2k_device::pcb_reset() +{ + prg16_89ab(0); + prg16_cdef(7); + chr8(0, CHRRAM); + + m_latch = 0; + m_reg = 0; +} + void nes_bmc_12in1_device::device_start() { common_start(); @@ -878,18 +906,16 @@ void nes_bmc_64in1_device::pcb_reset() void nes_bmc_70in1_device::device_start() { common_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mode)); + save_item(NAME(m_latch)); } void nes_bmc_70in1_device::pcb_reset() { - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, CHRROM); - m_reg[0] = 0; - m_reg[1] = 0; - m_mode = 0; + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; + chr8(0, m_chr_source); + + m_latch[0] = m_latch[1] = 0; + update_banks(); } void nes_bmc_72in1_device::device_start() @@ -919,24 +945,6 @@ void nes_bmc_150in1_device::pcb_reset() chr8(0, CHRROM); } -void nes_bmc_800in1_device::device_start() -{ - common_start(); - save_item(NAME(m_reg)); - save_item(NAME(m_mode)); -} - -void nes_bmc_800in1_device::pcb_reset() -{ - m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg16_89ab(m_prg_chunks - 1); - prg16_cdef(m_prg_chunks - 1); - chr8(0, m_chr_source); - m_reg[0] = 0; - m_reg[1] = 0; - m_mode = 0; -} - void nes_bmc_1200in1_device::device_start() { common_start(); @@ -2243,6 +2251,48 @@ void nes_bmc_64y2k_device::write_h(offs_t offset, uint8_t data) /*------------------------------------------------- + Board BMC-TELETUBBIES + (name assigned by BootGod who said the board has + no markings, a glop top, and an 8K VRAM chip) + + Games: Y2K 420 in 1 + + iNES: mapper 237 + + In MAME: Supported. + + -------------------------------------------------*/ + +void nes_bmc_420y2k_device::write_h(offs_t offset, u8 data) +{ + LOG_MMC(("bmc_420y2k write_h, offset: %04x, data: %02x\n", offset, data)); + + if (BIT(m_latch, 1)) // lock bit + m_reg = (m_reg & ~0x07) | (data & 0x07); + else + { + m_latch = offset; + m_reg = data; + } + + u8 bank = BIT(m_latch, 2) << 5 | (m_reg & 0x1f); + u8 mode = BIT(m_reg, 6); + prg16_89ab(bank & ~mode); // strangely for UNROM games it DOESN'T ignore the NROM mode bit + prg16_cdef(bank | (BIT(m_reg, 7) ? mode : 0x07)); + + set_nt_mirroring(BIT(m_reg, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); +} + +u8 nes_bmc_420y2k_device::read_h(offs_t offset) +{ + LOG_MMC(("bmc_420y2k read_h, offset: %04x\n", offset)); + // latch bit 0 is only used to determine the menu, and the behavior of + // this cart seems hardwired to OR $02 (ORing $00-$03 allows four menus) + return hi_access_rom(offset | (m_latch & 1) << 1); +} + +/*------------------------------------------------- + BMC-12IN1 Unknown Bootleg Multigame Board @@ -2432,56 +2482,86 @@ void nes_bmc_64in1_device::write_h(offs_t offset, uint8_t data) /*------------------------------------------------- - BMC-70IN1 + BMC-70IN1 (FIXME: according to NesDev the boards for this + and BMC-800IN1 are Realtec 8031 and 8155. Which is which?) - Unknown Bootleg Multigame Board - Games: + Games: 35 in 1, 68 in 1, 70 in 1 - iNES: mapper + iNES: mapper 236 - This is same hardware as BMC-800IN1 below, but this - cart has CHR and slightly diff bankswitch. - DSW not emulated yet. + This is the same hardware as BMC-800IN1 below, but + these carts have CHRROM and lack the extended PRG + bank switching. Solder pads/jumpers not emulated yet. - In MESS: Preliminary Supported. + In MAME: Supported. + + TODO: Determine if Excitebike on 68 in 1 is actually + bugged on the real cartridge. It sets mirroring bit + to horizontal when it should be vertical. -------------------------------------------------*/ -void nes_bmc_70in1_device::write_h(offs_t offset, uint8_t data) +void nes_bmc_70in1_device::update_banks() { - LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data)); + update_prg(m_latch[1] & 0x07); + chr8(m_latch[0] & 0x07, CHRROM); +} - if (offset < 0x4000) +void nes_bmc_70in1_device::update_prg(u8 bank) +{ + if (BIT(m_latch[1], 5)) // NROM mode { - set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); - chr8(offset & 7, CHRROM); + u8 mode = !BIT(m_latch[1], 4); + prg16_89ab(bank & ~mode); + prg16_cdef(bank | mode); } - else + else // UNROM mode { - switch (offset & 0x30) - { - case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; - case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; - } - prg16_89ab(m_reg[0]); - prg16_cdef(m_reg[1]); + prg16_89ab(bank); + prg16_cdef(bank | 0x07); } } +void nes_bmc_70in1_device::write_h(offs_t offset, u8 data) +{ + LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data)); + m_latch[BIT(offset, 14)] = offset; + update_banks(); + set_nt_mirroring(BIT(m_latch[0], 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); +} + uint8_t nes_bmc_70in1_device::read_h(offs_t offset) { LOG_MMC(("bmc70in1 read_h, offset: %04x\n", offset)); - if (m_mode) - offset = (offset & 0x7ff0) | m_mode; + if ((m_latch[1] & 0x30) == 0x10) + offset = (offset & ~0x0f) | m_jumper; // TODO: make jumper selectable return hi_access_rom(offset); } /*------------------------------------------------- + BMC-800IN1 + + Games: 800 in 1 + + iNES: mapper 236 + + This is the same hardware as BMC-70IN1, but this + cart supports larger PRG and has unbanked CHRRAM. + + In MAME: Supported. + + -------------------------------------------------*/ + +void nes_bmc_800in1_device::update_banks() +{ + update_prg((m_latch[0] & 0x07) << 3 | (m_latch[1] & 0x07)); +} + +/*------------------------------------------------- + BMC-72IN1, BMC-110IN1 Unknown Bootleg Multigame Board @@ -2609,56 +2689,6 @@ void nes_bmc_500in1_device::write_h(offs_t offset, u8 data) /*------------------------------------------------- - BMC-800IN1 - - Unknown Bootleg Multigame Board - Games: - - iNES: mapper - - DSW not emulated yet. - - In MESS: Preliminary Supported. - - -------------------------------------------------*/ - -void nes_bmc_800in1_device::write_h(offs_t offset, uint8_t data) -{ - LOG_MMC(("bmc800in1 write_h, offset: %04x, data: %02x\n", offset, data)); - - if (offset < 0x4000) - { - set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT); - - m_reg[0] = (m_reg[0]) | ((offset << 3) & 0x38); - m_reg[1] = (m_reg[1]) | ((offset << 3) & 0x38); - } - else - { - switch (offset & 0x30) - { - case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break; - case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break; - case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break; - } - } - prg16_89ab(m_reg[0]); - prg16_cdef(m_reg[1]); -} - -uint8_t nes_bmc_800in1_device::read_h(offs_t offset) -{ - LOG_MMC(("bmc800in1 read_h, offset: %04x\n", offset)); - - if (m_mode) - offset = (offset & 0x7ff0) | m_mode; - - return hi_access_rom(offset); -} - -/*------------------------------------------------- - BMC-1200IN1 Unknown Bootleg Multigame Board diff --git a/src/devices/bus/nes/multigame.h b/src/devices/bus/nes/multigame.h index fe4a780691c..6dfbed4ee7e 100644 --- a/src/devices/bus/nes/multigame.h +++ b/src/devices/bus/nes/multigame.h @@ -672,6 +672,28 @@ private: }; +// ======================> nes_bmc_420y2k_device + +class nes_bmc_420y2k_device : public nes_nrom_device +{ +public: + // construction/destruction + nes_bmc_420y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + virtual u8 read_h(offs_t offset) override; + virtual void write_h(offs_t offset, u8 data) override; + + virtual void pcb_reset() override; + +protected: + // device-level overrides + virtual void device_start() override; + +private: + u8 m_latch, m_reg; +}; + + // ======================> nes_bmc_12in1_device class nes_bmc_12in1_device : public nes_nrom_device @@ -790,20 +812,40 @@ class nes_bmc_70in1_device : public nes_nrom_device { public: // construction/destruction - nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - virtual uint8_t read_h(offs_t offset) override; - virtual void write_h(offs_t offset, uint8_t data) override; + virtual u8 read_h(offs_t offset) override; + virtual void write_h(offs_t offset, u8 data) override; virtual void pcb_reset() override; protected: + // construction/destruction + nes_bmc_70in1_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + // device-level overrides virtual void device_start() override; + virtual void update_banks(); + void update_prg(u8 bank); + + u8 m_latch[2]; + private: - uint8_t m_mode; - uint8_t m_reg[2]; + u8 m_jumper; +}; + + +// ======================> nes_bmc_800in1_device + +class nes_bmc_800in1_device : public nes_bmc_70in1_device +{ +public: + // construction/destruction + nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void update_banks() override; }; @@ -877,29 +919,6 @@ public: }; -// ======================> nes_bmc_800in1_device - -class nes_bmc_800in1_device : public nes_nrom_device -{ -public: - // construction/destruction - nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t read_h(offs_t offset) override; - virtual void write_h(offs_t offset, uint8_t data) override; - - virtual void pcb_reset() override; - -protected: - // device-level overrides - virtual void device_start() override; - -private: - uint8_t m_mode; - uint8_t m_reg[2]; -}; - - // ======================> nes_bmc_1200in1_device class nes_bmc_1200in1_device : public nes_nrom_device @@ -1144,6 +1163,7 @@ DECLARE_DEVICE_TYPE(NES_BMC_S700, nes_bmc_s700_device) DECLARE_DEVICE_TYPE(NES_BMC_BALL11, nes_bmc_ball11_device) DECLARE_DEVICE_TYPE(NES_BMC_22GAMES, nes_bmc_22games_device) DECLARE_DEVICE_TYPE(NES_BMC_64Y2K, nes_bmc_64y2k_device) +DECLARE_DEVICE_TYPE(NES_BMC_420Y2K, nes_bmc_420y2k_device) DECLARE_DEVICE_TYPE(NES_BMC_12IN1, nes_bmc_12in1_device) DECLARE_DEVICE_TYPE(NES_BMC_20IN1, nes_bmc_20in1_device) DECLARE_DEVICE_TYPE(NES_BMC_21IN1, nes_bmc_21in1_device) diff --git a/src/devices/bus/nes/nes_carts.cpp b/src/devices/bus/nes/nes_carts.cpp index 7dea84ea444..8237cb0bca0 100644 --- a/src/devices/bus/nes/nes_carts.cpp +++ b/src/devices/bus/nes/nes_carts.cpp @@ -101,8 +101,6 @@ void nes_cart(device_slot_interface &device) // SxROM device.option_add_internal("sxrom", NES_SXROM); device.option_add_internal("sorom", NES_SOROM); - device.option_add_internal("sxrom_a", NES_SXROM_A); // in MMC1-A PRG RAM is always enabled - device.option_add_internal("sorom_a", NES_SOROM_A); // in MMC1-A PRG RAM is always enabled // TxROM device.option_add_internal("txrom", NES_TXROM); // HKROM @@ -313,6 +311,7 @@ void nes_cart(device_slot_interface &device) device.option_add_internal("yung08", NES_YUNG08); device.option_add_internal("btl_0353", NES_0353); // used by Lucky (Roger) Rabbit FDS conversion device.option_add_internal("09034a", NES_09034A); + device.option_add_internal("l001", NES_L001); device.option_add_internal("batmanfs", NES_BATMANFS); device.option_add_internal("palthena", NES_PALTHENA); // used by Palthena no Kagami FDS conversion device.option_add_internal("tobidase", NES_TOBIDASE); // mapper 120 @@ -356,6 +355,7 @@ void nes_cart(device_slot_interface &device) device.option_add_internal("gouder", NES_GOUDER); device.option_add_internal("sa9602b", NES_SA9602B); device.option_add_internal("unl_shero", NES_SACHEN_SHERO); + device.option_add_internal("a9746", NES_A9746); // mapper 219 // misc multigame cart boards device.option_add_internal("benshieng", NES_BENSHIENG); device.option_add_internal("action52", NES_ACTION52); @@ -401,6 +401,7 @@ void nes_cart(device_slot_interface &device) device.option_add_internal("bmc_ball11", NES_BMC_BALL11); device.option_add_internal("bmc_22games", NES_BMC_22GAMES); device.option_add_internal("bmc_64y2k", NES_BMC_64Y2K); + device.option_add_internal("bmc_420y2k", NES_BMC_420Y2K); device.option_add_internal("bmc_12in1", NES_BMC_12IN1); device.option_add_internal("bmc_20in1", NES_BMC_20IN1); device.option_add_internal("bmc_21in1", NES_BMC_21IN1); @@ -471,7 +472,6 @@ void nes_cart(device_slot_interface &device) device.option_add_internal("konami_qtai", NES_NROM); // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED device.option_add_internal("unl_3d_block", NES_NROM); // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED device.option_add_internal("unl_c_n22m", NES_NROM); // [mentioned in FCEUMM source - we need more info] - UNSUPPORTED - device.option_add_internal("a9746", NES_NROM); // mapper 219 - UNSUPPORTED (no dump available); // legacy boards for FFE copier mappers (are there images available to fix/improve emulation?) device.option_add_internal("ffe3", NES_FFE3); device.option_add_internal("ffe4", NES_FFE4); diff --git a/src/devices/bus/nes/nes_ines.hxx b/src/devices/bus/nes/nes_ines.hxx index 74e3360f742..6f31c9abbe0 100644 --- a/src/devices/bus/nes/nes_ines.hxx +++ b/src/devices/bus/nes/nes_ines.hxx @@ -188,7 +188,7 @@ static const nes_mmc mmc_list[] = { 152, DIS_74X161X161X32 }, { 153, BANDAI_LZ93 }, { 154, NAMCOT_34X3 }, - { 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM + { 155, STD_SXROM }, // same as mapper 1 but forces the use of MMC1A { 156, OPENCORP_DAOU306 }, { 157, BANDAI_DATACH }, // Datach Reader games -> must go in the Datach subslot { 158, TENGEN_800037 }, @@ -252,7 +252,7 @@ static const nes_mmc mmc_list[] = { 216, RCM_GS2015 }, { 217, BMC_500IN1 }, { 218, NOCASH_NOCHR }, - // 219 UNL-A9746 (according to Cah4e3's code, no dump available (yet) + { 219, UNL_A9746 }, // 220 Unused - reserved for emulator debugging { 221, UNL_N625092 }, { 222, BTL_DRAGONNINJA }, @@ -269,8 +269,8 @@ static const nes_mmc mmc_list[] = { 233, BMC_42IN1RESET }, { 234, AVE_MAXI15 }, { 235, BMC_GOLD150 }, // 235 Golden Game x-in-1 - Unsupported - // 236 Game 800-in-1 - Unsupported, Realtec boards 8031 and 8155 - // 237 Teletubbies 420-in-1 multicart. Dump available? + { 236, BMC_70IN1 }, + { 237, BMC_TELETUBBIES }, { 238, UNL_603_5052 }, // 239 Unused { 240, CNE_SHLZ }, @@ -365,7 +365,7 @@ static const nes_mmc mmc_list[] = // 327 BMC-10-24-C-A1 6-in-1 { 328, UNL_RT01 }, // test cart (Russia) { 329, UNL_EDU2K }, - // 330 Sangokushi II - Haou no Tairiku hack - N163 bootleg + { 330, BTL_L001 }, // Sangokushi II bootleg (retitled part III) { 331, BMC_12IN1 }, { 332, BMC_WS }, { 333, BMC_8IN1 }, @@ -651,10 +651,8 @@ void nes_cart_slot_device::call_load_ines() // handle submappers if (submapper) { - // 001: MMC1 - if (mapper == 1 && submapper == 3) - pcb_id = STD_SXROM_A; - else if (mapper == 1 && submapper == 5) + // 001: MMC1 (other submappers are deprecated) + if (mapper == 1 && submapper == 5) logerror("Unimplemented NES 2.0 submapper: SEROM/SHROM/SH1ROM.\n"); // 002, 003, 007: UxROM, CNROM, AxROM else if (mapper == 2 && submapper == 2) @@ -780,6 +778,11 @@ void nes_cart_slot_device::call_load_ines() } break; + case STD_SXROM: + if (mapper == 155) + m_cart->set_mmc1_type(device_nes_cart_interface::mmc1_type::MMC1A); + break; + case NOCASH_NOCHR: // this mapper uses mirroring flags differently m_cart->set_four_screen_vram(false); @@ -903,6 +906,11 @@ void nes_cart_slot_device::call_load_ines() m_pcb_id = UNL_8237A; break; + case BMC_70IN1: + if (vrom_size == 0) + m_pcb_id = BMC_800IN1; + break; + case RCM_GS2004: if (prg_size >= 0x50000) m_pcb_id = RCM_GS2013; @@ -1155,10 +1163,8 @@ const char * nes_cart_slot_device::get_default_card_ines(get_default_card_softwa // handle submappers if (submapper) { - // 001: MMC1 - if (mapper == 1 && submapper == 3) - pcb_id = STD_SXROM_A; - else if (mapper == 1 && submapper == 5) + // 001: MMC1 (other submappers are deprecated) + if (mapper == 1 && submapper == 5) logerror("Unimplemented NES 2.0 submapper: SEROM/SHROM/SH1ROM.\n"); // 021, 023, 025: VRC4 / VRC2 else if (mapper == 21 || mapper == 23 || mapper == 25) @@ -1241,6 +1247,11 @@ const char * nes_cart_slot_device::get_default_card_ines(get_default_card_softwa pcb_id = UNL_8237A; break; + case BMC_70IN1: // Mapper 236 is used for 2 diff boards + if (ROM[5] == 0) + pcb_id = BMC_800IN1; + break; + case RCM_GS2004: // Mapper 283 is used for 2 diff boards if (ROM[4] >= 20) pcb_id = RCM_GS2013; diff --git a/src/devices/bus/nes/nes_pcb.hxx b/src/devices/bus/nes/nes_pcb.hxx index 410fb6197f1..799f17a15b6 100644 --- a/src/devices/bus/nes/nes_pcb.hxx +++ b/src/devices/bus/nes/nes_pcb.hxx @@ -32,8 +32,6 @@ static const nes_pcb pcb_list[] = { "un1rom", STD_UN1ROM }, { "sxrom", STD_SXROM }, { "sorom", STD_SOROM }, - { "sxrom_a", STD_SXROM_A }, - { "sorom_a", STD_SOROM_A }, { "txrom", STD_TXROM }, { "hkrom", STD_HKROM }, { "tqrom", STD_TQROM }, @@ -216,6 +214,7 @@ static const nes_pcb pcb_list[] = { "yung08", BTL_YUNG08 }, { "btl_0353", BTL_0353 }, { "09034a", BTL_09034A }, + { "l001", BTL_L001 }, { "batmanfs", BTL_BATMANFS }, { "palthena", BTL_PALTHENA }, { "tobidase", BTL_TOBIDASE }, // mapper 120 @@ -279,6 +278,7 @@ static const nes_pcb pcb_list[] = { "bmc_ball11", BMC_BALLGAMES_11IN1 }, { "bmc_22games", BMC_22GAMES }, { "bmc_64y2k", BMC_64IN1NR }, + { "bmc_420y2k", BMC_TELETUBBIES }, { "bmc_12in1", BMC_12IN1 }, { "bmc_20in1", BMC_20IN1 }, { "bmc_21in1", BMC_21IN1 }, @@ -339,6 +339,7 @@ static const nes_pcb pcb_list[] = { "tek90", JYCOMPANY_A }, { "sa9602b", SACHEN_SA9602B }, { "unl_shero", SACHEN_SHERO }, + { "a9746", UNL_A9746 }, { "mmalee2", UNL_MMALEE }, { "unl_2708", UNL_2708 }, { "unl_dh08", UNL_DH08 }, @@ -376,7 +377,6 @@ static const nes_pcb pcb_list[] = { "onebus", UNSUPPORTED_BOARD }, { "coolboy", UNSUPPORTED_BOARD }, { "btl_900218", UNSUPPORTED_BOARD }, // pirate The Lord of King, to be emulated soon - { "a9746", UNSUPPORTED_BOARD }, { "pec586", UNSUPPORTED_BOARD }, { "unl_drgnfgt", UNSUPPORTED_BOARD }, // Dragon Fighter by Flying Star { "test", TEST_BOARD }, @@ -627,6 +627,24 @@ void nes_cart_slot_device::call_load_pcb() // osd_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", nes_cart_get_line(get_feature("vrc6-pin9"), nes_cart_get_line(get_feature("vrc6-pin10")); } + if (m_pcb_id == STD_SXROM || m_pcb_id == STD_SOROM) + { + if (get_feature("mmc1_type") != nullptr) + { + using mmc1_type = device_nes_cart_interface::mmc1_type; + + const char *type = get_feature("mmc1_type"); + if (!strcmp(type, "MMC1")) + m_cart->set_mmc1_type(mmc1_type::MMC1); + else if (!strcmp(type, "MMC1A")) + m_cart->set_mmc1_type(mmc1_type::MMC1A); + else if (!strncmp(type, "MMC1B", 5)) // common prefix of several variants + m_cart->set_mmc1_type(mmc1_type::MMC1B); + else if (!strcmp(type, "MMC1C")) + m_cart->set_mmc1_type(mmc1_type::MMC1C); + } + } + if (m_pcb_id == STD_HKROM || m_pcb_id == TAITO_X1_017) mapper_sram_size = m_cart->get_mapper_sram_size(); diff --git a/src/devices/bus/nes/nes_slot.cpp b/src/devices/bus/nes/nes_slot.cpp index ebaf5ea0406..fef76b520d0 100644 --- a/src/devices/bus/nes/nes_slot.cpp +++ b/src/devices/bus/nes/nes_slot.cpp @@ -122,6 +122,7 @@ device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconf , m_misc_rom_size(0) , m_ce_mask(0) , m_ce_state(0) + , m_mmc1_type(mmc1_type::MMC1B) , m_vrc_ls_prg_a(0) , m_vrc_ls_prg_b(0) , m_vrc_ls_chr(0) diff --git a/src/devices/bus/nes/nes_slot.h b/src/devices/bus/nes/nes_slot.h index f634c7c1dc7..fc4459c458a 100644 --- a/src/devices/bus/nes/nes_slot.h +++ b/src/devices/bus/nes/nes_slot.h @@ -23,11 +23,10 @@ enum STD_CNROM, STD_CPROM, STD_EXROM, STD_FXROM, STD_GXROM, STD_HKROM, STD_PXROM, - STD_SXROM, STD_TXROM, STD_TXSROM, - STD_TKROM, STD_TQROM, + STD_SXROM, STD_SOROM, + STD_TXROM, STD_TXSROM, STD_TKROM, STD_TQROM, STD_UXROM, STD_UN1ROM, UXROM_CC, HVC_FAMBASIC, NES_QJ, PAL_ZZ, STD_EVENT, - STD_SXROM_A, STD_SOROM, STD_SOROM_A, STD_DISKSYS, STD_NROM368,//homebrew extension of NROM! // Discrete components boards (by various manufacturer) @@ -87,7 +86,7 @@ enum TXC_MJBLOCK, TXC_STRIKEW, TXC_TW, // Multigame Carts BMC_64IN1NR, BMC_190IN1, BMC_A65AS, BMC_A88S1, BMC_F15, - BMC_GN45, BMC_HIK8IN1, BMC_S24IN1SC03, BMC_T262, + BMC_GN45, BMC_HIK8IN1, BMC_S24IN1SC03, BMC_T262, BMC_TELETUBBIES, BMC_WS, BMC_SUPERBIG_7IN1, BMC_SUPERHIK_4IN1, BMC_BALLGAMES_11IN1, BMC_MARIOPARTY_7IN1, BMC_GOLD_7IN1, BMC_SUPER_700IN1, BMC_FAMILY_4646, BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1, @@ -116,9 +115,9 @@ enum UNL_43272, UNL_TF1201, UNL_CITYFIGHT, UNL_NINJARYU, UNL_EH8813A, UNL_RT01, // Bootleg boards BTL_0353, BTL_09034A, BTL_AISENSHINICOL, BTL_BATMANFS, - BTL_CONTRAJ, BTL_DRAGONNINJA, BTL_MARIOBABY, BTL_PALTHENA, - BTL_PIKACHUY2K, BTL_SBROS11, BTL_SMB2JA, BTL_SMB2JB, - BTL_SMB3, BTL_SHUIGUAN, BTL_TOBIDASE, BTL_YUNG08, + BTL_CONTRAJ, BTL_DRAGONNINJA, BTL_L001, BTL_MARIOBABY, + BTL_PALTHENA, BTL_PIKACHUY2K, BTL_SBROS11, BTL_SHUIGUAN, + BTL_SMB2JA, BTL_SMB2JB, BTL_SMB3, BTL_TOBIDASE, BTL_YUNG08, // Shenzhen Jncota JNCOTA_KT1001, // Kaiser @@ -176,6 +175,8 @@ enum class device_nes_cart_interface : public device_interface { public: + enum class mmc1_type : u8 { MMC1, MMC1A, MMC1B, MMC1C }; + // construction/destruction virtual ~device_nes_cart_interface(); @@ -214,6 +215,7 @@ public: void set_trainer(bool val) { m_has_trainer = val; } void set_ce(int mask, int state) { m_ce_mask = mask; m_ce_state = state; } + void set_mmc1_type(mmc1_type val) { m_mmc1_type = val; } void set_vrc_lines(int PRG_A, int PRG_B, int CHR) { m_vrc_ls_prg_a = PRG_A; m_vrc_ls_prg_b = PRG_B; m_vrc_ls_chr = CHR; } void set_n163_vol(int vol) { m_n163_vol = vol; } void set_x1_005_alt(bool val) { m_x1_005_alt_mirroring = val; } @@ -284,6 +286,7 @@ protected: int m_ce_mask; int m_ce_state; + mmc1_type m_mmc1_type; int m_vrc_ls_prg_a; int m_vrc_ls_prg_b; int m_vrc_ls_chr; diff --git a/src/devices/bus/nes/pirate.cpp b/src/devices/bus/nes/pirate.cpp index c6a68d48b98..fdc48fdc66b 100644 --- a/src/devices/bus/nes/pirate.cpp +++ b/src/devices/bus/nes/pirate.cpp @@ -36,8 +36,8 @@ DEFINE_DEVICE_TYPE(NES_AGCI_50282, nes_agci_device, "nes_agci50282", "NES Cart AGCI 50282 PCB") DEFINE_DEVICE_TYPE(NES_DREAMTECH01, nes_dreamtech_device, "nes_dreamtech", "NES Cart Dreamtech01 PCB") -DEFINE_DEVICE_TYPE(NES_FUKUTAKE, nes_fukutake_device, "nes_futuremedia", "NES Cart Fukutake Study Box PCB") -DEFINE_DEVICE_TYPE(NES_FUTUREMEDIA, nes_futuremedia_device, "nes_fukutake", "NES Cart FutureMedia PCB") +DEFINE_DEVICE_TYPE(NES_FUKUTAKE, nes_fukutake_device, "nes_fukutake", "NES Cart Fukutake Study Box PCB") +DEFINE_DEVICE_TYPE(NES_FUTUREMEDIA, nes_futuremedia_device, "nes_futuremedia", "NES Cart FutureMedia PCB") DEFINE_DEVICE_TYPE(NES_MAGSERIES, nes_magseries_device, "nes_magseries", "NES Cart Magical Series PCB") DEFINE_DEVICE_TYPE(NES_DAOU306, nes_daou306_device, "nes_daou306", "NES Cart Daou 306 PCB") DEFINE_DEVICE_TYPE(NES_CC21, nes_cc21_device, "nes_cc21", "NES Cart CC-21 PCB") diff --git a/src/devices/bus/ti99/gromport/cartridges.cpp b/src/devices/bus/ti99/gromport/cartridges.cpp index 7a9ccb95a6d..b4c3655a7e5 100644 --- a/src/devices/bus/ti99/gromport/cartridges.cpp +++ b/src/devices/bus/ti99/gromport/cartridges.cpp @@ -62,18 +62,18 @@ enum static char const *const pcbdefs[] = { - "standard", // PCB_STANDARD - "paged12k", // PCB_PAGED12K - "paged", // PCB_PAGED16K - "minimem", // PCB_MINIMEM - "super", // PCB_SUPER - "mbx", // PCB_MBX - "paged379i", // PCB_PAGED379I - "paged378", // PCB_PAGED378 - "paged377", // PCB_PAGED377 - "pagedcru", // PCB_PAGEDCRU - "gromemu", // PCB_GROMEMU - "paged7", // PCB_PAGED7 + "standard", // PCB_STANDARD + "paged12k", // PCB_PAGED12K + "paged", // PCB_PAGED16K + "minimem", // PCB_MINIMEM + "super", // PCB_SUPER + "mbx", // PCB_MBX + "paged379i", // PCB_PAGED379I + "paged378", // PCB_PAGED378 + "paged377", // PCB_PAGED377 + "pagedcru", // PCB_PAGEDCRU + "gromemu", // PCB_GROMEMU + "paged7", // PCB_PAGED7 nullptr }; diff --git a/src/devices/cpu/tms32082/dis_mp.cpp b/src/devices/cpu/tms32082/dis_mp.cpp index be0f9d92074..b194dd0e4d4 100644 --- a/src/devices/cpu/tms32082/dis_mp.cpp +++ b/src/devices/cpu/tms32082/dis_mp.cpp @@ -325,14 +325,14 @@ offs_t tms32082_mp_disassembler::disassemble(std::ostream &stream, offs_t pc, co case 0x0c: util::stream_format(*output, "brcr R%d", src1); break; case 0x0d: util::stream_format(*output, "brcr %s", get_creg_name(imm32)); break; - case 0x10: util::stream_format(*output, "shift%s.dz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x12: util::stream_format(*output, "shift%s.dm %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x14: util::stream_format(*output, "shift%s.ds %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x16: util::stream_format(*output, "shift%s.ez %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x18: util::stream_format(*output, "shift%s.em %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x1a: util::stream_format(*output, "shift%s.es %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x1c: util::stream_format(*output, "shift%s.iz %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; - case 0x1e: util::stream_format(*output, "shift%s.im %d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x10: util::stream_format(*output, "shift%s.dz R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x12: util::stream_format(*output, "shift%s.dm R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x14: util::stream_format(*output, "shift%s.ds R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x16: util::stream_format(*output, "shift%s.ez R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x18: util::stream_format(*output, "shift%s.em R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1a: util::stream_format(*output, "shift%s.es R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1c: util::stream_format(*output, "shift%s.iz R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; + case 0x1e: util::stream_format(*output, "shift%s.im R%d, %d, R%d, R%d", (op & (1 << 10)) ? "r" : "l", rotate, endmask, rs, rd); break; case 0x22: util::stream_format(*output, "and R%d, R%d, R%d", src1, rs, rd); break; case 0x23: util::stream_format(*output, "and 0x%08X, R%d, R%d", imm32, rs, rd); break; diff --git a/src/devices/cpu/tms32082/mp_ops.cpp b/src/devices/cpu/tms32082/mp_ops.cpp index cbae99b9d81..867a5ecf54b 100644 --- a/src/devices/cpu/tms32082/mp_ops.cpp +++ b/src/devices/cpu/tms32082/mp_ops.cpp @@ -24,18 +24,6 @@ #define ROTATE_L(x, r) ((x << r) | (x >> (32-r))) #define ROTATE_R(x, r) ((x >> r) | (x << (32-r))) -#define CMP_OVERFLOW32(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x80000000) ? 1 : 0) -#define CMP_OVERFLOW16(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x8000) ? 1 : 0) -#define CMP_OVERFLOW8(r, s, d) ((((d) ^ (s)) & ((d) ^ (r)) & 0x80) ? 1 : 0) -#define CARRY32(x) (((x) & (((uint64_t)1) << 32)) ? 1 : 0) -#define CARRY16(x) (((x) & 0x10000) ? 1 : 0) -#define CARRY8(x) (((x) & 0x100) ? 1 : 0) -#define SIGN32(x) (((x) & 0x80000000) ? 1 : 0) -#define SIGN16(x) (((x) & 0x8000) ? 1 : 0) -#define SIGN8(x) (((x) & 0x80) ? 1 : 0) - -#define SIGN_EXTEND(x, r) ((x) | (((x) & (0x80000000 >> r)) ? ((int32_t)(0x80000000) >> r) : 0)) - bool tms32082_mp_device::test_condition(int condition, uint32_t value) @@ -72,63 +60,64 @@ bool tms32082_mp_device::test_condition(int condition, uint32_t value) uint32_t tms32082_mp_device::calculate_cmp(uint32_t src1, uint32_t src2) { - uint16_t src1_16 = (uint16_t)(src1); - uint8_t src1_8 = (uint8_t)(src1); - uint16_t src2_16 = (uint16_t)(src2); - uint8_t src2_8 = (uint8_t)(src2); - - uint64_t res32 = (uint64_t)src1 - (uint64_t)src2; - int z32 = (res32 == 0) ? 1 : 0; - int n32 = SIGN32(res32); - int v32 = CMP_OVERFLOW32(res32, src2, src1); - int c32 = CARRY32(res32); - - uint32_t res16 = (uint32_t)src1_16 - (uint32_t)src2_16; - int z16 = (res16 == 0) ? 1 : 0; - int n16 = SIGN16(res16); - int v16 = CMP_OVERFLOW16(res16, src2_16, src1_16); - int c16 = CARRY16(res16); - - uint16_t res8 = (uint16_t)src1_8 - (uint16_t)src2_8; - int z8 = (res8 == 0) ? 1 : 0; - int n8 = SIGN8(res8); - int v8 = CMP_OVERFLOW8(res8, src2_8, src1_8); - int c8 = CARRY8(res8); + int32_t a32 = (uint32_t)(src1); + int16_t a16 = (uint16_t)(src1); + int8_t a8 = (uint8_t)(src1); + int32_t b32 = (uint32_t)(src2); + int16_t b16 = (uint16_t)(src2); + int8_t b8 = (uint8_t)(src2); + + int32_t res32 = a32 - b32; + int16_t res16 = a16 - b16; + int8_t res8 = a8 - b8; + + int z32 = res32 == 0; + int n32 = ((res32) & 0x80000000) ? 1 : 0; + int v32 = ((((a32) ^ (b32)) & ((a32) ^ (res32))) & 0x80000000) ? 1 : 0; + int c32 = (!((uint32_t)a32 < (uint32_t)b32)) ? 1 : 0; + int z16 = res16 == 0; + int n16 = ((res16) & 0x8000) ? 1 : 0; + int v16 = ((((a16) ^ (b16)) & ((a16) ^ (res16))) & 0x8000) ? 1 : 0; + int c16 = (!((uint16_t)a16 < (uint16_t)b16)) ? 1 : 0; + int z8 = res8 == 0; + int n8 = ((res8) & 0x80) ? 1 : 0; + int v8 = ((((a8) ^ (b8)) & ((a8) ^ (res8))) & 0x80) ? 1 : 0; + int c8 = (!((uint8_t)a8 < (uint8_t)b8)) ? 1 : 0; uint32_t flags = 0; // 32-bits (bits 20-29) - flags |= ((~c32) & 1) << 29; // higher than or same (C) - flags |= ((c32) & 1) << 28; // lower than (~C) - flags |= ((c32|z32) & 1) << 27; // lower than or same (~C|Z) - flags |= ((~c32&~z32) & 1) << 26; // higher than (C&~Z) - flags |= (((n32&v32)|(~n32&~v32)) & 1) << 25; // greater than or equal (N&V)|(~N&~V) - flags |= (((n32&~v32)|(~n32&v32)) & 1) << 24; // less than (N&~V)|(~N&V) - flags |= (((n32&~v32)|(~n32&v32)|(z32)) & 1) << 23; // less than or equal (N&~V)|(~N&V)|Z - flags |= (((n32&v32&~z32)|(~n32&~v32&~z32)) & 1) << 22; // greater than (N&V&~Z)|(~N&~V&~Z) - flags |= ((~z32) & 1) << 21; // not equal (~Z) - flags |= ((z32) & 1) << 20; // equal (Z) + flags |= ((c32) & 1) << 29; // higher than or same (C) + flags |= ((~c32) & 1) << 28; // lower than (~C) + flags |= ((~c32 | z32) & 1) << 27; // lower than or same (~C|Z) + flags |= ((c32 & ~z32) & 1) << 26; // higher than (C&~Z) + flags |= (((n32 & v32) | (~n32 & ~v32)) & 1) << 25; // greater than or equal (N&V)|(~N&~V) + flags |= (((n32 & ~v32) | (~n32 & v32)) & 1) << 24; // less than (N&~V)|(~N&V) + flags |= (((n32 & ~v32) | (~n32 & v32) | (z32)) & 1) << 23; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n32 & v32 & ~z32) | (~n32 & ~v32 & ~z32)) & 1) << 22; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z32) & 1) << 21; // not equal (~Z) + flags |= ((z32) & 1) << 20; // equal (Z) // 16-bits (bits 10-19) - flags |= ((~c16) & 1) << 19; // higher than or same (C) - flags |= ((c16) & 1) << 18; // lower than (~C) - flags |= ((c16|z16) & 1) << 17; // lower than or same (~C|Z) - flags |= ((~c16&~z16) & 1) << 16; // higher than (C&~Z) - flags |= (((n16&v16)|(~n16&~v16)) & 1) << 15; // greater than or equal (N&V)|(~N&~V) - flags |= (((n16&~v16)|(~n16&v16)) & 1) << 14; // less than (N&~V)|(~N&V) - flags |= (((n16&~v16)|(~n16&v16)|(z16)) & 1) << 13; // less than or equal (N&~V)|(~N&V)|Z - flags |= (((n16&v16&~z16)|(~n16&~v16&~z16)) & 1) << 12; // greater than (N&V&~Z)|(~N&~V&~Z) - flags |= ((~z16) & 1) << 11; // not equal (~Z) - flags |= ((z16) & 1) << 10; // equal (Z) + flags |= ((c16) & 1) << 19; // higher than or same (C) + flags |= ((~c16) & 1) << 18; // lower than (~C) + flags |= ((~c16 | z16) & 1) << 17; // lower than or same (~C|Z) + flags |= ((c16 & ~z16) & 1) << 16; // higher than (C&~Z) + flags |= (((n16 & v16) | (~n16 & ~v16)) & 1) << 15; // greater than or equal (N&V)|(~N&~V) + flags |= (((n16 & ~v16) | (~n16 & v16)) & 1) << 14; // less than (N&~V)|(~N&V) + flags |= (((n16 & ~v16) | (~n16 & v16) | (z16)) & 1) << 13; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n16 & v16 & ~z16) | (~n16 & ~v16 & ~z16)) & 1) << 12; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z16) & 1) << 11; // not equal (~Z) + flags |= ((z16) & 1) << 10; // equal (Z) // 8-bits (bits 0-9) - flags |= ((~c8) & 1) << 9; // higher than or same (C) - flags |= ((c8) & 1) << 8; // lower than (~C) - flags |= ((c8|z8) & 1) << 7; // lower than or same (~C|Z) - flags |= ((~c8&~z8) & 1) << 6; // higher than (C&~Z) - flags |= (((n8&v8)|(~n8&~v8)) & 1) << 5; // greater than or equal (N&V)|(~N&~V) - flags |= (((n8&~v8)|(~n8&v8)) & 1) << 4; // less than (N&~V)|(~N&V) - flags |= (((n8&~v8)|(~n8&v8)|(z8)) & 1) << 3; // less than or equal (N&~V)|(~N&V)|Z - flags |= (((n8&v8&~z8)|(~n8&~v8&~z8)) & 1) << 2; // greater than (N&V&~Z)|(~N&~V&~Z) - flags |= ((~z8) & 1) << 1; // not equal (~Z) - flags |= ((z8) & 1) << 0; // equal (Z) + flags |= ((c8) & 1) << 9; // higher than or same (C) + flags |= ((~c8) & 1) << 8; // lower than (~C) + flags |= ((~c8 | z8) & 1) << 7; // lower than or same (~C|Z) + flags |= ((c8 & ~z8) & 1) << 6; // higher than (C&~Z) + flags |= (((n8 & v8) | (~n8 & ~v8)) & 1) << 5; // greater than or equal (N&V)|(~N&~V) + flags |= (((n8 & ~v8) | (~n8 & v8)) & 1) << 4; // less than (N&~V)|(~N&V) + flags |= (((n8 & ~v8) | (~n8 & v8) | (z8)) & 1) << 3; // less than or equal (N&~V)|(~N&V)|Z + flags |= (((n8 & v8 & ~z8) | (~n8 & ~v8 & ~z8)) & 1) << 2; // greater than (N&V&~Z)|(~N&~V&~Z) + flags |= ((~z8) & 1) << 1; // not equal (~Z) + flags |= ((z8) & 1) << 0; // equal (Z) return flags; } @@ -287,7 +276,9 @@ void tms32082_mp_device::execute_short_imm() if (r) // right { res = ROTATE_R(source, rot) & compmask; - res = SIGN_EXTEND(res, rot); + // sign extend + if (res & (1 << (end - 1))) + res |= 0xffffffff << end; } else // left { @@ -312,8 +303,7 @@ void tms32082_mp_device::execute_short_imm() uint32_t endmask = SHIFT_MASK[end ? end : 32]; if (inv) endmask = ~endmask; - int shift = r ? 32-rot : rot; - uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32]; + uint32_t shiftmask = SHIFT_MASK[r ? 32 - rot : rot]; uint32_t compmask = endmask & shiftmask; uint32_t res; @@ -373,15 +363,16 @@ void tms32082_mp_device::execute_short_imm() uint32_t endmask = SHIFT_MASK[end ? end : 32]; if (inv) endmask = ~endmask; - int shift = r ? 32-rot : rot; - uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32]; + uint32_t shiftmask = SHIFT_MASK[r ? 32 - rot : rot]; uint32_t compmask = endmask & shiftmask; uint32_t res; if (r) // right { res = ROTATE_R(source, rot) & compmask; - res = SIGN_EXTEND(res, rot); + // sign extend + if (res & (1 << (31 - rot))) + res |= 0xffffffff << (31 - rot); } else // left { @@ -885,16 +876,15 @@ void tms32082_mp_device::execute_reg_long_imm() { int r = (m_ir & (1 << 10)); int inv = (m_ir & (1 << 11)); - int rot = m_reg[OP_ROTATE()]; + int rot = m_reg[OP_ROTATE()] & 0x1f; int end = OP_ENDMASK(); uint32_t source = m_reg[OP_RS()]; int rd = OP_RD(); - uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + uint32_t endmask = end ? SHIFT_MASK[end] : 0xffffffff; if (inv) endmask = ~endmask; - int shift = r ? 32-rot : rot; - uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32]; + uint32_t shiftmask = SHIFT_MASK[r ? 32 - rot : rot]; uint32_t compmask = endmask & shiftmask; uint32_t res; @@ -916,23 +906,24 @@ void tms32082_mp_device::execute_reg_long_imm() { int r = (m_ir & (1 << 10)); int inv = (m_ir & (1 << 11)); - int rot = m_reg[OP_ROTATE()]; + int rot = m_reg[OP_ROTATE()] & 0x1f; int end = OP_ENDMASK(); uint32_t source = m_reg[OP_RS()]; int rd = OP_RD(); - uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + uint32_t endmask = SHIFT_MASK[end ? end : 32]; if (inv) endmask = ~endmask; - int shift = r ? 32-rot : rot; - uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32]; + uint32_t shiftmask = SHIFT_MASK[r ? 32 - rot : rot]; uint32_t compmask = endmask & shiftmask; uint32_t res; if (r) // right { res = ROTATE_R(source, rot) & compmask; - res = SIGN_EXTEND(res, rot); + // sign extend + if (res & (1 << (31 - rot))) + res |= 0xffffffff << (31 - rot); } else // left { @@ -948,16 +939,15 @@ void tms32082_mp_device::execute_reg_long_imm() { int r = (m_ir & (1 << 10)); int inv = (m_ir & (1 << 11)); - int rot = m_reg[OP_ROTATE()]; + int rot = m_reg[OP_ROTATE()] & 0x1f; int end = OP_ENDMASK(); uint32_t source = m_reg[OP_RS()]; int rd = OP_RD(); - uint32_t endmask = end ? SHIFT_MASK[end ? end : 32] : m_reg[OP_ROTATE()+1]; + uint32_t endmask = end ? SHIFT_MASK[end] : 0xffffffff; if (inv) endmask = ~endmask; - int shift = r ? 32-rot : rot; - uint32_t shiftmask = SHIFT_MASK[shift ? shift : 32]; + uint32_t shiftmask = SHIFT_MASK[r ? 32 - rot : rot]; uint32_t compmask = endmask & ~shiftmask; uint32_t res; @@ -1301,29 +1291,30 @@ void tms32082_mp_device::execute_reg_long_imm() int ls_bit1 = m_ir & (1 << 10); int ls_bit2 = m_ir & (1 << 6); int rd = OP_RS(); - int src1 OP_SRC1(); + int src1 = OP_SRC1(); double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[src1 >> 1]) : (double)u2f(m_reg[src1])); + double source2 = pd ? u2d(m_fpair[rd >> 1]) : (double)(u2f(m_reg[rd])); + + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + } if (rd) { if (pd) { - double res = source * u2d(m_fpair[rd >> 1]); + double res = source * source2; m_fpair[rd >> 1] = d2u(res); } else { - float res = (float)(source) * u2f(m_reg[rd]); + float res = (float)(source * source2); m_reg[rd] = f2u(res); } } - - // parallel load/store op - if (!(ls_bit1 == 0 && ls_bit2 == 0)) - { - vector_loadstore(); - } break; } @@ -1342,6 +1333,12 @@ void tms32082_mp_device::execute_reg_long_imm() double source = has_imm ? (double)u2f(imm32) : (p1 ? u2d(m_fpair[rs1 >> 1]) : (double)u2f(m_reg[rs1])); + // parallel load/store op + if (!(ls_bit1 == 0 && ls_bit2 == 0)) + { + vector_loadstore(); + } + if (rd) { // destination register @@ -1369,12 +1366,6 @@ void tms32082_mp_device::execute_reg_long_imm() m_facc[acc] = source; } - - // parallel load/store op - if (!(ls_bit1 == 0 && ls_bit2 == 0)) - { - vector_loadstore(); - } break; } @@ -1390,7 +1381,7 @@ void tms32082_mp_device::execute_reg_long_imm() int ls_bit2 = m_ir & (1 << 6); int rd = OP_RD(); - float src1 = u2f(m_reg[OP_SRC1()]); + float src1 = has_imm ? u2f(imm32) : u2f(m_reg[OP_SRC1()]); float src2 = u2f(m_reg[OP_RS()]); float res = (src1 * src2) + (z ? 0.0f : m_facc[acc]); @@ -1412,7 +1403,7 @@ void tms32082_mp_device::execute_reg_long_imm() else m_reg[rd] = f2u((float)res); } - else + else if (pd) { // write to accumulator m_facc[acc] = (double)res; @@ -1433,7 +1424,7 @@ void tms32082_mp_device::execute_reg_long_imm() int ls_bit2 = m_ir & (1 << 6); int rd = OP_RD(); - float src1 = u2f(m_reg[OP_SRC1()]); + float src1 = has_imm ? u2f(imm32) : u2f(m_reg[OP_SRC1()]); float src2 = u2f(m_reg[OP_RS()]); float res = (z ? 0.0f : m_facc[acc]) - (src1 * src2); @@ -1455,7 +1446,7 @@ void tms32082_mp_device::execute_reg_long_imm() else m_reg[rd] = f2u((float)res); } - else + else if (pd) { // write to accumulator m_facc[acc] = (double)res; @@ -1501,7 +1492,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x11: // DP - SP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); float s2 = u2f(m_reg[rs]); uint64_t res = d2u(s1 + (double) s2); m_fpair[rd >> 1] = res; @@ -1509,7 +1500,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x15: // DP - DP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); double s2 = u2d(m_fpair[rs >> 1]); uint64_t res = d2u((double)(s1 + s2)); m_fpair[rd >> 1] = res; @@ -1559,7 +1550,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x11: // DP - SP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); float s2 = u2f(m_reg[rs]); uint64_t res = d2u(s1 - (double) s2); m_fpair[rd >> 1] = res; @@ -1567,7 +1558,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x15: // DP - DP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); double s2 = u2d(m_fpair[rs >> 1]); uint64_t res = d2u((double)(s1 - s2)); m_fpair[rd >> 1] = res; @@ -1617,7 +1608,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x11: // DP x SP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); float s2 = u2f(m_reg[rs]); uint64_t res = d2u(s1 * (double) s2); m_fpair[rd >> 1] = res; @@ -1625,7 +1616,7 @@ void tms32082_mp_device::execute_reg_long_imm() } case 0x15: // DP x DP -> DP { - double s1 = u2d(m_fpair[src1 >> 1]); + double s1 = has_imm ? u2f(imm32) : u2d(m_fpair[src1 >> 1]); double s2 = u2d(m_fpair[rs >> 1]); uint64_t res = d2u(s1 * s2); m_fpair[rd >> 1] = res; @@ -1694,7 +1685,7 @@ void tms32082_mp_device::execute_reg_long_imm() s = has_imm ? (double)(u2f(imm32)) : (double)u2f(m_reg[src1]); break; case 1: - s = u2d(m_fpair[src1 >> 1]); + s = has_imm ? (double)(u2f(imm32)) : u2d(m_fpair[src1 >> 1]); break; case 2: s = has_imm ? (double)((int32_t)(imm32)) : (double)(int32_t)(m_reg[src1]); @@ -1794,9 +1785,9 @@ void tms32082_mp_device::execute_reg_long_imm() for (int i=0; i < 32; i++) { - if (source & (1 << (31-i))) + if (source & (1 << i)) { - bit = i; + bit = 31 - i; break; } } diff --git a/src/devices/cpu/tms32082/tms32082.cpp b/src/devices/cpu/tms32082/tms32082.cpp index 25dc0af52ac..330627829da 100644 --- a/src/devices/cpu/tms32082/tms32082.cpp +++ b/src/devices/cpu/tms32082/tms32082.cpp @@ -72,40 +72,37 @@ std::unique_ptr<util::disasm_interface> tms32082_mp_device::create_disassembler( } -uint32_t tms32082_mp_device::mp_param_r(offs_t offset, uint32_t mem_mask) +void tms32082_mp_device::tc_command_execute(int channel, uint32_t entrypoint) { - //printf("mp_param_w: %08X, %08X\n", offset, mem_mask); - return m_param_ram[offset]; -} + [[maybe_unused]] static const char* CHANNEL_NAME[16] = { + "XPT15", "XPT14", "XPT13", "XPT12", "XPT11", "XPT10", "XPT9", "XPT8", + "XPT7", "XPT6", "XPT5", "XPT4", "XPT3", "XPT2", "XPT1", "MP" + }; -void tms32082_mp_device::mp_param_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - //printf("mp_param_w: %08X, %08X, %08X\n", offset, data, mem_mask); + uint32_t address = entrypoint; - COMBINE_DATA(&m_param_ram[offset]); + uint32_t next_entry = m_program.read_dword(address + 0); + uint32_t pt_options = m_program.read_dword(address + 4); - if (offset == 0x3f) + if ((pt_options & 0x00100000) == 0) { - // initiate Transfer Controller operation - // TODO: move TC functionality to separate device - uint32_t address = data; + // long-form transfer - uint32_t next_entry = m_program.read_dword(address + 0); - uint32_t pt_options = m_program.read_dword(address + 4); uint32_t src_addr = m_program.read_dword(address + 8); uint32_t dst_addr = m_program.read_dword(address + 12); uint32_t src_b_count = m_program.read_word(address + 16); uint32_t src_a_count = m_program.read_word(address + 18); - uint32_t dst_b_count = m_program.read_word(address + 20); - uint32_t dst_a_count = m_program.read_word(address + 22); + // uint32_t dst_b_count = m_program.read_word(address + 20); + // uint32_t dst_a_count = m_program.read_word(address + 22); uint32_t src_c_count = m_program.read_dword(address + 24); - uint32_t dst_c_count = m_program.read_dword(address + 28); + // uint32_t dst_c_count = m_program.read_dword(address + 28); uint32_t src_b_pitch = m_program.read_dword(address + 32); uint32_t dst_b_pitch = m_program.read_dword(address + 36); uint32_t src_c_pitch = m_program.read_dword(address + 40); uint32_t dst_c_pitch = m_program.read_dword(address + 44); - printf("TC operation:\n"); + /* + printf("TC operation (long form) %s:\n", CHANNEL_NAME[channel]); printf(" Next entry: %08X\n", next_entry); printf(" PT options: %08X\n", pt_options); printf(" SRC addr: %08X\n", src_addr); @@ -118,6 +115,7 @@ void tms32082_mp_device::mp_param_w(offs_t offset, uint32_t data, uint32_t mem_m printf(" DST B pitch: %08X\n", dst_b_pitch); printf(" SRC C pitch: %08X\n", src_c_pitch); printf(" DST C pitch: %08X\n", dst_c_pitch); + */ if (pt_options != 0x80000000) fatalerror("TC transfer, options = %08X\n", pt_options); @@ -145,6 +143,57 @@ void tms32082_mp_device::mp_param_w(offs_t offset, uint32_t data, uint32_t mem_m } } } + else + { + // short-form transfer + + bool stop = false; + + do + { + + // uint32_t src_addr = m_program.read_dword(address + 8); + // uint32_t dst_addr = m_program.read_dword(address + 12); + + // int count = pt_options & 0xffff; + stop = (pt_options & 0x80000000) ? true : false; + + /* + printf("TC operation (short form) %s [%08X]:\n", CHANNEL_NAME[channel], address); + printf(" Next entry: %08X\n", next_entry); + printf(" PT options: %08X\n", pt_options); + printf(" Byte count: %08X\n", count); + printf(" SRC addr: %08X\n", src_addr); + printf(" DST addr: %08X\n", dst_addr); + */ + + address = next_entry; + if (!stop) + { + next_entry = m_program.read_dword(address); + pt_options = m_program.read_dword(address + 4); + } + } while (!stop); + } +} + + +uint32_t tms32082_mp_device::mp_param_r(offs_t offset, uint32_t mem_mask) +{ + //printf("mp_param_w: %08X, %08X\n", offset, mem_mask); + return m_param_ram[offset]; +} + +void tms32082_mp_device::mp_param_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + //printf("mp_param_w: %08X, %08X, %08X\n", offset, data, mem_mask); + + COMBINE_DATA(&m_param_ram[offset]); + + if (offset >= 0x30 && offset <= 0x3f) + { + tc_command_execute(offset - 0x30, data); + } } @@ -255,48 +304,32 @@ void tms32082_mp_device::device_reset() m_intpen = 0; m_ie = 0; + + m_pp_status = 0xf0000; // start with all PPs halted } void tms32082_mp_device::processor_command(uint32_t command) { - printf("MP CMND %08X: ", command); + // unhalt PPs + if (command & 0x20000000) + { + if (command & 0x00000001) + m_pp_status &= ~0x10000; + if (command & 0x00000002) + m_pp_status &= ~0x20000; + } - if (command & 0x80000000) - printf("Reset "); + // halt PPs if (command & 0x40000000) - printf("Halt "); - if (command & 0x20000000) - printf("Unhalt "); - if (command & 0x10000000) - printf("ICR "); - if (command & 0x08000000) - printf("DCR "); - if (command & 0x00004000) - printf("Task "); - if (command & 0x00002000) - printf("Msg "); - - printf("to: "); - - if (command & 0x00000400) - printf("VC "); - if (command & 0x00000200) - printf("TC "); - if (command & 0x00000100) - printf("MP "); - if (command & 0x00000008) - printf("PP3 "); - if (command & 0x00000004) - printf("PP2 "); - if (command & 0x00000002) - printf("PP1 "); - if (command & 0x00000001) - printf("PP0 "); + { + if (command & 0x00000001) + m_pp_status |= 0x10000; + if (command & 0x00000002) + m_pp_status |= 0x20000; + } if (!m_cmd_callback.isnull()) m_cmd_callback(space(AS_PROGRAM), command); - - printf("\n"); } uint32_t tms32082_mp_device::read_creg(int reg) @@ -309,6 +342,11 @@ uint32_t tms32082_mp_device::read_creg(int reg) case 0x1: // EIP return m_eip; + case 0x2: // CONFIG + // Type = 0010: 2 Parallel Processors + // Release = 0011: Production release silicon + return (0x2 << 12) | (0x3 << 4); + case 0x4: // INTPEN return m_intpen; @@ -316,7 +354,7 @@ uint32_t tms32082_mp_device::read_creg(int reg) return m_ie; case 0xa: // PPERROR - return 0xe0000; + return m_pp_status; case 0xe: // TCOUNT return m_tcount; @@ -331,7 +369,7 @@ uint32_t tms32082_mp_device::read_creg(int reg) return m_outp; default: - printf("read_creg(): %08X\n", reg); + //printf("read_creg(): %08X\n", reg); break; } return 0; @@ -361,7 +399,6 @@ void tms32082_mp_device::write_creg(int reg, uint32_t data) case 0x6: // IE m_ie = data; - printf("IE = %08X\n", data); break; case 0xe: // TCOUNT @@ -381,7 +418,7 @@ void tms32082_mp_device::write_creg(int reg, uint32_t data) break; default: - printf("write_creg(): %08X, %08X\n", reg, data); + //printf("write_creg(): %08X, %08X\n", reg, data); break; } } diff --git a/src/devices/cpu/tms32082/tms32082.h b/src/devices/cpu/tms32082/tms32082.h index a3e3135b568..415ce95d564 100644 --- a/src/devices/cpu/tms32082/tms32082.h +++ b/src/devices/cpu/tms32082/tms32082.h @@ -134,6 +134,8 @@ protected: write32mo_delegate m_cmd_callback; + uint32_t m_pp_status; + void check_interrupts(); void processor_command(uint32_t command); uint32_t fetch(); @@ -146,6 +148,7 @@ protected: bool test_condition(int condition, uint32_t value); uint32_t calculate_cmp(uint32_t src1, uint32_t src2); void vector_loadstore(); + void tc_command_execute(int channel, uint32_t entrypoint); }; diff --git a/src/devices/cpu/tx0/tx0.cpp b/src/devices/cpu/tx0/tx0.cpp index 51bc1ba6c6b..0b669c48dca 100644 --- a/src/devices/cpu/tx0/tx0.cpp +++ b/src/devices/cpu/tx0/tx0.cpp @@ -42,8 +42,9 @@ #define INCREMENT_PC_8KW (PC = (PC+1) & ADDRESS_MASK_8KW) -DEFINE_DEVICE_TYPE(TX0_8KW, tx0_8kw_device, "tx0_8kw_cpu", "MIT Lincoln Laboratory TX-0 8KW") -DEFINE_DEVICE_TYPE(TX0_64KW, tx0_64kw_device, "tx0_64kw_cpu", "MIT Lincoln Laboratory TX-0 64KW") +DEFINE_DEVICE_TYPE(TX0_8KW, tx0_8kw_device, "tx0_8kw_cpu", "MIT Lincoln Laboratory TX-0 8KW (new)") +DEFINE_DEVICE_TYPE(TX0_8KW_OLD, tx0_8kwo_device, "tx0_8kwo_cpu", "MIT Lincoln Laboratory TX-0 8KW (old)") +DEFINE_DEVICE_TYPE(TX0_64KW, tx0_64kw_device, "tx0_64kw_cpu", "MIT Lincoln Laboratory TX-0 64KW") tx0_device::tx0_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int addr_bits, int address_mask, int ir_mask) @@ -66,8 +67,18 @@ tx0_device::tx0_device(const machine_config &mconfig, device_type type, const ch m_program_config.m_is_octal = true; } +tx0_8kw_device::tx0_8kw_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : tx0_device(mconfig, type, tag, owner, clock, 13, ADDRESS_MASK_8KW, 037) +{ +} + tx0_8kw_device::tx0_8kw_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : tx0_device(mconfig, TX0_8KW, tag, owner, clock, 13, ADDRESS_MASK_8KW, 037) + : tx0_8kw_device(mconfig, TX0_8KW, tag, owner, clock) +{ +} + +tx0_8kwo_device::tx0_8kwo_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : tx0_8kw_device(mconfig, TX0_8KW_OLD, tag, owner, clock) { } @@ -583,6 +594,221 @@ void tx0_64kw_device::execute_instruction_64kw() /* (1.2) TBR = Store the contents of the TBR in the MBR. */ MBR |= m_tbr; + if ((MAR & 0000003) == 2 && ((MAR & 0000600) >> 7) == 1) + /* LMB and MBL used simultaneously interchange LR and MBR */ + std::swap(LR, MBR); + else if ((MAR & 0000003) == 2) + /* (1.3) LMB = Store the contents of the LR in the MBR. */ + MBR = LR; + else if (((MAR & 0000600) >> 7) == 1) + /* (1.3) MLR = Store the contents of the MBR (memory buffer + register) in the live reg. */ + LR = MBR; + + if (((MAR & 0000600) >> 7) == 2) + /* (1.4) SHR = Shift the AC right one place, i.e. multiply the AC + by 2^-1 */ + AC >>= 1; + + if (((MAR & 0000600) >> 7) == 3) + /* (1.4) CYR = Cycle the AC right one digital position (AC(17) will + become AC(0)) */ + AC = (AC >> 1) | ((AC & 1) << 17); + + if (MAR & 0000020) + /* (1.4) PAD = Partial add AC to MBR, that is, for every digital + position of the MBR that contains a one, complement the digit + in the corresponding digital position of the AC. This is also + called a half add. */ + AC ^= MBR; + + if (MAR & 0000010) + { /* (1.7) CRY = Partial add the 18 digits of the AC to the + corresponding 18 digits of the carry. + + To determine what the 18 digits of the carry are, use the + following rule: + + "Grouping the AC and MBR digits into pairs and proceeding from + right to left, assign the carry digit of the next pair to a one + if in the present pair MBR = 1 and AC = 0 or if in the present + pair AC = 1 and carry 1. + + (Note: the 0th digit pair determines the 17th pair's carry + digit)" */ + AC ^= MBR; + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + } + + if (((MAR & 0030000) >> 12) == 3) + /* (1.8) Hlt = Halt the computer */ + m_run = 0; + + break; + } + } +} + +/* execute one instruction */ +void tx0_8kwo_device::execute_instruction_8kw() +{ + if (! m_cycle) + { + m_cycle = 1; /* most frequent case */ + switch (IR) + { + case 0: /* STOre */ + case 4: /* Store LR */ + case 8: /* ADD */ + case 12: /* Load LR */ + break; + + case 16: /* TRansfer on Negative */ + if (AC & 0400000) + { + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + } + break; + + case 20: /* TRAnsfer */ + PC = MAR & 0017777; + m_cycle = 0; /* instruction only takes one cycle if branch + is taken */ + break; + + case 24: /* OPeRate */ + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + if (IR & 004) + /* (0.8) CLL = Clear the left nine digital positions of the AC */ + AC &= 0000777; + + if (IR & 002) + /* (0.8) CLR = Clear the right nine digital positions of the AC */ + AC &= 0777000; + + if (((IR & 001) == 01) && ((MAR & 010000) == 000000)) + { + /* (0.8) IOS In-Out Stop = Stop machine so that an In-Out command + (specified by digits 6 7 8 of MAR) may be executed */ + /* ((MAR & 0007000) >> 9) is device ID */ + /* 7: */ + /* (0.8) P7H = Punch holes 1-6 in flexo tape specified by AC + digital positions 2, 5, 8, 11, 14, and 17. Also punches a 7th + hole on tape. */ + /* 6: */ + /* (0.8) P6H = Same as P7H but no seventh hole */ + /* 4: */ + /* (0.8) PNT = Print one flexowriter character specified by AC + digits 2, 5, 8, 11, 14, and 17. */ + /* 1: */ + /* (0.8) R1C = Read one line of flexo tape so that tape positions + 1, 2, 3, 4, 5, and 6 will be put in the AC digital positions 0, + 3, 6, 9, 12 and 15. */ + /* 3: */ + /* (0.8) R3C = Read one line of flexo tape into AC digits 0, 3, 6, + 9, 12 and 15. Then cycle the AC one digital position; read the + next line on tape into AC digits 0, 3, 6, 9, 12 and 15, cycle + the AC right one digital position and read the third and last + line into AC digits 0, 3, 6, 9, 12 and 15. (This command is + equal to a triple CYR-R1C.) */ + /* 2: */ + /* (0.8) DIS = Intensify a point on the scope with x and y + coordinates where x is specified by AC digits 0-8 with digit 0 + being used as the sign and y is specified by AC digits 9-17 + with digit 9 being used as the sign for y. The complement + system is in effect when the signs are negative. */ + /* (5 is undefined) */ + int index = (MAR & 0007000) >> 9; + + m_ios = 0; + call_io_handler(index); + m_ioh = 1; + } + + if (((IR & 001) == 00) && ((MAR & 010000) == 010000)) + { /* (IOS) EX0 through EX7 = operate user's EXternal equipment. */ + switch ((MAR & 0007000) >> 9) + { + /* ... */ + } + } + break; + } + } + else + { + m_cycle = 0; /* always true */ + switch (IR) + { + case 0: /* STOre */ + tx0_write(MAR, (MBR = AC)); + break; + + case 4: /* Store LR */ + tx0_write(MAR, (MBR = LR)); + break; + + case 8: /* ADD */ + MBR = tx0_read(MAR); + + AC = AC + MBR; + AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ + + break; + + case 12: /* Load LR */ + LR = MBR = tx0_read(MAR); + break; + + case 16: /* TRansfer on Negative */ + case 20: /* TRAnsfer */ + break; + + case 24: /* OPeRate */ + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + MBR = 0; + + if ((MAR & 0000104) == 0000100) + /* (1.1) PEN = Read the light pen flip-flops 1 and 2 into AC(0) and + AC(1). */ + /*...*/{ } + + if ((MAR & 0000104) == 0000004) + /* (1.1) TAC = Insert a one in each digital position of the AC + wherever there is a one in the corresponding digital position + of the TAC. */ + AC |= m_tac; + + if ((MAR & 0000003) == 1) + /* (1.2) AMB = Store the contents of the AC in the MBR. */ + MBR = AC; + + if (MAR & 0000040) + /* (1.2) COM = Complement every digit in the accumulator */ + AC ^= 0777777; + + if ((MAR & 0000003) == 3) + /* (1.2) TBR = Store the contents of the TBR in the MBR. */ + MBR |= m_tbr; + + uint32_t tmp = MBR; + if ((MAR & 0000003) == 2) /* (1.3) LMB = Store the contents of the LR in the MBR. */ MBR = LR; @@ -590,7 +816,15 @@ void tx0_64kw_device::execute_instruction_64kw() if (((MAR & 0000600) >> 7) == 1) /* (1.3) MLR = Store the contents of the MBR (memory buffer register) in the live reg. */ - LR = MBR; + LR = tmp; + + if ((MAR & 0000704) == 0000104) + /* (1.3) ORL = Inclusive or MBR into LR. */ + LR |= tmp; + + if ((MAR & 0000704) == 0000304) + /* (1.3) ANL = And MBR into LR. */ + LR &= tmp; if (((MAR & 0000600) >> 7) == 2) /* (1.4) SHR = Shift the AC right one place, i.e. multiply the AC @@ -629,7 +863,7 @@ void tx0_64kw_device::execute_instruction_64kw() AC = (AC + (AC >> 18)) & 0777777; /* propagate carry around */ } - if (((MAR & 0030000) >> 12) == 3) + if (((IR & 001) == 01) && ((MAR & 017000) == 010000)) /* (1.8) Hlt = Halt the computer */ m_run = 0; @@ -969,11 +1203,8 @@ void tx0_8kw_device::execute_instruction_8kw() } if (((! (MAR & 0000400)) && (MAR & 0000200)) && ((! (MAR & 0000004)) && (MAR & 0000002))) - { /* LMB and MBL used simultaneously interchange LR and MBR */ - int tmp = MBR; - MBR = LR; - LR = tmp; - } + /* LMB and MBL used simultaneously interchange LR and MBR */ + std::swap(LR, MBR); else if ((! (MAR & 0000400)) && (MAR & 0000200)) /* (1.4) MBL = Transfer MBR contents to LR */ LR = MBR; @@ -1073,6 +1304,11 @@ std::unique_ptr<util::disasm_interface> tx0_8kw_device::create_disassembler() return std::make_unique<tx0_8kw_disassembler>(); } +std::unique_ptr<util::disasm_interface> tx0_8kwo_device::create_disassembler() +{ + return std::make_unique<tx0_8kwo_disassembler>(); +} + std::unique_ptr<util::disasm_interface> tx0_64kw_device::create_disassembler() { return std::make_unique<tx0_64kw_disassembler>(); diff --git a/src/devices/cpu/tx0/tx0.h b/src/devices/cpu/tx0/tx0.h index 51c729bd743..8c57c08e8f7 100644 --- a/src/devices/cpu/tx0/tx0.h +++ b/src/devices/cpu/tx0/tx0.h @@ -133,11 +133,27 @@ public: tx0_8kw_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock); protected: + tx0_8kw_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual void execute_run() override; virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; private: - void execute_instruction_8kw(); + virtual void execute_instruction_8kw(); +}; + + +class tx0_8kwo_device : public tx0_8kw_device +{ +public: + // construction/destruction + tx0_8kwo_device(const machine_config &mconfig, const char *_tag, device_t *_owner, uint32_t _clock); + +protected: + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + +private: + virtual void execute_instruction_8kw() override; }; @@ -156,7 +172,8 @@ private: }; -DECLARE_DEVICE_TYPE(TX0_64KW, tx0_64kw_device) -DECLARE_DEVICE_TYPE(TX0_8KW, tx0_8kw_device) +DECLARE_DEVICE_TYPE(TX0_64KW, tx0_64kw_device) +DECLARE_DEVICE_TYPE(TX0_8KW_OLD, tx0_8kwo_device) +DECLARE_DEVICE_TYPE(TX0_8KW, tx0_8kw_device) #endif // MAME_CPU_TX0_TX0_H diff --git a/src/devices/cpu/tx0/tx0dasm.cpp b/src/devices/cpu/tx0/tx0dasm.cpp index a810f280b47..1c6ca3e5d7c 100644 --- a/src/devices/cpu/tx0/tx0dasm.cpp +++ b/src/devices/cpu/tx0/tx0dasm.cpp @@ -38,7 +38,7 @@ 1.4 | 600020 (PAD) Partial add (exclusive or) MBR to AC 1.4 | 600400 (SHR) Shift AC right once 1.4 | 600600 (CYR) Cycle AC right once - 1.7 | 600010 (CRY) Add carry digits to AC (according to LR) + 1.7 | 600010 (CRY) Add carry digits to AC (according to MBR) 1.8 | 603000 (HLT) Halt computer ANL and ORL were added in the first half of 1959 (M-5001-6). @@ -72,7 +72,7 @@ 1.6 | 600400 (SHR) Shift AC right once 1.6 | 600600 (CYR) Cycle AC right once 1.6 | 607000 (SPF) Set PFR from MBR - 1.7 | 600010 (CRY) Add carry digits to AC (according to LR) + 1.7 | 600010 (CRY) Add carry digits to AC (according to MBR) 1.8 | 600001 (MBX) Transfer MBR to XR 1.8 | 603000 (HLT) Halt computer @@ -119,7 +119,15 @@ offs_t tx0_64kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const // Addressable instructions (only 3 in this version) util::stream_format(stream, "%s %06o", s_addressable_insts[(inst & 0600000) >> 13], inst & 0177777); } - else switch (inst) + else + dasm_opr(stream, inst); + + return 1 | SUPPORTED; +} + +void tx0_64kw_disassembler::dasm_opr(std::ostream &stream, u32 inst) +{ +switch (inst) { case 0600012: stream << "cry"; @@ -245,6 +253,10 @@ offs_t tx0_64kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const stream << "clc"; break; + case 0740062: + stream << "lcc"; + break; + case 0740200: stream << "cal"; break; @@ -276,6 +288,46 @@ offs_t tx0_64kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const util::stream_format(stream, "opr %o", inst & 0177777); break; } +} + +offs_t tx0_8kwo_disassembler::disassemble(std::ostream &stream, offs_t pc, const tx0_8kwo_disassembler::data_buffer &opcodes, const tx0_8kwo_disassembler::data_buffer ¶ms) +{ + u32 inst = opcodes.r32(pc) & 0777777; + + if (inst < 0600000) + { + // Addressable instructions (only 6 in this version) + if ((inst & 060000) != 0) + util::stream_format(stream, "%06o", inst); + else + util::stream_format(stream, "%s %05o", s_addressable_insts[(inst & 0700000) >> 13], inst & 017777); + } + else switch (inst) + { + case 0600105: + stream << "orl"; + break; + + case 0600125: + stream << "ora"; + break; + + case 0600305: + stream << "anl"; + break; + + case 0600325: + stream << "ana"; + break; + + case 0610000: case 0611000: case 0612000: case 0613000: case 0614000: case 0615000: case 0616000: case 0617000: + util::stream_format(stream, "ex%d", BIT(inst, 9, 3)); + break; + + default: + dasm_opr(stream, inst); + break; + } return 1 | SUPPORTED; } @@ -309,10 +361,10 @@ offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const } else { - if ((inst & 037000) == 02000) + if ((inst & 0137020) == 0102020) { stream << "tbr"; - if ((inst & 0100757) == 0) + if ((inst & 000757) == 0) return 1 | SUPPORTED; stream << 'U'; } @@ -642,6 +694,10 @@ offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const stream << "alo"; break; + case 040227: + stream << "anl 20"; // no consistent mnemonic used in program macros + break; + case 040230: stream << "all"; break; @@ -662,6 +718,10 @@ offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const stream << "anlUcom"; break; + case 040250: + stream << "alrUamz"; + break; + case 040260: stream << "alc"; break; @@ -694,6 +754,10 @@ offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const stream << "clc"; break; + case 0100041: + stream << "clcUxro"; + break; + case 0100062: stream << "lcc"; break; @@ -718,6 +782,18 @@ offs_t tx0_8kw_disassembler::disassemble(std::ostream &stream, offs_t pc, const stream << "cal"; break; + case 0100201: + stream << "calUxro"; + break; + + case 0100212: + stream << "lalUlro"; + break; + + case 0100222: + stream << "lacUlro"; + break; + case 0100240: stream << "calUcom"; break; diff --git a/src/devices/cpu/tx0/tx0dasm.h b/src/devices/cpu/tx0/tx0dasm.h index ff9b82e3a5e..0ede659b70e 100644 --- a/src/devices/cpu/tx0/tx0dasm.h +++ b/src/devices/cpu/tx0/tx0dasm.h @@ -12,8 +12,20 @@ public: tx0_64kw_disassembler() = default; virtual ~tx0_64kw_disassembler() = default; +protected: virtual u32 opcode_alignment() const override; virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + + void dasm_opr(std::ostream &stream, u32 inst); +}; + +class tx0_8kwo_disassembler : public tx0_64kw_disassembler +{ +public: + tx0_8kwo_disassembler() = default; + +protected: + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; }; class tx0_8kw_disassembler : public util::disasm_interface @@ -22,6 +34,7 @@ public: tx0_8kw_disassembler() = default; virtual ~tx0_8kw_disassembler() = default; +protected: virtual u32 opcode_alignment() const override; virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; }; diff --git a/src/devices/machine/8042kbdc.h b/src/devices/machine/8042kbdc.h index affee6f6c7a..d28c17c9cf8 100644 --- a/src/devices/machine/8042kbdc.h +++ b/src/devices/machine/8042kbdc.h @@ -114,7 +114,7 @@ private: optional_ioport m_mousebtn_port; kbdc8042_type_t m_keybtype; - kbdc8042_interrupt_type_t m_interrupttype; + kbdc8042_interrupt_type_t m_interrupttype; devcb_write_line m_system_reset_cb; devcb_write_line m_gate_a20_cb; diff --git a/src/devices/machine/clock.cpp b/src/devices/machine/clock.cpp index 803e3d3a55f..4bd89fe791a 100644 --- a/src/devices/machine/clock.cpp +++ b/src/devices/machine/clock.cpp @@ -12,9 +12,6 @@ pulse width (active time) can be set directly with set_pulse_width. Output signal at machine start is right after falling edge. -TODO: -- add one-shot trigger? eg. monostable 555 - */ #include "emu.h" diff --git a/src/devices/machine/smpc.cpp b/src/devices/machine/smpc.cpp index bff704cdcb3..4f2e9ca8295 100644 --- a/src/devices/machine/smpc.cpp +++ b/src/devices/machine/smpc.cpp @@ -594,11 +594,17 @@ void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int par // ... m_command_in_progress = false; m_oreg[31] = m_comreg; - sf_ack(true); //clear hand-shake flag (TODO: diagnostic wants this to have bit 3 high) + // TODO: diagnostic also wants this to have bit 3 high + sf_ack(true); //set hand-shake flag return; -// case 0x0a: // NETLINKON -// case 0x0b: // NETLINKOFF + case 0x0a: // NETLINKON + // TODO: understand where NetLink actually lies and implement delegation accordingly + // (is it really an SH1 device like suggested by the space access or it overlays on CS2 bus?) + popmessage("%s: NetLink enabled", this->tag()); + [[fallthrough]]; + case 0x0b: // NETLINKOFF + break; case 0x0d: // SYSRES // send a 1 -> 0 to device reset lines @@ -614,10 +620,6 @@ void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int par case 0x0f: // CKCHG320 m_dotsel(m_comreg & 1); - // send a NMI to Master SH2 if enabled - if(m_NMI_reset == false) - master_sh2_nmi(); - // assert Slave SH2 line m_sshres(1); // clear PLL system halt @@ -625,6 +627,12 @@ void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int par // setup the new dot select m_cur_dotsel = (m_comreg & 1) ^ 1; + + // send a NMI to Master SH2 if enabled + // it is unconditionally requested: + // bigichig, capgen1, capgen4 and capgen5 triggers a SLEEP opcode from BIOS call and expects this to wake them up. + //if(m_NMI_reset == false) + master_sh2_nmi(); break; case 0x10: // INTBACK @@ -659,7 +667,7 @@ void smpc_hle_device::device_timer(emu_timer &timer, device_timer_id id, int par break; default: - logerror("%s unemulated %02x command\n",this->tag(),m_comreg); + logerror("%s: unemulated %02x command\n",this->tag(),m_comreg); return; } diff --git a/src/devices/machine/stvcd.cpp b/src/devices/machine/stvcd.cpp index 88af2d7e0cf..9e62335f448 100644 --- a/src/devices/machine/stvcd.cpp +++ b/src/devices/machine/stvcd.cpp @@ -135,6 +135,10 @@ void stvcd_device::io_regs(address_map &map) map(0x9001c, 0x9001f).mirror(0x08000).rw(FUNC(stvcd_device::cr2_r), FUNC(stvcd_device::cr2_w)).umask32(0xffffffff); map(0x90020, 0x90023).mirror(0x08000).rw(FUNC(stvcd_device::cr3_r), FUNC(stvcd_device::cr3_w)).umask32(0xffffffff); map(0x90024, 0x90027).mirror(0x08000).rw(FUNC(stvcd_device::cr4_r), FUNC(stvcd_device::cr4_w)).umask32(0xffffffff); + + // NetLink access + // dragndrm expects this value, most likely for status + map(0x8502a, 0x8502a).lr8(NAME([] () -> u8 { return 0x11; })); } u32 stvcd_device::datatrns_r(offs_t offset, uint32_t mem_mask) @@ -221,14 +225,14 @@ inline u32 stvcd_device::dataxfer_long_r() transpart->size -= xferdnum; transpart->numblks -= xfersectnum; - /* TODO: is this correct? */ + // TODO: is this correct? xfertype32 = XFERTYPE32_INVALID; } } break; default: - osd_printf_error("CD: unhandled 32-bit transfer type\n"); + osd_printf_error("CD: unhandled 32-bit transfer type %d\n", (int)xfertype32); break; } @@ -269,7 +273,7 @@ inline void stvcd_device::dataxfer_long_w(u32 data) break; default: - printf("CD: unhandled 32-bit transfer type write\n"); + printf("CD: unhandled 32-bit transfer type write %d\n", (int)xfertype32); break; } } @@ -462,7 +466,9 @@ void stvcd_device::stvcd_w(offs_t offset, uint32_t data, uint32_t mem_mask) */ int stvcd_device::get_timing_command(void) { - /* TODO: calculate timings based off command params */ + // TODO: calculate timings based off command params + // given the CMOK returns it looks like SH2 expects way slower responses + // (loops for 0x7xx times at most, max number of iterations is 0x240000) return 16667; } @@ -769,7 +775,7 @@ void stvcd_device::cmd_play_disc() } else { - /* TODO: Waku Waku 7 sets up track 0, that basically doesn't make any sense. Just skip it for now. */ + // FIXME: Waku Waku 7 sets up track 0, that basically doesn't make any sense. Just skip it for now. popmessage("Warning: track mode == 0, contact MAMEdev"); cr_standard_return(cd_stat); hirqreg |= (CMOK); @@ -814,9 +820,12 @@ void stvcd_device::cmd_play_disc() else { /* resume from a pause state */ - /* TODO: Galaxy Fight calls 10ff ffff ffff ffff, but then it calls 0x04->0x02->0x06->0x11->0x04->0x02->0x06 command sequence - (and current implementation nukes start/end FAD addresses at 0x04). I'm sure that this doesn't work like this, but there could - be countless possible combinations ... */ + // FIXME: verify implementation with Galaxy Fight + // it calls 10ff ffff ffff ffff, but then it follows up with + // 0x04->0x02->0x06->0x11->0x04->0x02->0x06 command sequence + // (and current implementation nukes start/end FAD addresses at 0x04). + // I'm sure that this doesn't work like this, but there could + // be countless possible combinations ... if(fadstoplay == 0) { cd_curfad = cdrom_get_track_start(cdrom, cur_track-1); @@ -1130,7 +1139,8 @@ void stvcd_device::cmd_get_filter_mode() void stvcd_device::cmd_set_filter_connection() { // Set Filter Connection - /* TODO: maybe condition false is cr3 low? */ + // FIXME: verify usage of cr3 LSB + // (false condition?) uint8_t fnum = (cr3>>8)&0xff; LOG("%s:CD: Set Filter Connection %x => mode %x parm %04x\n", machine().describe_context(), fnum, cr1 & 0xf, cr2); @@ -1181,7 +1191,7 @@ void stvcd_device::cmd_reset_selector() } /* reset false filter output conditions */ - /* TODO: check these two. */ + /// TODO: verify default value for these two if(cr1 & 0x80) { for(i=0;i<MAX_FILTERS;i++) @@ -1396,8 +1406,9 @@ void stvcd_device::cmd_get_sector_data() if (bufnum >= MAX_FILTERS) { + // TODO: find actual SW that does this + // (may conceal a bigger issue) osd_printf_error("CD: invalid buffer number\n"); - /* TODO: why this is happening? */ cr_standard_return(CD_STAT_REJECT); hirqreg |= (CMOK|EHST); return; @@ -1439,14 +1450,15 @@ void stvcd_device::cmd_delete_sector_data() if (bufnum >= MAX_FILTERS) { + // TODO: mustn't happen osd_printf_error("CD: invalid buffer number\n"); - /* TODO: why this is happening? */ cr_standard_return(CD_STAT_REJECT); hirqreg |= (CMOK|EHST); return; } - /* TODO: Phantasy Star 2 throws this one. */ + // pstarcol PS2 does this + // TODO: verify if implementation is correct if (partitions[bufnum].numblks == 0) { osd_printf_error("CD: buffer is already empty\n"); @@ -1459,10 +1471,15 @@ void stvcd_device::cmd_delete_sector_data() for (i = sectofs; i < (sectofs + sectnum); i++) { - partitions[bufnum].size -= partitions[bufnum].blocks[i]->size; - cd_free_block(partitions[bufnum].blocks[i]); - partitions[bufnum].blocks[i] = (blockT *)nullptr; - partitions[bufnum].bnum[i] = 0xff; + // pstarcol PS2 tries to delete partial partitions, + // need to guard against it (otherwise it would crash after first attract cycle) + if (partitions[bufnum].size > 0) + { + partitions[bufnum].size -= partitions[bufnum].blocks[i]->size; + cd_free_block(partitions[bufnum].blocks[i]); + partitions[bufnum].blocks[i] = (blockT *)nullptr; + partitions[bufnum].bnum[i] = 0xff; + } } cd_defragblocks(&partitions[bufnum]); @@ -1492,14 +1509,15 @@ void stvcd_device::cmd_get_and_delete_sector_data() if (bufnum >= MAX_FILTERS) { + // TODO: mustn't happen osd_printf_error("CD: invalid buffer number\n"); - /* TODO: why this is happening? */ cr_standard_return(CD_STAT_REJECT); hirqreg |= (CMOK|EHST); return; } /* Yoshimoto Mahjong uses the REJECT status to verify when the data is ready. */ + // TODO: verify again if it's really REJECT or something else if (partitions[bufnum].numblks < sectnum) { osd_printf_error("CD: buffer is not full %08x %08x\n",partitions[bufnum].numblks,sectnum); @@ -1708,7 +1726,11 @@ void stvcd_device::cmd_get_target_file_info() cr3 = 0; cr4 = 0; - printf("%08x %08x\n",curdir[temp].firstfad,curdir[temp].length); + // TODO: chaossd and sengblad does this + // (iso9660 parsing doesn't read beyond the first sector) + if (curdir[temp].firstfad == 0 || curdir[temp].length == 0) + throw emu_fatalerror("File ID not found in XFERTYPE_FILEINFO_1"); +// printf("%08x %08x\n",curdir[temp].firstfad,curdir[temp].length); // first 4 bytes = FAD finfbuf[0] = (curdir[temp].firstfad>>24)&0xff; finfbuf[1] = (curdir[temp].firstfad>>16)&0xff; @@ -1724,6 +1746,7 @@ void stvcd_device::cmd_get_target_file_info() finfbuf[10] = temp; finfbuf[11] = curdir[temp].flags; + xfertype = XFERTYPE_FILEINFO_1; xfercount = 0; } @@ -1988,8 +2011,9 @@ TIMER_DEVICE_CALLBACK_MEMBER( stvcd_device::stv_sector_cb ) else m_sector_timer->adjust(attotime::from_hz(75*cd_speed)); // 75 / 150 sectors / second = 150 / 300kBytes/second - /* TODO: doesn't boot if a disk isn't in? */ - /* TODO: Check out when this really happens. (Daytona USA original version definitely wants it to be on).*/ + // TODO: Saturn refuses to boot with this if a disk isn't in and condition is applied!? + // TODO: Check out actual timing of SCDQ acquisition. + // (Daytona USA original version definitely wants it to be on). //if(((cd_stat & 0x0f00) != CD_STAT_NODISC) && ((cd_stat & 0x0f00) != CD_STAT_OPEN)) hirqreg |= SCDQ; diff --git a/src/devices/sound/ics2115.cpp b/src/devices/sound/ics2115.cpp index d97ca8dea9a..0afc0787ed0 100644 --- a/src/devices/sound/ics2115.cpp +++ b/src/devices/sound/ics2115.cpp @@ -434,7 +434,7 @@ int ics2115_device::fill_output(ics2115_voice& voice, std::vector<write_stream_v { constexpr int RAMP_SHIFT = 6; const u32 volacc = (voice.vol.acc >> 14) & 0xfff; - const u16 vlefti = volacc - m_panlaw[255 - voice.vol.pan]; // left index from acc - pan law + const u16 vlefti = volacc - m_panlaw[255 - voice.vol.pan]; // left index from acc - pan law const u16 vrighti = volacc - m_panlaw[voice.vol.pan]; // right index from acc - pan law //check negative values so no cracks, is it a hardware feature ? const u16 vleft = vlefti > 0 ? (m_volume[vlefti] * voice.state.ramp >> RAMP_SHIFT) : 0; diff --git a/src/devices/video/upd3301.cpp b/src/devices/video/upd3301.cpp index 9da9f70af7c..ed57a55d760 100644 --- a/src/devices/video/upd3301.cpp +++ b/src/devices/video/upd3301.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder +// copyright-holders:Curt Coder, Angelo Salese /********************************************************************** NEC uPD3301 Programmable CRT Controller emulation @@ -10,12 +10,20 @@ TODO: - - attributes - - N interrupt + - pinpoint how much of pc8001/pc8801 drawing functions should actually be inherited + here; + - N interrupt (special control character) - light pen - reset counters - proper DMA timing (now the whole screen is transferred at the end of the frame, accurate timing requires CCLK timer which kills performance) + - DMA burst mode; + - cleanup: variable namings should be more verbose + (i.e. not be a single letter like m_y, m_z, m_b ...); + - sorcerml (pc8801) has buggy DMA burst mode, causing an underrun (hence a status U interrupt); + - jettermi (pc8801) expects to colorize its underlying 400 b&w mode by masking with the + text color attributes here; + - xak2 (pc8801) throws text garbage on legacy renderer (verify); */ @@ -77,33 +85,35 @@ DEFINE_DEVICE_TYPE(UPD3301, upd3301_device, "upd3301", "NEC uPD3301") // upd3301_device - constructor //------------------------------------------------- -upd3301_device::upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, UPD3301, tag, owner, clock), - device_video_interface(mconfig, *this), - m_write_int(*this), - m_write_drq(*this), - m_write_hrtc(*this), - m_write_vrtc(*this), - m_display_cb(*this), - m_width(0), - m_status(0), - m_param_count(0), - m_data_fifo_pos(0), - m_attr_fifo_pos(0), - m_input_fifo(0), - m_me(0), - m_h(80), - m_l(20), - m_r(10), - m_v(6), - m_z(32), - m_attr_blink(0), - m_attr_frame(0), - m_cm(0), - m_cx(0), - m_cy(0), - m_cursor_blink(0), - m_cursor_frame(0) +upd3301_device::upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, UPD3301, tag, owner, clock) + , device_video_interface(mconfig, *this) + , m_write_int(*this) + , m_write_drq(*this) + , m_write_hrtc(*this) + , m_write_vrtc(*this) + , m_write_rvv(*this) + , m_display_cb(*this) + , m_attr_fetch_cb(*this) + , m_width(0) + , m_status(0) + , m_param_count(0) + , m_data_fifo_pos(0) + , m_attr_fifo_pos(0) + , m_input_fifo(0) + , m_me(0) + , m_h(80) + , m_l(20) + , m_r(10) + , m_v(6) + , m_z(32) + , m_attr_blink(0) + , m_attr_frame(0) + , m_cm(0) + , m_cx(0) + , m_cy(0) + , m_cursor_blink(0) + , m_cursor_frame(0) { } @@ -120,7 +130,9 @@ void upd3301_device::device_start() m_write_int.resolve_safe(); m_write_hrtc.resolve_safe(); m_write_vrtc.resolve_safe(); + m_write_rvv.resolve(); m_display_cb.resolve(); + m_attr_fetch_cb.resolve(); // allocate timers m_hrtc_timer = timer_alloc(TIMER_HRTC); @@ -148,9 +160,7 @@ void upd3301_device::device_start() save_item(NAME(m_r)); save_item(NAME(m_v)); save_item(NAME(m_z)); - save_item(NAME(m_at1)); - save_item(NAME(m_at0)); - save_item(NAME(m_sc)); + save_item(NAME(m_gfx_mode)); save_item(NAME(m_attr)); save_item(NAME(m_attr_blink)); save_item(NAME(m_attr_frame)); @@ -161,6 +171,7 @@ void upd3301_device::device_start() save_item(NAME(m_cursor_frame)); save_item(NAME(m_data_fifo)); save_item(NAME(m_attr_fifo)); + save_item(NAME(m_reverse_display)); } @@ -173,6 +184,10 @@ void upd3301_device::device_reset() set_interrupt(0); set_drq(0); + m_cm = 0; + m_b = 48; + m_reverse_display = false; + recompute_parameters(); } @@ -191,40 +206,68 @@ void upd3301_device::device_clock_changed() // device_timer - handle timer events //------------------------------------------------- +// this snipped was inside screen_update fn +// bad idea: it causes all sort of desync glitches when emulation unthrottles +// TODO: verify if FIFO clear-out happens on vblank-in or -out +inline void upd3301_device::reset_fifo_vrtc() +{ + m_y = 0; + m_data_fifo_pos = 0; + m_attr_fifo_pos = 0; + + m_cursor_frame++; + + if (m_cursor_frame == m_b) + { + m_cursor_frame = 0; + m_cursor_blink = !m_cursor_blink; + } + + m_attr_frame++; + if (m_attr_frame == (m_b << 1)) + { + m_attr_frame = 0; + m_attr_blink = !m_attr_blink; + } +} + void upd3301_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch (id) { - case TIMER_HRTC: - LOG("UPD3301 HRTC: %u\n", param); + case TIMER_HRTC: + LOG("UPD3301 HRTC: %u\n", param); - m_write_hrtc(param); - m_hrtc = param; + m_write_hrtc(param); + m_hrtc = param; - update_hrtc_timer(param); - break; + update_hrtc_timer(param); + break; - case TIMER_VRTC: - LOG("UPD3301 VRTC: %u\n", param); + case TIMER_VRTC: + LOG("UPD3301 VRTC: %u\n", param); - m_write_vrtc(param); - m_vrtc = param; + m_write_vrtc(param); + m_vrtc = param; - update_vrtc_timer(param); - if(!(m_status & STATUS_VE)) - break; + update_vrtc_timer(param); + if(!(m_status & STATUS_VE)) + break; - if (param && !m_me) - { - m_status |= STATUS_E; - set_interrupt(1); - } - else if(!param) - set_drq(1); - break; + if(!param) + reset_fifo_vrtc(); + + if (param && !m_me) + { + m_status |= STATUS_E; + set_interrupt(1); + } + else if(!param) + set_drq(1); + break; - case TIMER_DRQ: - break; + case TIMER_DRQ: + break; } } @@ -239,13 +282,16 @@ uint8_t upd3301_device::read(offs_t offset) switch (offset & 0x01) { - case 0: // data - break; + case 0: // data + // TODO: light pen + if (!machine().side_effects_disabled()) + popmessage("light pen reading"); + break; - case 1: // status - data = m_status; - m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U); - break; + case 1: // status + data = m_status; + m_status &= ~(STATUS_LP | STATUS_E |STATUS_N | STATUS_U); + break; } return data; @@ -260,135 +306,185 @@ void upd3301_device::write(offs_t offset, uint8_t data) { switch (offset & 0x01) { - case 0: // data - switch (m_mode) - { - case MODE_RESET: - switch (m_param_count) + case 0: // data + switch (m_mode) { - case 0: - m_dma_mode = BIT(data, 7); - m_h = (data & 0x7f) + 2; - LOG("UPD3301 DMA Mode: %s\n", m_dma_mode ? "character" : "burst"); - LOG("UPD3301 H: %u\n", m_h); + case MODE_RESET: + switch (m_param_count) + { + case 0: + m_dma_mode = BIT(data, 7); + // number of characters per line -2 + // TODO: doesn't seem to like anything beyond 80 + m_h = (data & 0x7f) + 2; + if (m_h > 80) + popmessage("Illegal width set %d", m_h); + LOG("UPD3301 DMA Mode: %s\n", m_dma_mode ? "character" : "burst"); + LOG("UPD3301 H: %u\n", m_h); + break; + + case 1: + // cursor/attribute blink rate + m_b = ((data >> 6) + 1) * 16; + // number of lines displayed -1 + // (or in other words, tilemap y size) + m_l = (data & 0x3f) + 1; + LOG("UPD3301 B: %u\n", m_b); + LOG("UPD3301 L: %u\n", m_l); + break; + + case 2: + // skip line (pseudo-interlace?) + m_s = BIT(data, 7); + if (m_s) + popmessage("skip line enable"); + // cursor mode + // (00) not blinking underline cursor + // (01) blinking underline cursor + // (10) not blinking solid cursor + // (11) blinking solid cursor + // NB: there must be at least 14 lines per char to make underline valid + m_c = (data >> 5) & 0x03; + if (m_c != 3) + popmessage("cursor mode %02x", m_c); + // Number of lines per character -1 + m_r = (data & 0x1f) + 1; + LOG("UPD3301 S: %u\n", m_s); + LOG("UPD3301 C: %u\n", m_c); + LOG("UPD3301 R: %u\n", m_r); + break; + + case 3: + // vblank lines -1 (1 to 8) + m_v = (data >> 5) + 1; + // hblank width -2 (6 to 33) + m_z = (data & 0x1f) + 2; + LOG("UPD3301 V: %u\n", m_v); + LOG("UPD3301 Z: %u\n", m_z); + recompute_parameters(); + break; + + case 4: + // AT|SC + // (00|0) transparent b&w with special control character + // (00|1) no attributes, no special control + // (01|0) transparent color + // (10|0) non-transparent b&w, special control + // (10|1) non-transparent b&w, no special control + // any other setting are invalid + //m_at1 = BIT(data, 7); + //m_at0 = BIT(data, 6); + //m_sc = BIT(data, 5); + m_gfx_mode = (data & 0xe0) >> 5; + if (m_gfx_mode & 0x5) + popmessage("attr mode %02x", m_gfx_mode); + // Max number of attributes per line -1 + // can't be higher than 20 + m_attr = std::min((data & 0x1f) + 1, 20); + LOG("UPD3301 AT1: %u AT0: %u SC: %u\n", BIT(data, 7), BIT(data, 6), BIT(data, 5)); + LOG("UPD3301 ATTR: %u\n", m_attr); + + m_mode = MODE_NONE; + break; + } + + m_param_count++; break; - case 1: - m_b = ((data >> 6) + 1) * 16; - m_l = (data & 0x3f) + 1; - LOG("UPD3301 B: %u\n", m_b); - LOG("UPD3301 L: %u\n", m_l); - break; + case MODE_LOAD_CURSOR_POSITION: + switch (m_param_count) + { + case 0: + m_cx = data & 0x7f; + LOG("UPD3301 CX: %u\n", m_cx); + break; - case 2: - m_s = BIT(data, 7); - m_c = (data >> 4) & 0x03; - m_r = (data & 0x1f) + 1; - LOG("UPD3301 S: %u\n", m_s); - LOG("UPD3301 C: %u\n", m_c); - LOG("UPD3301 R: %u\n", m_r); - break; + case 1: + m_cy = data & 0x3f; + LOG("UPD3301 CY: %u\n", m_cy); - case 3: - m_v = (data >> 5) + 1; - m_z = (data & 0x1f) + 2; - LOG("UPD3301 V: %u\n", m_v); - LOG("UPD3301 Z: %u\n", m_z); - recompute_parameters(); - break; + m_mode = MODE_NONE; + break; + } - case 4: - m_at1 = BIT(data, 7); - m_at0 = BIT(data, 6); - m_sc = BIT(data, 5); - m_attr = (data & 0x1f) + 1; - LOG("UPD3301 AT1: %u\n", m_at1); - LOG("UPD3301 AT0: %u\n", m_at0); - LOG("UPD3301 SC: %u\n", m_sc); - LOG("UPD3301 ATTR: %u\n", m_attr); - - m_mode = MODE_NONE; + m_param_count++; break; - } - m_param_count++; + default: + LOG("UPD3301 Invalid Parameter Byte %02x!\n", data); + } break; - case MODE_LOAD_CURSOR_POSITION: - switch (m_param_count) + case 1: // command + m_mode = MODE_NONE; + m_param_count = 0; + + switch (data & 0xe0) { - case 0: - m_cx = data & 0x7f; - LOG("UPD3301 CX: %u\n", m_cx); + case COMMAND_RESET: + LOG("UPD3301 Reset\n"); + m_mode = MODE_RESET; + // TODO: this also disables external display such as Graphic VRAM in PC-8801 + set_display(0); + set_interrupt(0); break; - case 1: - m_cy = data & 0x3f; - LOG("UPD3301 CY: %u\n", m_cy); - - m_mode = MODE_NONE; + case COMMAND_START_DISPLAY: + { + LOG("UPD3301 Start Display\n"); + bool new_rvv = bool(BIT(data, 0)); + // misscmd (pc8001) enables this + if (m_reverse_display != new_rvv) + { + m_reverse_display = new_rvv; + if (!m_write_rvv.isnull()) + m_write_rvv(m_reverse_display); + else if (m_reverse_display == true) + logerror("%s: reverse display enabled (warning)\n", machine().describe_context()); + } + set_display(1); + reset_counters(); break; } - m_param_count++; - break; - - default: - LOG("UPD3301 Invalid Parameter Byte %02x!\n", data); - } - break; - - case 1: // command - m_mode = MODE_NONE; - m_param_count = 0; - - switch (data & 0xe0) - { - case COMMAND_RESET: - LOG("UPD3301 Reset\n"); - m_mode = MODE_RESET; - set_display(0); - set_interrupt(0); - break; - - case COMMAND_START_DISPLAY: - LOG("UPD3301 Start Display\n"); - set_display(1); - reset_counters(); - break; - - case COMMAND_SET_INTERRUPT_MASK: - LOG("UPD3301 Set Interrupt Mask\n"); - m_me = BIT(data, 0); - m_mn = BIT(data, 1); - LOG("UPD3301 ME: %u\n", m_me); - LOG("UPD3301 MN: %u\n", m_mn); - break; + case COMMAND_SET_INTERRUPT_MASK: + LOG("UPD3301 Set Interrupt Mask\n"); + // vblank irq mask + m_me = BIT(data, 0); + // special control character irq mask + m_mn = BIT(data, 1); + // TODO: writing a negated bit 0 makes status bit 7 to be held high? + LOG("UPD3301 ME: %u\n", m_me); + LOG("UPD3301 MN: %u\n", m_mn); + break; - case COMMAND_READ_LIGHT_PEN: - LOG("UPD3301 Read Light Pen\n"); - m_mode = MODE_READ_LIGHT_PEN; - break; + case COMMAND_READ_LIGHT_PEN: + LOG("UPD3301 Read Light Pen\n"); + // TODO: similar to cursor parameters except on read + // (plus an HR to bit 7 param [0]) + m_mode = MODE_READ_LIGHT_PEN; + break; - case COMMAND_LOAD_CURSOR_POSITION: - LOG("UPD3301 Load Cursor Position\n"); - m_mode = MODE_LOAD_CURSOR_POSITION; - m_cm = BIT(data, 0); - LOG("UPD3301 CM: %u\n", m_cm); - break; + case COMMAND_LOAD_CURSOR_POSITION: + LOG("UPD3301 Load Cursor Position\n"); + m_mode = MODE_LOAD_CURSOR_POSITION; + // (1) show cursor (0) disable cursor + m_cm = BIT(data, 0); + LOG("UPD3301 CM: %u\n", m_cm); + break; - case COMMAND_RESET_INTERRUPT: - LOG("UPD3301 Reset Interrupt\n"); - set_interrupt(0); - break; + case COMMAND_RESET_INTERRUPT: + LOG("UPD3301 Reset Interrupt\n"); + set_interrupt(0); + break; - case COMMAND_RESET_COUNTERS: - LOG("UPD3301 Reset Counters\n"); - m_mode = MODE_RESET_COUNTERS; - reset_counters(); + case COMMAND_RESET_COUNTERS: + LOG("UPD3301 Reset Counters\n"); + m_mode = MODE_RESET_COUNTERS; + reset_counters(); + break; + } break; - } - break; } } @@ -406,17 +502,23 @@ void upd3301_device::dack_w(uint8_t data) if (m_data_fifo_pos < m_h) { - m_data_fifo[m_data_fifo_pos][m_input_fifo] = data; + m_data_fifo[m_input_fifo][m_data_fifo_pos] = data; m_data_fifo_pos++; } else { - m_attr_fifo[m_attr_fifo_pos][m_input_fifo] = data; + m_attr_fifo[m_input_fifo][m_attr_fifo_pos] = data; m_attr_fifo_pos++; } if ((m_data_fifo_pos == m_h) && (m_attr_fifo_pos == (m_attr << 1))) { + const u8 attr_max_size = 80; + // first attribute start is always overwritten with a 0 + m_attr_fifo[m_input_fifo][0] = 0; + // last parameter always extends up to the end of the row + // (7narabe (pc8001) fills last row value with white when exausting available slots) + m_attr_fifo[m_input_fifo][40] = attr_max_size; m_input_fifo = !m_input_fifo; m_data_fifo_pos = 0; @@ -466,23 +568,70 @@ int upd3301_device::vrtc_r() // draw_scanline - //------------------------------------------------- +UPD3301_FETCH_ATTRIBUTE( upd3301_device::default_attr_fetch ) +{ + const u8 attr_max_size = 80; + std::array<u16, attr_max_size> attr_extend_info; + + // TODO: uPD3301 may actually fetch in LIFO order + for (int ex = 0; ex < attr_fifo_size; ex+=2) + { + u8 attr_start = std::min(attr_row[ex], attr_max_size); + u8 attr_value = attr_row[ex+1]; + u8 attr_end = std::min(attr_row[ex+2], attr_max_size); + // if the target is == 0 then just consider max size instead + // (starfire (pc8001) wants this otherwise will black screen on gameplay) + if (attr_end == 0) + attr_end = attr_max_size; + + //printf("%04x %d %d [%02x]\n", ex, attr_start, attr_end, attr_value); + + for (int i = attr_start; i < attr_end; i++) + attr_extend_info[i] = attr_value; + + if (attr_end == attr_max_size) + break; + } + + return attr_extend_info; +} + void upd3301_device::draw_scanline() { + // Olympia Boss never bothers in writing a correct attribute table for rows on resident OS, + // it just extends the full attribute RAM with a start: 0 end: 0xff value: 0. + // According to doc notes anything beyond width 80 is puked by the CRTC, therefore we clamp. + const u8 attr_max_size = 80; + const std::array<u8, 41> attr_fifo = m_attr_fifo[!m_input_fifo]; + + // expose attribute handling to our client + // PC-8801 schematics definitely shows extra TTL connections for handling its "8 to 16-bit" attribute conversion. + // It also practically needs to read the attribute mapping for various extra side-effects such as colorized 400 line 1bpp + // cfr. "その他 / other" section at http://mydocuments.g2.xrea.com/html/p8/vraminfo.html + std::array<u16, attr_max_size> extend_attr = m_attr_fetch_cb(attr_fifo, m_gfx_mode, m_y, m_attr << 1, m_h); + for (int lc = 0; lc < m_r; lc++) { + bool is_lowestline = lc == m_r - 1; for (int sx = 0; sx < m_h; sx++) { int y = m_y + lc; - uint8_t cc = m_data_fifo[sx][!m_input_fifo]; - int hlgt = 0; // TODO - int rvv = 0; // TODO - int vsp = 0; // TODO - int sl0 = 0; // TODO - int sl12 = 0; // TODO + uint8_t cc = m_data_fifo[!m_input_fifo][sx]; int csr = m_cm && m_cursor_blink && ((y / m_r) == m_cy) && (sx == m_cx); - int gpa = 0; // TODO - m_display_cb(m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa); + // datasheet mentions these but I find zero unambiguous information for PC-8001/PC-8801, i.e.: + // - "highlight" should be attribute blinking? + // - is "gpa" actually NEC-ese for attr bus? + // - is sl0 / sl12 NEC names for upper/lower line? +// int hlgt = 0; +// int rvv = 0; +// int vsp = 0; +// int sl0 = 0; +// int sl12 = 0; +// int gpa = 0; + +// m_display_cb(m_bitmap, y, sx, cc, lc, hlgt, rvv, vsp, sl0, sl12, csr, gpa); + m_display_cb(m_bitmap, y, sx, cc, lc, csr, m_attr_blink, extend_attr[sx], m_gfx_mode, is_lowestline); } } @@ -496,33 +645,13 @@ void upd3301_device::draw_scanline() uint32_t upd3301_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - if (m_status & STATUS_VE) - { - m_y = 0; - m_data_fifo_pos = 0; - m_attr_fifo_pos = 0; + bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect); - m_cursor_frame++; + if (!(m_status & STATUS_VE)) + return 0; - if (m_cursor_frame == m_b) - { - m_cursor_frame = 0; - m_cursor_blink = !m_cursor_blink; - } - - m_attr_frame++; + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); - if (m_attr_frame == (m_b << 1)) - { - m_attr_frame = 0; - m_attr_blink = !m_attr_blink; - } - copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect); - } - else - { - bitmap.fill(rgb_t(0x00,0x00,0x00), cliprect); - } return 0; } diff --git a/src/devices/video/upd3301.h b/src/devices/video/upd3301.h index 281c17a9980..7532dc61c5b 100644 --- a/src/devices/video/upd3301.h +++ b/src/devices/video/upd3301.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder +// copyright-holders:Curt Coder, Angelo Salese /********************************************************************** NEC uPD3301 Programmable CRT Controller emulation @@ -40,8 +40,10 @@ // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa) +//#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa) +#define UPD3301_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int csr, bool attr_blink_on, u16 attr, u8 gfx_mode, bool is_lowestline) +#define UPD3301_FETCH_ATTRIBUTE(_name) std::array<u16, 80> _name(const std::array<u8, 41> attr_row, u8 gfx_mode, int y, u8 attr_fifo_size, u8 row_size) //************************************************************************** // TYPE DEFINITIONS @@ -54,18 +56,24 @@ class upd3301_device : public device_t, public device_video_interface { public: - typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)> draw_character_delegate; +// typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int hlgt, int rvv, int vsp, int sl0, int sl12, int csr, int gpa)> draw_character_delegate; + typedef device_delegate<void (bitmap_rgb32 &bitmap, int y, int sx, uint8_t cc, uint8_t lc, int csr, bool attr_blink_on, u16 attr, u8 gfx_mode, bool is_lowerline)> draw_character_delegate; + typedef device_delegate<std::array<u16, 80> (const std::array<u8, 41> attr_row, u8 gfx_mode, int y, u8 attr_fifo_size, u8 row_size)> fetch_attribute_delegate; // construction/destruction upd3301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); void set_character_width(int value) { m_width = value; } template <typename... T> void set_display_callback(T &&... args) { m_display_cb.set(std::forward<T>(args)...); } + template <typename... T> void set_attribute_fetch_callback(T &&... args) { m_attr_fetch_cb.set(std::forward<T>(args)...); } + + UPD3301_FETCH_ATTRIBUTE( default_attr_fetch ); auto drq_wr_callback() { return m_write_drq.bind(); } auto int_wr_callback() { return m_write_int.bind(); } auto hrtc_wr_callback() { return m_write_hrtc.bind(); } auto vrtc_wr_callback() { return m_write_vrtc.bind(); } + auto rvv_wr_callback() { return m_write_rvv.bind(); } uint8_t read(offs_t offset); void write(offs_t offset, uint8_t data); @@ -100,13 +108,16 @@ private: void recompute_parameters(); void draw_scanline(); + inline void reset_fifo_vrtc(); devcb_write_line m_write_int; devcb_write_line m_write_drq; devcb_write_line m_write_hrtc; devcb_write_line m_write_vrtc; + devcb_write_line m_write_rvv; draw_character_delegate m_display_cb; + fetch_attribute_delegate m_attr_fetch_cb; int m_width; // screen drawing @@ -121,8 +132,8 @@ private: int m_param_count; // parameter count // FIFOs - uint8_t m_data_fifo[80][2]; // row data FIFO - uint8_t m_attr_fifo[40][2]; // attribute FIFO + u8 m_data_fifo[2][80]; // row data FIFO + std::array<std::array<u8, 40+1>, 2> m_attr_fifo; // attribute FIFO (+1 for extending to end of row) int m_data_fifo_pos; // row data FIFO position int m_attr_fifo_pos; // attribute FIFO position int m_input_fifo; // which FIFO is in input mode @@ -143,9 +154,10 @@ private: int m_z; // horizontal blanking width // attributes - int m_at1; // - int m_at0; // - int m_sc; // +// int m_at1; // +// int m_at0; // +// int m_sc; // + u8 m_gfx_mode; // AT1 + AT0 + SC int m_attr; // attributes per row int m_attr_blink; // attribute blink int m_attr_frame; // attribute blink frame counter @@ -157,6 +169,9 @@ private: int m_cursor_blink; // cursor blink int m_cursor_frame; // cursor blink frame counter + // misc + bool m_reverse_display; + // timers emu_timer *m_hrtc_timer; emu_timer *m_vrtc_timer; diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp index 31a89b5ce1a..590f4faccac 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -47,10 +47,12 @@ using test_delegate = delegate<char (void const *&)>; // type //------------------------------------------------- +#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) test_delegate make_diamond_class_delegate(char (diamond_inheritance::*func)(void const *&), diamond_inheritance *obj) { return test_delegate(func, obj); } +#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) //------------------------------------------------- @@ -1391,6 +1393,7 @@ void validate_delegates_mfp() if (&o != addr) osd_printf_error("Error testing delegate this pointer adjustment for virtual member function through base class pointer %p -> %p (expected %p)\n", static_cast<void const *>(static_cast<base_b *>(&o)), addr, static_cast<void const *>(&o)); +#if !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) // test creating delegates for a forward-declared class cb1 = make_diamond_class_delegate(&diamond_inheritance::get_derived_a, &d); cb2 = make_diamond_class_delegate(&diamond_inheritance::get_derived_b, &d); @@ -1409,8 +1412,8 @@ void validate_delegates_mfp() if (static_cast<virtual_derived_b *>(&d) != addr) osd_printf_error("Error testing delegate this pointer adjustment for incomplete class %p -> %p (expected %p)\n", static_cast<void const *>(&d), addr, static_cast<void const *>(static_cast<virtual_derived_b *>(&d))); +#if defined(_MSC_VER) && !defined(__clang__) // test MSVC extension allowing casting member pointer types across virtual inheritance relationships -#if defined(_MSC_VER) cb1 = make_diamond_class_delegate(&diamond_inheritance::get_base, &d); addr = nullptr; @@ -1419,7 +1422,8 @@ void validate_delegates_mfp() osd_printf_error("Error testing delegate non-virtual member function dispatch for incomplete class\n"); if (static_cast<virtual_base *>(&d) != addr) osd_printf_error("Error testing delegate this pointer adjustment for incomplete class %p -> %p (expected %p)\n", static_cast<void const *>(&d), addr, static_cast<void const *>(static_cast<virtual_base *>(&d))); -#endif // defined(_MSC_VER) +#endif // defined(_MSC_VER) && !defined(__clang__) +#endif // !defined(_LIBCPP_VERSION) || (_LIBCPP_VERSION >= 7000) } diff --git a/src/frontend/mame/infoxml.cpp b/src/frontend/mame/infoxml.cpp index 44c4aac98d6..99faf0cbd68 100644 --- a/src/frontend/mame/infoxml.cpp +++ b/src/frontend/mame/infoxml.cpp @@ -52,6 +52,51 @@ public: bool operator()(const std::add_pointer_t<device_type> &lhs, const std::add_pointer_t<device_type> &rhs) const; }; + +class device_filter +{ +public: + device_filter(const std::function<bool(const char *shortname, bool &done)> &callback) + : m_callback(callback) + , m_done(false) + { + } + + // methods + bool filter(const char *shortname); + + // accessors + bool done() const { return m_done; } + +private: + const std::function<bool(const char *shortname, bool &done)> & m_callback; + bool m_done; +}; + + +class filtered_driver_enumerator +{ +public: + filtered_driver_enumerator(driver_enumerator &drivlist, device_filter &devfilter) + : m_drivlist(drivlist) + , m_devfilter(devfilter) + , m_done(false) + { + } + + // methods + std::vector<std::reference_wrapper<const game_driver>> next(int count); + + // accessors + bool done() const { return m_done || m_devfilter.done(); } + +private: + driver_enumerator & m_drivlist; + device_filter & m_devfilter; + bool m_done; +}; + + typedef std::set<std::add_pointer_t<device_type>, device_type_compare> device_type_set; std::string normalize_string(const char *string); @@ -386,16 +431,22 @@ void info_xml_creator::output(std::ostream &out, const std::function<bool(const { struct prepared_info { + prepared_info() = default; + prepared_info(const prepared_info &) = delete; + prepared_info(prepared_info &&) = default; + prepared_info &operator=(const prepared_info &) = delete; + std::string m_xml_snippet; device_type_set m_dev_set; }; // prepare a driver enumerator and the queue driver_enumerator drivlist(m_lookup_options); - bool drivlist_done = false; - bool filter_done = false; + device_filter devfilter(filter); + filtered_driver_enumerator filtered_drivlist(drivlist, devfilter); bool header_outputted = false; + // essentially a local method to emit the header if necessary auto output_header_if_necessary = [this, &header_outputted](std::ostream &out) { if (!header_outputted) @@ -406,79 +457,97 @@ void info_xml_creator::output(std::ostream &out, const std::function<bool(const }; // only keep a device set when we're asked to track it - std::unique_ptr<device_type_set> devfilter; + std::optional<device_type_set> devset; if (include_devices && filter) - devfilter = std::make_unique<device_type_set>(); + devset.emplace(); + + // prepare a queue of tasks - this is a FIFO queue because of the + // need to be deterministic + std::queue<std::future<prepared_info>> tasks; - // prepare a queue of futures - std::queue<std::future<prepared_info>> queue; + // while we want to be deterministic, asynchronous task scheduling is not; so we want to + // track the amount of active tasks so that we can keep on spawning tasks even if we're + // waiting on the task in the front of the queue + std::atomic<unsigned int> active_task_count = 0; + unsigned int maximum_active_task_count = std::thread::hardware_concurrency() + 10; + unsigned int maximum_outstanding_task_count = maximum_active_task_count + 20; - // try enumerating drivers and outputting them - while (!queue.empty() || (!drivlist_done && !filter_done)) + // loop until we're done enumerating drivers, and until there are no outstanding tasks + while (!filtered_drivlist.done() || !tasks.empty()) { - // try populating the queue - while (queue.size() < 20 && !drivlist_done && !filter_done) + // loop until there are as many outstanding tasks as possible (we want to separately cap outstanding + // tasks and active tasks) + while (!filtered_drivlist.done() + && active_task_count < maximum_active_task_count + && tasks.size() < maximum_outstanding_task_count) { - if (!drivlist.next()) - { - // at this point we are done enumerating through drivlist and it is no - // longer safe to call next(), so record that we're done - drivlist_done = true; - } - else if (!filter || filter(drivlist.driver().name, filter_done)) + // we want to launch a task; grab a packet of drivers to process + std::vector<std::reference_wrapper<const game_driver>> drivers = filtered_drivlist.next(20); + if (drivers.empty()) + break; + + // do the dirty work asychronously + auto task_proc = [&drivlist, drivers{ std::move(drivers) }, include_devices, &active_task_count] { - const game_driver &driver(drivlist.driver()); - std::future<prepared_info> future_pi = std::async(std::launch::async, [&drivlist, &driver, &devfilter] - { - prepared_info result; - std::ostringstream stream; - - output_one(stream, drivlist, driver, devfilter ? &result.m_dev_set : nullptr); - result.m_xml_snippet = stream.str(); - return result; - }); - queue.push(std::move(future_pi)); - } + prepared_info result; + std::ostringstream stream; + + // output each of the drivers + for (const game_driver &driver : drivers) + output_one(stream, drivlist, driver, include_devices ? &result.m_dev_set : nullptr); + + // capture the XML snippet + result.m_xml_snippet = stream.str(); + + // we're done with the task; decrement the counter and return + active_task_count--; + return result; + }; + + // add this task to the queue + active_task_count++; + tasks.emplace(std::async(std::launch::async, std::move(task_proc))); } - // now that we have the queue populated, try grabbing one (assuming that it is not empty) - if (!queue.empty()) + // we've put as many outstanding tasks out as we can; are there any tasks outstanding? + if (!tasks.empty()) { - // wait for the future to complete and get the info - prepared_info pi = queue.front().get(); - queue.pop(); + // wait for the task at the front of the queue to complete and get the info, in the + // spirit of determinism + prepared_info pi = tasks.front().get(); + tasks.pop(); - // emit the XML + // emit whatever XML we accumulated in the task output_header_if_necessary(out); out << pi.m_xml_snippet; - // merge devices into devfilter, if appropriate - if (devfilter) + // merge devices into devset, if appropriate + if (devset) { for (const auto &x : pi.m_dev_set) - devfilter->insert(x); + devset->insert(x); } } } // iterate through the device types if not everything matches a driver - if (devfilter && !filter_done) + if (devset && !devfilter.done()) { for (device_type type : registered_device_types) { - if (!filter || filter(type.shortname(), filter_done)) - devfilter->insert(&type); + if (devfilter.filter(type.shortname())) + devset->insert(&type); - if (filter_done) + if (devfilter.done()) break; } } // output devices (both devices with roms and slot devices) - if (include_devices && (!devfilter || !devfilter->empty())) + if (include_devices && (!devset || !devset->empty())) { output_header_if_necessary(out); - output_devices(out, m_lookup_options, devfilter.get()); + output_devices(out, m_lookup_options, devset ? &*devset : nullptr); } if (header_outputted) @@ -523,6 +592,43 @@ std::string normalize_string(const char *string) //------------------------------------------------- +// device_filter::filter - apply the filter, if +// present +//------------------------------------------------- + +bool device_filter::filter(const char *shortname) +{ + return !m_done && (!m_callback || m_callback(shortname, m_done)); +} + + +//------------------------------------------------- +// filtered_driver_enumerator::next - take a number +// of game_drivers, while applying filters +//------------------------------------------------- + +std::vector<std::reference_wrapper<const game_driver>> filtered_driver_enumerator::next(int count) +{ + std::vector<std::reference_wrapper<const game_driver>> results; + while (!done() && results.size() < count) + { + if (!m_drivlist.next()) + { + // at this point we are done enumerating through drivlist and it is no + // longer safe to call next(), so record that we're done + m_done = true; + } + else if (m_devfilter.filter(m_drivlist.driver().name)) + { + const game_driver &driver(m_drivlist.driver()); + results.push_back(driver); + } + } + return results; +} + + +//------------------------------------------------- // output_header - print the XML DTD and open // the root element //------------------------------------------------- diff --git a/src/frontend/mame/ui/viewgfx.cpp b/src/frontend/mame/ui/viewgfx.cpp index 1c263fed451..b10a62aee13 100644 --- a/src/frontend/mame/ui/viewgfx.cpp +++ b/src/frontend/mame/ui/viewgfx.cpp @@ -96,7 +96,7 @@ struct ui_gfx_state int yoffs; // current Y offset int zoom; // zoom factor, either x or 1/x bool zoom_frac; // zoom via reciprocal fractions - bool auto_zoom; // auto-zoom toggle + bool auto_zoom; // auto-zoom toggle uint8_t rotate; // current rotation (orientation) value uint32_t flags; // render flags } tilemap; diff --git a/src/lib/formats/rpk.cpp b/src/lib/formats/rpk.cpp index a5b146d74aa..6171b6a4cb0 100644 --- a/src/lib/formats/rpk.cpp +++ b/src/lib/formats/rpk.cpp @@ -2,48 +2,48 @@ // copyright-holders:Michael Zapf /*************************************************************************** - rpk.cpp + rpk.cpp - RPK format support + RPK format support - A RPK file ("rompack") contains a collection of dump files and a layout - file that defines the kind of circuit board (PCB) used in the cartridge - and the mapping of dumps to sockets on the board. + A RPK file ("rompack") contains a collection of dump files and a layout + file that defines the kind of circuit board (PCB) used in the cartridge + and the mapping of dumps to sockets on the board. Example: - <?xml version="1.0" encoding="utf-8"?> - <romset> - <resources> - <rom id="gromimage" file="ed-assmg.bin" /> - </resources> - <configuration> - <pcb type="standard"> - <socket id="grom_socket" uses="gromimage"/> - </pcb> - </configuration> - </romset> + <?xml version="1.0" encoding="utf-8"?> + <romset> + <resources> + <rom id="gromimage" file="ed-assmg.bin" /> + </resources> + <configuration> + <pcb type="standard"> + <socket id="grom_socket" uses="gromimage"/> + </pcb> + </configuration> + </romset> DTD: - <!ELEMENT romset (resources, configuration)> - <!ELEMENT resources (rom|ram)+> - <!ELEMENT rom EMPTY> - <!ELEMENT ram EMPTY> - <!ELEMENT configuration (pcb)> - <!ELEMENT pcb (socket)+> - <!ELEMENT socket EMPTY> - <!ATTLIST romset version CDATA #IMPLIED> - <!ATTLIST rom id ID #REQUIRED - <!ATTLIST rom file CDATA #REQUIRED> - <!ATTLIST rom crc CDATA #IMPLIED> - <!ATTLIST rom sha1 CDATA #IMPLIED> - <!ATTLIST ram id ID #REQUIRED> - <!ATTLIST ram type (volatile|persistent) #IMPLIED> - <!ATTLIST ram store (internal|external) #IMPLIED> - <!ATTLIST ram file CDATA #IMPLIED> - <!ATTLIST ram length CDATA #REQUIRED> - <!ATTLIST pcb type CDATA #REQUIRED> - <!ATTLIST socket id ID #REQUIRED> - <!ATTLIST socket uses IDREF #REQUIRED> + <!ELEMENT romset (resources, configuration)> + <!ELEMENT resources (rom|ram)+> + <!ELEMENT rom EMPTY> + <!ELEMENT ram EMPTY> + <!ELEMENT configuration (pcb)> + <!ELEMENT pcb (socket)+> + <!ELEMENT socket EMPTY> + <!ATTLIST romset version CDATA #IMPLIED> + <!ATTLIST rom id ID #REQUIRED + <!ATTLIST rom file CDATA #REQUIRED> + <!ATTLIST rom crc CDATA #IMPLIED> + <!ATTLIST rom sha1 CDATA #IMPLIED> + <!ATTLIST ram id ID #REQUIRED> + <!ATTLIST ram type (volatile|persistent) #IMPLIED> + <!ATTLIST ram store (internal|external) #IMPLIED> + <!ATTLIST ram file CDATA #IMPLIED> + <!ATTLIST ram length CDATA #REQUIRED> + <!ATTLIST pcb type CDATA #REQUIRED> + <!ATTLIST socket id ID #REQUIRED> + <!ATTLIST socket uses IDREF #REQUIRED> ***************************************************************************/ @@ -55,7 +55,7 @@ namespace { /*************************************************************************** - TYPE DEFINITIONS + TYPE DEFINITIONS ***************************************************************************/ class rpk_category_impl : public std::error_category @@ -67,7 +67,7 @@ public: /*************************************************************************** - GLOBAL VARIABLES + GLOBAL VARIABLES ***************************************************************************/ rpk_category_impl const f_rpk_category_instance; @@ -75,7 +75,7 @@ rpk_category_impl const f_rpk_category_instance; /*************************************************************************** - RPK READER + RPK READER ***************************************************************************/ //------------------------------------------------- @@ -220,7 +220,7 @@ std::error_condition rpk_reader::read(std::unique_ptr<util::random_read> &&strea /*************************************************************************** - RPK FILE + RPK FILE ***************************************************************************/ //------------------------------------------------- @@ -347,7 +347,7 @@ std::error_condition rpk_file::add_ram_socket(std::string &&id, const util::xml: /*************************************************************************** - RPK SOCKET + RPK SOCKET ***************************************************************************/ //------------------------------------------------- @@ -416,7 +416,7 @@ std::error_condition rpk_socket::read_file(std::vector<std::uint8_t> &result) co /*************************************************************************** - RPK EXCEPTION HANDLING + RPK EXCEPTION HANDLING ***************************************************************************/ //------------------------------------------------- diff --git a/src/lib/formats/rpk.h b/src/lib/formats/rpk.h index 55b6f0a4839..f6e6360c21c 100644 --- a/src/lib/formats/rpk.h +++ b/src/lib/formats/rpk.h @@ -2,9 +2,9 @@ // copyright-holders:Michael Zapf /*************************************************************************** - rpk.h + rpk.h - RPK format support + RPK format support ***************************************************************************/ @@ -22,7 +22,7 @@ /*************************************************************************** - TYPE DEFINITIONS + TYPE DEFINITIONS ***************************************************************************/ class rpk_reader; @@ -57,12 +57,12 @@ public: std::error_condition read_file(std::vector<std::uint8_t> &result) const; private: - rpk_file & m_rpk; - std::string m_id; - socket_type m_type; - std::string m_filename; - std::optional<util::hash_collection> m_hashes; - std::uint32_t m_length; + rpk_file & m_rpk; + std::string m_id; + socket_type m_type; + std::string m_filename; + std::optional<util::hash_collection> m_hashes; + std::uint32_t m_length; }; @@ -87,9 +87,9 @@ public: const std::list<rpk_socket> &sockets() const { return m_sockets; } private: - util::archive_file::ptr m_zipfile; - int m_pcb_type; - std::list<rpk_socket> m_sockets; + util::archive_file::ptr m_zipfile; + int m_pcb_type; + std::list<rpk_socket> m_sockets; // accesors util::archive_file &zipfile() { return *m_zipfile; } @@ -127,8 +127,8 @@ public: std::error_condition read(std::unique_ptr<util::random_read> &&stream, rpk_file::ptr &result) const; private: - char const *const * m_pcb_types; - bool m_supports_ram; + char const *const * m_pcb_types; + bool m_supports_ram; }; diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp index 6f73c925da1..eff36ba6192 100644 --- a/src/lib/util/delegate.cpp +++ b/src/lib/util/delegate.cpp @@ -148,39 +148,76 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function); while (true) { + // Assumes Windows calling convention, and doesn't consider that + // the "this" pointer could be in RDX if RCX is a pointer to + // space for an oversize scalar result. Since the result area + // is uninitialised on entry, you won't see something that looks + // like a vtable dispatch through RCX in this case - it won't + // behave badly, it just won't bypass virtual call thunks in the + // rare situations where the return type is an oversize scalar. if (0xe9 == func[0]) { // relative jump with 32-bit displacement (typically a resolved PLT entry) LOG("Found relative jump at %p ", func); func += 5 + *reinterpret_cast<std::int32_t const *>(func + 1); LOG("redirecting to %p\n", func); + continue; } - else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) + else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2])) { - // virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] - // Assumes Windows calling convention, and doesn't consider - // that the "this" pointer could be in RDX if RCX is a - // pointer to space for an oversize scalar result. Since - // the result area is uninitialised on entry, you won't see - // something that looks like a vtable dispatch through RCX - // in this case - it won't behave badly, it just won't - // bypass virtual call thunks in the rare situations where - // the return type is an oversize scalar. - LOG("Found virtual member function thunk at %p ", func); - std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); - if (0x20 == func[4]) // no displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr); - else if (0x60 == func[4]) // 8-bit displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); - else // 32-bit displacement - func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); - LOG("redirecting to %p\n", func); - } - else - { - // not something we can easily bypass - break; + if ((0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4]))) + { + // MSVC virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + if (0x20 == func[4]) // no displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr); + else if (0x60 == func[4]) // 8-bit displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); + else // 32-bit displacement + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x48 == func[3]) && (0x8b == func[4])) + { + // clang virtual function call thunk - mov rax,QWORD PTR [rcx] ; mov rax,QWORD PTR [rax+...] ; jmp rax + if ((0x40 == func[5]) && (0x48 == func[7]) && (0xff == func[8]) && (0xe0 == func[9])) + { + // 8-bit displacement + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 6)); + LOG("redirecting to %p\n", func); + continue; + } + else if ((0x80 == func[5]) && (0x48 == func[10]) && (0xff == func[11]) && (0xe0 == func[12])) + { + // 32-bit displacement + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 6)); + LOG("redirecting to %p\n", func); + continue; + } + } } + + // clang uses unoptimised thunks if optimisation is disabled + // Without optimisation, clang produces thunks like: + // 50 push rax + // 48 89 0c 24 mov QWORD PTR [rsp],rcx + // 48 8b 0c 24 mov rcx,QWORD PTR [rsp] + // 48 8b 01 mov rax,QWORD PTR [rcx] + // 48 8b 80 xx xx xx xx mov rax,QWORD PTR [rax+...] + // 41 5a pop r10 + // 48 ff e0 jmp rax + // Trying to decode these thunks likely isn't worth the effort. + // Chasing performance in unoptimised builds isn't very useful, + // and the format of these thinks may be fragile. + + // not something we can easily bypass + break; } return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); #elif defined(__aarch64__) || defined(_M_ARM64) @@ -190,7 +227,19 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi // Assumes little Endian mode. Instructions are always stored // in little Endian format on AArch64, so if big Endian mode is // to be supported, the values need to be swapped. - if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) + if ((0x90000010 == (func[0] & 0x9f00001f)) && (0x91000210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) + { + // page-relative jump with +/-4GB reach - adrp xip0,... ; add xip0,xip0,#... ; br xip0 + LOG("Found page-relative jump at %p ", func); + std::int64_t const page = + (std::uint64_t(func[0] & 0x60000000) >> 17) | + (std::uint64_t(func[0] & 0x00ffffe0) << 9) | + ((func[0] & 0x00800000) ? (~std::uint64_t(0) << 33) : 0); + std::uint32_t const offset = (func[1] & 0x003ffc00) >> 10; + func = reinterpret_cast<std::uint32_t const *>(((std::uintptr_t(func) + page) & (~std::uintptr_t(0) << 12)) + offset); + LOG("redirecting to %p\n", func); + } + else if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2])) { // virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0 LOG("Found virtual member function thunk at %p ", func); @@ -203,6 +252,36 @@ delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generi // not something we can easily bypass break; } + + // clang uses horribly sub-optimal thunks for AArch64 + // Without optimisation, clang produces thunks like: + // d10143ff sub sp,sp,#80 + // f90027e7 str x7,[sp,#72] + // f90023e6 str x6,[sp,#64] + // f9001fe5 str x5,[sp,#56] + // f9001be4 str x4,[sp,#48] + // f90017e3 str x3,[sp,#40] + // f90013e2 str x2,[sp,#32] + // f9000fe1 str x1,[sp,#24] + // f90007e0 str x0,[sp,#8] + // f94007e0 ldr x0,[sp,#8] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910143ff add sp,sp,#80 + // d61f0120 br x9 + // With optimisation, clang produces thunks like: + // d10103ff sub sp,sp,#64 + // a9008be1 stp x1,x2,[sp,#8] + // a90193e3 stp x3,x4,[sp,#24] + // a9029be5 stp x5,x6,[sp,#40] + // f9001fe7 str x7,[sp,#56] + // f9400009 ldr x9,[x0] + // f9400129 ldr x9,[x9,#...] + // 910103ff add sp,sp,#64 + // d61f0120 br x9 + // It's more effort than it's worth to try decoding these + // thunks. + } return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); #else diff --git a/src/mame/arcade.flt b/src/mame/arcade.flt index fff6fef6a4e..131ce9e3c07 100644 --- a/src/mame/arcade.flt +++ b/src/mame/arcade.flt @@ -1524,10 +1524,11 @@ zwackery.cpp -ng_mv2f -ng_mv4f //saturn.cpp +-hisaturn -saturn --saturnjp -saturneu +-saturnjp +-saturnkr -vsaturn --hisaturn //vectrex.cpp -vectrex diff --git a/src/mame/drivers/4enraya.cpp b/src/mame/drivers/4enraya.cpp index ffd8224a931..1cfeb83af07 100644 --- a/src/mame/drivers/4enraya.cpp +++ b/src/mame/drivers/4enraya.cpp @@ -677,10 +677,10 @@ ROM_END TourVision was a Spanish developer, PCB had TourVision stickers, but this kind of machine was illegal in Spain, so made for the French market instead - Ariège Amusements was the exclusive distributor of TourVision products until 1991, Paradise Automatique was a spin-off of this distributor + Ariège Amusements was the exclusive distributor of TourVision products until 1991, Paradise Automatique was a spin-off of this distributor and was legally created in 1992 to import/export food vending machines, video games and audiovisual appliances and continued to work with TourVision. - + A version of this exists (on newer hardware?) with the title 'Lucky Gum' or 'Luck Gum' however the supported game shows no title screen so the title is unknown. */ diff --git a/src/mame/drivers/acesp.cpp b/src/mame/drivers/acesp.cpp index 1f39b35d536..9ad8f15365b 100644 --- a/src/mame/drivers/acesp.cpp +++ b/src/mame/drivers/acesp.cpp @@ -116,8 +116,8 @@ void ace_sp_state::ace_sp_map(address_map &map) // 0x33 - lamp stb // 0x34 - shift stb // 0x35 - shift clk - map(0x36, 0x36).ram().rw(FUNC(ace_sp_state::serial_r), FUNC(ace_sp_state::serial_w)); // 0x36 - sio - + map(0x36, 0x36).ram().rw(FUNC(ace_sp_state::serial_r), FUNC(ace_sp_state::serial_w)); // 0x36 - sio + // 0x37 - watchdog? map(0x0038, 0x003b).rw("pia0", FUNC(pia6821_device::read), FUNC(pia6821_device::write)); /* 0x3c */ diff --git a/src/mame/drivers/agat.cpp b/src/mame/drivers/agat.cpp index 4f7b20828b4..56d5f7b95f7 100644 --- a/src/mame/drivers/agat.cpp +++ b/src/mame/drivers/agat.cpp @@ -586,19 +586,19 @@ uint8_t agat_base_state::controller_strobe_r() void agat_base_state::controller_strobe_w(uint8_t data) { // 555 monostable one-shot timers; a running timer cannot be restarted - if (machine().time().as_double() >= m_joystick_x1_time) + if (machine().time().as_double() >= m_joystick_x1_time) { m_joystick_x1_time = machine().time().as_double() + m_x_calibration * m_joy1x->read(); } - if (machine().time().as_double() >= m_joystick_y1_time) + if (machine().time().as_double() >= m_joystick_y1_time) { m_joystick_y1_time = machine().time().as_double() + m_y_calibration * m_joy1y->read(); } - if (machine().time().as_double() >= m_joystick_x2_time) + if (machine().time().as_double() >= m_joystick_x2_time) { m_joystick_x2_time = machine().time().as_double() + m_x_calibration * m_joy2x->read(); } - if (machine().time().as_double() >= m_joystick_y2_time) + if (machine().time().as_double() >= m_joystick_y2_time) { m_joystick_y2_time = machine().time().as_double() + m_y_calibration * m_joy2y->read(); } diff --git a/src/mame/drivers/ampoker2.cpp b/src/mame/drivers/ampoker2.cpp index 17aa59aee8c..349f6f95ad7 100644 --- a/src/mame/drivers/ampoker2.cpp +++ b/src/mame/drivers/ampoker2.cpp @@ -1323,7 +1323,7 @@ ROM_END */ ROM_START( ampkr2jsp ) - ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "3A". + ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "3A". ROM_LOAD( "u6", 0x0000, 0x10000, CRC(183b67a6) SHA1(8d5b1ce401e8783641c666a5b190a1f052f2dfca) ) ROM_REGION( 0x4000, "gfx1", 0 ) @@ -1335,7 +1335,7 @@ ROM_START( ampkr2jsp ) ROM_END ROM_START( ampkr2jspa ) - ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "zarate". + ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "zarate". ROM_LOAD( "u6", 0x0000, 0x10000, CRC(35aa7c52) SHA1(8aa422b1b86d0366fe4736d97470fc330335ae78) ) ROM_REGION( 0x4000, "gfx1", 0 ) @@ -1346,7 +1346,7 @@ ROM_START( ampkr2jspa ) ROM_END ROM_START( ampkr2jspb ) - ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "novomatic". + ROM_REGION( 0x10000, "maincpu", 0 ) // The set is marked as "novomatic". ROM_LOAD( "u6", 0x0000, 0x10000, CRC(e2f5ff56) SHA1(ab793a4f15673d6d4447024172f6fa6c61719fe7) ) ROM_REGION( 0x4000, "gfx1", 0 ) diff --git a/src/mame/drivers/apple2.cpp b/src/mame/drivers/apple2.cpp index d43eb3fa842..6020af74499 100644 --- a/src/mame/drivers/apple2.cpp +++ b/src/mame/drivers/apple2.cpp @@ -678,19 +678,19 @@ u8 apple2_state::controller_strobe_r() void apple2_state::controller_strobe_w(u8 data) { // 558 monostable one-shot timers; a running timer cannot be restarted - if (machine().time().as_double() >= m_joystick_x1_time) + if (machine().time().as_double() >= m_joystick_x1_time) { m_joystick_x1_time = machine().time().as_double() + m_x_calibration * m_gameio->pdl0_r(); } - if (machine().time().as_double() >= m_joystick_y1_time) + if (machine().time().as_double() >= m_joystick_y1_time) { m_joystick_y1_time = machine().time().as_double() + m_y_calibration * m_gameio->pdl1_r(); } - if (machine().time().as_double() >= m_joystick_x2_time) + if (machine().time().as_double() >= m_joystick_x2_time) { m_joystick_x2_time = machine().time().as_double() + m_x_calibration * m_gameio->pdl2_r(); } - if (machine().time().as_double() >= m_joystick_y2_time) + if (machine().time().as_double() >= m_joystick_y2_time) { m_joystick_y2_time = machine().time().as_double() + m_y_calibration * m_gameio->pdl3_r(); } diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp index ed169af47b9..c9e2ece12e7 100644 --- a/src/mame/drivers/apple2e.cpp +++ b/src/mame/drivers/apple2e.cpp @@ -232,9 +232,9 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele #define CNXX_UNCLAIMED -1 #define CNXX_INTROM -2 -#define IRQ_SLOT 0 -#define IRQ_VBL 1 -#define IRQ_MOUSEXY 2 +static constexpr int IRQ_SLOT = 0; +static constexpr int IRQ_VBL = 1; +static constexpr int IRQ_MOUSEXY = 2; class apple2e_state : public driver_device { @@ -286,12 +286,14 @@ public: m_ds1315(*this, "nsc") { m_accel_laser = false; + m_has_laser_mouse = false; m_isiic = false; m_isiicplus = false; m_iscec = false; m_iscecm = false; m_iscec2000 = false; m_spectrum_text = false; + m_inverse_text = false; m_pal = false; #if IICP_NEW_IWM m_cur_floppy = nullptr; @@ -377,6 +379,7 @@ public: void auxram4000_w(offs_t offset, u8 data); u8 c000_r(offs_t offset); void c000_w(offs_t offset, u8 data); + u8 c000_laser_r(offs_t offset); void c000_laser_w(offs_t offset, u8 data); u8 c000_iic_r(offs_t offset); void c000_iic_w(offs_t offset, u8 data); @@ -413,6 +416,8 @@ public: void lc_w(offs_t offset, u8 data); u8 lc_romswitch_r(offs_t offset); void lc_romswitch_w(offs_t offset, u8 data); + u8 laser_mouse_r(offs_t offset); + void laser_mouse_w(offs_t offset, u8 data); DECLARE_WRITE_LINE_MEMBER(a2bus_irq_w); DECLARE_WRITE_LINE_MEMBER(a2bus_nmi_w); DECLARE_WRITE_LINE_MEMBER(a2bus_inh_w); @@ -425,9 +430,10 @@ public: u8 nsc_backing_r(offs_t offset); void apple2cp(machine_config &config); - void laser128ex2(machine_config &config); void spectred(machine_config &config); void laser128(machine_config &config); + void laser128o(machine_config &config); + void laser128ex2(machine_config &config); void apple2c_iwm(machine_config &config); void apple2c_mem(machine_config &config); void cec(machine_config &config); @@ -456,6 +462,7 @@ public: void r2000bank_map(address_map &map); void r4000bank_map(address_map &map); void spectred_keyb_map(address_map &map); + void init_laser128(); void init_128ex(); void init_spect(); void init_pal(); @@ -495,7 +502,7 @@ private: bool m_mockingboard4c; bool m_intc8rom; - bool m_isiic, m_isiicplus, m_iscec, m_iscecm, m_iscec2000, m_spectrum_text, m_pal; + bool m_isiic, m_isiicplus, m_iscec, m_iscecm, m_iscec2000, m_spectrum_text, m_inverse_text, m_pal; u8 m_migram[0x800]; u16 m_migpage; @@ -504,6 +511,7 @@ private: bool m_accel_present; bool m_accel_temp_slowdown; bool m_accel_laser; + bool m_has_laser_mouse; int m_accel_stage; u32 m_accel_speed; u8 m_accel_slotspk, m_accel_gameio; @@ -1233,6 +1241,7 @@ void apple2e_state::machine_reset() void apple2e_state::init_128ex() { m_accel_laser = true; + m_has_laser_mouse = true; } void apple2e_state::init_spect() @@ -1240,6 +1249,12 @@ void apple2e_state::init_spect() m_spectrum_text = true; } +void apple2e_state::init_laser128() +{ + m_inverse_text = true; + m_has_laser_mouse = true; +} + void apple2e_state::init_pal() { m_pal = true; @@ -1274,7 +1289,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(apple2e_state::apple2_interrupt) { int scanline = param; - if (m_isiic) + if ((m_isiic) || (m_has_laser_mouse)) { update_iic_mouse(); } @@ -1337,7 +1352,19 @@ u32 apple2e_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co { m_video->hgr_update(screen, bitmap, cliprect, 0, 159); } - m_video->text_update(screen, bitmap, cliprect, 160, 191); + + if (m_spectrum_text) + { + m_video->text_update_spectrum(screen, bitmap, cliprect, 160, 191); + } + else if (m_inverse_text) + { + m_video->text_update_inverse(screen, bitmap, cliprect, 160, 191); + } + else + { + m_video->text_update(screen, bitmap, cliprect, 160, 191); + } } else { @@ -1385,6 +1412,10 @@ u32 apple2e_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co { m_video->text_update_spectrum(screen, bitmap, cliprect, 0, 191); } + else if (m_inverse_text) + { + m_video->text_update_inverse(screen, bitmap, cliprect, 0, 191); + } else { m_video->text_update(screen, bitmap, cliprect, 0, 191); @@ -2068,6 +2099,25 @@ u8 apple2e_state::c000_r(offs_t offset) return read_floatingbus(); } +u8 apple2e_state::c000_laser_r(offs_t offset) +{ + u8 uFloatingBus7 = read_floatingbus() & 0x7f; + + switch (offset) + { + case 0x63: // read mouse button + return (m_mouseb->read() ? 0 : 0x80) | uFloatingBus7; + + case 0x66: // read mouse xdir + return (m_x1 ? 0x80 : 0) | uFloatingBus7; + + case 0x67: // read mouse ydir + return (m_y1 ? 0x80 : 0) | uFloatingBus7; + } + + return c000_r(offset); +} + void apple2e_state::c000_laser_w(offs_t offset, u8 data) { if ((m_accel_laser) && (offset == 0x74)) @@ -2095,6 +2145,11 @@ void apple2e_state::c000_laser_w(offs_t offset, u8 data) } else { + if ((offset & 0xf0) == 0x70) + { + lower_irq(IRQ_VBL); + } + c000_w(offset, data); } } @@ -2660,6 +2715,75 @@ void apple2e_state::update_iic_mouse() } } +u8 apple2e_state::laser_mouse_r(offs_t offset) +{ + u8 uFloatingBus7 = read_floatingbus() & 0x7f; + + switch (offset) + { + case 0x8: // read X0Edge + return (m_x0edge ? 0x80 : 0x00) | uFloatingBus7; + + case 0x9: // read Y0Edge + return (m_y0edge ? 0x80 : 0x00) | uFloatingBus7; + + case 0xa: // read XYMask + return (m_xy ? 0x80 : 0x00) | uFloatingBus7; + + case 0xb: // read VBL mask + return (m_vblmask ? 0x80 : 0x00) | uFloatingBus7; + + case 0xc: // mouse X1 IRQ status + return (m_xirq ? 0x80 : 0) | uFloatingBus7; + + case 0xd: // mouse Y1 IRQ status + return (m_yirq ? 0x80 : 0) | uFloatingBus7; + + case 0xe: // VBL interrupt status + return ((m_irqmask & IRQ_VBL) ? 0x80 : 0) | uFloatingBus7; + } + + return 0xff; +} + +void apple2e_state::laser_mouse_w(offs_t offset, u8 data) +{ + // these are the same as the //c mouse registers, but with bit 4 of the + // address inverted, pretty much. + switch (offset) + { + case 0x0: // RisX0Edge + m_x0edge = false; break; + + case 0x1: // FalX0Edge + m_x0edge = true; break; + + case 0x2: // RisY0Edge + m_y0edge = false; break; + + case 0x3: // FalY0Edge + m_y0edge = true; break; + + case 0x4: // DisXY + m_xy = false; break; + + case 0x5: // EnbXY + m_xy = true; break; + + case 0x6: // DisVBL + lower_irq(IRQ_VBL); + m_vblmask = false; break; + + case 0x7: // EnVBL + m_vblmask = true; break; + + case 0xf: // clear XY interrupt + lower_irq(IRQ_MOUSEXY); + m_xirq = m_yirq = false; + break; + } +} + u8 apple2e_state::c080_r(offs_t offset) { if(!machine().side_effects_disabled()) @@ -3333,10 +3457,11 @@ void apple2e_state::laser128_map(address_map &map) map(0x0800, 0x1fff).m(m_0800bank, FUNC(address_map_bank_device::amap8)); map(0x2000, 0x3fff).m(m_2000bank, FUNC(address_map_bank_device::amap8)); map(0x4000, 0xbfff).m(m_4000bank, FUNC(address_map_bank_device::amap8)); - map(0xc000, 0xc07f).rw(FUNC(apple2e_state::c000_r), FUNC(apple2e_state::c000_laser_w)); + map(0xc000, 0xc07f).rw(FUNC(apple2e_state::c000_laser_r), FUNC(apple2e_state::c000_laser_w)); map(0xc080, 0xc0ff).rw(FUNC(apple2e_state::c080_r), FUNC(apple2e_state::c080_w)); map(0xc098, 0xc09b).rw(m_acia1, FUNC(mos6551_device::read), FUNC(mos6551_device::write)); map(0xc0a8, 0xc0ab).rw(m_acia2, FUNC(mos6551_device::read), FUNC(mos6551_device::write)); + map(0xc0c0, 0xc0cf).rw(FUNC(apple2e_state::laser_mouse_r), FUNC(apple2e_state::laser_mouse_w)); map(0xc0d0, 0xc0d3).rw(FUNC(apple2e_state::memexp_r), FUNC(apple2e_state::memexp_w)); map(0xc0e0, 0xc0ef).rw(m_laserudc, FUNC(applefdc_base_device::read), FUNC(applefdc_base_device::write)); map(0xc100, 0xc2ff).m(m_c100bank, FUNC(address_map_bank_device::amap8)); @@ -4148,6 +4273,15 @@ INPUT_PORTS_END static INPUT_PORTS_START( laser128 ) PORT_INCLUDE( apple2e_common ) PORT_INCLUDE( apple2_sysconfig_no_accel ) + + PORT_START(MOUSE_BUTTON_TAG) /* Mouse - button */ + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button") PORT_CODE(MOUSECODE_BUTTON1) + + PORT_START(MOUSE_XAXIS_TAG) /* Mouse - X AXIS */ + PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(20) PORT_KEYDELTA(0) PORT_PLAYER(1) + + PORT_START(MOUSE_YAXIS_TAG) /* Mouse - Y AXIS */ + PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(20) PORT_KEYDELTA(0) PORT_PLAYER(1) INPUT_PORTS_END static INPUT_PORTS_START( apple2cp ) @@ -5153,6 +5287,31 @@ void apple2e_state::laser128(machine_config &config) m_ram->set_default_size("128K").set_extra_options("128K, 384K, 640K, 896K, 1152K"); } +void apple2e_state::laser128o(machine_config &config) +{ + apple2c(config); + M65C02(config.replace(), m_maincpu, 1021800); + m_maincpu->set_addrmap(AS_PROGRAM, &apple2e_state::laser128_map); + + LEGACY_APPLEFDC(config, m_laserudc, &fdc_interface); + FLOPPY_APPLE(config, FLOPPY_0, &floppy_interface, 15, 16); + FLOPPY_APPLE(config, FLOPPY_1, &floppy_interface, 15, 16); + + config.device_remove("sl4"); + config.device_remove("sl6"); + + A2BUS_LASER128_ORIG(config, "sl1", A2BUS_7M_CLOCK).set_onboard(m_a2bus); + A2BUS_LASER128_ORIG(config, "sl2", A2BUS_7M_CLOCK).set_onboard(m_a2bus); + A2BUS_LASER128_ORIG(config, "sl3", A2BUS_7M_CLOCK).set_onboard(m_a2bus); + A2BUS_LASER128_ORIG(config, "sl4", A2BUS_7M_CLOCK).set_onboard(m_a2bus); + A2BUS_SLOT(config, "sl5", m_a2bus, apple2_cards, nullptr); + A2BUS_LASER128_ORIG(config, "sl6", A2BUS_7M_CLOCK).set_onboard(m_a2bus); + A2BUS_SLOT(config, "sl7", m_a2bus, apple2_cards, nullptr); + + // original Laser 128 doesn't have the Slinky memory expansion + m_ram->set_default_size("128K").set_extra_options("128K"); +} + void apple2e_state::laser128ex2(machine_config &config) { apple2c(config); @@ -5404,11 +5563,41 @@ ROM_END ROM_START(laser128) ROM_REGION(0x2000,"gfx1",0) - ROM_LOAD ( "341-0265-a.chr", 0x0000, 0x1000, BAD_DUMP CRC(2651014d) SHA1(b2b5d87f52693817fc747df087a4aa1ddcdb1f10)) // need to dump real laser rom - ROM_LOAD ( "341-0265-a.chr", 0x1000, 0x1000, BAD_DUMP CRC(2651014d) SHA1(b2b5d87f52693817fc747df087a4aa1ddcdb1f10)) // need to dump real laser rom + ROM_LOAD( "laser 128 video rom vt27-0706-0.bin", 0x000000, 0x002000, CRC(7884cc0f) SHA1(693a0a66191465825b8f7b5e746b463f3000e9cc) ) ROM_REGION(0x10000,"maincpu",0) - ROM_LOAD("laser128.256", 0x0000, 0x8000, CRC(39e59ed3) SHA1(cbd2f45c923725bfd57f8548e65cc80b13bc18da)) + ROM_SYSTEM_BIOS(0, "871222", "v4.3") + ROMX_LOAD( "laser 128 v4.3 871222.bin", 0x000000, 0x008000, CRC(e091af13) SHA1(3232f7036a68b996fd4126d5e19e855c4d5c64df), ROM_BIOS(0) ) + + ROM_SYSTEM_BIOS(1, "870917", "v4.2") + ROMX_LOAD( "laser 128 v4.2 870917.bin", 0x000000, 0x008000, CRC(39e59ed3) SHA1(cbd2f45c923725bfd57f8548e65cc80b13bc18da), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS(2, "870724", "v4.1") + ROMX_LOAD( "laser 128 v4.1 870724.bin", 0x000000, 0x008000, CRC(ce087911) SHA1(f6dba711f0d727f1d13b0256f10ba62bde6d7f5b), ROM_BIOS(2) ) + + ROM_REGION( 0x800, "keyboard", ROMREGION_ERASE00 ) + ROM_LOAD( "342-0132-c.e12", 0x000, 0x800, BAD_DUMP CRC(e47045f4) SHA1(12a2e718f5f4acd69b6c33a45a4a940b1440a481) ) // need to dump real laser rom +ROM_END + +ROM_START(laser128o) + ROM_REGION(0x2000,"gfx1",0) + ROM_LOAD( "laser 128 video rom vt27-0706-0.bin", 0x000000, 0x002000, CRC(7884cc0f) SHA1(693a0a66191465825b8f7b5e746b463f3000e9cc) ) + + ROM_REGION(0x10000,"maincpu",0) + ROM_SYSTEM_BIOS(0, "871212", "v3.3") + ROMX_LOAD( "laser 128 v3.3 871212.bin", 0x000000, 0x008000, CRC(3f5deffe) SHA1(4e7195b941c51ba83d5ef16e1f78e3f62bccd8cd), ROM_BIOS(0) ) + + ROM_SYSTEM_BIOS(1, "870320", "v3.0") + ROMX_LOAD( "laser 128 v3.0 870320.bin", 0x000000, 0x008000, CRC(145d39ff) SHA1(087e992548c2e9849d4262a0eb505548f846c7f5), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS(2, "870203", "v2.9") + ROMX_LOAD( "laser 128 v2.9 870203.bin", 0x000000, 0x008000, CRC(7e12fe93) SHA1(d7be7ba05725111354e4bdbaaef620a2a8ea65f7), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS(3, "860915", "860915") + ROMX_LOAD( "laser 128 860915.bin", 0x000000, 0x008000, CRC(8d1a181d) SHA1(8fae95776c3d8a581c621cd258e118b8dfdb0cfd), ROM_BIOS(3) ) + + ROM_SYSTEM_BIOS(4, "860801", "860801") + ROMX_LOAD( "laser 128 860801.bin", 0x000000, 0x008000, CRC(a88c2fcf) SHA1(ec163bb6e7e07cb256e0ed0f8d148cf85313e9f9), ROM_BIOS(4) ) ROM_REGION( 0x800, "keyboard", ROMREGION_ERASE00 ) ROM_LOAD( "342-0132-c.e12", 0x000, 0x800, BAD_DUMP CRC(e47045f4) SHA1(12a2e718f5f4acd69b6c33a45a4a940b1440a481) ) // need to dump real laser rom @@ -5605,7 +5794,8 @@ COMP( 1984, apple2c, 0, apple2, apple2c, apple2c, apple2e_state, COMP( 1985?,spectred, apple2e, 0, spectred, apple2e, apple2e_state, init_spect, "Scopus/Spectrum", "Spectrum ED" , MACHINE_SUPPORTS_SAVE ) COMP( 1986, tk3000, apple2c, 0, tk3000, apple2e, apple2e_state, empty_init, "Microdigital", "TK3000//e" , MACHINE_SUPPORTS_SAVE ) COMP( 1989, prav8c, apple2e, 0, apple2e, apple2e, apple2e_state, empty_init, "Pravetz", "Pravetz 8C", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) -COMP( 1987, laser128, apple2c, 0, laser128, laser128, apple2e_state, empty_init, "Video Technology", "Laser 128 (version 4.2)", MACHINE_SUPPORTS_SAVE ) +COMP( 1987, laser128, apple2c, 0, laser128, laser128, apple2e_state, init_laser128, "Video Technology", "Laser 128", MACHINE_SUPPORTS_SAVE ) +COMP( 1987, laser128o, apple2c, 0, laser128o, laser128, apple2e_state, init_laser128, "Video Technology", "Laser 128 (original hardware)", MACHINE_SUPPORTS_SAVE ) COMP( 1988, las128ex, apple2c, 0, laser128, laser128, apple2e_state, init_128ex, "Video Technology", "Laser 128ex (version 4.5)", MACHINE_SUPPORTS_SAVE ) COMP( 1988, las128e2, apple2c, 0, laser128ex2, laser128, apple2e_state, init_128ex, "Video Technology", "Laser 128ex2 (version 6.1)", MACHINE_SUPPORTS_SAVE ) COMP( 1985, apple2c0, apple2c, 0, apple2c_iwm, apple2c, apple2e_state, empty_init, "Apple Computer", "Apple //c (UniDisk 3.5)", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/drivers/apple2gs.cpp b/src/mame/drivers/apple2gs.cpp index e01bc172779..7df85e9c9cb 100644 --- a/src/mame/drivers/apple2gs.cpp +++ b/src/mame/drivers/apple2gs.cpp @@ -1543,7 +1543,7 @@ void apple2gs_state::machine_reset() m_ramrd = false; m_ramwrt = false; m_ioudis = true; - m_newvideo = 0x01; // verified on ROM03 hardware + m_newvideo = 0x01; // verified on ROM03 hardware m_clock_frame = 0; m_mouse_x = 0x00; m_mouse_y = 0x00; diff --git a/src/mame/drivers/atarig42.cpp b/src/mame/drivers/atarig42.cpp index 0fd418de9c8..2a17942f426 100644 --- a/src/mame/drivers/atarig42.cpp +++ b/src/mame/drivers/atarig42.cpp @@ -375,7 +375,7 @@ INPUT_PORTS_END INPUT_PORTS_START( dangerex ) - PORT_START("IN0") /* e00000 */ + PORT_START("IN0") /* e00000 */ PORT_BIT( 0x000f, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_CUSTOM ) // Toggle 0 - D4 PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_CUSTOM ) // Toggle 1 - D5 @@ -798,7 +798,7 @@ ROM_END ROM_START( dangerex ) - ROM_REGION( 0x80004, "maincpu", 0 ) /* 68000 code */ + ROM_REGION( 0x80004, "maincpu", 0 ) /* 68000 code */ ROM_LOAD16_BYTE( "dx8d-0h.8d", 0x00000, 0x20000, CRC(4957b65d) SHA1(de9f187b6496cf96d29c4b1b29887abc2bdf9bf0) ) ROM_LOAD16_BYTE( "dx8c-0l.8c", 0x00001, 0x20000, CRC(aedcb497) SHA1(7e201b7db5c0ff661f782566a6b17299d514c77a) ) ROM_LOAD16_BYTE( "dx9d-1h.9d", 0x40000, 0x20000, CRC(2eb943e2) SHA1(87dbf11720e2938bf5755b13231fc668ab3e0e05) ) @@ -849,7 +849,7 @@ ROM_START( dangerex ) ROM_REGION( 0x800, "eeprom", 0 ) ROM_LOAD( "dx-eeprom.5c", 0x0000, 0x800, CRC(d14e813d) SHA1(b206ce85f7a87986d401d34eafa188b5bffae08c) ) - ROM_REGION( 0x0600, "proms", 0 ) /* microcode for growth renderer */ + ROM_REGION( 0x0600, "proms", 0 ) /* microcode for growth renderer */ ROM_LOAD( "092-1001.20p", 0x0000, 0x0200, NO_DUMP ) ROM_LOAD( "092-1002.22p", 0x0200, 0x0200, NO_DUMP ) ROM_LOAD( "092-1003.21p", 0x0400, 0x0200, NO_DUMP ) diff --git a/src/mame/drivers/barni.cpp b/src/mame/drivers/barni.cpp index d47eec28897..766c226382b 100644 --- a/src/mame/drivers/barni.cpp +++ b/src/mame/drivers/barni.cpp @@ -218,21 +218,21 @@ void barni_state::barni(machine_config &config) config.set_default_layout(layout_barni); PIA6821(config, m_pia1, 0); -// m_pia1->writepa_handler().set(FUNC(barni_state::pia1_pa_w)); -// m_pia1->writepb_handler().set(FUNC(barni_state::pia1_pb_w)); -// m_pia1->readpa_handler().set(FUNC(barni_state::pia1_pa_r)); +// m_pia1->writepa_handler().set(FUNC(barni_state::pia1_pa_w)); +// m_pia1->writepb_handler().set(FUNC(barni_state::pia1_pb_w)); +// m_pia1->readpa_handler().set(FUNC(barni_state::pia1_pa_r)); PIA6821(config, m_pia2, 0); -// m_pia2->writepa_handler().set(FUNC(barni_state::pia2_pa_w)); -// m_pia2->writepb_handler().set(FUNC(barni_state::pia2_pb_w)); -// m_pia2->readpa_handler().set(FUNC(barni_state::pia2_pa_r)); +// m_pia2->writepa_handler().set(FUNC(barni_state::pia2_pa_w)); +// m_pia2->writepb_handler().set(FUNC(barni_state::pia2_pb_w)); +// m_pia2->readpa_handler().set(FUNC(barni_state::pia2_pa_r)); MOS6522(config, m_via, 4'000'000 / 4); // to check m_via->irq_handler().set_inputline(m_maincpu, M6809_IRQ_LINE); m_via->writepa_handler().set(FUNC(barni_state::via_pa_w)); m_via->writepb_handler().set(FUNC(barni_state::via_pb_w)); -// m_via->ca2_handler().set(FUNC(barni_state::via_ca2_w)); -// m_via->cb2_handler().set(FUNC(barni_state::via_cb2_w)); +// m_via->ca2_handler().set(FUNC(barni_state::via_ca2_w)); +// m_via->cb2_handler().set(FUNC(barni_state::via_cb2_w)); // SOUND BOARD M6802(config, m_audiocpu, 4000000); // guess - crystal value not shown diff --git a/src/mame/drivers/conchess.cpp b/src/mame/drivers/conchess.cpp index 19ae4c19d74..e2bea9699dc 100644 --- a/src/mame/drivers/conchess.cpp +++ b/src/mame/drivers/conchess.cpp @@ -228,7 +228,7 @@ void conchess_state::concstd(machine_config &config) M6502(config, m_maincpu, 4_MHz_XTAL/2); m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); - const attotime irq_period = attotime::from_hz(4_MHz_XTAL/2 / 0x1000); + const attotime irq_period = attotime::from_hz(4_MHz_XTAL / 0x2000); m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); SENSORBOARD(config, m_board).set_type(sensorboard_device::MAGNETS); @@ -244,7 +244,7 @@ void conchess_state::concstd(machine_config &config) /* sound hardware */ SPEAKER(config, "mono").front_center(); - BEEP(config, m_beeper, 4_MHz_XTAL/2 / 0x200); + BEEP(config, m_beeper, 4_MHz_XTAL / 0x400); m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); } @@ -256,13 +256,13 @@ void conchess_state::concply5(machine_config &config) R65C02(config.replace(), m_maincpu, 11_MHz_XTAL/2); m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); - const attotime irq_period = attotime::from_hz(11_MHz_XTAL/2 / 0x2000); + const attotime irq_period = attotime::from_hz(11_MHz_XTAL / 0x4000); m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); SOFTWARE_LIST(config.replace(), "cart_list").set_original("conchess_plymate"); /* sound hardware */ - BEEP(config.replace(), m_beeper, 11_MHz_XTAL/2 / 0x400); + BEEP(config.replace(), m_beeper, 11_MHz_XTAL / 0x800); m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); } @@ -274,11 +274,11 @@ void conchess_state::concply8(machine_config &config) R65C02(config.replace(), m_maincpu, 16_MHz_XTAL/2); m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); - const attotime irq_period = attotime::from_hz(16_MHz_XTAL/2 / 0x2000); + const attotime irq_period = attotime::from_hz(16_MHz_XTAL / 0x4000); m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); /* sound hardware */ - BEEP(config.replace(), m_beeper, 16_MHz_XTAL/2 / 0x800); + BEEP(config.replace(), m_beeper, 16_MHz_XTAL / 0x1000); m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); } @@ -290,13 +290,13 @@ void conchess_state::concplyv(machine_config &config) M65C02(config.replace(), m_maincpu, 12.288_MHz_XTAL/2); m_maincpu->set_addrmap(AS_PROGRAM, &conchess_state::main_map); - const attotime irq_period = attotime::from_hz(12.288_MHz_XTAL/2 / 0x2000); + const attotime irq_period = attotime::from_hz(12.288_MHz_XTAL / 0x4000); m_maincpu->set_periodic_int(FUNC(conchess_state::irq0_line_assert), irq_period); SOFTWARE_LIST(config.replace(), "cart_list").set_original("conchess_victoria"); /* sound hardware */ - BEEP(config.replace(), m_beeper, 12.288_MHz_XTAL/2 / 0x800); + BEEP(config.replace(), m_beeper, 12.288_MHz_XTAL / 0x1000); m_beeper->add_route(ALL_OUTPUTS, "mono", 0.25); } diff --git a/src/mame/drivers/cybstorm.cpp b/src/mame/drivers/cybstorm.cpp index 216fbad30b6..dbd7318286c 100644 --- a/src/mame/drivers/cybstorm.cpp +++ b/src/mame/drivers/cybstorm.cpp @@ -12,8 +12,8 @@ Known bugs: * STAIN effect not 100% correct - Possible bugs: - * Tilemap offsets shifted by 1 pixel? + Possible bugs: + * Tilemap offsets shifted by 1 pixel? ***************************************************************************/ diff --git a/src/mame/drivers/fidel_eag68k.cpp b/src/mame/drivers/fidel_eag68k.cpp index 380d3d6a8bc..4ce43644894 100644 --- a/src/mame/drivers/fidel_eag68k.cpp +++ b/src/mame/drivers/fidel_eag68k.cpp @@ -472,7 +472,7 @@ void eagv5_state::main_map(address_map &map) void eagv5_state::sub_map(address_map &map) { map(0x000000, 0x00ffff).rom(); - map(0x000001, 0x000001).mirror(0x00fffe).w(m_sublatch, FUNC(generic_latch_8_device::write)); + map(0x000000, 0x000001).mirror(0x00fffe).w(m_sublatch, FUNC(generic_latch_8_device::write)).umask16(0x00ff); map(0x044000, 0x047fff).ram(); map(0x140000, 0x140000).r(FUNC(eagv5_state::sub_ack_r)); map(0x140001, 0x140001).r(m_mainlatch, FUNC(generic_latch_8_device::read)); diff --git a/src/mame/drivers/konamigx.cpp b/src/mame/drivers/konamigx.cpp index c3b31babc6c..e5c659bc1df 100644 --- a/src/mame/drivers/konamigx.cpp +++ b/src/mame/drivers/konamigx.cpp @@ -2578,6 +2578,35 @@ ROM_START( winspike ) ROM_LOAD( "705a22.9g", 0x000000, 4*1024*1024, CRC(1a9246f6) SHA1(a40ff43310d035f7b88c4e397a4ee75151578c17) ) ROM_END +/* Winning Spike - Version AAA (Asia) */ +ROM_START( winspikea ) + /* main program */ + ROM_REGION( 0x800000, "maincpu", 0 ) + GX_BIOS + ROM_LOAD32_WORD_SWAP( "705aaa02.31b", 0x200002, 512*1024, CRC(43d1bad9) SHA1(e7c9c50270112e027f88d05e664c35abedc6b2e2) ) + ROM_LOAD32_WORD_SWAP( "705aaa03.27b", 0x200000, 512*1024, CRC(2af78cca) SHA1(9f6fa586cd4cd0a3e863d67d1bc1d67d35e21ca8) ) + + /* sound program */ + ROM_REGION( 0x40000, "soundcpu", 0 ) + ROM_LOAD16_BYTE("705a08.9c", 0x000000, 128*1024, CRC(0d531639) SHA1(14a72925f75528e7b4d6b701b2b51f4557f031f0) ) + ROM_LOAD16_BYTE("705a09.7c", 0x000001, 128*1024, CRC(24e58845) SHA1(a01caced5bad9d98a3f33d72ca5eb9096c45e4ba) ) + + ROM_REGION( 0x800000, "k056832", ROMREGION_ERASE00 ) + ROM_LOAD16_BYTE( "705a19.17h", 0x000000, 0x100000, CRC(bab84b30) SHA1(8522a0dc5e37524f51d632e9d975e949a14c0dc3) ) + ROM_LOAD16_BYTE( "705a18.22h", 0x000001, 0x100000, CRC(eb97fb5f) SHA1(13de0ad060fd6f1312fa10edde1fef6481e8df64) ) + + /* sprites */ + ROM_REGION( 0x1000000, "k055673", ROMREGION_ERASE00 ) + ROM_LOAD64_WORD( "705a17.25g", 0x000000, 0x400000, CRC(971d2812) SHA1(ee0819faf6f6c8420d5d3742cb39dfb76b9ce7a4) ) + ROM_LOAD64_WORD( "705a13.28g", 0x000002, 0x400000, CRC(3b62584b) SHA1(69718f47ff1e8d65a11972af1ed5068db175f625) ) + ROM_LOAD64_WORD( "705a11.30g", 0x000004, 0x400000, CRC(68542ce9) SHA1(a4294da1d1026e3a9d070575e5855935389a705f) ) + ROM_LOAD64_WORD( "705a10.33g", 0x000006, 0x400000, CRC(fc4dc78b) SHA1(520cdcf9ca20ec1c84be734e06e183e7a871090b) ) + + /* sound data */ + ROM_REGION( 0x400000, "k054539", 0 ) + ROM_LOAD( "705a22.9g", 0x000000, 4*1024*1024, CRC(1a9246f6) SHA1(a40ff43310d035f7b88c4e397a4ee75151578c17) ) +ROM_END + /* Winning Spike (Version JAA) @@ -3893,6 +3922,7 @@ static const GXGameInfoT gameDefs[] = { "salmndr2", 7, 6, BPP66 }, { "salmndr2a", 7, 6, BPP66 }, { "winspike", 8, 7, BPP4 }, + { "winspikea", 8, 7, BPP4 }, { "winspikej", 8, 7, BPP4 }, { "soccerss", 7, 0, BPP4 }, { "soccerssu", 7, 0, BPP4 }, @@ -4067,6 +4097,7 @@ GAME( 1996, salmndr2a, salmndr2, salmndr2, gokuparo, konamigx_state, init_k // bad sprite colours, part of tilemap gets blanked out when a game starts (might be more protection) GAME( 1997, winspike, konamigx, winspike, common, konamigx_state, init_konamigx, ROT0, "Konami", "Winning Spike (ver EAA)", MACHINE_UNEMULATED_PROTECTION | MACHINE_IMPERFECT_GRAPHICS ) +GAME( 1997, winspikea, winspike, winspike, common, konamigx_state, init_konamigx, ROT0, "Konami", "Winning Spike (ver AAA)", MACHINE_UNEMULATED_PROTECTION | MACHINE_IMPERFECT_GRAPHICS ) GAME( 1997, winspikej, winspike, winspike, common, konamigx_state, init_konamigx, ROT0, "Konami", "Winning Spike (ver JAA)", MACHINE_UNEMULATED_PROTECTION | MACHINE_IMPERFECT_GRAPHICS ) /* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/src/mame/drivers/konmedal020.cpp b/src/mame/drivers/konmedal020.cpp index 41346454bf6..d44dcddaa18 100644 --- a/src/mame/drivers/konmedal020.cpp +++ b/src/mame/drivers/konmedal020.cpp @@ -121,4 +121,4 @@ ROM_END } // Anonymous namespace -GAME( 1997, gs471, 0, gs471, gs471, konmedal020_state, empty_init, ROT0, "Konami", "Unknown medal game GS471", MACHINE_NOT_WORKING ) +GAME( 1997, gs471, 0, gs471, gs471, konmedal020_state, empty_init, ROT0, "Konami", "unknown medal game GS471", MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/mpu4.cpp b/src/mame/drivers/mpu4.cpp index acb4be7a6ff..bae54af37e7 100644 --- a/src/mame/drivers/mpu4.cpp +++ b/src/mame/drivers/mpu4.cpp @@ -1517,7 +1517,7 @@ ROM_END BARCREST SAMPLED SOUND _________________________ - | · | + | · | | · | | · | | · |_____________ @@ -1543,7 +1543,7 @@ Just one different byte between the three "Escalera y Tobogan" sets, at address 1268: 0xF4 1269: 0xF5 1270: 0xF6 -May be the game serial number hard-encoded on the EPROM? +May be the game serial number hard-encoded on the EPROM? */ ROM_START( m4esctbg ) ROM_REGION( 0x20000, "maincpu", 0 ) diff --git a/src/mame/drivers/naomi.cpp b/src/mame/drivers/naomi.cpp index e7b4d49ddb4..bf6d54e3fd0 100644 --- a/src/mame/drivers/naomi.cpp +++ b/src/mame/drivers/naomi.cpp @@ -5115,7 +5115,7 @@ ROM_START( mushikk ) NAOMI_DEFAULT_EEPROM ROM_REGION( 0x4000000, "rom_board", ROMREGION_ERASEFF ) - ROM_LOAD( "epr-24265.ic11", 0x0000000, 0x0400000, CRC(dccb210b) SHA1(35891f97bec251083b2c927e926d73685d750a4d) ) + ROM_LOAD( "epr-24265.ic11", 0x0000000, 0x0400000, CRC(dccb210b) SHA1(35891f97bec251083b2c927e926d73685d750a4d) ) ROM_LOAD32_WORD( "opr-24266.ic17s", 0x1000000, 0x0800000, CRC(293e5350) SHA1(7107d3378fe3a73e868bc03e0572b19e91152a3b) ) ROM_LOAD32_WORD( "opr-24267.ic18", 0x1000002, 0x0800000, CRC(80798f9a) SHA1(a843a052dce254f9a5a7b7024f21e4e6f8621666) ) ROM_LOAD32_WORD( "opr-24268.ic19s", 0x2000000, 0x0800000, CRC(b512c772) SHA1(f45084f2e242e07e47c25eeeed44624274a95a7e) ) diff --git a/src/mame/drivers/olyboss.cpp b/src/mame/drivers/olyboss.cpp index df710367f37..b711c8a0ac6 100644 --- a/src/mame/drivers/olyboss.cpp +++ b/src/mame/drivers/olyboss.cpp @@ -172,7 +172,7 @@ void olyboss_state::olyboss_io(address_map &map) { map.global_mask(0xff); map.unmap_value_high(); - map(0x0, 0x8).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write)); + map(0x00, 0x08).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write)); map(0x10, 0x11).m(m_fdc, FUNC(upd765a_device::map)); //map(0x20, 0x20) //beeper? map(0x30, 0x30).rw(m_uic, FUNC(am9519_device::data_r), FUNC(am9519_device::data_w)); @@ -269,8 +269,8 @@ UPD3301_DRAW_CHARACTER_MEMBER( olyboss_state::olyboss_display_pixels ) for (int i = 0; i < 8; i++) { - int color = BIT(data, 7) ^ rvv; - bitmap.pix(y, (sx * 8) + i) = color?0xffffff:0; + int color = BIT(data, 7); + bitmap.pix(y, (sx * 8) + i) = color ? 0xffffff : 0; data <<= 1; } } @@ -458,6 +458,7 @@ void olyboss_state::olybossd(machine_config &config) UPD3301(config, m_crtc, XTAL(14'318'181)); m_crtc->set_character_width(8); m_crtc->set_display_callback(FUNC(olyboss_state::olyboss_display_pixels)); + m_crtc->set_attribute_fetch_callback(m_crtc, FUNC(upd3301_device::default_attr_fetch)); m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w)); m_crtc->int_wr_callback().set(m_uic, FUNC(am9519_device::ireq0_w)).invert(); m_crtc->set_screen(SCREEN_TAG); diff --git a/src/mame/drivers/pc8001.cpp b/src/mame/drivers/pc8001.cpp index f34f2cd00ad..9e790f900b4 100644 --- a/src/mame/drivers/pc8001.cpp +++ b/src/mame/drivers/pc8001.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder +// copyright-holders:Curt Coder, Angelo Salese /* http://www2.odn.ne.jp/~haf09260/Pc80/EnrPc.htm @@ -12,14 +12,28 @@ TODO: - - uPD3301 attributes - - PCG1000 - - Intel 8251 - - cassette - - floppy - - PC-8011 - - PC-8021 - - PC-8031 + - uPD3301 attributes; + - PCG-1000; + - Intel 8251; + - cassette; + - dip-switches; + - PC-8011 (expansion unit) + - PC-8021; + - PC-8031 (mini disk unit, in progress) + - pc8001mk2sr: verify how much needs to be ported from pc8801.cpp code + (Has 3 bitplane GVRAM like PC-8801 V1 mode); + - waitstates & DMA penalty (some games are suspciously fast); + - buzzer has pretty ugly aliasing in places; + + Notes: + - pc8001 v1.01 / v1.02 sports a buggy readout of the expansion ROM at PC=17a1: + It expects an header read of 0x41-0x42 at offset $6000-6001, but second read at + PC=0x17aa is just a comparison to $6000 == 0x42, which is impossible at that point + unless external aid is given. This has been fixed in v1.10; + - Color Magical (pc8001gp:flop5 option 7) transfers two 8 color screens at + even/odd frame intervals, effectively boosting the number of available colors to 27. + This trick is kinda flickery even on real HW, no wonder it looks ugly in MAME, + can it be improved? */ @@ -28,6 +42,150 @@ #include "screen.h" #include "speaker.h" +WRITE_LINE_MEMBER( pc8001_base_state::crtc_reverse_w ) +{ + // rvv acts as a global flip for reverse attribute meaning + // (does not act on underlying palette) + // TODO: what happens if RVV changes mid-frame? + // I suspect monitor resync more likely than rasters. + m_screen_reverse = state; +} + +UPD3301_FETCH_ATTRIBUTE( pc8001_base_state::attr_fetch ) +{ + const u8 attr_max_size = 80; + const bool is_color_mode = gfx_mode == 0x2; + std::array<u16, attr_max_size> attr_extend_info = m_crtc->default_attr_fetch(attr_row, gfx_mode, y, attr_fifo_size, row_size); + + // further extend the attributes if we are in color mode + if (is_color_mode) + { + // TODO: defaults + // flgworld (pc8001) gameplay sets up: + // - 0x00 0x00 0x02 0x88 on playfield + // \- (wanting the default from the first defined color) + // - 0x00 0x00 0x00 0x48 0x12 0x88 for first row + // \- (Expecting "FLAG WORLD" wording to be red while the "P"s in green wtf) + // undermon (pc8001) instruction screen sets up: + // - 0x00 0x00 0x06 0xb8 + // \- (expecting blue fill up to 0x06) + u8 attr_color = 0xe8; + u8 attr_decoration = 0x00; + + for (int ex = 0; ex < row_size; ex++) + { + u16 cur_attr = attr_extend_info[ex]; + if (BIT(cur_attr, 3)) + attr_color = cur_attr; + else + attr_decoration = cur_attr; + attr_extend_info[ex] = (attr_color << 8) | attr_decoration; + } + } + + return attr_extend_info; +} + +UPD3301_DRAW_CHARACTER_MEMBER( pc8001_base_state::draw_text ) +{ + // punt if we are in width 40 (discarded on this end) + if (sx % 2 && !m_width80) + return; + + const bool is_color_mode = gfx_mode == 0x2; + u8 tile; + const u8 tile_width = m_width80 ? 8 : 16; + const u8 dot_width = (m_width80 ^ 1) + 1; + const u8 y_double = m_screen_is_24KHz ? 2 : 1; + const u8 y_height = y_double * 8; + + bool semigfx_tile, reverse, attr_blink, secret; + bool upperline, lowerline; + u8 color; + + if (is_color_mode) + { + color = (attr & 0xe000) >> 13; + semigfx_tile = bool(BIT(attr, 12)); + // bit 7 is used by 2001spc and many others, no effect? + } + else + { + color = 7; + semigfx_tile = bool(BIT(attr, 7)); + } + + lowerline = bool(BIT(attr, 5)); + upperline = bool(BIT(attr, 4)); + reverse = bool(BIT(attr, 2)); + attr_blink = bool(BIT(attr, 1)); + secret = bool(BIT(attr, 0)); + + if (semigfx_tile) + tile = cc; + else + { + if (lc > y_height - 1) + tile = 0; + else + tile = m_cgrom->base()[(cc << 3) | (lc >> (y_double-1))]; + } + + // secret blacks out every tile connections, + // has lower priority over blinking and other attribute decorations + if (secret) + tile = 0; + + if (csr) + tile ^= 0xff; + else if (attr_blink_on && attr_blink) + tile = 0; + + // upper/lower line aren't affected by secret and blinking, only reverse + // TODO: should downshift chars by one + if (lc == 0 && upperline) + tile = 0xff; + + if (is_lowestline && lowerline) + tile = 0xff; + + if (reverse ^ m_screen_reverse) + tile ^= 0xff; + +// if (m_width80) + { + u8 pen; + + for (int xi = 0; xi < tile_width; xi += dot_width) + { + int res_x = (sx * 8) + xi; + if (semigfx_tile) + { + u8 mask = (xi & (4 << (dot_width - 1))) ? 0x10 : 0x01; + mask <<= (lc & (0x3 << y_double)) >> y_double; + pen = tile & mask; + } + else + { + pen = tile; + pen = (pen >> (7 - (xi >> (dot_width - 1)))) & 1; + } + + for (int di = 0; di < dot_width; di++) + bitmap.pix(y, res_x + di) = m_crtc_palette->pen(pen ? color : 0); + } + } +} + +uint32_t pc8001_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bitmap.fill(0, cliprect); + // TODO: superimposing + // TODO: merging with previous frame for Color Magical (is it driver area?) + m_crtc->screen_update(screen, bitmap, cliprect); + return 0; +} + /* Read/Write Handlers */ void pc8001_state::port10_w(uint8_t data) @@ -57,7 +215,7 @@ void pc8001_state::port10_w(uint8_t data) m_cent_data_out->write(data); } -void pc8001_state::port30_w(uint8_t data) +void pc8001_base_state::port30_w(uint8_t data) { /* @@ -80,8 +238,7 @@ void pc8001_state::port30_w(uint8_t data) /* color mode */ m_color = BIT(data, 1); - /* cassette motor */ - m_cassette->change_state(BIT(data,3) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); + m_cassette->change_state(BIT(data, 3) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR); } void pc8001mk2_state::port31_w(uint8_t data) @@ -100,6 +257,7 @@ void pc8001mk2_state::port31_w(uint8_t data) 7 background color */ + membank("bank2")->set_entry(data & 1); } WRITE_LINE_MEMBER( pc8001_state::write_centronics_busy ) @@ -129,12 +287,13 @@ uint8_t pc8001_state::port40_r() */ - uint8_t data = 0x08; + uint8_t data = 0x00; data |= m_centronics_busy; data |= m_centronics_ack << 1; data |= m_rtc->data_out_r() << 4; data |= m_crtc->vrtc_r() << 5; + // TODO: enable line from pc80s31k (bit 3, active_low) return data; } @@ -158,15 +317,15 @@ void pc8001_state::port40_w(uint8_t data) m_centronics->write_strobe(BIT(data, 0)); - m_rtc->clk_w(BIT(data, 2)); m_rtc->stb_w(BIT(data, 1)); + m_rtc->clk_w(BIT(data, 2)); m_beep->set_state(BIT(data, 5)); } /* Memory Maps */ -void pc8001_state::pc8001_mem(address_map &map) +void pc8001_state::pc8001_map(address_map &map) { map(0x0000, 0x5fff).bankrw("bank1"); map(0x6000, 0x7fff).bankrw("bank2"); @@ -217,10 +376,10 @@ void pc8001_state::pc8001_io(address_map &map) // map(0xe6, 0xe6).w(FUNC(pc8001_state::irq_mask_w)); // map(0xe7, 0xe7).w(FUNC(pc8001_state::pc8012_memory_mode_w)); // map(0xe8, 0xfb) unused - map(0xfc, 0xff).rw(I8255A_TAG, FUNC(i8255_device::read), FUNC(i8255_device::write)); + map(0xfc, 0xff).m(m_pc80s31, FUNC(pc80s31_device::host_map)); } -void pc8001mk2_state::pc8001mk2_mem(address_map &map) +void pc8001mk2_state::pc8001mk2_map(address_map &map) { map(0x0000, 0x5fff).bankrw("bank1"); map(0x6000, 0x7fff).bankrw("bank2"); @@ -231,8 +390,8 @@ void pc8001mk2_state::pc8001mk2_mem(address_map &map) void pc8001mk2_state::pc8001mk2_io(address_map &map) { pc8001_io(map); - map(0x30, 0x30).w(FUNC(pc8001mk2_state::port30_w)); - map(0x31, 0x31).w(FUNC(pc8001mk2_state::port31_w)); + map(0x30, 0x30).portr("DSW1").w(FUNC(pc8001mk2_state::port30_w)); + map(0x31, 0x31).portr("DSW2").w(FUNC(pc8001mk2_state::port31_w)); // map(0x5c, 0x5c).w(FUNC(pc8001mk2_state::gram_on_w)); // map(0x5f, 0x5f).w(FUNC(pc8001mk2_state::gram_off_w)); // map(0xe8, 0xe8) kanji_address_lo_w, kanji_data_lo_r @@ -250,6 +409,40 @@ void pc8001mk2_state::pc8001mk2_io(address_map &map) // map(0xfb, 0xfb) DMA type 5 inch FDC data register } +void pc8001mk2sr_state::port33_w(u8 data) +{ + // TODO: needs progressive flush +#ifdef UNUSED_FUNCTION + if (data & 0x80) + { + membank("bank1")->set_entry(2); + membank("bank2")->set_entry(2 | (m_n80sr_bank & 1)); + } + else + { + membank("bank1")->set_entry(0); + membank("bank2")->set_entry(0); + } +#endif +} + +u8 pc8001mk2sr_state::port71_r() +{ + return m_n80sr_bank; +} + +void pc8001mk2sr_state::port71_w(u8 data) +{ + m_n80sr_bank = data; +} + +void pc8001mk2sr_state::pc8001mk2sr_io(address_map &map) +{ + pc8001mk2_io(map); + map(0x33, 0x33).w(FUNC(pc8001mk2sr_state::port33_w)); + map(0x71, 0x71).rw(FUNC(pc8001mk2sr_state::port71_r), FUNC(pc8001mk2sr_state::port71_w)); +} + /* Input Ports */ static INPUT_PORTS_START( pc8001 ) @@ -353,60 +546,84 @@ static INPUT_PORTS_START( pc8001 ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) - PORT_START("DSW1") +// PORT_START("DSW1") INPUT_PORTS_END -/* uPD3301 Interface */ - -static const rgb_t PALETTE_PC8001[] = -{ - rgb_t::black(), - rgb_t(0x00, 0x00, 0xff), - rgb_t(0xff, 0x00, 0x00), - rgb_t(0xff, 0x00, 0xff), - rgb_t(0x00, 0xff, 0x00), - rgb_t(0x00, 0xff, 0xff), - rgb_t(0xff, 0xff, 0x00), - rgb_t::white() -}; - -UPD3301_DRAW_CHARACTER_MEMBER( pc8001_state::pc8001_display_pixels ) -{ - uint8_t data = m_char_rom->base()[(cc << 3) | lc]; - - if (lc >= 8) return; - if (csr) data = 0xff; - - if (m_width80) - { - for (int i = 0; i < 8; i++) - { - int color = BIT(data, 7) ^ rvv; +static INPUT_PORTS_START( pc8001mk2 ) + PORT_INCLUDE( pc8001 ) - bitmap.pix(y, (sx * 8) + i) = PALETTE_PC8001[color ? 7 : 0]; - - data <<= 1; - } - } - else - { - if (sx % 2) return; - - for (int i = 0; i < 8; i++) - { - int color = BIT(data, 7) ^ rvv; - - bitmap.pix(y, (sx/2 * 16) + (i * 2)) = PALETTE_PC8001[color ? 7 : 0]; - bitmap.pix(y, (sx/2 * 16) + (i * 2) + 1) = PALETTE_PC8001[color ? 7 : 0]; + PORT_START("DSW1") + PORT_DIPNAME( 0x01, 0x00, "Boot Mode" ) + PORT_DIPSETTING( 0x00, "N-BASIC" ) + PORT_DIPSETTING( 0x01, "N80-BASIC" ) + PORT_DIPNAME( 0x02, 0x02, "DSW1" ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + + PORT_START("DSW2") + PORT_DIPNAME( 0x01, 0x01, "DSW2" ) + PORT_DIPSETTING( 0x01, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x02, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x10, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END - data <<= 1; - } - } -} +static INPUT_PORTS_START( pc8001mk2sr ) + PORT_INCLUDE( pc8001mk2 ) + + PORT_MODIFY("DSW1") + // This is really a tri-state dip on front panel + // BIOS just expects bit 1 to be off for SR mode + PORT_DIPNAME( 0x03, 0x02, "Boot Mode" ) + PORT_DIPSETTING( 0x00, "N80SR-BASIC (duplicate)") + PORT_DIPSETTING( 0x01, "N80SR-BASIC" ) + PORT_DIPSETTING( 0x02, "N-BASIC" ) + PORT_DIPSETTING( 0x03, "N80-BASIC" ) + PORT_DIPNAME( 0x04, 0x04, "DSW1" ) + PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x00, DEF_STR( On ) ) +INPUT_PORTS_END /* 8257 Interface */ -WRITE_LINE_MEMBER( pc8001_state::hrq_w ) +WRITE_LINE_MEMBER( pc8001_base_state::hrq_w ) { /* HACK - this should be connected to the BUSREQ line of Z80 */ m_maincpu->set_input_line(INPUT_LINE_HALT, state); @@ -415,7 +632,7 @@ WRITE_LINE_MEMBER( pc8001_state::hrq_w ) m_dma->hlda_w(state); } -uint8_t pc8001_state::dma_mem_r(offs_t offset) +uint8_t pc8001_base_state::dma_mem_r(offs_t offset) { address_space &program = m_maincpu->space(AS_PROGRAM); @@ -424,6 +641,14 @@ uint8_t pc8001_state::dma_mem_r(offs_t offset) /* Machine Initialization */ +void pc8001_base_state::machine_start() +{ + save_item(NAME(m_width80)); + save_item(NAME(m_color)); + save_item(NAME(m_screen_reverse)); + save_item(NAME(m_screen_is_24KHz)); +} + void pc8001_state::machine_start() { address_space &program = m_maincpu->space(AS_PROGRAM); @@ -441,6 +666,7 @@ void pc8001_state::machine_start() membank("bank1")->configure_entry(1, m_rom->base()); program.install_read_bank(0x0000, 0x5fff, membank("bank1")); program.unmap_write(0x0000, 0x5fff); + membank("bank2")->configure_entry(1, m_rom->base() + 0x6000); switch (m_ram->size()) { @@ -464,55 +690,81 @@ void pc8001_state::machine_start() program.install_readwrite_bank(0x0000, 0x5fff, membank("bank1")); program.install_readwrite_bank(0x6000, 0xbfff, membank("bank2")); program.install_readwrite_bank(0x8000, 0xffff, membank("bank3")); - membank("bank2")->set_entry(0); +// membank("bank2")->set_entry(0); break; } + // PC8001 is 15KHz only + set_screen_frequency(false); +} + +void pc8001_state::machine_reset() +{ membank("bank1")->set_entry(1); + membank("bank2")->set_entry(1); membank("bank3")->set_entry(0); +} - /* register for state saving */ - save_item(NAME(m_width80)); - save_item(NAME(m_color)); +void pc8001mk2sr_state::machine_start() +{ + pc8001_state::machine_start(); + + membank("bank1")->configure_entry(2, m_n80sr_rom->base()); + membank("bank2")->configure_entry(2, m_n80sr_rom->base() + 0x6000); + membank("bank2")->configure_entry(3, m_n80sr_rom->base() + 0x8000); + + save_item(NAME(m_n80sr_bank)); +} + +void pc8001mk2sr_state::machine_reset() +{ + pc8001_state::machine_reset(); + + //membank("bank1")->set_entry(2); + //membank("bank2")->set_entry(2); } /* Machine Drivers */ void pc8001_state::pc8001(machine_config &config) { + constexpr XTAL MASTER_CLOCK = XTAL(4'000'000); + constexpr XTAL VIDEO_CLOCK = XTAL(14'318'181); + /* basic machine hardware */ - Z80(config, m_maincpu, XTAL(4'000'000)); - m_maincpu->set_addrmap(AS_PROGRAM, &pc8001_state::pc8001_mem); + Z80(config, m_maincpu, MASTER_CLOCK); + m_maincpu->set_addrmap(AS_PROGRAM, &pc8001_state::pc8001_map); m_maincpu->set_addrmap(AS_IO, &pc8001_state::pc8001_io); + PC80S31(config, m_pc80s31, MASTER_CLOCK); + config.set_perfect_quantum(m_maincpu); + config.set_perfect_quantum("pc80s31:fdc_cpu"); + /* video hardware */ - screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(60); - screen.set_screen_update(UPD3301_TAG, FUNC(upd3301_device::screen_update)); - screen.set_size(640, 220); - screen.set_visarea(0, 640-1, 0, 200-1); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_raw(VIDEO_CLOCK, 896, 0, 640, 260, 0, 200); + m_screen->set_screen_update(FUNC(pc8001_state::screen_update)); +// m_screen->set_palette(m_crtc_palette); - /* sound hardware */ - SPEAKER(config, "mono").front_center(); - BEEP(config, m_beep, 2000).add_route(ALL_OUTPUTS, "mono", 0.25); + PALETTE(config, m_crtc_palette, palette_device::BRG_3BIT); - /* devices */ - I8251(config, I8251_TAG, 0); - - I8255A(config, I8255A_TAG, 0); + UPD3301(config, m_crtc, VIDEO_CLOCK); + m_crtc->set_character_width(8); + m_crtc->set_display_callback(FUNC(pc8001_state::draw_text)); + m_crtc->set_attribute_fetch_callback(FUNC(pc8001_state::attr_fetch)); + m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w)); + m_crtc->rvv_wr_callback().set(FUNC(pc8001_state::crtc_reverse_w)); + m_crtc->set_screen(m_screen); - I8257(config, m_dma, XTAL(4'000'000)); + I8257(config, m_dma, MASTER_CLOCK); m_dma->out_hrq_cb().set(FUNC(pc8001_state::hrq_w)); m_dma->in_memr_cb().set(FUNC(pc8001_state::dma_mem_r)); m_dma->out_iow_cb<2>().set(m_crtc, FUNC(upd3301_device::dack_w)); - UPD1990A(config, m_rtc); + /* devices */ + I8251(config, I8251_TAG, 0); - UPD3301(config, m_crtc, XTAL(14'318'181)); - m_crtc->set_character_width(8); - m_crtc->set_display_callback(FUNC(pc8001_state::pc8001_display_pixels)); - m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w)); - m_crtc->set_screen(SCREEN_TAG); + UPD1990A(config, m_rtc); CENTRONICS(config, m_centronics, centronics_devices, "printer"); m_centronics->ack_handler().set(FUNC(pc8001_state::write_centronics_ack)); @@ -526,84 +778,91 @@ void pc8001_state::pc8001(machine_config &config) m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05); RAM(config, RAM_TAG).set_default_size("16K").set_extra_options("32K,64K"); -} - -void pc8001mk2_state::pc8001mk2(machine_config &config) -{ - /* basic machine hardware */ - Z80(config, m_maincpu, XTAL(4'000'000)); - m_maincpu->set_addrmap(AS_PROGRAM, &pc8001mk2_state::pc8001mk2_mem); - m_maincpu->set_addrmap(AS_IO, &pc8001mk2_state::pc8001mk2_io); - /* video hardware */ - screen_device &screen(SCREEN(config, SCREEN_TAG, SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(60); - screen.set_screen_update(UPD3301_TAG, FUNC(upd3301_device::screen_update)); - screen.set_size(640, 220); - screen.set_visarea(0, 640-1, 0, 200-1); + SOFTWARE_LIST(config, "disk_n_list").set_original("pc8001_flop"); /* sound hardware */ SPEAKER(config, "mono").front_center(); - BEEP(config, m_beep, 2000).add_route(ALL_OUTPUTS, "mono", 0.25); - - /* devices */ - I8251(config, I8251_TAG, 0); - - I8255A(config, I8255A_TAG, 0); + // TODO: unknown clock, is it really a beeper? + BEEP(config, m_beep, 2400).add_route(ALL_OUTPUTS, "mono", 0.25); +} - I8257(config, m_dma, XTAL(4'000'000)); - m_dma->out_hrq_cb().set(FUNC(pc8001_state::hrq_w)); - m_dma->in_memr_cb().set(FUNC(pc8001_state::dma_mem_r)); - m_dma->out_iow_cb<2>().set(m_crtc, FUNC(upd3301_device::dack_w)); +void pc8001mk2_state::pc8001mk2(machine_config &config) +{ + pc8001(config); + m_maincpu->set_addrmap(AS_PROGRAM, &pc8001mk2_state::pc8001mk2_map); + m_maincpu->set_addrmap(AS_IO, &pc8001mk2_state::pc8001mk2_io); - UPD1990A(config, m_rtc); + // TODO: video HW has extra GVRAM setup - UPD3301(config, m_crtc, XTAL(14'318'181)); - m_crtc->set_character_width(8); - m_crtc->set_display_callback(FUNC(pc8001_state::pc8001_display_pixels)); - m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq2_w)); - m_crtc->set_screen(SCREEN_TAG); + RAM(config.replace(), RAM_TAG).set_default_size("64K"); - CENTRONICS(config, m_centronics, centronics_devices, "printer"); + SOFTWARE_LIST(config, "disk_n80_list").set_original("pc8001mk2_flop"); +} - OUTPUT_LATCH(config, m_cent_data_out); - m_centronics->set_output_latch(*m_cent_data_out); +void pc8001mk2sr_state::pc8001mk2sr(machine_config &config) +{ + pc8001mk2(config); + m_maincpu->set_addrmap(AS_IO, &pc8001mk2sr_state::pc8001mk2sr_io); - CASSETTE(config, m_cassette); - m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED); - m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05); + // TODO: mods for SR mode support - RAM(config, RAM_TAG).set_default_size("64K"); + SOFTWARE_LIST(config, "disk_n80sr_list").set_original("pc8001mk2sr_flop"); } /* ROMs */ ROM_START( pc8001 ) - ROM_REGION( 0x6000, Z80_TAG, 0 ) + ROM_REGION( 0x8000, Z80_TAG, ROMREGION_ERASEFF ) + // PCB pictures shows divided by 3 ROMs (and 4th socket unpopulated) ROM_SYSTEM_BIOS( 0, "v101", "N-BASIC v1.01" ) - ROMX_LOAD( "n80v101.rom", 0x00000, 0x6000, CRC(a2cc9f22) SHA1(6d2d838de7fea20ddf6601660d0525d5b17bf8a3), ROM_BIOS(0) ) + ROMX_LOAD( "n80v101.rom", 0x00000, 0x6000, BAD_DUMP CRC(a2cc9f22) SHA1(6d2d838de7fea20ddf6601660d0525d5b17bf8a3), ROM_BIOS(0) ) ROM_SYSTEM_BIOS( 1, "v102", "N-BASIC v1.02" ) - ROMX_LOAD( "n80v102.rom", 0x00000, 0x6000, CRC(ed01ca3f) SHA1(b34a98941499d5baf79e7c0e5578b81dbede4a58), ROM_BIOS(1) ) + ROMX_LOAD( "n80v102.rom", 0x00000, 0x6000, BAD_DUMP CRC(ed01ca3f) SHA1(b34a98941499d5baf79e7c0e5578b81dbede4a58), ROM_BIOS(1) ) ROM_SYSTEM_BIOS( 2, "v110", "N-BASIC v1.10" ) - ROMX_LOAD( "n80v110.rom", 0x00000, 0x6000, CRC(1e02d93f) SHA1(4603cdb7a3833e7feb257b29d8052c872369e713), ROM_BIOS(2) ) + ROMX_LOAD( "n80v110.rom", 0x00000, 0x6000, BAD_DUMP CRC(1e02d93f) SHA1(4603cdb7a3833e7feb257b29d8052c872369e713), ROM_BIOS(2) ) - ROM_REGION( 0x800, UPD3301_TAG, 0) + ROM_REGION( 0x800, CGROM_TAG, 0) ROM_LOAD( "font.rom", 0x000, 0x800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) ) ROM_END ROM_START( pc8001mk2 ) ROM_REGION( 0x8000, Z80_TAG, 0 ) - ROM_LOAD( "n80_2.rom", 0x00000, 0x8000, CRC(03cce7b6) SHA1(c12d34e42021110930fed45a8af98db52136f1fb) ) + // N-BASIC v1.3 + // N80-BASIC v1.0 + ROM_LOAD( "n80_2.rom", 0x0000, 0x8000, CRC(03cce7b6) SHA1(c12d34e42021110930fed45a8af98db52136f1fb) ) - ROM_REGION( 0x800, UPD3301_TAG, 0) + ROM_REGION( 0x800, CGROM_TAG, 0) ROM_LOAD( "font.rom", 0x0000, 0x0800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) ) ROM_REGION( 0x20000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_END +ROM_START( pc8001mk2sr ) + ROM_REGION( 0x8000, Z80_TAG, 0 ) + // N-BASIC v1.6 + // N80-BASIC v1.2 + ROM_LOAD( "n80_2sr.rom", 0x0000, 0x8000, CRC(dcb71282) SHA1(e8db5dc5eae11da14e48656d324874e59f2e3844) ) + + ROM_REGION (0x10000, N80SR_ROM_TAG, ROMREGION_ERASEFF ) + // N80SR-BASIC v1.0 + ROM_LOAD( "n80_3.rom", 0x0000, 0xa000, BAD_DUMP CRC(d99ef247) SHA1(9bfa5009d703cd31caa734d932d2a847d74cbfa6) ) + + ROM_REGION( 0x2000, CGROM_TAG, 0) + ROM_LOAD( "font80sr.rom", 0x000000, 0x001000, CRC(784c0b17) SHA1(565dc8e5e46b1633cb434d12b4d8b3a662546b33) ) + ROM_LOAD( "fonthira.rom", 0x001000, 0x000800, CRC(fe7059d5) SHA1(10c5f85adcce540cbd0a11352e2c38a84c989a26) ) + ROM_LOAD( "fontkata.rom", 0x001800, 0x000800, CRC(56653188) SHA1(84b90f69671d4b72e8f219e1fe7cd667e976cf7f) ) + + ROM_REGION( 0x20000, "kanji", 0) + ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) +ROM_END + /* System Drivers */ // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1979, pc8001, 0, 0, pc8001, pc8001, pc8001_state, empty_init, "NEC", "PC-8001", MACHINE_NOT_WORKING ) -COMP( 1983, pc8001mk2, pc8001, 0, pc8001mk2, pc8001, pc8001mk2_state, empty_init, "NEC", "PC-8001mkII", MACHINE_NOT_WORKING ) +// 1978?, pc8001g, Wirewrapped prototype version +COMP( 1979, pc8001, 0, 0, pc8001, pc8001, pc8001_state, empty_init, "NEC", "PC-8001", MACHINE_NOT_WORKING ) +// 1981 pc8001a, US version of PC-8001 with Greek alphabet instead of Kana +COMP( 1983, pc8001mk2, pc8001, 0, pc8001mk2, pc8001mk2, pc8001mk2_state, empty_init, "NEC", "PC-8001mkII", MACHINE_NOT_WORKING ) +COMP( 1985, pc8001mk2sr, pc8001, 0, pc8001mk2sr, pc8001mk2sr, pc8001mk2sr_state, empty_init, "NEC", "PC-8001mkIISR", MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/pc8801.cpp b/src/mame/drivers/pc8801.cpp index a50c1d6317f..2e975032af3 100644 --- a/src/mame/drivers/pc8801.cpp +++ b/src/mame/drivers/pc8801.cpp @@ -25,29 +25,17 @@ probably others (does bus have an actual codename or just "PC-8801 bus"?); - below notes states that plain PC-8801 doesn't have a disk CPU, but the BIOS clearly checks the floppy ports. Wrong info or check for external board anyway? - - fix "jumps" in mouse support pointer (noticeable in Balance of Power); - - per-game specific TODO: - - 100yen Soft 8 Revival Special: tight loop with vblank bit, but vblank irq takes too much time to execute its code; - - 177: gameplay is too fast (parent pc8801 only); - - 1942: missing sound, enables a masked irq; - - Acro Jet: hangs waiting for an irq (floppy issue); - - Arcus: doesn't surpass Wolf Team logo; - - Advanced Fantasian: garbage during gameplay (floppy?) - - American Success: reads the light pen? - - Attacker: resets after a bunch of animation frames; - - Balance of Power: uses the SIO port for something ... + - fix "jumps" in PC-8872 mouse pointer (noticeable in balpower); + + per-game specific TODO (move to XML): - Belloncho Shintai Kensa: hangs - Bishoujo Baseball Gakuen: checks ym2608 after intro screen; - The Black Onyx: writes a katakana msg: "sono kata ha koko ni orimasen" then doesn't show up anything. (Needs user disk?) - - Boukenshatachi: dies after the intro. - Campaign Ban Daisenryaku 2: Hangs at title screen? - - Carigraph: inputs doesn't work? - Can Can Bunny: bitmap artifacts on intro, caused by a fancy usage of the attribute vram; - Can Can Bunny: no sound (regression); - Can Can Bunny Superior: black screen during the intro - Chou Bishoujo Densetsu CROQUIS: accesses ports 0xa0-0xa3 and 0xc2-0xc3 - - Combat: mono gfx mode enabled, but I don't see any noticeable quirk? - Cranston Manor (actually N88-Basic demo): no sound - Datenshi Kyouko: gfx garbage on the right edge? - Final Crisis: sound stuck with OPNA? @@ -56,10 +44,7 @@ - Gaudi - Barcelona no Kaze: fails PCM loading - GeGeGe no Kitarou: title screen text/bitmap contrast is pretty ugly (BTANB?); - Grobda: palette is ugly (parent pc8801 only); - - Makaimura: after losing a life the game doesn't work properly anymore, copy protection? - Music Collection Vol. 2 - Final Fantasy Tokushuu: sound irq dies pretty soon - - N-BASIC: cursor doesn't show up; - - The Return of Ishtar: z80 exception after entering the name. - Star Cruiser: bad kanji data? - Star Cruiser: reads at i/o 0x8e? - Wanderers from Ys: user data disk looks screwed? It loads with everything as maximum as per now ... @@ -120,11 +105,6 @@ - Fruit Panic - FSD Sample Ongaku Shuu Vol. 1-7 - Gaia no Kiba (Disk I/O error at 150) - - Gaiflame - - Gambler Jiko Chuushin ha - - Gambler Jiko Chuushin ha 2 - - Gambler Jiko Chuushin ha 3 - - Gambler Jiko Chuushin ha 3 (demo) - Gambler Jiko Chuushin ha Mahjong Puzzle Collection - Gambler Jiko Chuushin ha Mahjong Puzzle Collection (demo) * Game Music Library @@ -142,14 +122,12 @@ * MakaiMura (attempts to r/w the sio ports, but it's clearly crashed) * Mugen Senshi Valis (at Telenet logo, it also appears to have a nasty copy protection when taking a specific item (untested)) - Mr. Pro Yakyuu - - Panorama Toh - PC-8034 (app) - PC-8037SR (app) - P1 (app) - Pattern Editor 88 (app) - Super Shunbo II (app) (Load error) - Super TII (app) - * The Return of Ishtar - Tobira wo Akete (random crashes in parent pc8801 only) list of games that doesn't like i8214_irq_level == 5 in sound irq @@ -360,6 +338,8 @@ void pc8801_state::draw_bitmap_3bpp(bitmap_ind16 &bitmap,const rectangle &clipre void pc8801_state::draw_bitmap_1bpp(bitmap_ind16 &bitmap,const rectangle &cliprect) { + // TODO: jettermi really masks the color attribute from 3301 + // (we currently draw it in b&w, should be colorized) uint32_t count = 0; uint8_t color = (m_gfx_ctrl & 1) ? 7 & ((m_layer_mask ^ 0xe) >> 1) : 7; uint8_t is_cursor = 0; @@ -803,9 +783,7 @@ uint8_t pc8801_state::pc8801_mem_r(offs_t offset) window_offset = (offset & 0x3ff) + (m_window_offset_bank << 8); - if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10)) - printf("Read from 0xf000 - 0xffff window offset\n"); //accessed by Castle Excellent, no noticeable quirk - + // castlex and imenes accesses this if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10)) return pc8801_high_wram_r(window_offset & 0xfff); @@ -864,9 +842,9 @@ void pc8801_state::pc8801_mem_w(offs_t offset, uint8_t data) window_offset = (offset & 0x3ff) + (m_window_offset_bank << 8); - if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10)) - printf("Write to 0xf000 - 0xffff window offset\n"); //accessed by Castle Excellent, no noticeable quirk - + // castlex and imenes accesses this + // TODO: high TVRAM even + // (uPD3301 reads from this instead of the regular work RAM) if(((window_offset & 0xf000) == 0xf000) && (m_misc_ctrl & 0x10)) pc8801_high_wram_w(window_offset & 0xfff,data); else @@ -1117,6 +1095,20 @@ void pc8801_state::pc8801_window_bank_inc_w(uint8_t data) m_window_offset_bank&=0xff; } +/* + * I/O Port $32 (R/W) + * + * x--- ---- sound irq mask (0) irq enabled (1) irq masked + * -x-- ---- Graphic VRAM access mode (0) independent access mode (1) ALU mode + * --x- ---- analog (1) / digital (0) palette select + * ---x ---- high speed RAM select (for TVRAM) (1) main RAM bank (0) dedicated Text RAM + * ---- xx-- Screen output mode + * ---- 00-- TV / video mode + * ---- 01-- None (as in disabling the screen entirely?) + * ---- 10-- Analog RGB mode + * ---- 11-- Optional mode + * ---- --xx internal EROM selection + */ uint8_t pc8801_state::pc8801_misc_ctrl_r() { return m_misc_ctrl; @@ -1124,11 +1116,6 @@ uint8_t pc8801_state::pc8801_misc_ctrl_r() void pc8801_state::pc8801_misc_ctrl_w(uint8_t data) { - /* - x--- ---- sound irq mask, active low - --x- ---- analog (1) / digital (0) palette select - */ - m_misc_ctrl = data; #if USE_PROPER_I8214 @@ -1182,6 +1169,7 @@ void pc8801_state::pc8801_palram_w(offs_t offset, uint8_t data) // TODO: What happens to the palette contents when the analog/digital palette mode changes? // Preserve content? Translation? Undefined? m_palette->set_pen_color(offset, pal3bit(m_palram[offset].r), pal3bit(m_palram[offset].g), pal3bit(m_palram[offset].b)); + // TODO: at least analog mode can do rasters } void pc8801_state::pc8801_layer_masking_w(uint8_t data) @@ -1472,7 +1460,7 @@ uint8_t pc8801_state::pc8801_sound_board_r(offs_t offset) void pc8801_state::pc8801_sound_board_w(offs_t offset, uint8_t data) { if(m_has_opna) - m_opna->write(offset,data); + m_opna->write(offset, data); else if((offset & 2) == 0) m_opn->write(offset, data); } @@ -1590,95 +1578,7 @@ void pc8801_state::pc8801_io(address_map &map) // map(0xf3, 0xf3).noprw(); /* DMA floppy (unknown) */ // map(0xf4, 0xf7).noprw(); /* DMA 5'floppy (may be not released) */ // map(0xf8, 0xfb).noprw(); /* DMA 8'floppy (unknown) */ - map(0xfc, 0xff).rw("d8255_master", FUNC(i8255_device::read), FUNC(i8255_device::write)); -} - -uint8_t pc8801_state::cpu_8255_c_r() -{ -// machine().scheduler().synchronize(); // force resync - - return m_i8255_1_pc >> 4; -} - -void pc8801_state::cpu_8255_c_w(uint8_t data) -{ -// machine().scheduler().synchronize(); // force resync - - m_i8255_0_pc = data; -} - - -uint8_t pc8801_state::fdc_8255_c_r() -{ -// machine().scheduler().synchronize(); // force resync - - return m_i8255_0_pc >> 4; -} - -void pc8801_state::fdc_8255_c_w(uint8_t data) -{ -// machine().scheduler().synchronize(); // force resync - - m_i8255_1_pc = data; -} - -void pc8801_state::pc8801fdc_mem(address_map &map) -{ - map(0x0000, 0x1fff).rom(); - map(0x4000, 0x7fff).ram(); -} - -TIMER_CALLBACK_MEMBER(pc8801_state::pc8801fd_upd765_tc_to_zero) -{ - // TODO: holein1 explictly reads TC port at PC=504e followed by an HALT opcode, failing to boot - // is this gonna unbreak HALT state too? - m_fdc->tc_w(false); -} - -void pc8801_state::upd765_mc_w(uint8_t data) -{ - m_fdd[0]->get_device()->mon_w(!(data & 1)); - m_fdd[1]->get_device()->mon_w(!(data & 2)); -} - -uint8_t pc8801_state::upd765_tc_r() -{ - //printf("%04x 1\n",m_fdccpu->pc()); - - if (!machine().side_effects_disabled()) - { - m_fdc->tc_w(true); - //TODO: I'm not convinced that this works correctly with current hook-up ... 1000 usec is needed by Aploon, a bigger value breaks Alpha. - //OTOH, 50 seems more than enough for the new upd... - machine().scheduler().timer_set(attotime::from_usec(50), timer_expired_delegate(FUNC(pc8801_state::pc8801fd_upd765_tc_to_zero),this)); - } - return 0xff; // value is meaningless -} - -void pc8801_state::fdc_irq_vector_w(uint8_t data) -{ - popmessage("Write to FDC IRQ vector I/O %02x, contact MESSdev\n",data); - m_fdc_irq_opcode = data; -} - -void pc8801_state::fdc_drive_mode_w(uint8_t data) -{ - logerror("FDC drive mode %02x\n", data); - m_fdd[0]->get_device()->set_rpm(data & 0x01 ? 360 : 300); - m_fdd[1]->get_device()->set_rpm(data & 0x02 ? 360 : 300); - - m_fdc->set_rate(data & 0x20 ? 500000 : 250000); -} - -void pc8801_state::pc8801fdc_io(address_map &map) -{ - map.global_mask(0xff); - map(0xf0, 0xf0).w(FUNC(pc8801_state::fdc_irq_vector_w)); // Interrupt Opcode Port - map(0xf4, 0xf4).w(FUNC(pc8801_state::fdc_drive_mode_w)); // Drive mode, 2d, 2dd, 2hd - map(0xf7, 0xf7).nopw(); // printer port output - map(0xf8, 0xf8).rw(FUNC(pc8801_state::upd765_tc_r), FUNC(pc8801_state::upd765_mc_w)); // (R) Terminal Count Port (W) Motor Control Port - map(0xfa, 0xfb).m(m_fdc, FUNC(upd765a_device::map)); - map(0xfc, 0xff).rw("d8255_slave", FUNC(i8255_device::read), FUNC(i8255_device::write)); + map(0xfc, 0xff).m(m_pc80s31, FUNC(pc80s31_device::host_map)); } void pc8801_state::opna_map(address_map &map) @@ -2005,12 +1905,6 @@ static GFXDECODE_START( gfx_pc8801 ) GFXDECODE_ENTRY( "kanji", 0, kanji_layout, 0, 8 ) GFXDECODE_END -/* Floppy Configuration */ - -static void pc88_floppies(device_slot_interface &device) -{ - device.option_add("525hd", FLOPPY_525_HD); -} #if 0 /* Cassette Configuration */ @@ -2164,10 +2058,6 @@ INTERRUPT_GEN_MEMBER(pc8801_state::pc8801_vrtc_irq) void pc8801_state::machine_start() { - m_fdd[0]->get_device()->set_rpm(300); - m_fdd[1]->get_device()->set_rpm(300); - m_fdc->set_rate(250000); - m_rtc->cs_w(1); m_rtc->oe_w(1); @@ -2203,11 +2093,8 @@ void pc8801_state::machine_reset() // pc8801_dynamic_res_change(machine()); - m_fdc_irq_opcode = 0; //TODO: copied from PC-88VA, could be wrong here ... should be 0x7f ld a,a in the latter case m_mouse.phase = 0; - m_fdccpu->set_input_line_vector(0, 0); // Z80 - { m_txt_color = 2; } @@ -2277,7 +2164,8 @@ MACHINE_RESET_MEMBER(pc8801_state,pc8801_clock_speed) m_clock_setting = ioport("CFG")->read() & 0x80; m_maincpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000)); - m_fdccpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000)); // correct? + // TODO: FDC board shouldn't be connected to the clock setting, verify +// m_fdccpu->set_unscaled_clock(m_clock_setting ? XTAL(4'000'000) : XTAL(8'000'000)); m_baudrate_val = 0; } @@ -2348,28 +2236,11 @@ void pc8801_state::pc8801(machine_config &config) m_maincpu->set_vblank_int("screen", FUNC(pc8801_state::pc8801_vrtc_irq)); m_maincpu->set_irq_acknowledge_callback(FUNC(pc8801_state::pc8801_irq_callback)); - /* sub CPU(5 inch floppy drive) */ - Z80(config, m_fdccpu, MASTER_CLOCK); /* 4 MHz */ - m_fdccpu->set_addrmap(AS_PROGRAM, &pc8801_state::pc8801fdc_mem); - m_fdccpu->set_addrmap(AS_IO, &pc8801_state::pc8801fdc_io); - - //config.set_maximum_quantum(attotime::from_hz(300000)); + PC80S31(config, m_pc80s31, MASTER_CLOCK); config.set_perfect_quantum(m_maincpu); + config.set_perfect_quantum("pc80s31:fdc_cpu"); - i8255_device &d8255_master(I8255(config, "d8255_master")); - d8255_master.in_pa_callback().set("d8255_slave", FUNC(i8255_device::pb_r)); - d8255_master.in_pb_callback().set("d8255_slave", FUNC(i8255_device::pa_r)); - d8255_master.in_pc_callback().set(FUNC(pc8801_state::cpu_8255_c_r)); - d8255_master.out_pc_callback().set(FUNC(pc8801_state::cpu_8255_c_w)); - - i8255_device &d8255_slave(I8255(config, "d8255_slave")); - d8255_slave.in_pa_callback().set("d8255_master", FUNC(i8255_device::pb_r)); - d8255_slave.in_pb_callback().set("d8255_master", FUNC(i8255_device::pa_r)); - d8255_slave.in_pc_callback().set(FUNC(pc8801_state::fdc_8255_c_r)); - d8255_slave.out_pc_callback().set(FUNC(pc8801_state::fdc_8255_c_w)); - - UPD765A(config, m_fdc, 8'000'000, true, true); - m_fdc->intrq_wr_callback().set_inputline(m_fdccpu, INPUT_LINE_IRQ0); +// config.set_maximum_quantum(attotime::from_hz(MASTER_CLOCK/1024)); #if USE_PROPER_I8214 I8214(config, I8214_TAG, MASTER_CLOCK); @@ -2386,9 +2257,8 @@ void pc8801_state::pc8801(machine_config &config) i8251.txd_handler().set(FUNC(pc8801_state::txdata_callback)); i8251.rts_handler().set(FUNC(pc8801_state::rxrdy_w)); - FLOPPY_CONNECTOR(config, "upd765:0", pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats); - FLOPPY_CONNECTOR(config, "upd765:1", pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats); - SOFTWARE_LIST(config, "disk_list").set_original("pc8801_flop"); + SOFTWARE_LIST(config, "disk_n88_list").set_original("pc8801_flop"); + SOFTWARE_LIST(config, "disk_n_list").set_original("pc8001_flop"); /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); @@ -2431,21 +2301,27 @@ void pc8801_state::pc8801(machine_config &config) TIMER(config, "rtc_timer").configure_periodic(FUNC(pc8801_state::pc8801_rtc_irq), attotime::from_hz(600)); } -void pc8801_state::pc8801fh(machine_config &config) +void pc8801_state::pc8801mk2mr(machine_config &config) { pc8801(config); + PC80S31K(config.replace(), m_pc80s31, MASTER_CLOCK); +} + +void pc8801_state::pc8801fh(machine_config &config) +{ + pc8801mk2mr(config); MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_clock_speed ) } void pc8801_state::pc8801ma(machine_config &config) { - pc8801(config); + pc8801fh(config); MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_dic ) } void pc8801_state::pc8801mc(machine_config &config) { - pc8801(config); + pc8801ma(config); MCFG_MACHINE_RESET_OVERRIDE(pc8801_state, pc8801_cdrom ) } @@ -2457,9 +2333,6 @@ ROM_START( pc8801 ) ROM_LOAD( "n88.rom", 0x0000, 0x8000, CRC(ffd68be0) SHA1(3518193b8207bdebf22c1380c2db8c554baff329) ) ROM_LOAD( "n88_0.rom", 0x8000, 0x2000, CRC(61984bab) SHA1(d1ae642aed4f0584eeb81ff50180db694e5101d4) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) ) - ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF) ROM_LOAD_OPTIONAL( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) @@ -2477,9 +2350,6 @@ ROM_START( pc8801mk2 ) ROM_LOAD( "m2_n88.rom", 0x0000, 0x8000, CRC(f35169eb) SHA1(ef1f067f819781d9fb2713836d195866f0f81501) ) ROM_LOAD( "m2_n88_0.rom", 0x8000, 0x2000, CRC(5eb7a8d0) SHA1(95a70af83b0637a5a0f05e31fb0452bb2cb68055) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) ) - ROM_REGION( 0x40000, "kanji", ROMREGION_ERASEFF) ROM_LOAD_OPTIONAL( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) @@ -2498,13 +2368,6 @@ ROM_START( pc8801mk2sr ) ROM_LOAD( "n88_2.rom", 0xc000, 0x2000, CRC(af2b6efa) SHA1(b7c8bcea219b77d9cc3ee0efafe343cc307425d1) ) ROM_LOAD( "n88_3.rom", 0xe000, 0x2000, CRC(7713c519) SHA1(efce0b51cab9f0da6cf68507757f1245a2867a72) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "kanji2.rom", 0x20000, 0x20000, CRC(154803cc) SHA1(7e6591cd465cbb35d6d3446c5a83b46d30fafe95) ) // it should not be here @@ -2524,13 +2387,6 @@ ROM_START( pc8801mk2fr ) ROM_LOAD( "m2fr_n88_2.rom", 0xc000, 0x2000, CRC(98c3a7b2) SHA1(fc4980762d3caa56964d0ae583424756f511d186) ) ROM_LOAD( "m2fr_n88_3.rom", 0xe000, 0x2000, CRC(0ca08abd) SHA1(a5a42d0b7caa84c3bc6e337c9f37874d82f9c14b) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "m2fr_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) @@ -2549,13 +2405,6 @@ ROM_START( pc8801mk2mr ) ROM_LOAD( "m2mr_n88_2.rom", 0xc000, 0x2000, CRC(11176e0b) SHA1(f13f14f3d62df61498a23f7eb624e1a646caea45) ) ROM_LOAD( "m2mr_n88_3.rom", 0xe000, 0x2000, CRC(0ca08abd) SHA1(a5a42d0b7caa84c3bc6e337c9f37874d82f9c14b) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "m2mr_disk.rom", 0x0000, 0x2000, CRC(2447516b) SHA1(1492116f15c426f9796dc2bb6fcccf2656c0ca75) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "m2mr_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2575,13 +2424,6 @@ ROM_START( pc8801mh ) ROM_LOAD( "mh_n88_2.rom", 0xc000, 0x2000, CRC(6aa6b6d8) SHA1(2a077ab444a4fd1470cafb06fd3a0f45420c39cc) ) ROM_LOAD( "mh_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "mh_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "mh_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2601,13 +2443,6 @@ ROM_START( pc8801fa ) ROM_LOAD( "fa_n88_2.rom", 0xc000, 0x2000, CRC(6aee9a4e) SHA1(e94278682ef9e9bbb82201f72c50382748dcea2a) ) ROM_LOAD( "fa_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "fa_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0 ) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "fa_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2627,13 +2462,6 @@ ROM_START( pc8801ma ) // newer floppy BIOS and Jisyo (dictionary) ROM ROM_LOAD( "ma_n88_2.rom", 0xc000, 0x2000, CRC(6aee9a4e) SHA1(e94278682ef9e9bbb82201f72c50382748dcea2a) ) ROM_LOAD( "ma_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "ma_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0 ) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "ma_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2657,13 +2485,6 @@ ROM_START( pc8801ma2 ) ROM_LOAD( "ma2_n88_2.rom", 0xc000, 0x2000, CRC(1d6277b6) SHA1(dd9c3e50169b75bb707ef648f20d352e6a8bcfe4) ) ROM_LOAD( "ma2_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "ma2_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) ) - - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "ma2_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2686,16 +2507,9 @@ ROM_START( pc8801mc ) ROM_LOAD( "mc_n88_2.rom", 0xc000, 0x2000, CRC(1d6277b6) SHA1(dd9c3e50169b75bb707ef648f20d352e6a8bcfe4) ) ROM_LOAD( "mc_n88_3.rom", 0xe000, 0x2000, CRC(692cbcd8) SHA1(af452aed79b072c4d17985830b7c5dca64d4b412) ) - ROM_REGION( 0x10000, "fdccpu", 0) - ROM_LOAD( "mc_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004) ) - ROM_REGION( 0x10000, "cdrom", 0 ) ROM_LOAD( "cdbios.rom", 0x0000, 0x10000, CRC(5c230221) SHA1(6394a8a23f44ea35fcfc3e974cf940bc8f84d62a) ) - /* No idea of the proper size: it has never been dumped */ - ROM_REGION( 0x2000, "audiocpu", 0) - ROM_LOAD( "soundbios.rom", 0x0000, 0x2000, NO_DUMP ) - ROM_REGION( 0x40000, "kanji", 0 ) ROM_LOAD( "kanji1.rom", 0x00000, 0x20000, CRC(6178bd43) SHA1(82e11a177af6a5091dd67f50a2f4bafda84d6556) ) ROM_LOAD( "mc_kanji2.rom", 0x20000, 0x20000, CRC(376eb677) SHA1(bcf96584e2ba362218b813be51ea21573d1a2a78) ) @@ -2716,15 +2530,15 @@ COMP( 1983, pc8801mk2, pc8801, 0, pc8801, pc88sr, pc8801_state, empt COMP( 1985, pc8801mk2sr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIISR", MACHINE_NOT_WORKING ) //COMP( 1985, pc8801mk2tr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIITR", MACHINE_NOT_WORKING ) COMP( 1985, pc8801mk2fr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIFR", MACHINE_NOT_WORKING ) -COMP( 1985, pc8801mk2mr, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIMR", MACHINE_NOT_WORKING ) +COMP( 1985, pc8801mk2mr, pc8801, 0, pc8801mk2mr, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801mkIIMR", MACHINE_NOT_WORKING ) -//COMP( 1986, pc8801fh, 0, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FH", MACHINE_NOT_WORKING ) +//COMP( 1986, pc8801fh, 0, 0, pc8801mk2fr, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FH", MACHINE_NOT_WORKING ) COMP( 1986, pc8801mh, pc8801, 0, pc8801fh, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MH", MACHINE_NOT_WORKING ) COMP( 1987, pc8801fa, pc8801, 0, pc8801fh, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FA", MACHINE_NOT_WORKING ) COMP( 1987, pc8801ma, pc8801, 0, pc8801ma, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MA", MACHINE_NOT_WORKING ) -//COMP( 1988, pc8801fe, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE", MACHINE_NOT_WORKING ) +//COMP( 1988, pc8801fe, pc8801, 0, pc8801fa, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE", MACHINE_NOT_WORKING ) COMP( 1988, pc8801ma2, pc8801, 0, pc8801ma, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MA2", MACHINE_NOT_WORKING ) -//COMP( 1989, pc8801fe2, pc8801, 0, pc8801, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE2", MACHINE_NOT_WORKING ) +//COMP( 1989, pc8801fe2, pc8801, 0, pc8801fa, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801FE2", MACHINE_NOT_WORKING ) COMP( 1989, pc8801mc, pc8801, 0, pc8801mc, pc88sr, pc8801_state, empty_init, "NEC", "PC-8801MC", MACHINE_NOT_WORKING ) //COMP( 1989, pc98do, 0, 0, pc88va, pc88sr, pc8801_state, empty_init, "NEC", "PC-98DO", MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/pc88va.cpp b/src/mame/drivers/pc88va.cpp index 7e6bc817e80..7e2dbb70afa 100644 --- a/src/mame/drivers/pc88va.cpp +++ b/src/mame/drivers/pc88va.cpp @@ -13,7 +13,7 @@ - What exact kind of garbage happens if you try to enable both direct and palette color modes to a graphic layer? - unemulated upd71071 demand mode; - - What is exactly supposed to be a "bus slot"? + - What is exactly supposed to be a "bus slot"? Does it have an official name? - fdc "intelligent mode" has 0x7f as irq vector ... 0x7f is ld a,a and it IS NOT correctly hooked up by the current z80 core - PC-88VA stock version has two bogus opcodes. One is at 0xf0b15, another at 0xf0b31. diff --git a/src/mame/drivers/rollext.cpp b/src/mame/drivers/rollext.cpp index adb2c2d9aca..be7d9cb13c4 100644 --- a/src/mame/drivers/rollext.cpp +++ b/src/mame/drivers/rollext.cpp @@ -63,214 +63,339 @@ ROM [0xc0050000] 0x10000 floats copied to [0x40180000] + ROM [0xff800000 - 0xff80171f] sound data headers, 32 bytes each + Word 0: sound data pointer (offset from 0xff800000) + Word 1: uncompressed length? + Word 2: ? + Word 3: same as word 1? + Word 4: ? + Word 5: ? + Word 6: ? + Word 7: 0 + + ROM [0xff801720 -> ] compressed audio data + + [0x0000100c] bitmask of active sound channels (max 16 channels?) + [0x00001018 -> ] sound channel data, 64 bytes each + +0x00: sound data pointer in ROM + +0x04: 0 + +0x08: uncompressed length + +0x0c: uncompressed length + +0x10: 0? + +0x14: 0 - sample rate? + +0x18: 0? + +0x1c: sample rate? (halfword) + +0x1e: ?? (halfword) + +0x20: ? + +0x24: ? + +0x28: ? + +0x2c: ? + +0x30: ? + +0x34: ? + +0x36: ? (halfword) + +0x38: ? + +0x3c: ? + + Texture ROM decode: {ic45} {ic47} {ic58} {ic60} [2,0][0,0] [2,1][0,1] [3,0][1,0] [3,1][1,1] + + + TODO: + + - TMS320C82 parallel processors are not emulated + * PP0 transfers polygon data from a software FIFO to the graphics processor. This is currently HLE'd. + * PP1 most likely does sound mixing. This is currently not emulated. + - Alpha blending (probably based on palette index like on gaelco3d) + - Minor Z-buffer issues + - Wrong textures in a few places (could be a CPU core bug) + - Networking + */ #include "emu.h" #include "cpu/tms32082/tms32082.h" #include "video/poly.h" +#include "video/rgbutil.h" +#include "machine/eepromser.h" #include "screen.h" +#define BILINEAR 1 + struct rollext_polydata { - uint32_t tex_bottom; - uint32_t tex_left; + uint32_t tex_origin_y; + uint32_t tex_origin_x; uint32_t pal; + float uoz_dx; + float uoz_dy; + float voz_dx; + float voz_dy; + float ooz_dx; + float ooz_dy; + float baseu; + float basev; + float basez; + uint32_t zmul; }; class rollext_renderer : public poly_manager<float, rollext_polydata, 4> { + friend class rollext_state; + public: rollext_renderer(screen_device &screen) : poly_manager<float, rollext_polydata, 4>(screen.machine()) { - m_fb = std::make_unique<bitmap_rgb32>(1024, 1024); + m_fb[0] = std::make_unique<bitmap_rgb32>(1024, 1024); + m_fb[1] = std::make_unique<bitmap_rgb32>(1024, 1024); + + m_zb = std::make_unique<bitmap_ind32>(1024, 1024); + + + m_palette = std::make_unique<rgb_t[]>(32768); + m_texture_mask = std::make_unique<uint8_t[]>(2048 * 16384); + + m_fb_current = 0; } + template<bool UseZ> void render_texture_scan(int32_t scanline, const extent_t &extent, const rollext_polydata &extradata, int threadid); - void set_texture_ram(uint8_t* texture_ram); - void set_palette_ram(uint16_t* palette_ram); + void set_texture_ram(uint8_t* texture_ram) { m_texture_ram = texture_ram; } void process_display_list(screen_device &screen, uint32_t* dispram); + void palette_write(int index, uint16_t data); + void texture_mask_write(int index, uint8_t data); + void clear_fb(); void display(bitmap_rgb32 *bitmap, const rectangle &cliprect); private: - std::unique_ptr<bitmap_rgb32> m_fb; + std::unique_ptr<bitmap_rgb32> m_fb[2]; + std::unique_ptr<rgb_t[]> m_palette; + std::unique_ptr<uint8_t[]> m_texture_mask; + + std::unique_ptr<bitmap_ind32> m_zb; + + int m_fb_current; uint8_t *m_texture_ram; - uint16_t *m_palette_ram; }; -void rollext_renderer::set_texture_ram(uint8_t* texture_ram) +template<bool UseZ> +void rollext_renderer::render_texture_scan(int32_t scanline, const extent_t &extent, const rollext_polydata &extradata, int threadid) { - m_texture_ram = texture_ram; -} + uint32_t *fb = &m_fb[m_fb_current]->pix(scanline); + uint32_t* const zb = &m_zb->pix(scanline); -void rollext_renderer::set_palette_ram(uint16_t* palette_ram) -{ - m_palette_ram = palette_ram; -} + uint32_t tex_origin_y = extradata.tex_origin_y; + uint32_t tex_origin_x = extradata.tex_origin_x; -void rollext_renderer::render_texture_scan(int32_t scanline, const extent_t &extent, const rollext_polydata &extradata, int threadid) -{ - float u = extent.param[0].start; - float v = extent.param[1].start; - float du = extent.param[0].dpdx; - float dv = extent.param[1].dpdx; + float baseu = extradata.baseu; + float basev = extradata.basev; + float basez = extradata.basez; + float uoz_dx = extradata.uoz_dx; + float uoz_dy = extradata.uoz_dy; + float voz_dx = extradata.voz_dx; + float voz_dy = extradata.voz_dy; + float ooz_dx = extradata.ooz_dx; + float ooz_dy = extradata.ooz_dy; - uint32_t *fb = &m_fb->pix(scanline); + uint32_t zmul = extradata.zmul; - uint32_t texbot = extradata.tex_bottom; - uint32_t texleft = extradata.tex_left; + int palnum = extradata.pal << 8; - int palnum = extradata.pal; + float uoz = baseu + (uoz_dx * (extent.startx - 256)) + (-uoz_dy * (scanline - 192)); + float voz = basev + (voz_dx * (extent.startx - 256)) + (-voz_dy * (scanline - 192)); + float ooz = basez + (ooz_dx * (extent.startx - 256)) + (-ooz_dy * (scanline - 192)); for (int x = extent.startx; x < extent.stopx; x++) { - int iu = (int)(u * 29.0f); - int iv = (int)(v * 29.0f); + float z = recip_approx(ooz); + uint32_t zbufval = (int)(z * zmul); + + if (zbufval <= zb[x] || !UseZ) + { + float u = uoz * z; + float v = voz * z; - uint8_t p = m_texture_ram[((texbot - iv) * 2048) + texleft + iu]; + int tx = tex_origin_x + (int)(u); + int ty = tex_origin_y + (int)(v); - uint16_t texel = m_palette_ram[(palnum * 256) + BYTE_XOR_BE(p)]; - int r = ((texel >> 10) & 0x1f) << 3; - int g = ((texel >> 5) & 0x1f) << 3; - int b = (texel & 0x1f) << 3; - fb[x] = 0xff000000 | (r << 16) | (g << 8) | b; +#if BILINEAR + float intu, intv; - u += du; - v += dv; + int fracu = modff(u, &intu) * 255.0f; + int fracv = modff(v, &intv) * 255.0f; + + uint32_t mask00 = m_texture_mask[((ty & 0x3fff) * 2048) + (tx & 0x7ff)]; + uint32_t mask01 = m_texture_mask[((ty & 0x3fff) * 2048) + ((tx+1) & 0x7ff)]; + uint32_t mask10 = m_texture_mask[(((ty+1) & 0x3fff) * 2048) + (tx & 0x7ff)]; + uint32_t mask11 = m_texture_mask[(((ty+1) & 0x3fff) * 2048) + ((tx+1) & 0x7ff)]; + const uint32_t mask_level = rgbaint_t::bilinear_filter(mask00, mask01, mask10, mask11, fracu, fracv); + + if (mask_level < 0xff) + { + uint32_t tex00 = m_palette[palnum + BYTE_XOR_BE(m_texture_ram[((ty) & 0x3fff) * 2048 + ((tx) & 0x7ff)])]; + uint32_t tex01 = m_palette[palnum + BYTE_XOR_BE(m_texture_ram[((ty) & 0x3fff) * 2048 + ((tx + 1) & 0x7ff)])]; + uint32_t tex10 = m_palette[palnum + BYTE_XOR_BE(m_texture_ram[((ty + 1) & 0x3fff) * 2048 + ((tx) & 0x7ff)])]; + uint32_t tex11 = m_palette[palnum + BYTE_XOR_BE(m_texture_ram[((ty + 1) & 0x3fff) * 2048 + ((tx + 1) & 0x7ff)])]; + + const uint32_t texsam = rgbaint_t::bilinear_filter(tex00, tex01, tex10, tex11, fracu, fracv); + + rgbaint_t texel_color(texsam); + rgbaint_t fb_color(fb[x]); + texel_color.blend(fb_color, 255-mask_level); + + fb[x] = texel_color.to_rgba_clamp(); + if (UseZ) + zb[x] = zbufval; + } +#else + uint8_t mask = m_texture_mask[((ty & 0x3fff) * 2048) + (tx & 0x7ff)]; + if (mask == 0) + { + uint8_t pen = m_texture_ram[((ty & 0x3fff) * 2048) + (tx & 0x7ff)]; + uint32_t texel = m_palette[palnum + BYTE_XOR_BE(pen)]; + fb[x] = texel; + if (UseZ) + zb[x] = zbufval; + } +#endif + } + + uoz += uoz_dx; + voz += voz_dx; + ooz += ooz_dx; } } void rollext_renderer::process_display_list(screen_device &screen, uint32_t* disp_ram) { - const rectangle& visarea = screen.visible_area(); - - render_delegate rd = render_delegate(&rollext_renderer::render_texture_scan, this); + rectangle visarea = rectangle(0, 511, 0, 383); int num = disp_ram[0xffffc/4]; for (int i=0; i < num; i++) { - int ii = i * 0x60; - - vertex_t vert[4]; + int ii = i * 0x18; - //int x[4]; - //int y[4]; + vertex_t vert[5]; // Poly data: - // Word 0: xxxxxxxx -------- -------- -------- Command? 0xFC for quads - // -------- -------- xxxxxxxx -------- Palette? - // -------- -------- -------- xxxxxxxx Number of verts? (4 for quads) - - // Word 1: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 1 X - + // Word 0: x------- -------- -------- -------- ? + // -x------ -------- -------- -------- ? set to 1 for polygons, 0 on command 0x9c (viewport setup command?) + // --x----- -------- -------- -------- ? set to 1 for no perspective + // ---x---- -------- -------- -------- ? always 1? + // ----x--- -------- -------- -------- ? always 1? + // -----x-- -------- -------- -------- the PP transfer code checks for 1 + // ------x- -------- -------- -------- always 0? + // -------x -------- -------- -------- Texture page + // -------- -------- -xxxxxxx -------- Palette + // -------- -------- -------- -----xxx Number of verts (3,4,5 used) + // Word 1: (float) Vertex 1 X // Word 2: xxxxxxxx xxxxx--- -------- -------- Texture Origin Bottom // -------- -----xxx xxxxxxxx -------- Texture Origin Left + // Word 3: (float) Vertex 1 Y + // Word 4: xxxxxxxx xxxxxxxx xxxxxxxx x------- Z buffer multiplier (int) + // Word 5: (float) Vertex 2 X + // Word 6: (float) U/Z per X pixel increment + // Word 7: (float) Vertex 2 Y + // Word 8: (float) U/Z per Y pixel increment + // Word 9: (float) Vertex 3 X + // Word 10: (float) 1/Z per X pixel increment + // Word 11: (float) Vertex 3 Y + // Word 12: (float) 1/Z per Y pixel increment + // Word 13: (float) Vertex 4 X (if quad) + // Word 14: (float) V/Z per X pixel increment + // Word 15: (float) Vertex 4 Y (if quad) + // Word 16: (float) V/Z per Y pixel increment + // Word 17: (float) Vertex 5 X (if 5 verts) + // Word 18: (float) Base U coordinate + // Word 19: (float) Vertex 5 Y (if 5 verts) + // Word 20: (float) Base Z coordinate + // Word 21: (float) Unused? PP code checks for 0 (validity check?) + // Word 22: (float) Base V coordinate + // Word 23: (float) ? Seems to be a copy of the last X coordinate + + for (int j=0; j < 5; j++) + { + float fx = u2f(disp_ram[ii + (j * 4) + 1]); + float fy = u2f(disp_ram[ii + (j * 4) + 3]); - // Word 3: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 1 Y - - // Word 4: -------- -------- xxxxxxxx xxxxxxxx ? - - // Word 5: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 2 X - - // Word 6: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Unknown float - - // Word 7: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 2 Y - - // Word 8: -------- -------- -------- -------- ? - - // Word 9: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 3 X - - // Word 10: -------- -------- -------- -------- ? - - // Word 11: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 3 Y - - // Word 12: -------- -------- -------- -------- ? - - // Word 13: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 4 X - - // Word 14: -------- -------- -------- -------- ? - - // Word 15: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Vertex 4 Y - - // Word 16: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Unknown float - - // Word 17: -------- -------- -------- -------- ? - - // Word 18: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Unknown float - - // Word 19: -------- -------- -------- -------- ? - - // Word 20: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Unknown float - - // Word 21: -------- -------- -------- -------- ? - - // Word 22: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Unknown float + vert[j].x = (int)(fx + 256.0f); + vert[j].y = (int)(-fy + 192.0f); + } - // Word 23: -------- -------- -------- -------- ? + rollext_polydata& extra = object_data().next(); - for (int j=0; j < 4; j++) - { - uint32_t ix = disp_ram[(ii + (j*0x10) + 0x4) / 4]; - uint32_t iy = disp_ram[(ii + (j*0x10) + 0xc) / 4]; + extra.tex_origin_y = (disp_ram[ii + 2] >> 19) & 0x1fff; + extra.tex_origin_x = (disp_ram[ii + 2] >> 8) & 0x7ff; + extra.pal = (disp_ram[ii + 0] >> 8) & 0x7f; - vert[j].x = (int)((u2f(ix) / 2.0f) + 256.0f); - vert[j].y = (int)((u2f(iy) / 2.0f) + 192.0f); - } + extra.tex_origin_y |= (disp_ram[ii + 0] & 0x01000000) ? 0x2000 : 0; - vert[0].p[0] = 0.0f; vert[0].p[1] = 1.0f; - vert[1].p[0] = 0.0f; vert[1].p[1] = 0.0f; - vert[2].p[0] = 1.0f; vert[2].p[1] = 0.0f; - vert[3].p[0] = 1.0f; vert[3].p[1] = 1.0f; + extra.uoz_dx = u2f(disp_ram[ii + 6]); + extra.uoz_dy = u2f(disp_ram[ii + 8]); + extra.voz_dx = u2f(disp_ram[ii + 14]); + extra.voz_dy = u2f(disp_ram[ii + 16]); + extra.ooz_dx = u2f(disp_ram[ii + 10]); + extra.ooz_dy = u2f(disp_ram[ii + 12]); + extra.baseu = u2f(disp_ram[ii + 18]); + extra.basev = u2f(disp_ram[ii + 22]); + extra.basez = u2f(disp_ram[ii + 20]); - rollext_polydata &extra = object_data().next(); + extra.zmul = (uint32_t)(disp_ram[ii + 4]) >> 7; - extra.tex_bottom = (disp_ram[(ii + 8) / 4] >> 19) & 0x1fff; - extra.tex_left = (disp_ram[(ii + 8) / 4] >> 8) & 0x7ff; - extra.pal = (disp_ram[(ii + 0) / 4] >> 8) & 0x1f; + int num_verts = (disp_ram[ii + 0] & 0x7); -#if 0 - printf("P%d\n", i); - for (int j=0; j < 6; j++) + if (disp_ram[ii + 0] & 0x40000000) { - printf(" %08X %08X %08X %08X", disp_ram[(ii + (j*0x10) + 0) / 4], disp_ram[(ii + (j*0x10) + 4) / 4], disp_ram[(ii + (j*0x10) + 8) / 4], disp_ram[(ii + (j*0x10) + 12) / 4]); - printf(" %f %f %f %f\n", u2f(disp_ram[(ii + (j*0x10) + 0) / 4]), u2f(disp_ram[(ii + (j*0x10) + 4) / 4]), u2f(disp_ram[(ii + (j*0x10) + 8) / 4]), u2f(disp_ram[(ii + (j*0x10) + 12) / 4])); + if (num_verts == 4) + render_polygon<4, 0>(visarea, render_delegate(&rollext_renderer::render_texture_scan<true>, this), vert); + else if (num_verts == 3) + render_triangle<0>(visarea, render_delegate(&rollext_renderer::render_texture_scan<true>, this), vert[0], vert[1], vert[2]); + else if (num_verts == 5) + render_polygon<5, 0>(visarea, render_delegate(&rollext_renderer::render_texture_scan<true>, this), vert); } -#endif - - render_triangle<4>(visarea, rd, vert[0], vert[1], vert[2]); - render_triangle<4>(visarea, rd, vert[0], vert[2], vert[3]); } - - wait(); } void rollext_renderer::clear_fb() { - rectangle visarea; - visarea.min_x = 0; - visarea.max_x = 511; - visarea.min_y = 0; - visarea.max_y = 383; + rectangle visarea(0, 511, 0, 383); + + m_zb->fill(0xffffffff, visarea); + m_fb[m_fb_current]->fill(0xff000000, visarea); +} + +void rollext_renderer::palette_write(int index, uint16_t data) +{ + m_palette[index] = rgb_t(0xff, pal5bit(data >> 10), pal5bit(data >> 5), pal5bit(data)); +} - m_fb->fill(0xff000000, visarea); +void rollext_renderer::texture_mask_write(int index, uint8_t data) +{ + int x = index & 0xff; + int y = index >> 8; + // expand to bytes for easier access + for (auto j = 0; j < 8; j++) + { + m_texture_mask[(y * 2048) + (x * 8) + j] = (data & (1 << j)) ? 0xff : 0x00; + } } void rollext_renderer::display(bitmap_rgb32 *bitmap, const rectangle &cliprect) { - copybitmap_trans(*bitmap, *m_fb, 0, 0, 0, 0, cliprect, 0); + wait(); + copybitmap_trans(*bitmap, *m_fb[m_fb_current], 0, 0, 0, 0, cliprect, 0); } @@ -283,10 +408,12 @@ public: rollext_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), - m_palette_ram(*this, "palette_ram"), - m_texture_mask(*this, "texture_mask"), m_disp_ram(*this, "disp_ram"), - m_screen(*this, "screen") + m_screen(*this, "screen"), + m_in(*this, "INPUTS%u", 1U), + m_analog(*this, "ANALOG%u", 1U), + m_eeprom_in(*this, "EEPROMIN"), + m_eeprom_out(*this, "EEPROMOUT") { } @@ -296,20 +423,35 @@ public: private: required_device<tms32082_mp_device> m_maincpu; - required_shared_ptr<uint32_t> m_palette_ram; - required_shared_ptr<uint32_t> m_texture_mask; required_shared_ptr<uint32_t> m_disp_ram; required_device<screen_device> m_screen; - uint32_t a0000000_r(offs_t offset); - void a0000000_w(uint32_t data); + uint32_t a0000000_r(offs_t offset, uint32_t mem_mask = ~0); + void a0000000_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint32_t b0000000_r(offs_t offset); + void palette_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + void texture_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + void cmd_callback(address_space &space, uint32_t data); + uint32_t fifo_ptr_r(offs_t offset, uint32_t mem_mask = ~0); + void fifo_ptr_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + std::unique_ptr<uint8_t[]> m_texture; std::unique_ptr<rollext_renderer> m_renderer; + uint32_t m_fifo_ptr; + + uint8_t m_adc_reg; + uint8_t m_adc_input; + uint8_t m_adc_readbit; + + required_ioport_array<3> m_in; + required_ioport_array<1> m_analog; + required_ioport m_eeprom_in; + required_ioport m_eeprom_out; + INTERRUPT_GEN_MEMBER(vblank_interrupt); virtual void machine_start() override; virtual void machine_reset() override; @@ -347,72 +489,84 @@ void rollext_state::video_start() m_renderer = std::make_unique<rollext_renderer>(*m_screen); m_renderer->set_texture_ram(m_texture.get()); - m_renderer->set_palette_ram((uint16_t*)&m_palette_ram[0]); } uint32_t rollext_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { -#if 0 - uint16_t *pal = (uint16_t*)&m_palette_ram[0]; - - int palnum = 31; - // 24,25,31 for basic font - // 29 = trees - - int ii=0; - for (int j=0; j < 384; j++) - { - uint32_t *fb = &bitmap.pix(j); - for (int i=0; i < 512; i++) - { - uint8_t p = m_texture[ii++]; - - uint16_t rgb = pal[(palnum * 256) + BYTE_XOR_BE(p)]; - int r = ((rgb >> 10) & 0x1f) << 3; - int g = ((rgb >> 5) & 0x1f) << 3; - int b = (rgb & 0x1f) << 3; - - fb[i] = 0xff000000 | (r << 16) | (g << 8) | b; - } - ii += 1536; - } -#endif - m_renderer->display(&bitmap, cliprect); - - //m_renderer->clear_fb(); - - //m_disp_ram[0xffffc/4] = 0; - - return 0; } -uint32_t rollext_state::a0000000_r(offs_t offset) +uint32_t rollext_state::a0000000_r(offs_t offset, uint32_t mem_mask) { switch (offset) { - case 0: // ?? + case 0: // inputs { - uint32_t data = 0x20200; + uint32_t data = 0; - //data |= ioport("INPUTS1")->read(); - //data |= 0xfff7fff7; + if (ACCESSING_BITS_16_23) + { + // -------- ---x---- -------- -------- ADC channel 0 + // -------- --x----- -------- -------- ADC channel 1? + // -------- -x------ -------- -------- ADC channel 2? + // -------- x------- -------- -------- ADC channel 3? + + data |= (m_adc_readbit & 1) ? 0x100000 : 0; + + data |= m_in[0]->read() << 16; + } + if (ACCESSING_BITS_8_15) + { + data |= 0x200; // 0 causes inf loop + data |= m_eeprom_in->read() << 8; + } + if (ACCESSING_BITS_0_7) + { + data |= m_in[1]->read(); + } return data; } case 1: - return 0xffffffff; + uint32_t data = 0; + data |= m_in[2]->read(); + return data; } return 0xffffffff; } -void rollext_state::a0000000_w(uint32_t data) +void rollext_state::a0000000_w(offs_t offset, uint32_t data, uint32_t mem_mask) { - // FPGA interface? + if (offset == 0) + { + if (ACCESSING_BITS_8_15) + { + m_eeprom_out->write(data >> 8, 0xff); + } + } + else if (offset == 1) + { + if (ACCESSING_BITS_16_23) + { + uint8_t newdata = data >> 16; + if ((newdata & 0x20) == 0 && (m_adc_reg & 0x20) != 0) + { + m_adc_input = m_analog[0]->read(); + } + + if (newdata & 0x10) + { + m_adc_readbit = (m_adc_input >> 7) & 1; + m_adc_input <<= 1; + } + + m_adc_reg = newdata; + } + } } uint32_t rollext_state::b0000000_r(offs_t offset) @@ -425,7 +579,7 @@ uint32_t rollext_state::b0000000_r(offs_t offset) return 0; } - return 0; + return 0xffffffff; } void rollext_state::cmd_callback(address_space &space, uint32_t data) @@ -440,64 +594,11 @@ void rollext_state::cmd_callback(address_space &space, uint32_t data) // simulate PP behavior for now... space.write_dword(0x00000084, 3); - uint32_t num = space.read_dword(0x90); - - int consume_num = num; - if (consume_num > 32) - consume_num = 32; - - printf("PP num %d\n", num); - printf("0x00000084 = %08X\n", space.read_dword(0x84)); - - - uint32_t ra = 0x1000280; - - /* - printf("FIFO push:\n"); - - for (int i=0; i < consume_num; i++) - { - printf("Entry %d:\n", i); - for (int k=0; k < 6; k++) - { - for (int l=0; l < 4; l++) - { - uint32_t dd = m_program->read_dword(ra); - ra += 4; - - printf("%08X(%f) ", dd, u2f(dd)); - } - printf("\n"); - } - printf("\n"); - } - */ - - ra = 0x1000280; - - int oldnum = space.read_dword(0x600ffffc); - uint32_t rb = 0x60000000 + (oldnum * 0x60); - - for (int i=0; i < consume_num; i++) - { - for (int k=0; k < 24; k++) - { - uint32_t dd = space.read_dword(ra); - ra += 4; - - space.write_dword(rb, dd); - rb += 4; - } - } - space.write_dword(0x600ffffc, oldnum+consume_num); + m_renderer->m_fb_current ^= 1; + m_renderer->clear_fb(); m_renderer->process_display_list(*m_screen, m_disp_ram); - - space.write_dword(0x600ffffc, 0); - - space.write_dword(0x00000090, 0); - space.write_dword(0x00000094, 0); - + m_maincpu->space().write_dword(0x600ffffc, 0); } } // PP1 @@ -511,14 +612,48 @@ void rollext_state::cmd_callback(address_space &space, uint32_t data) } } +void rollext_state::palette_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (ACCESSING_BITS_16_31) + { + m_renderer->palette_write((offset * 2) + 1, data >> 16); + } + if (ACCESSING_BITS_0_15) + { + m_renderer->palette_write(offset * 2, data & 0xffff); + } +} + +void rollext_state::texture_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + if (ACCESSING_BITS_24_31) + { + m_renderer->texture_mask_write((offset * 4) + 1, data >> 24); + } + if (ACCESSING_BITS_16_23) + { + m_renderer->texture_mask_write((offset * 4) + 0, data >> 16); + } + if (ACCESSING_BITS_8_15) + { + m_renderer->texture_mask_write((offset * 4) + 3, data >> 8); + } + if (ACCESSING_BITS_0_7) + { + m_renderer->texture_mask_write((offset * 4) + 2, data & 0xff); + } +} + + + // Master Processor memory map void rollext_state::memmap(address_map &map) { map(0x40000000, 0x40ffffff).ram().share("main_ram"); map(0x60000000, 0x600fffff).ram().share("disp_ram"); - map(0x80000000, 0x8000ffff).ram().share("palette_ram"); - map(0x90000000, 0x9007ffff).ram().share("texture_mask"); + map(0x80000000, 0x8000ffff).w(FUNC(rollext_state::palette_w)); + map(0x90000000, 0x9007ffff).w(FUNC(rollext_state::texture_mask_w)); map(0xa0000000, 0xa00000ff).rw(FUNC(rollext_state::a0000000_r), FUNC(rollext_state::a0000000_w)); map(0xb0000000, 0xb0000007).r(FUNC(rollext_state::b0000000_r)); map(0xc0000000, 0xc03fffff).rom().region("rom1", 0); @@ -527,20 +662,87 @@ void rollext_state::memmap(address_map &map) static INPUT_PORTS_START(rollext) - PORT_START("INPUTS1") - PORT_BIT( 0xfff7fff7, IP_ACTIVE_LOW, IPT_UNUSED ) - PORT_SERVICE_NO_TOGGLE( 0x00080008, IP_ACTIVE_LOW) /* Test Button */ - + PORT_SERVICE_NO_TOGGLE(0x8, IP_ACTIVE_LOW) // test button + PORT_BIT(0x4, IP_ACTIVE_LOW, IPT_VOLUME_DOWN) + PORT_BIT(0x2, IP_ACTIVE_LOW, IPT_SERVICE1) + PORT_BIT(0x1, IP_ACTIVE_LOW, IPT_VOLUME_UP) + + PORT_START("INPUTS2") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_START) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("View Change") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("Right Brake") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("Left Brake") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Left Smash") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Right Smash") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("INPUTS3") + PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_COIN1) + + PORT_START("EEPROMIN") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_READ_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, do_read) + + PORT_START("EEPROMOUT") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_OUTPUT) PORT_WRITE_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, clk_write) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OUTPUT) PORT_WRITE_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, cs_write) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OUTPUT) PORT_WRITE_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, di_write) + + PORT_START("ANALOG1") + PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_MINMAX(0x00, 0xff) PORT_SENSITIVITY(35) PORT_KEYDELTA(5) PORT_NAME("Seat Tilt") INPUT_PORTS_END +uint32_t rollext_state::fifo_ptr_r(offs_t offset, uint32_t mem_mask) +{ + return m_fifo_ptr; +} + +void rollext_state::fifo_ptr_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + m_fifo_ptr = data; + if (m_fifo_ptr > 0) + { + // simulate PP behavior for now... + uint32_t num = m_fifo_ptr; + + int consume_num = num; + if (consume_num > 32) + consume_num = 32; + + uint32_t ra = 0x1000280; + + int oldnum = m_maincpu->space().read_dword(0x600ffffc); + uint32_t rb = 0x60000000 + (oldnum * 0x60); + + for (int i = 0; i < consume_num; i++) + { + for (int k = 0; k < 24; k++) + { + uint32_t dd = m_maincpu->space().read_dword(ra); + ra += 4; + + m_maincpu->space().write_dword(rb, dd); + rb += 4; + } + } + m_maincpu->space().write_dword(0x600ffffc, oldnum + consume_num); + m_maincpu->space().write_dword(0x00000090, 0); + } +} + + + void rollext_state::machine_reset() { } void rollext_state::machine_start() { + // hook to fifo pointer for simulating PP0 + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x90, 0x93, read32s_delegate(*this, FUNC(rollext_state::fifo_ptr_r)), write32s_delegate(*this, FUNC(rollext_state::fifo_ptr_w))); } @@ -548,8 +750,7 @@ void rollext_state::rollext(machine_config &config) { TMS32082_MP(config, m_maincpu, 60000000); m_maincpu->set_addrmap(AS_PROGRAM, &rollext_state::memmap); - //m_maincpu->set_vblank_int("screen", FUNC(rollext_state::vblank_interrupt)); - m_maincpu->set_periodic_int(FUNC(rollext_state::irq1_line_assert), attotime::from_hz(60)); + m_maincpu->set_vblank_int("screen", FUNC(rollext_state::vblank_interrupt)); //m_maincpu->set_periodic_int(FUNC(rollext_state::irq3_line_assert), attotime::from_hz(500)); tms32082_pp_device &pp0(TMS32082_PP(config, "pp0", 60000000)); @@ -557,6 +758,8 @@ void rollext_state::rollext(machine_config &config) config.set_maximum_quantum(attotime::from_hz(100)); + EEPROM_93C66_16BIT(config, "eeprom"); + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_refresh_hz(60); m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); diff --git a/src/mame/drivers/saturn.cpp b/src/mame/drivers/saturn.cpp index 94a6309610c..3e1b93d9c51 100644 --- a/src/mame/drivers/saturn.cpp +++ b/src/mame/drivers/saturn.cpp @@ -463,26 +463,50 @@ public: void saturnjp(machine_config &config); void saturneu(machine_config &config); void saturnus(machine_config &config); + void saturnkr(machine_config &config); - void init_saturnus(); - void init_saturneu(); - void init_saturnjp(); + template <bool is_pal> void init_saturn(); DECLARE_INPUT_CHANGED_MEMBER(tray_open); DECLARE_INPUT_CHANGED_MEMBER(tray_close); private: - DECLARE_MACHINE_START(saturn); DECLARE_MACHINE_RESET(saturn); + // SMPC region codes, hardwired via jumper setting. + // - Given the scheme bit 3 should determine if the region is PAL or NTSC. + // - 0 and F are "prohibited", others are "Sega reserved". + // - Documentation states that 2 is "TAIWAN" and 6 is "KOREA", + // but games on latter definitely wants 2 rather than 6. + // We currently swap, former actual slot needs to be confirmed. + enum { + REGION_NTSC_0 = 0, + REGION_NTSC_JAPAN, +// REGION_NTSC_TAIWAN, + REGION_NTSC_KOREA, + REGION_NTSC_3, + REGION_NTSC_USA, // & Canada, Mexico + REGION_NTSC_BRAZIL, +// REGION_NTSC_KOREA, + REGION_NTSC_TAIWAN, // & Philippines + REGION_NTSC_7, + REGION_PAL_8, + REGION_PAL_9, + REGION_PAL_ASIA, // China, Middle East, East Asia not covered above + REGION_PAL_B, + REGION_PAL_EUROPE, // Australia, South Africa + REGION_PAL_AMERICA, // Non-NTSC Central/South America + REGION_PAL_E, + REGION_PAL_F + }; + uint8_t saturn_cart_type_r(); uint32_t abus_dummy_r(offs_t offset); uint32_t saturn_null_ram_r(); void saturn_null_ram_w(uint32_t data); - void saturn_init_driver(int rgn); uint8_t saturn_pdr1_direct_r(); uint8_t saturn_pdr2_direct_r(); void saturn_pdr1_direct_w(uint8_t data); @@ -548,7 +572,7 @@ void sat_console_state::saturn_mem(address_map &map) map(0x05f80000, 0x05fbffff).rw(FUNC(sat_console_state::saturn_vdp2_regs_r), FUNC(sat_console_state::saturn_vdp2_regs_w)); map(0x05fe0000, 0x05fe00cf).m(m_scu, FUNC(sega_scu_device::regs_map)); //rw(FUNC(sat_console_state::saturn_scu_r), FUNC(sat_console_state::saturn_scu_w)); map(0x06000000, 0x060fffff).ram().mirror(0x21f00000).share("workram_h"); - map(0x45000000, 0x46ffffff).nopw(); + map(0x40000000, 0x46ffffff).nopw(); // associative purge page map(0x60000000, 0x600003ff).nopw(); // cache address array map(0xc0000000, 0xc0000fff).ram(); // cache data array, Dragon Ball Z sprites relies on this } @@ -884,7 +908,7 @@ void sat_console_state::saturnus(machine_config &config) SATURN_CART_SLOT(config, "exp", saturn_cart, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("sat_cart"); - m_smpc_hle->set_region_code(4); + m_smpc_hle->set_region_code(REGION_NTSC_USA); } void sat_console_state::saturneu(machine_config &config) @@ -897,7 +921,7 @@ void sat_console_state::saturneu(machine_config &config) SATURN_CART_SLOT(config, "exp", saturn_cart, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("sat_cart"); - m_smpc_hle->set_region_code(12); + m_smpc_hle->set_region_code(REGION_PAL_EUROPE); } void sat_console_state::saturnjp(machine_config &config) @@ -910,13 +934,27 @@ void sat_console_state::saturnjp(machine_config &config) SATURN_CART_SLOT(config, "exp", saturn_cart, nullptr); SOFTWARE_LIST(config, "cart_list").set_original("sat_cart"); - m_smpc_hle->set_region_code(1); + m_smpc_hle->set_region_code(REGION_NTSC_JAPAN); +} + +void sat_console_state::saturnkr(machine_config &config) +{ + saturn(config); + SATURN_CDB(config, "saturn_cdb", 16000000); + + SOFTWARE_LIST(config, "cd_list").set_original("saturn").set_filter("NTSC-K"); + + SATURN_CART_SLOT(config, "exp", saturn_cart, nullptr); + SOFTWARE_LIST(config, "cart_list").set_original("sat_cart"); + + m_smpc_hle->set_region_code(REGION_NTSC_KOREA); } -void sat_console_state::saturn_init_driver(int rgn) +template <bool is_pal> void sat_console_state::init_saturn() { - m_vdp2.pal = (rgn == 12) ? 1 : 0; + // TODO: setter for (missing) VDP2 device + m_vdp2.pal = is_pal; // set compatible options m_maincpu->sh2drc_set_options(SH2DRC_STRICT_VERIFY|SH2DRC_STRICT_PCREL); @@ -939,25 +977,8 @@ void sat_console_state::saturn_init_driver(int rgn) m_backupram = make_unique_clear<uint8_t[]>(0x8000); } -void sat_console_state::init_saturnus() -{ - saturn_init_driver(4); -} - -void sat_console_state::init_saturneu() -{ - saturn_init_driver(12); -} - -void sat_console_state::init_saturnjp() -{ - saturn_init_driver(1); -} - - -/* Japanese Saturn */ -ROM_START(saturnjp) - ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) /* SH2 code */ +ROM_START( saturnjp ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "101", "Japan v1.01 (941228)") ROMX_LOAD("sega_101.bin", 0x00000000, 0x00080000, CRC(224b752c) SHA1(df94c5b4d47eb3cc404d88b33a8fda237eaf4720), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "1003", "Japan v1.003 (941012)") @@ -966,9 +987,8 @@ ROM_START(saturnjp) ROMX_LOAD("sega_100.bin", 0x00000000, 0x00080000, CRC(2aba43c2) SHA1(2b8cb4f87580683eb4d760e4ed210813d667f0a2), ROM_BIOS(2)) ROM_END -/* Overseas Saturn */ -ROM_START(saturn) - ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) /* SH2 code */ +ROM_START( saturn ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "101a", "Overseas v1.01a (941115)") /* Confirmed by ElBarto */ ROMX_LOAD("mpr-17933.bin", 0x00000000, 0x00080000, CRC(4afcf0fa) SHA1(faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3), ROM_BIOS(0)) @@ -976,8 +996,8 @@ ROM_START(saturn) ROMX_LOAD("sega_100a.bin", 0x00000000, 0x00080000, CRC(f90f0089) SHA1(3bb41feb82838ab9a35601ac666de5aacfd17a58), ROM_BIOS(1)) ROM_END -ROM_START(saturneu) - ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) /* SH2 code */ +ROM_START( saturneu ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "101a", "Overseas v1.01a (941115)") /* Confirmed by ElBarto */ ROMX_LOAD("mpr-17933.bin", 0x00000000, 0x00080000, CRC(4afcf0fa) SHA1(faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3), ROM_BIOS(0)) @@ -985,13 +1005,20 @@ ROM_START(saturneu) ROMX_LOAD("sega_100a.bin", 0x00000000, 0x00080000, CRC(f90f0089) SHA1(3bb41feb82838ab9a35601ac666de5aacfd17a58), ROM_BIOS(1)) ROM_END -ROM_START(vsaturn) - ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) /* SH2 code */ +ROM_START( saturnkr ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) + // undumped, uses Japanese VA1 motherboard with v1.02a BIOS rev, + // with extra checks for region jumpers that disables Japanese language if setting matches '2' (no Korea option tho) + ROM_LOAD("sega_101.bin", 0x00000000, 0x00080000, BAD_DUMP CRC(224b752c) SHA1(df94c5b4d47eb3cc404d88b33a8fda237eaf4720) ) +ROM_END + +ROM_START( vsaturn ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) ROM_LOAD("vsaturn.bin", 0x00000000, 0x00080000, CRC(e4d61811) SHA1(4154e11959f3d5639b11d7902b3a393a99fb5776)) ROM_END -ROM_START(hisaturn) - ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) /* SH2 code */ +ROM_START( hisaturn ) + ROM_REGION32_BE( 0x80000, "bios", ROMREGION_ERASEFF ) ROM_SYSTEM_BIOS(0, "102", "v1.02 (950519)") ROMX_LOAD("mpr-18100.bin", 0x000000, 0x080000, CRC(3408dbf4) SHA1(8a22710e09ce75f39625894366cafe503ed1942d), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "101", "v1.01 (950130)") @@ -999,8 +1026,9 @@ ROM_START(hisaturn) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -CONS( 1994, saturn, 0, 0, saturnus, saturn, sat_console_state, init_saturnus, "Sega", "Saturn (USA)", MACHINE_NOT_WORKING ) -CONS( 1994, saturnjp, saturn, 0, saturnjp, saturn, sat_console_state, init_saturnjp, "Sega", "Saturn (Japan)", MACHINE_NOT_WORKING ) -CONS( 1994, saturneu, saturn, 0, saturneu, saturn, sat_console_state, init_saturneu, "Sega", "Saturn (PAL)", MACHINE_NOT_WORKING ) -CONS( 1995, vsaturn, saturn, 0, saturnjp, saturn, sat_console_state, init_saturnjp, "JVC", "V-Saturn", MACHINE_NOT_WORKING ) -CONS( 1995, hisaturn, saturn, 0, saturnjp, saturn, sat_console_state, init_saturnjp, "Hitachi", "HiSaturn", MACHINE_NOT_WORKING ) +CONS( 1994, saturn, 0, 0, saturnus, saturn, sat_console_state, init_saturn<false>, "Sega", "Saturn (USA)", MACHINE_NOT_WORKING ) +CONS( 1994, saturnjp, saturn, 0, saturnjp, saturn, sat_console_state, init_saturn<false>, "Sega", "Saturn (Japan)", MACHINE_NOT_WORKING ) +CONS( 1994, saturneu, saturn, 0, saturneu, saturn, sat_console_state, init_saturn<true>, "Sega", "Saturn (PAL)", MACHINE_NOT_WORKING ) +CONS( 1995, saturnkr, saturn, 0, saturnkr, saturn, sat_console_state, init_saturn<false>, "Samsung", "Saturn (Korea)", MACHINE_NOT_WORKING ) +CONS( 1995, vsaturn, saturn, 0, saturnjp, saturn, sat_console_state, init_saturn<false>, "JVC", "V-Saturn", MACHINE_NOT_WORKING ) +CONS( 1995, hisaturn, saturn, 0, saturnjp, saturn, sat_console_state, init_saturn<false>, "Hitachi", "HiSaturn", MACHINE_NOT_WORKING ) diff --git a/src/mame/drivers/segac2.cpp b/src/mame/drivers/segac2.cpp index 1be460ff039..112a4571dea 100644 --- a/src/mame/drivers/segac2.cpp +++ b/src/mame/drivers/segac2.cpp @@ -674,11 +674,11 @@ void pclub_state::print_club_camera_w(uint16_t data) void segac2_state::segac_map(address_map &map) { map(0x000000, 0x1fffff).rom(); - map(0x800001, 0x800001).mirror(0x13fdfe).rw(FUNC(segac2_state::prot_r), FUNC(segac2_state::prot_w)); - map(0x800201, 0x800201).mirror(0x13fdfe).w(FUNC(segac2_state::control_w)); + map(0x800000, 0x800001).mirror(0x13fdfe).rw(FUNC(segac2_state::prot_r), FUNC(segac2_state::prot_w)).umask16(0x00ff); + map(0x800200, 0x800201).mirror(0x13fdfe).w(FUNC(segac2_state::control_w)).umask16(0x00ff); map(0x840000, 0x84001f).mirror(0x13fee0).rw("io", FUNC(sega_315_5296_device::read), FUNC(sega_315_5296_device::write)).umask16(0x00ff); map(0x840100, 0x840107).mirror(0x13fef8).rw(m_ymsnd, FUNC(ym3438_device::read), FUNC(ym3438_device::write)).umask16(0x00ff); - map(0x880101, 0x880101).mirror(0x13fefe).w(FUNC(segac2_state::counter_timer_w)); + map(0x880100, 0x880101).mirror(0x13fefe).w(FUNC(segac2_state::counter_timer_w)).umask16(0x00ff); map(0x8c0000, 0x8c0fff).mirror(0x13f000).rw(FUNC(segac2_state::palette_r), FUNC(segac2_state::palette_w)).share("paletteram"); map(0xc00000, 0xc0001f).mirror(0x18ff00).rw(m_vdp, FUNC(sega315_5313_device::vdp_r), FUNC(sega315_5313_device::vdp_w)); map(0xe00000, 0xe0ffff).mirror(0x1f0000).ram().share("nvram"); diff --git a/src/mame/drivers/spg2xx_jakks.cpp b/src/mame/drivers/spg2xx_jakks.cpp index da3125d5e32..7deed4f8473 100644 --- a/src/mame/drivers/spg2xx_jakks.cpp +++ b/src/mame/drivers/spg2xx_jakks.cpp @@ -216,7 +216,7 @@ CONS( 2004, jak_mpacw,0, 0, jakks_mpac, jak_mpac, jakks_state, empty_init, "JA // This was available in 2 different case styles, initially an underwater / jellyfish themed one, then later // reissued in a 'SpongeBob head' style case reminiscent of the undumpable 2003 SpongeBob plug and play but // with 2 buttons in the top left corner instead of 1 -// +// // The software on both versions of Jellyfish Dodge is believed to be the same, the build date can be seen in // the 'hidden' test mode. // diff --git a/src/mame/drivers/tasc.cpp b/src/mame/drivers/tasc.cpp index 13a0c1ec7c2..e795f1cd1f5 100644 --- a/src/mame/drivers/tasc.cpp +++ b/src/mame/drivers/tasc.cpp @@ -6,7 +6,7 @@ Tasc ChessSystem Commonly known as Tasc R30, it's basically a dedicated ChessMachine. The King chess engines are also compatible with Tasc's The ChessMachine software -on PC, however the prototype Gideon 2.1(internally: Rebel 2.01) is not. +on PC, however the prototype Gideon 3.1(internally: 2.1, Rebel 2.01) is not. WARNING: Don't configure more than 512KB RAM for R30 The King 2.50, it will still be playable but will actually use less than 512KB RAM and become weaker. @@ -378,4 +378,4 @@ ROM_END CONS( 1995, tascr30, 0, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.50)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING | MACHINE_CLICKABLE_ARTWORK ) CONS( 1993, tascr30a, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.20)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING | MACHINE_CLICKABLE_ARTWORK ) CONS( 1993, tascr30b, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (The King 2.23, TM version)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING | MACHINE_CLICKABLE_ARTWORK ) // competed in several chesscomputer tournaments -CONS( 1993, tascr30g, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (Gideon 2.1, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING | MACHINE_CLICKABLE_ARTWORK ) // made in 1993, later released in 2012 +CONS( 1993, tascr30g, tascr30, 0, tasc, tasc, tasc_state, empty_init, "Tasc", "ChessSystem R30 (Gideon 3.1, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_TIMING | MACHINE_CLICKABLE_ARTWORK ) // made in 1993, later released in 2012 diff --git a/src/mame/drivers/tx0.cpp b/src/mame/drivers/tx0.cpp index fcbf223a12e..101992c4b9a 100644 --- a/src/mame/drivers/tx0.cpp +++ b/src/mame/drivers/tx0.cpp @@ -1612,6 +1612,31 @@ void tx0_state::tx0_64kw(machine_config &config) SOFTWARE_LIST(config, "ptp_list").set_original("tx0_ptp").set_filter("64,OLDCODE"); } +void tx0_state::tx0_8kwo(machine_config &config) +{ + tx0_64kw(config); + + /* basic machine hardware */ + /* TX0 CPU @ approx. 167 kHz (no master clock, but the memory cycle time is + approximately 6usec) */ + TX0_8KW_OLD(config.replace(), m_maincpu, 166667); + m_maincpu->cpy().set(FUNC(tx0_state::tx0_io_cpy)); + m_maincpu->r1l().set(FUNC(tx0_state::tx0_io_r1l)); + m_maincpu->dis().set(FUNC(tx0_state::tx0_io_dis)); + m_maincpu->r3l().set(FUNC(tx0_state::tx0_io_r3l)); + m_maincpu->prt().set(FUNC(tx0_state::tx0_io_prt)); + m_maincpu->rsv().set_nop(); + m_maincpu->p6h().set(FUNC(tx0_state::tx0_io_p6h)); + m_maincpu->p7h().set(FUNC(tx0_state::tx0_io_p7h)); + m_maincpu->sel().set(FUNC(tx0_state::tx0_sel)); + m_maincpu->res().set(FUNC(tx0_state::tx0_io_reset_callback)); + m_maincpu->set_addrmap(AS_PROGRAM, &tx0_state::tx0_8kw_map); + /* dummy interrupt: handles input */ + m_maincpu->set_vblank_int("screen", FUNC(tx0_state::tx0_interrupt)); + + SOFTWARE_LIST(config.replace(), "ptp_list").set_original("tx0_ptp").set_filter("8,OLDCODE"); +} + void tx0_state::tx0_8kw(machine_config &config) { tx0_64kw(config); @@ -1642,6 +1667,11 @@ ROM_START(tx0_64kw) /* space filled with our font */ ROM_END +ROM_START(tx0_8kwo) + ROM_REGION(tx0_fontdata_size, "gfx1", ROMREGION_ERASEFF) + /* space filled with our font */ +ROM_END + ROM_START(tx0_8kw) ROM_REGION(tx0_fontdata_size, "gfx1", ROMREGION_ERASEFF) /* space filled with our font */ @@ -1653,6 +1683,7 @@ ROM_END ***************************************************************************/ -// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS -COMP( 1956, tx0_64kw, 0, 0, tx0_64kw, tx0, tx0_state, init_tx0, "MIT", "TX-0 original demonstrator (64 kWords of RAM)", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING) -COMP( 1962, tx0_8kw, tx0_64kw, 0, tx0_8kw, tx0, tx0_state, init_tx0, "MIT", "TX-0 upgraded system (8 kWords of RAM)", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING) +// YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME FLAGS +COMP( 1956, tx0_64kw, tx0_8kw, 0, tx0_64kw, tx0, tx0_state, init_tx0, "MIT", "TX-0 original demonstrator (64 kWords of RAM)", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING) +COMP( 1959, tx0_8kwo, tx0_8kw, 0, tx0_8kwo, tx0, tx0_state, init_tx0, "MIT", "TX-0 upgraded system (8 kWords of RAM, old order code)", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING) +COMP( 1962, tx0_8kw, 0, 0, tx0_8kw, tx0, tx0_state, init_tx0, "MIT", "TX-0 upgraded system (8 kWords of RAM, new order code)", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING) diff --git a/src/mame/includes/pc8001.h b/src/mame/includes/pc8001.h index 12002ed8dcd..d2c4ed50e8f 100644 --- a/src/mame/includes/pc8001.h +++ b/src/mame/includes/pc8001.h @@ -1,11 +1,11 @@ // license:BSD-3-Clause -// copyright-holders:Curt Coder +// copyright-holders:Curt Coder, Angelo Salese + #pragma once #ifndef MAME_INCLUDES_PC8001_H #define MAME_INCLUDES_PC8001_H - #include "cpu/z80/z80.h" #include "imagedev/cassette.h" #include "machine/buffer.h" @@ -15,86 +15,151 @@ #include "machine/i8251.h" #include "machine/ram.h" #include "machine/upd1990a.h" +#include "machine/pc80s31k.h" #include "sound/beep.h" #include "video/upd3301.h" +#include "emupal.h" +#include "screen.h" #define Z80_TAG "z80" +#define N80SR_ROM_TAG "n80sr_rom" #define I8251_TAG "i8251" -#define I8255A_TAG "i8255" #define I8257_TAG "i8257" #define UPD1990A_TAG "upd1990a" #define UPD3301_TAG "upd3301" +#define CGROM_TAG "cgrom" #define CENTRONICS_TAG "centronics" -#define SCREEN_TAG "screen" -class pc8001_state : public driver_device +class pc8001_base_state : public driver_device { public: - pc8001_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, Z80_TAG), - m_rtc(*this, UPD1990A_TAG), - m_dma(*this, I8257_TAG), - m_crtc(*this, UPD3301_TAG), - m_cassette(*this, "cassette"), - m_centronics(*this, CENTRONICS_TAG), - m_cent_data_out(*this, "cent_data_out"), - m_beep(*this, "beeper"), - m_ram(*this, RAM_TAG), - m_rom(*this, Z80_TAG), - m_char_rom(*this, UPD3301_TAG) - { } + pc8001_base_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, Z80_TAG) + , m_crtc(*this, UPD3301_TAG) + , m_crtc_palette(*this, "crtc_palette") + , m_dma(*this, I8257_TAG) + , m_cassette(*this, "cassette") + , m_cgrom(*this, CGROM_TAG) + {} +protected: required_device<cpu_device> m_maincpu; - required_device<upd1990a_device> m_rtc; - required_device<i8257_device> m_dma; required_device<upd3301_device> m_crtc; + required_device<palette_device> m_crtc_palette; + required_device<i8257_device> m_dma; required_device<cassette_image_device> m_cassette; - required_device<centronics_device> m_centronics; - required_device<output_latch_device> m_cent_data_out; - required_device<beep_device> m_beep; - required_device<ram_device> m_ram; - required_memory_region m_rom; - required_memory_region m_char_rom; + required_memory_region m_cgrom; + void port30_w(u8 data); virtual void machine_start() override; + void set_screen_frequency(bool is_24KHz) { m_screen_is_24KHz = is_24KHz; }; - void port10_w(uint8_t data); - void port30_w(uint8_t data); - uint8_t port40_r(); - void port40_w(uint8_t data); + DECLARE_WRITE_LINE_MEMBER( crtc_reverse_w ); + UPD3301_DRAW_CHARACTER_MEMBER( draw_text ); + UPD3301_FETCH_ATTRIBUTE( attr_fetch ); DECLARE_WRITE_LINE_MEMBER( hrq_w ); uint8_t dma_mem_r(offs_t offset); +private: + bool m_screen_reverse; + bool m_screen_is_24KHz; + /* video state */ int m_width80; int m_color; +}; + +class pc8001_state : public pc8001_base_state +{ +public: + pc8001_state(const machine_config &mconfig, device_type type, const char *tag) + : pc8001_base_state(mconfig, type, tag) + , m_pc80s31(*this, "pc80s31") + , m_rtc(*this, UPD1990A_TAG) + , m_screen(*this, "screen") + , m_centronics(*this, CENTRONICS_TAG) + , m_cent_data_out(*this, "cent_data_out") + , m_beep(*this, "beeper") + , m_ram(*this, RAM_TAG) + , m_rom(*this, Z80_TAG) + { } + + void pc8001(machine_config &config); + +protected: + void pc8001_io(address_map &map); + void pc8001_map(address_map &map); + + virtual void machine_start() override; + virtual void machine_reset() override; + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + + required_device<pc80s31_device> m_pc80s31; + required_device<upd1990a_device> m_rtc; + required_device<screen_device> m_screen; + required_device<centronics_device> m_centronics; + required_device<output_latch_device> m_cent_data_out; + required_device<beep_device> m_beep; + required_device<ram_device> m_ram; + required_memory_region m_rom; + +private: + void port10_w(uint8_t data); + uint8_t port40_r(); + void port40_w(uint8_t data); int m_centronics_busy; int m_centronics_ack; DECLARE_WRITE_LINE_MEMBER(write_centronics_busy); DECLARE_WRITE_LINE_MEMBER(write_centronics_ack); - UPD3301_DRAW_CHARACTER_MEMBER( pc8001_display_pixels ); - void pc8001(machine_config &config); - void pc8001_io(address_map &map); - void pc8001_mem(address_map &map); }; class pc8001mk2_state : public pc8001_state { public: pc8001mk2_state(const machine_config &mconfig, device_type type, const char *tag) - : pc8001_state(mconfig, type, tag), - m_kanji_rom(*this, "kanji") + : pc8001_state(mconfig, type, tag) + , m_kanji_rom(*this, "kanji") + , m_dsw(*this, "DSW%d", 1U) { } - required_memory_region m_kanji_rom; - - void port31_w(uint8_t data); void pc8001mk2(machine_config &config); + +protected: void pc8001mk2_io(address_map &map); - void pc8001mk2_mem(address_map &map); + void pc8001mk2_map(address_map &map); + + required_memory_region m_kanji_rom; + required_ioport_array<2> m_dsw; +private: + void port31_w(uint8_t data); +}; + +class pc8001mk2sr_state : public pc8001mk2_state +{ +public: + pc8001mk2sr_state(const machine_config &mconfig, device_type type, const char *tag) + : pc8001mk2_state(mconfig, type, tag) + , m_n80sr_rom(*this, N80SR_ROM_TAG) + { } + + void pc8001mk2sr(machine_config &config); + +private: + virtual void machine_start() override; + virtual void machine_reset() override; + void pc8001mk2sr_io(address_map &map); + + required_memory_region m_n80sr_rom; + + void port33_w(u8 data); + u8 port71_r(); + void port71_w(u8 data); + + u8 m_n80sr_bank; }; #endif diff --git a/src/mame/includes/pc8801.h b/src/mame/includes/pc8801.h index 5365f1d6094..5b76aeb2945 100644 --- a/src/mame/includes/pc8801.h +++ b/src/mame/includes/pc8801.h @@ -5,12 +5,12 @@ PC-8801 (c) 1981 NEC ********************************************************************************************/ + #ifndef MAME_INCLUDES_PC8801_H #define MAME_INCLUDES_PC8801_H #pragma once - #include "cpu/z80/z80.h" #include "bus/centronics/ctronics.h" #include "imagedev/cassette.h" @@ -20,7 +20,7 @@ #include "machine/i8255.h" #include "machine/timer.h" #include "machine/upd1990a.h" -#include "machine/upd765.h" +#include "machine/pc80s31k.h" #include "sound/beep.h" #include "sound/ymopn.h" #include "emupal.h" @@ -41,9 +41,7 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_screen(*this, "screen") - , m_fdccpu(*this, "fdccpu") - , m_fdc(*this, "upd765") - , m_fdd(*this, "upd765:%u", 0U) + , m_pc80s31(*this, "pc80s31") , m_pic(*this, I8214_TAG) , m_rtc(*this, UPD1990A_TAG) , m_cassette(*this, "cassette") @@ -53,16 +51,28 @@ public: , m_palette(*this, "palette") { } - void pc8801mc(machine_config &config); - void pc8801fh(machine_config &config); void pc8801(machine_config &config); + void pc8801mk2mr(machine_config &config); + void pc8801fh(machine_config &config); void pc8801ma(machine_config &config); + void pc8801mc(machine_config &config); protected: virtual void video_start() override; virtual void machine_start() override; virtual void machine_reset() override; + required_device<cpu_device> m_maincpu; + required_device<screen_device> m_screen; + required_device<pc80s31_device> m_pc80s31; + optional_device<i8214_device> m_pic; + required_device<upd1990a_device> m_rtc; + required_device<cassette_image_device> m_cassette; + required_device<beep_device> m_beeper; + required_device<ym2608_device> m_opna; + required_device<ym2203_device> m_opn; + required_device<palette_device> m_palette; + private: struct crtc_t { @@ -78,19 +88,6 @@ private: attotime time; }; - required_device<cpu_device> m_maincpu; - required_device<screen_device> m_screen; - required_device<cpu_device> m_fdccpu; - required_device<upd765a_device> m_fdc; - required_device_array<floppy_connector, 2> m_fdd; - optional_device<i8214_device> m_pic; - required_device<upd1990a_device> m_rtc; - required_device<cassette_image_device> m_cassette; - required_device<beep_device> m_beeper; - required_device<ym2608_device> m_opna; - required_device<ym2203_device> m_opn; - required_device<palette_device> m_palette; - std::unique_ptr<uint8_t[]> m_work_ram; std::unique_ptr<uint8_t[]> m_hi_work_ram; std::unique_ptr<uint8_t[]> m_ext_work_ram; diff --git a/src/mame/includes/tx0.h b/src/mame/includes/tx0.h index 37eb320b803..76b12820c7d 100644 --- a/src/mame/includes/tx0.h +++ b/src/mame/includes/tx0.h @@ -145,6 +145,7 @@ public: { } void tx0_64kw(machine_config &config); + void tx0_8kwo(machine_config &config); void tx0_8kw(machine_config &config); void init_tx0(); diff --git a/src/mame/layout/ace_sp_dmd.lay b/src/mame/layout/ace_sp_dmd.lay index e00e8abeabd..d3876c787e2 100644 --- a/src/mame/layout/ace_sp_dmd.lay +++ b/src/mame/layout/ace_sp_dmd.lay @@ -14,7 +14,7 @@ license:CC0 <color state="0" red="0.125" green="0.125" blue="0.125" /> </disk> </element> - + <group name="dmd"> <repeat count="24"> <param name="s" start="0" increment="64" /> diff --git a/src/mame/machine/ace_sp_reelctrl.cpp b/src/mame/machine/ace_sp_reelctrl.cpp index b4fd316b235..dbec9211045 100644 --- a/src/mame/machine/ace_sp_reelctrl.cpp +++ b/src/mame/machine/ace_sp_reelctrl.cpp @@ -42,7 +42,7 @@ void ace_sp_reelctrl_base_device::device_add_mconfig(machine_config &config) } ROM_START( ace_sp_reelctrl ) - ROM_REGION16_BE( 0x0800, "mcu", 0 ) + ROM_REGION16_BE( 0x0800, "mcu", 0 ) ROM_LOAD( "ace reel mcu v9 _space_.bin", 0, 0x0800, CRC(d7b91fe0) SHA1(44f78da8138caf4f79f1e8e9a2abe53d79c0fe79) ) // MC68705P3 internal ROM ROM_END @@ -52,7 +52,7 @@ const tiny_rom_entry *ace_sp_reelctrl_device::device_rom_region() const } ROM_START( ace_sp_reelctrl_pcp ) - ROM_REGION16_BE( 0x0800, "mcu", 0 ) + ROM_REGION16_BE( 0x0800, "mcu", 0 ) ROM_LOAD( "pcp reel mcu fcr 1 _space_.bin", 0, 0x0800, CRC(1c8019bf) SHA1(d1d6ea68d9aace4a4ea0de212f17426bccfe5856) ) // MC68705P3 internal ROM ROM_END diff --git a/src/mame/machine/nes.cpp b/src/mame/machine/nes.cpp index 29831ada9a8..2f4e29e5323 100644 --- a/src/mame/machine/nes.cpp +++ b/src/mame/machine/nes.cpp @@ -80,6 +80,7 @@ void nes_state::machine_start() BMC_800IN1, BMC_8157, BMC_GOLD150, + BMC_TELETUBBIES, BMC_VT5201, BTL_PALTHENA, CAMERICA_ALADDIN, diff --git a/src/mame/machine/pc80s31k.cpp b/src/mame/machine/pc80s31k.cpp new file mode 100644 index 00000000000..eb05acb8cfd --- /dev/null +++ b/src/mame/machine/pc80s31k.cpp @@ -0,0 +1,460 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, Olivier Galibert +/************************************************************************************************** + + NEC PC-80S31(K) Mini Disk Unit + + Z80 + μPD765 + PPI that connects in cross with an host PPI + + "Mini" as compared to the PC-8881 8-inch floppy I/F + + Design is decidedly derived from Epson TF-20 and friends, + cfr. devices/bus/epson_sio/tf20.cpp + + TODO: + - What's PC-80S32? Is it the 88VA version or a different beast? + - PC=0x7dd reads from FDC bit 3 in ST3 (twosid_r fn), + expecting a bit 3 high for all the PC8001 games otherwise keeps looping and eventually dies. + Are those incorrectly identified as 2DD? Hacked to work for now; + - set_input_line_vector fn doesn't work properly when issued from a device_reset, + we currently just implement the irq_callback instead; + - Bus option; + - Cascade mode, i.e. the CN2 connector used to accept a second disk unit for drive 2 & 3; + - pc80s31k: verify that irq vector write (I/O port $f0) belongs here or just + whatever PC88VA uses. + - printer interface (used for debugging? 4-bit serial?) + - Pinpoint what host I/O ports $f6, $f7 truly are + (direct FDC access from this device or a different beast? cfr. play6lim with pc8001mk2) + - filemst tries to access undocumented I/O port $09 at PC=5000: + \- If that's 0 then it tries to read a vector at [0x8000]; + \- It then tries to read at memory [0xc0ff], set the value read in [0xf012]; + \- Expects that ROM [0x0000] is not equal to 0xc3; + Bottom line: Is it trying to access some custom HW? + +=================================================================================================== + +PCB (PC-80S31K) + +=================================================================================================== + + |--------------------------------------| + | P1 P2 P3 X1 | + | | + | CN2 | + | B6102C022 | + | FD1 FD2 (**) | + | | | | + | CN1 ------- D765AC D2364EC (*)| + | (*)| + | D8255AC-2 B6101C017 D780C-1 | + | | + |--------------------------------------| + + PCB is marked PC-80S31KFDC NEC-14T + P1, P2, P3 are power supplies (+5V, +12V, -5V for P1, lacks -5V for the other two) + μPD2364EC is at position IC13, it's a 8192 size ROM. (***) + (*) are μPD41416C + (**) marked as JP, unpopulated x 3; + μPB6101/2 are bipolar TTL gate arrays, presumably + Cannot read marking of X1 (8 MHz?) + + (***) Given this, we guess that PC80S31 is the 2D version while the 'K + variant is the 2D/2DD/2HD version. + +=================================================================================================== + +Command Protocol + +=================================================================================================== + +Command & parameters are normally communicated from Host via port B +(read on port A on FDC side) +An RPi implementation can be seen at https://github.com/MinatsuT/RPi_PC-80S31 + +[0x00] Initialize +[0x01] Write to disk + %1 number of sectors + %2 drive number + %3 track number + %4 sector number +1 +[0x02] Read from disk + %1 number of sectors + %2 drive number + %3 track number + %4 sector number +1 +[0x03] Send data to host +[0x04] Copy data in-place + %1 number of sectors + %2 source drive + %3 source track + %4 source sector number +1 + %5 destination drive + %6 destination track + %7 destination sector number +1 +[0x05] Format + %1 drive number +[0x06] Send result status to Host + x--- ---- I/O complete + -x-- ---- has unread buffer + ---- ---x error occurred +[0x07] Drive status +[0x0b] Send memory data +%1-%2 address start +%3-%4 length +[0x11] Fast write to disk + %1 number of sectors + %2 drive number + %3 track number + %4 sector number +1 +[0x12] Fast send data + (picks up number of sector etc. from previous issued commands?) +[0x14] Device status + x--- ---- ESIG: error + -x-- ---- WPDR: write protected + --x- ---- RDY: ready + ---x ---- TRK0: track 0 + ---- x--- DSDR: double sided drive + ---- -x-- HDDR: head + ---- --xx DS1, DS2: drive select + (same as 765 ST3?) +[0x17] Mode change + %1 ---- xxxx mode select + +FDC normally puts ST0-1-2 to RAM buffers $7f0d-f, CHRN data in $7f10-13 + +=================================================================================================== + +Port C +Used as a communication protocol flags + +=================================================================================================== + + Host side + (swap 4-bit nibbles and r/w direction for FDC side, all bits are active high): + x--- ---- (w) ATN AtenTioN: + host sends a command to FDC, interrupts current one + (looks unconnected the other way around?) + -x-- ---- (w) DAC DAta aCcepted: + host just picked up data from FDC + --x- ---- (w) RFD Ready For Data: + host requests data from FDC + ---x ---- (w) DAV DAta Valid: + host outputs data to port B + ---- -x-- (r) DAC DAta aCcepted: + FDC has accepted data from port B + ---- --x- (r) RFD Ready For Data: + FDC requests data from host + ---- ---x (r) DAV DAta Valid: + FDC has output data to port A + +**************************************************************************************************/ + +#include "emu.h" +#include "pc80s31k.h" + +//#define VERBOSE 1 +#include "logmacro.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + + +// device type definition +DEFINE_DEVICE_TYPE(PC80S31, pc80s31_device, "pc80s31", "NEC PC-80S31 Mini Disk Unit I/F") +DEFINE_DEVICE_TYPE(PC80S31K, pc80s31k_device, "pc80s31k", "NEC PC-80S31K Mini Disk Unit I/F") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + + +//------------------------------------------------- +// pc80s31_device - constructor +//------------------------------------------------- + + +pc80s31_device::pc80s31_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_fdc(*this, "fdc") + , m_floppy(*this, "fdc:%u", 0U) + , m_fdc_cpu(*this, "fdc_cpu") + , m_fdc_rom(*this, "fdc_rom") + , m_ppi_host(*this, "ppi_host") + , m_ppi_fdc(*this, "ppi_fdc") + , m_latch(*this, "latch_%u", 0U) +{ +} + + +pc80s31_device::pc80s31_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pc80s31_device(mconfig, PC80S31, tag, owner, clock) +{ + +} + +ROM_START( pc80s31 ) + // TODO: exact identification of these + ROM_REGION( 0x2000, "fdc_rom", ROMREGION_ERASEFF ) + ROM_SYSTEM_BIOS( 0, "disk", "disk BIOS" ) + ROMX_LOAD( "disk.rom", 0x0000, 0x0800, CRC(2158d307) SHA1(bb7103a0818850a039c67ff666a31ce49a8d516f), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "mk2fr", "mkIIFR disk BIOS" ) + ROMX_LOAD( "mk2fr_disk.rom", 0x0000, 0x0800, CRC(2163b304) SHA1(80da2dee49d4307f00895a129a5cfeff00cf5321), ROM_BIOS(1) ) + + ROM_FILL( 0x7df, 1, 0x00 ) + ROM_FILL( 0x7e0, 1, 0x00 ) +ROM_END + +const tiny_rom_entry *pc80s31_device::device_rom_region() const +{ + return ROM_NAME( pc80s31 ); +} + +//------------------------------------------------- +// device_add_mconfig - device-specific machine +// configuration addiitons +//------------------------------------------------- + +void pc80s31_device::host_map(address_map &map) +{ + map(0, 3).rw(m_ppi_host, FUNC(i8255_device::read), FUNC(i8255_device::write)); +} + +void pc80s31_device::fdc_map(address_map &map) +{ + map(0x0000, 0x1fff).rom().region("fdc_rom", 0); + map(0x4000, 0x7fff).ram(); +} + +void pc80s31_device::fdc_io(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0xff); +// map(0x09, 0x09).r accessed by filemst (pc8801), cfr. notes + +// map(0xf0, 0xf0).w(FUNC(pc8801_state::fdc_irq_vector_w)); // Interrupt Opcode Port +// map(0xf4, 0xf4).w(FUNC(pc8801_state::fdc_drive_mode_w)); // Drive mode, 2d, 2dd, 2hd +// map(0xf6, 0xf6).nopw(); // printer related + map(0xf7, 0xf7).nopw(); // printer port output + map(0xf8, 0xf8).rw(FUNC(pc80s31_device::terminal_count_r), FUNC(pc80s31_device::motor_control_w)); + map(0xfa, 0xfb).m(m_fdc, FUNC(upd765a_device::map)); + map(0xfc, 0xff).rw(m_ppi_fdc, FUNC(i8255_device::read), FUNC(i8255_device::write)); +} + +static void pc88_floppies(device_slot_interface &device) +{ + // TODO: definitely not correct for base device + device.option_add("525hd", FLOPPY_525_HD); +} + +IRQ_CALLBACK_MEMBER(pc80s31_device::irq_cb) +{ + return m_irq_vector; +} + +void pc80s31_device::device_add_mconfig(machine_config &config) +{ + constexpr XTAL fdc_xtal = XTAL(4'000'000); + Z80(config, m_fdc_cpu, fdc_xtal); + m_fdc_cpu->set_addrmap(AS_PROGRAM, &pc80s31_device::fdc_map); + m_fdc_cpu->set_addrmap(AS_IO, &pc80s31_device::fdc_io); + m_fdc_cpu->set_irq_acknowledge_callback(FUNC(pc80s31_device::irq_cb)); + + UPD765A(config, m_fdc, XTAL(4'000'000), true, true); + m_fdc->intrq_wr_callback().set_inputline(m_fdc_cpu, INPUT_LINE_IRQ0); + + for (auto &floppy : m_floppy) + { + FLOPPY_CONNECTOR(config, floppy, pc88_floppies, "525hd", floppy_image_device::default_mfm_floppy_formats); + floppy->enable_sound(true); + } + + for (auto &latch : m_latch) + GENERIC_LATCH_8(config, latch); + + I8255A(config, m_ppi_host); + m_ppi_host->in_pa_callback().set(FUNC(pc80s31_device::latch_r<0>)); + m_ppi_host->out_pa_callback().set(FUNC(pc80s31_device::latch_w<1>)); + m_ppi_host->in_pb_callback().set(FUNC(pc80s31_device::latch_r<2>)); + m_ppi_host->out_pb_callback().set(FUNC(pc80s31_device::latch_w<3>)); + m_ppi_host->in_pc_callback().set(FUNC(pc80s31_device::latch_r<4>)); + m_ppi_host->out_pc_callback().set(FUNC(pc80s31_device::latch_w<5>)); + + // 8255AC-2 + I8255A(config, m_ppi_fdc); + m_ppi_fdc->in_pa_callback().set(FUNC(pc80s31_device::latch_r<3>)); + m_ppi_fdc->out_pa_callback().set(FUNC(pc80s31_device::latch_w<2>)); + m_ppi_fdc->in_pb_callback().set(FUNC(pc80s31_device::latch_r<1>)); + m_ppi_fdc->out_pb_callback().set(FUNC(pc80s31_device::latch_w<0>)); + m_ppi_fdc->in_pc_callback().set(FUNC(pc80s31_device::latch_r<5>)); + m_ppi_fdc->out_pc_callback().set(FUNC(pc80s31_device::latch_w<4>)); +} + +//------------------------------------------------- +// device_timer - device-specific timers +//------------------------------------------------- + +void pc80s31_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + assert(id == 0); + + m_fdc->tc_w(false); + + // several games tries to scan invalid IDs from their structures, if this hits then + // it's possibly an attempt to scan a missing sector from the floppy structure. + // cfr. acrojet: the third read data command issued tries to access a CHRN of (0, 0, 16, 256) + // and checks at PC=500B if any of these status flags are satisfied: + // ST0 & 0xdf + // ST1 & 0xff + // ST2 & 0x73 + // Data doesn't matter, it also seems to have some activity to the printer port + // (debugging left on?) + if ((u8)m_fdc_cpu->state_int(Z80_HALT) == 1) + { + logerror("%s: attempt to trigger TC while in HALT state (read ID copy protection warning)\n", machine().describe_context()); +// throw emu_fatalerror("copy protection hit"); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pc80s31_device::device_start() +{ + m_tc_zero_timer = timer_alloc(0); + + save_item(NAME(m_irq_vector)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + + +void pc80s31_device::device_reset() +{ + m_floppy[0]->get_device()->set_rpm(300); + m_floppy[1]->get_device()->set_rpm(300); + m_fdc->set_rate(250000); + + // TODO: doesn't seem to work for devices? + m_fdc_cpu->set_input_line_vector(0, 0); + m_irq_vector = 0; + + m_tc_zero_timer->adjust(attotime::never); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +// Comms are simple dual port connected in cross fashion. +// Even at "perfect" interleave tho we need to mailbox the connections. +// - barbatus will hang at Artec logo the first time around (works if you soft reset); +template <unsigned N> u8 pc80s31_device::latch_r() +{ + const int port_mask = N & 4 ? 0x0f : 0xff; +// machine().scheduler().synchronize(); + return m_latch[N]->read() & port_mask; +} + +template <unsigned N> void pc80s31_device::latch_w(u8 data) +{ + const int lower_nibble = N & 4; +// machine().scheduler().synchronize(); + if (lower_nibble) + { + LOG("%s: %s port C write %02x (ATN=%d DAC=%d RFD=%d DAV=%d)\n" + , N & 1 ? "host" : "fdc" + , machine().describe_context() + , data + , BIT(data, 7) + , BIT(data, 6) + , BIT(data, 5) + , BIT(data, 4) + ); + } + return m_latch[N]->write(data >> lower_nibble); +} + +u8 pc80s31_device::terminal_count_r(address_space &space) +{ + if (!machine().side_effects_disabled()) + { + m_fdc->tc_w(true); + // TODO: accurate time of this going off + m_tc_zero_timer->reset(); + m_tc_zero_timer->adjust(attotime::from_usec(50)); + } + // value is meaningless (never readback) + // TODO: verify this being 0xff or open bus + return space.unmap(); +} + +void pc80s31_device::motor_control_w(uint8_t data) +{ + // FIXME: on pc80s31k device (particularly on later releases) this stays always on + // babylon: just spins indefinitely at PC=6d8 (using the internal routines), + // waiting for DAV or ATN being on. Never hits the port until a flag is issued. + // prajator: on idle times it spins at PC=7060, waiting for ATN and keep issuing a 0xff here. + // valis2: calls PC=7009 subroutine for idle, waits for ATN on. + // It eventually writes a 0 here, not before an extremely long time + // (~10000 frames!) + m_floppy[0]->get_device()->mon_w(!(data & 1)); + m_floppy[1]->get_device()->mon_w(!(data & 2)); + + // TODO: according to docs a value of 0x07 enables precompensation to tracks 0-19, 0xf enables it on 20-39 +} + +//************************************************************************** +// +// PC80S31K device overrides +// +//************************************************************************** + +pc80s31k_device::pc80s31k_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pc80s31_device(mconfig, PC80S31K, tag, owner, clock) +{ + +} + +ROM_START( pc80s31k ) + // TODO: exact identification of these + ROM_REGION( 0x2000, "fdc_rom", ROMREGION_ERASEFF ) + ROM_SYSTEM_BIOS( 0, "ma", "MA disk BIOS") + ROMX_LOAD( "ma_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004), ROM_BIOS(0) ) + ROM_SYSTEM_BIOS( 1, "mk2mr", "mkIIMR disk BIOS" ) + ROMX_LOAD( "m2mr_disk.rom", 0x0000, 0x2000, CRC(2447516b) SHA1(1492116f15c426f9796dc2bb6fcccf2656c0ca75), ROM_BIOS(1) ) + ROM_SYSTEM_BIOS( 2, "mh", "MH disk BIOS" ) + ROMX_LOAD( "mh_disk.rom", 0x0000, 0x2000, CRC(a222ecf0) SHA1(79e9c0786a14142f7a83690bf41fb4f60c5c1004), ROM_BIOS(2) ) + // TODO: this may belong to PC-80S32 + ROM_SYSTEM_BIOS( 3, "88va", "PC88VA disk BIOS") + ROMX_LOAD( "vasubsys.rom", 0x0000, 0x2000, CRC(08962850) SHA1(a9375aa480f85e1422a0e1385acb0ea170c5c2e0), ROM_BIOS(3) ) +ROM_END + +const tiny_rom_entry *pc80s31k_device::device_rom_region() const +{ + return ROM_NAME( pc80s31k ); +} + +void pc80s31k_device::drive_mode_w(uint8_t data) +{ + // TODO: fix implementation + // anything that isn't a 2D doesn't really set proper parameters in here + logerror("FDC drive mode %02x\n", data); + m_floppy[0]->get_device()->set_rpm(BIT(data, 0) ? 360 : 300); + m_floppy[1]->get_device()->set_rpm(BIT(data, 1) ? 360 : 300); + + m_fdc->set_rate(BIT(data, 5) ? 500000 : 250000); +} + +void pc80s31k_device::fdc_io(address_map &map) +{ + pc80s31_device::fdc_io(map); + + map(0xf0, 0xf0).lw8(NAME([this] (u8 data) { m_irq_vector = data; })); + map(0xf4, 0xf4).w(FUNC(pc80s31k_device::drive_mode_w)); +} diff --git a/src/mame/machine/pc80s31k.h b/src/mame/machine/pc80s31k.h new file mode 100644 index 00000000000..b21d2845daf --- /dev/null +++ b/src/mame/machine/pc80s31k.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + +NEC PC-80S31K + +***************************************************************************/ + +#ifndef MAME_MACHINE_PC80S31K_H +#define MAME_MACHINE_PC80S31K_H + +#pragma once + +#include "cpu/z80/z80.h" +#include "imagedev/floppy.h" +#include "machine/gen_latch.h" +#include "machine/i8255.h" +#include "machine/upd765.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class pc80s31_device : public device_t +{ +public: + // construction/destruction + pc80s31_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void host_map(address_map &map); + +protected: + pc80s31_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + //virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + virtual void fdc_io(address_map &map); + + required_device<upd765a_device> m_fdc; + required_device_array<floppy_connector, 2> m_floppy; + u8 m_irq_vector; + +private: + required_device<z80_device> m_fdc_cpu; + required_memory_region m_fdc_rom; + required_device<i8255_device> m_ppi_host; + required_device<i8255_device> m_ppi_fdc; + required_device_array<generic_latch_8_device, 6> m_latch; + + void fdc_map(address_map &map); + + template <unsigned N> u8 latch_r(); + template <unsigned N> void latch_w(u8 data); + + u8 terminal_count_r(address_space &space); + void motor_control_w(u8 data); + + emu_timer *m_tc_zero_timer; + + IRQ_CALLBACK_MEMBER(irq_cb); +}; + +class pc80s31k_device : public pc80s31_device +{ +public: + pc80s31k_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual const tiny_rom_entry *device_rom_region() const override; + virtual void fdc_io(address_map &map) override; + +private: + void drive_mode_w(u8 data); +}; + +// device type definition +DECLARE_DEVICE_TYPE(PC80S31, pc80s31_device) +DECLARE_DEVICE_TYPE(PC80S31K, pc80s31k_device) + +#endif // MAME_MACHINE_PC80S31K_H diff --git a/src/mame/mame.lst b/src/mame/mame.lst index a3ebb528f54..501fba57489 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -19380,6 +19380,7 @@ vsnetscreb // 1996.?? GX627 (Europe) vsnetscrj // 1996.12 GX627 (Japan) vsnetscru // 1996.?? GX627 (US) winspike // 1997.?? GX705 (Europe) +winspikea // 1997.?? GX705 (Asia) winspikej // 1997.07 GX705 (Japan) @source:konamim2.cpp @@ -33855,8 +33856,9 @@ pc6001sr // pc6601 // @source:pc8001.cpp -pc8001 // -pc8001mk2 // +pc8001 // 1979 +pc8001mk2 // 1983 +pc8001mk2sr // 1985 @source:pc8401a.cpp pc8401a // roms needed @@ -36970,6 +36972,7 @@ hisaturn // Hitachi HiSaturn saturn // 1995 Sega Saturn (USA) saturneu // 1995 Sega Saturn (Europe) saturnjp // 1994 Sega Saturn (Japan) +saturnkr // 1995 Samsung Saturn (Korea) vsaturn // JVC V-Saturn @source:sauro.cpp @@ -41735,6 +41738,7 @@ twinsed2 // (c) 1994 Electronic Devices @source:tx0.cpp tx0_64kw // April 1956 MIT TX-0 (64kw RAM) +tx0_8kwo // 1959 MIT TX-0 (8kw RAM) tx0_8kw // 1962 MIT TX-0 (8kw RAM) @source:tx1.cpp diff --git a/src/mame/video/apple2.cpp b/src/mame/video/apple2.cpp index 91babf1809a..683002f8bb9 100644 --- a/src/mame/video/apple2.cpp +++ b/src/mame/video/apple2.cpp @@ -786,6 +786,66 @@ void a2_video_device::text_update(screen_device &screen, bitmap_ind16 &bitmap, c } } +void a2_video_device::text_update_inverse(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow) +{ + uint8_t const *const aux_page = m_aux_ptr ? m_aux_ptr : m_ram_ptr; + + uint32_t const start_address = m_page2 ? 0x800 : 0x400; + + beginrow = (std::max)(beginrow, cliprect.top() - (cliprect.top() % 8)); + endrow = (std::min)(endrow, cliprect.bottom() - (cliprect.bottom() % 8) + 7); + + const int startrow = (beginrow / 8) * 8; + const int stoprow = ((endrow / 8) + 1) * 8; + const int startcol = (cliprect.left() / 14); + const int stopcol = ((cliprect.right() / 14) + 1); + + //printf("TXT: row %d startcol %d stopcol %d left %d right %d\n", beginrow, startcol, stopcol, cliprect.left(), cliprect.right()); + + int fg = 0; + int bg = 0; + switch (m_sysconfig & 0x03) + { + case 0: case 4: bg = WHITE; break; + case 1: bg = WHITE; break; + case 2: bg = GREEN; break; + case 3: bg = ORANGE; break; + } + + for (int row = startrow; row < stoprow; row += 8) + { + if (m_80col) + { + for (int col = startcol; col < stopcol; col++) + { + /* calculate address */ + uint32_t const address = start_address + ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)); + + plot_text_character(bitmap, col * 14, row, 1, aux_page[address], + fg, bg); + plot_text_character(bitmap, col * 14 + 7, row, 1, m_ram_ptr[address], + fg, bg); + } + } + else + { + for (int col = startcol; col < stopcol; col++) + { + /* calculate address */ + uint32_t const address = start_address + ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)); + if (((m_sysconfig & 7) == 4) && (m_dhires)) + { + u8 tmp = aux_page[address]; + fg = tmp>>4; + bg = tmp & 0xf; + } + + plot_text_character(bitmap, col * 14, row, 2, m_ram_ptr[address], fg, bg); + } + } + } +} + void a2_video_device::text_update_orig(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow) { int row, col; diff --git a/src/mame/video/apple2.h b/src/mame/video/apple2.h index f03fd6a596a..70af5a1d986 100644 --- a/src/mame/video/apple2.h +++ b/src/mame/video/apple2.h @@ -51,6 +51,7 @@ public: DECLARE_WRITE_LINE_MEMBER(an2_w); void text_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); + void text_update_inverse(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); void text_update_ultr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); void text_update_orig(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); void text_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow); diff --git a/src/mame/video/kikikai.cpp b/src/mame/video/kikikai.cpp index 9105d1f23b8..6e3f96011e7 100644 --- a/src/mame/video/kikikai.cpp +++ b/src/mame/video/kikikai.cpp @@ -18,74 +18,63 @@ void kikikai_state::main_bankswitch_w(uint8_t data) uint32_t kikikai_state::screen_update_kicknrun(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - int offs; - int sx, sy, xc, yc; - int gfx_num, gfx_attr, gfx_offs; - - - /* Bubble Bobble doesn't have a real video RAM. All graphics (characters */ - /* and sprites) are stored in the same memory region, and information on */ - /* the background character columns is stored inthe area dd00-dd3f */ + // Similar to bublbobl.cpp, Video hardware generates sprites only. bitmap.fill(255, cliprect); - sx = 0; + int sx = 0; - /* the score display seems to be outside of the main objectram. */ - for (offs = 0x1500; offs < 0x2000; offs += 4) + // the score display seems to be outside of the main objectram + for (int offs = 0x1500; offs < 0x2000; offs += 4) { - int height; - if (offs >= 0x1800 && offs < 0x1980) continue; if (offs >= 0x19c0) continue; - /* skip empty sprites */ - /* this is dword aligned so the uint32_t * cast shouldn't give problems */ - /* on any architecture */ + // skip empty sprites + // this is dword aligned so the uint32_t * cast shouldn't give problems on any architecture if (*(uint32_t *)(&m_mainram[offs]) == 0) continue; - gfx_num = m_mainram[offs + 1]; - gfx_attr = m_mainram[offs + 3]; + const int gfx_num = m_mainram[offs + 1]; + const int gfx_attr = m_mainram[offs + 3]; - if (!BIT(gfx_num, 7)) /* 16x16 sprites */ + int gfx_offs, height; + if (!BIT(gfx_num, 7)) // 16x16 sprites { gfx_offs = ((gfx_num & 0x1f) * 0x80) + ((gfx_num & 0x60) >> 1) + 12; height = 2; } - else /* tilemaps (each sprite is a 16x256 column) */ + else // tilemaps (each sprite is a 16x256 column) { gfx_offs = ((gfx_num & 0x3f) * 0x80); height = 32; } - if ((gfx_num & 0xc0) == 0xc0) /* next column */ + if ((gfx_num & 0xc0) == 0xc0) // next column sx += 16; else { sx = m_mainram[offs + 2]; //if (gfx_attr & 0x40) sx -= 256; } - sy = 256 - height * 8 - (m_mainram[offs + 0]); + const int sy = 256 - height * 8 - (m_mainram[offs + 0]); - for (xc = 0; xc < 2; xc++) + for (int xc = 0; xc < 2; xc++) { - for (yc = 0; yc < height; yc++) + for (int yc = 0; yc < height; yc++) { - int goffs, code, color, flipx, flipy, x, y; - - goffs = gfx_offs + xc * 0x40 + yc * 0x02; - code = m_mainram[goffs] + ((m_mainram[goffs + 1] & 0x07) << 8) + const int goffs = gfx_offs + xc * 0x40 + yc * 0x02; + const int code = m_mainram[goffs] + ((m_mainram[goffs + 1] & 0x07) << 8) + ((m_mainram[goffs + 1] & 0x80) << 4) + (m_charbank << 12); - color = ((m_mainram[goffs + 1] & 0x38) >> 3) + ((gfx_attr & 0x02) << 2); - flipx = m_mainram[goffs + 1] & 0x40; - flipy = 0; + const int color = ((m_mainram[goffs + 1] & 0x38) >> 3) + ((gfx_attr & 0x02) << 2); + const int flipx = m_mainram[goffs + 1] & 0x40; + const int flipy = 0; - //x = sx + xc * 8; - x = (sx + xc * 8) & 0xff; - y = (sy + yc * 8) & 0xff; + //const int x = sx + xc * 8; + const int x = (sx + xc * 8) & 0xff; + const int y = (sy + yc * 8) & 0xff; m_gfxdecode->gfx(0)->transpen(bitmap,cliprect, code, diff --git a/src/mame/video/sknsspr.cpp b/src/mame/video/sknsspr.cpp index 518e2a4bfb5..d474ff0d8da 100644 --- a/src/mame/video/sknsspr.cpp +++ b/src/mame/video/sknsspr.cpp @@ -156,7 +156,7 @@ void sknsspr_device::skns_sprite_kludge(int x, int y) while(ys < sy && yd >= clip.min_y) #define z_draw_pixel() \ - u8 val = src[(xs >> 16) & 0x3f]; \ + u8 val = src[(xs >> 16) & 0x3f]; \ if(val) \ bitmap.pix(yd>>16, xd>>16) = val + colour; diff --git a/src/osd/modules/debugger/debuggdbstub.cpp b/src/osd/modules/debugger/debuggdbstub.cpp index 55f09087f35..9f26fb2c778 100644 --- a/src/osd/modules/debugger/debuggdbstub.cpp +++ b/src/osd/modules/debugger/debuggdbstub.cpp @@ -421,7 +421,7 @@ class debug_gdbstub : public osd_module, public debug_module public: debug_gdbstub() : osd_module(OSD_DEBUG_PROVIDER, "gdbstub"), debug_module(), - m_readbuf_state(PACKET_START), + m_readbuf_state(PACKET_START), m_machine(nullptr), m_maincpu(nullptr), m_state(nullptr), diff --git a/src/osd/modules/debugger/qt/debuggerview.cpp b/src/osd/modules/debugger/qt/debuggerview.cpp index 263fcfe1e73..a1c8bcf2aec 100644 --- a/src/osd/modules/debugger/qt/debuggerview.cpp +++ b/src/osd/modules/debugger/qt/debuggerview.cpp @@ -331,8 +331,8 @@ void DebuggerView::copyVisibleSlot() for (uint32_t col = 0; col < visarea.x; ++col) text += wchar_t(viewdata[col].byte); std::string::size_type const nonblank = text.find_last_not_of("\t\n\v\r "); - if ((nonblank != std::string::npos) && (nonblank >= start)) - text.resize(nonblank + 1); + if (nonblank != std::string::npos) + text.resize((std::max)(start, nonblank + 1)); text += "\n"; } diff --git a/src/osd/modules/debugger/win/debugviewinfo.cpp b/src/osd/modules/debugger/win/debugviewinfo.cpp index d6e94c1ba3e..6965d032dfa 100644 --- a/src/osd/modules/debugger/win/debugviewinfo.cpp +++ b/src/osd/modules/debugger/win/debugviewinfo.cpp @@ -320,8 +320,8 @@ void debugview_info::handle_context_menu(unsigned command) for (uint32_t col = 0; col < visarea.x; ++col) text += wchar_t(viewdata[col].byte); std::wstring::size_type const nonblank = text.find_last_not_of(L"\t\n\v\r "); - if ((nonblank != std::wstring::npos) && (nonblank >= start)) - text.resize(nonblank + 1); + if (nonblank != std::wstring::npos) + text.resize((std::max)(start, nonblank + 1)); text += L"\r\n"; } diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index dca4793aeac..dd8457f1e41 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -596,6 +596,7 @@ static const dasm_table_entry dasm_table[] = { "tp0320", be, 0, []() -> util::disasm_interface * { return new tp0320_disassembler; } }, { "tx0_64kw", be, -2, []() -> util::disasm_interface * { return new tx0_64kw_disassembler; } }, { "tx0_8kw", be, -2, []() -> util::disasm_interface * { return new tx0_8kw_disassembler; } }, + { "tx0_8kwo", be, -2, []() -> util::disasm_interface * { return new tx0_8kwo_disassembler; } }, { "ucom4", le, 0, []() -> util::disasm_interface * { return new ucom4_disassembler; } }, { "unsp10", be, -1, []() -> util::disasm_interface * { return new unsp_disassembler; } }, { "unsp12", be, -1, []() -> util::disasm_interface * { return new unsp_12_disassembler; } }, |