From d812485217e3eaeb4f6289b784ff0c589dcf1072 Mon Sep 17 00:00:00 2001 From: angelosa Date: Mon, 10 Jul 2023 00:14:33 +0200 Subject: [PATCH] video/pc_vga_paradise.cpp: preliminary implementation of WD90C11A, add basic Extended CRTC to WD90C00 * Can setup VESA modes 100h to 104h --- src/devices/bus/isa/svga_paradise.cpp | 8 +- src/devices/video/pc_vga.h | 1 - src/devices/video/pc_vga_paradise.cpp | 262 ++++++++++++++++++++++++-- src/devices/video/pc_vga_paradise.h | 46 ++++- 4 files changed, 297 insertions(+), 20 deletions(-) diff --git a/src/devices/bus/isa/svga_paradise.cpp b/src/devices/bus/isa/svga_paradise.cpp index 009d9a49b54..05fce18481d 100644 --- a/src/devices/bus/isa/svga_paradise.cpp +++ b/src/devices/bus/isa/svga_paradise.cpp @@ -241,8 +241,8 @@ void isa16_wd90c00_jk_device::device_add_mconfig(machine_config &config) WD90C00(config, m_vga, 0); m_vga->set_screen("screen"); - // 512KB (+ option for 1MB? Verify) - m_vga->set_vram_size(0x80000); + // 256kB, 512kB, 1MB + m_vga->set_vram_size(0x100000); } void isa16_wd90c00_jk_device::io_isa_map(address_map &map) @@ -291,9 +291,9 @@ void isa16_wd90c11_lr_device::device_add_mconfig(machine_config &config) screen.set_screen_update("vga", FUNC(wd90c00_vga_device::screen_update)); // TODO: bump to WD90C11A - WD90C00(config, m_vga, 0); + WD90C11A(config, m_vga, 0); m_vga->set_screen("screen"); - // 512kB + // 512KB (+ option for 1MB? Verify with interlace) m_vga->set_vram_size(0x80000); } diff --git a/src/devices/video/pc_vga.h b/src/devices/video/pc_vga.h index 64715853808..a23e004da8e 100644 --- a/src/devices/video/pc_vga.h +++ b/src/devices/video/pc_vga.h @@ -291,7 +291,6 @@ protected: address_space_config m_seq_space_config; address_space_config m_atc_space_config; -private: bool m_ioas = false; }; diff --git a/src/devices/video/pc_vga_paradise.cpp b/src/devices/video/pc_vga_paradise.cpp index 3c300c5bcc0..b3fc9f14bc1 100644 --- a/src/devices/video/pc_vga_paradise.cpp +++ b/src/devices/video/pc_vga_paradise.cpp @@ -18,6 +18,7 @@ TODO: - Memory Data pins (MD) & CNF - /EBROM signal (for enabling ROM readback) +- AIDA16 & UniVBE VESA suite detects 'C11 as 'C30, is the ROM mislabeled? **************************************************************************************************/ @@ -26,30 +27,34 @@ TODO: #include "screen.h" +#define LOG_WARN (1U << 1) #define LOG_BANK (1U << 2) // log banking r/ws #define LOG_LOCKED (1U << 8) // log locking mechanism -#define VERBOSE (LOG_GENERAL | LOG_LOCKED) +#define VERBOSE (LOG_GENERAL | LOG_WARN | LOG_LOCKED) //#define LOG_OUTPUT_FUNC osd_printf_info #include "logmacro.h" -#define LOGBANK(...) LOGMASKED(LOG_BANK, __VA_ARGS__) +#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__) +#define LOGBANK(...) LOGMASKED(LOG_BANK, __VA_ARGS__) #define LOGLOCKED(...) LOGMASKED(LOG_LOCKED, __VA_ARGS__) DEFINE_DEVICE_TYPE(PVGA1A, pvga1a_vga_device, "pvga1a_vga", "Paradise Systems PVGA1A") -DEFINE_DEVICE_TYPE(WD90C00, wd90c00_vga_device, "wd90c00_vga", "Western Digital WD90C00 VGA Controller") +DEFINE_DEVICE_TYPE(WD90C00, wd90c00_vga_device, "wd90c00_vga", "Western Digital WD90C00 \"PVGA1B\" VGA Controller") +DEFINE_DEVICE_TYPE(WD90C11A, wd90c11a_vga_device, "wd90c11a_vga", "Western Digital WD90C11A \"PVGA1M\" VGA Controller") +//DEFINE_DEVICE_TYPE(WD90C30, wd90c30_vga_device, "wd90c30_vga", "Western Digital WD90C30 \"PVGA1D\" VGA Controller") pvga1a_vga_device::pvga1a_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, type, tag, owner, clock) , m_ext_gc_view(*this, "ext_gc_view") { + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(pvga1a_vga_device::gc_map), this)); } pvga1a_vga_device::pvga1a_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : pvga1a_vga_device(mconfig, PVGA1A, tag, owner, clock) { - m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(pvga1a_vga_device::gc_map), this)); } void pvga1a_vga_device::device_start() @@ -102,7 +107,7 @@ void pvga1a_vga_device::gc_map(address_map &map) map(0x09, 0x0e).view(m_ext_gc_view); m_ext_gc_view[0](0x09, 0x0e).lr8( NAME([this] (offs_t offset) { - LOGLOCKED("Attempt to R ext. register offset %02x while locked\n", offset + 9); + LOGLOCKED("Attempt to R ext. GC register offset %02x while locked\n", offset + 9); return 0xff; }) ); @@ -196,6 +201,7 @@ void pvga1a_vga_device::video_select_w(offs_t offset, u8 data) { LOG("PR2 Video Select W %02x\n", data); m_video_select = data; + recompute_params(); } /* @@ -251,6 +257,7 @@ void pvga1a_vga_device::video_control_w(offs_t offset, u8 data) * [0x0f] PR5 Lock/Status * * xxxx ---- MD7/MD4 config reads + * ---- x--- MD8 config read (on later chipsets) * ---- -xxx lock register * ---- -101 unlock, any other value locks r/w to the extensions */ @@ -272,12 +279,16 @@ void pvga1a_vga_device::ext_gc_unlock_w(offs_t offset, u8 data) * *************************************/ -wd90c00_vga_device::wd90c00_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pvga1a_vga_device(mconfig, WD90C00, tag, owner, clock) +wd90c00_vga_device::wd90c00_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : pvga1a_vga_device(mconfig, type, tag, owner, clock) , m_ext_crtc_view(*this, "ext_crtc_view") { m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(wd90c00_vga_device::crtc_map), this)); - m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(wd90c00_vga_device::gc_map), this)); +} + +wd90c00_vga_device::wd90c00_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : wd90c00_vga_device(mconfig, WD90C00, tag, owner, clock) +{ } void wd90c00_vga_device::device_reset() @@ -287,6 +298,11 @@ void wd90c00_vga_device::device_reset() m_pr10_scratch = 0; m_ext_crtc_write_unlock = false; m_ext_crtc_view.select(0); + m_egasw = 0xf0; + m_interlace_start = 0; + m_interlace_end = 0; + m_interlace_mode = false; + m_pr15 = 0; } void wd90c00_vga_device::crtc_map(address_map &map) @@ -296,20 +312,43 @@ void wd90c00_vga_device::crtc_map(address_map &map) map(0x2a, 0x3f).view(m_ext_crtc_view); m_ext_crtc_view[0](0x2a, 0x3f).lr8( NAME([this] (offs_t offset) { - LOGLOCKED("Attempt to R ext. register offset %02x while locked\n", offset + 0x2a); + LOGLOCKED("Attempt to R ext. CRTC register offset %02x while locked\n", offset + 0x2a); return 0xff; }) ); -// m_ext_crtc_view[1](0x2a, 0x2a) PR11 EGA Switches + m_ext_crtc_view[1](0x2a, 0x2a).rw(FUNC(wd90c00_vga_device::egasw_r), FUNC(wd90c00_vga_device::egasw_w)); m_ext_crtc_view[1](0x2b, 0x2b).ram(); // PR12 scratch pad -// m_ext_crtc_view[1](0x2c, 0x2c) PR13 Interlace H/2 Start -// m_ext_crtc_view[1](0x2d, 0x2d) PR14 Interlace H/2 End -// m_ext_crtc_view[1](0x2e, 0x2e) PR15 Misc Control 1 + m_ext_crtc_view[1](0x2c, 0x2d).rw(FUNC(wd90c00_vga_device::interlace_r), FUNC(wd90c00_vga_device::interlace_w)); + m_ext_crtc_view[1](0x2e, 0x2e).rw(FUNC(wd90c00_vga_device::misc_control_1_r), FUNC(wd90c00_vga_device::misc_control_1_w)); // m_ext_crtc_view[1](0x2f, 0x2f) PR16 Misc Control 2 // m_ext_crtc_view[1](0x30, 0x30) PR17 Misc Control 3 // m_ext_crtc_view[1](0x31, 0x3f) } +void wd90c00_vga_device::recompute_params() +{ + u8 xtal_select = (vga.miscellaneous_output & 0x0c) >> 2; + int xtal; + // TODO: VTB disables video select bit 1 for 1024x768 mode (with no interlace mode setup) + // Uses VCLK1, without the bump will select 26.43 Hz as refresh rate + const u8 multiplier = BIT(m_video_select, 1) ? 1 : 2; + + switch(xtal_select & 3) + { + // VCLK0 + case 0: xtal = XTAL(25'174'800).value() * multiplier; break; + // VCLK1 + case 1: xtal = XTAL(28'636'363).value() * multiplier; break; + // VCLK2, selected in 800x600 modes + case 2: + default: + xtal = XTAL(42'000'000).value(); + break; + } + + recompute_params_clock(1, xtal); +} + /* * [0x29] PR10 Unlock PR11/PR17 * @@ -333,3 +372,200 @@ void wd90c00_vga_device::ext_crtc_unlock_w(offs_t offset, u8 data) m_ext_crtc_view.select(m_ext_crtc_write_unlock); m_pr10_scratch = data & 0x70; } + +/* + * [0x2a] PR11 EGA Switches + * + * xxxx ---- EGA switches (MD15-MD12), latches high if written to. + * ---- x--- EGA emulation on Analog Display + * ---- -x-- Lock Clock Select (disables external chip select for VCLK1) + * ---- --x- Locks GC $5 bits 6:5, sequencer $1 bits 5:2, sequencer $3 bits 5:0 + * ---- ---x Locks sequencer $1 bit 0 (8/9 dot mode) + */ +u8 wd90c00_vga_device::egasw_r(offs_t offset) +{ + const u8 ega_config = (m_input_sense->read() << 4); + LOG("PR11 EGA Switch R (%02x | %02x)\n", ega_config, m_egasw); + return (ega_config | m_egasw); +} + +void wd90c00_vga_device::egasw_w(offs_t offset, u8 data) +{ + LOG("PR11 EGA Switch W %02x\n", data); + m_egasw = data & 0xff; +} + +/* + * [0x2c] PR13 Interlace H/2 Start + * + * xxxx xxxx Horizontal interlace start + * + * [0x2d] PR14 Interlace H/2 End + * + * x--- ---- Enable EGA IRQ in AT bus mode (N/A for VGA operation and MCA bus) + * -x-- ---- EGA vertical double scan + * --x- ---- Enable interlace mode + * ---x xxxx Interlace H/2 End + * + */ +u8 wd90c00_vga_device::interlace_r(offs_t offset) +{ + if (!offset) + { + LOG("PR13 Interlace H/2 Start R\n"); + return m_interlace_start; + } + + LOG("PR14 Interlace H/2 End R\n"); + return (m_interlace_mode << 5) | (m_interlace_end); +} + +void wd90c00_vga_device::interlace_w(offs_t offset, u8 data) +{ + if (!offset) + { + LOG("PR13 Interlace H/2 Start W %02x\n", data); + m_interlace_start = data; + return; + } + + LOG("PR14 Interlace H/2 End W %02x\n", data); + m_interlace_mode = bool(BIT(data, 5)); + m_interlace_end = data & 0x1f; +} + +/* + * [0x2e] PR15 Misc Control 1 + * + * x--- ---- Read $46e8 enable + * -x-- ---- + * --x- ---- VCLK1, VCLK2 Latched Outputs + * ---x ---- Select MCLK as video clock + * ---- x--- 8514/A Interlace compatibility + * ---- -x-- Enable Page Mode + * ---- --x- Select Display Enable + * ---- ---x Disable Border + */ +u8 wd90c00_vga_device::misc_control_1_r(offs_t offset) +{ + LOG("PR15 Misc Control 1 R (%02x)\n", m_pr15); + return m_pr15; +} + +void wd90c00_vga_device::misc_control_1_w(offs_t offset, u8 data) +{ + LOG("PR15 Misc Control 1 W %02x\n", data); + m_pr15 = data; +} + +/* + * [0x2f] PR16 Misc Control 2 + */ + +/* + * [0x30] PR17 Misc Control 3 + */ + +/************************************** + * + * Western Digital WD90C11A + * + *************************************/ + +wd90c11a_vga_device::wd90c11a_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : wd90c00_vga_device(mconfig, type, tag, owner, clock) + , m_ext_seq_view(*this, "ext_seq_view") +{ + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(wd90c11a_vga_device::sequencer_map), this)); +} + +wd90c11a_vga_device::wd90c11a_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : wd90c11a_vga_device(mconfig, WD90C11A, tag, owner, clock) +{ +} + +void wd90c11a_vga_device::device_reset() +{ + wd90c00_vga_device::device_reset(); + + m_ext_seq_unlock = false; + m_ext_seq_view.select(0); + m_pr31 = 0; +} + +void wd90c11a_vga_device::sequencer_map(address_map &map) +{ + wd90c00_vga_device::sequencer_map(map); + map(0x06, 0x06).rw(FUNC(wd90c11a_vga_device::ext_seq_status_r), FUNC(wd90c11a_vga_device::ext_seq_unlock_w)); + map(0x07, 0x1f).view(m_ext_seq_view); + m_ext_seq_view[0](0x07, 0x1f).lr8( + NAME([this] (offs_t offset) { + LOGLOCKED("Attempt to R ext. Sequencer register offset %02x while locked\n", offset + 0x07); + return 0xff; + }) + ); +// m_ext_seq_view[1](0x07, 0x07) PR21 Display Configuration and Scratch Pad + m_ext_seq_view[1](0x08, 0x08).ram(); // PR22 'C11A only Scratch Pad + m_ext_seq_view[1](0x09, 0x09).ram(); // PR23 'C11A only Scratch Pad +// m_ext_seq_view[1](0x10, 0x10) PR30 Memory Interface and FIFO Control + m_ext_seq_view[1](0x11, 0x11).rw(FUNC(wd90c11a_vga_device::sys_if_control_r), FUNC(wd90c11a_vga_device::sys_if_control_w)); +// m_ext_seq_view[1](0x12, 0x12) PR32 Miscellaneous Control 4 +} + +// unlock also dictates index mask +u8 wd90c11a_vga_device::sequencer_data_r(offs_t offset) +{ + const u8 seq_index = vga.sequencer.index & (m_ext_seq_unlock ? 0xff : 0x07); + return space(SEQ_REG).read_byte(seq_index); +} + +void wd90c11a_vga_device::sequencer_data_w(offs_t offset, u8 data) +{ + const u8 seq_index = vga.sequencer.index & (m_ext_seq_unlock ? 0xff : 0x07); + vga.sequencer.data[seq_index] = data; + space(SEQ_REG).write_byte(seq_index, data); + recompute_params(); +} + +/* + * [0x06] PR20 Unlock PR21/PR32 + * + * -x-x x--- Ext. Sequencer unlock + * -1-0 1--- Unlocks, any other value locks + */ +u8 wd90c11a_vga_device::ext_seq_status_r(offs_t offset) +{ + return (m_ext_seq_unlock ? 0x48 : 0x00); +} + +void wd90c11a_vga_device::ext_seq_unlock_w(offs_t offset, u8 data) +{ + m_ext_seq_unlock = (data & 0x58) == 0x48; + LOG("PR20 %s state (%02x)\n", m_ext_seq_unlock ? "unlock" : "lock", data); + m_ext_seq_view.select(m_ext_seq_unlock); +} + +/* + * [0x11] PR31 System Interface Control + * + * Defaults to 0x6d on ct486 + * + * x--- ---- Read/Write Offset Enable + * -x-- ---- Turbo Mode for Blanked Lines + * --x- ---- Turbo Mode for Text + * ---x x--- CPU RDY release Control + * ---- -x-- Enable Write Buffer + * ---- --x- Enable 16-bit I/O for ATC + * ---- ---x Enable 16-bit I/O for CRTC, Sequencer & GC + */ +u8 wd90c11a_vga_device::sys_if_control_r(offs_t offset) +{ + LOG("PR31 System Interface Control R (%02x)\n", m_pr31); + return m_pr31; +} + +void wd90c11a_vga_device::sys_if_control_w(offs_t offset, u8 data) +{ + LOG("PR31 System Interface Control W %02x\n", data); + m_pr31 = data; +} \ No newline at end of file diff --git a/src/devices/video/pc_vga_paradise.h b/src/devices/video/pc_vga_paradise.h index 5ebf022c312..80dd6e95863 100644 --- a/src/devices/video/pc_vga_paradise.h +++ b/src/devices/video/pc_vga_paradise.h @@ -25,6 +25,8 @@ protected: virtual void gc_map(address_map &map) override; memory_view m_ext_gc_view; + + u8 m_video_select = 0; private: u8 address_offset_r(offs_t offset); void address_offset_w(offs_t offset, u8 data); @@ -42,7 +44,6 @@ private: u8 m_memory_size = 0; u8 m_video_control = 0; bool m_ext_gc_unlock = false; - u8 m_video_select = 0; u8 m_crtc_lock = 0; }; @@ -52,19 +53,60 @@ public: wd90c00_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: - virtual void crtc_map(address_map &map) override; + wd90c00_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual void device_reset() override; + virtual void crtc_map(address_map &map) override; + virtual void recompute_params() override; + memory_view m_ext_crtc_view; private: u8 ext_crtc_status_r(offs_t offset); void ext_crtc_unlock_w(offs_t offset, u8 data); + u8 egasw_r(offs_t offset); + void egasw_w(offs_t offset, u8 data); + u8 interlace_r(offs_t offset); + void interlace_w(offs_t offset, u8 data); + u8 misc_control_1_r(offs_t offset); + void misc_control_1_w(offs_t offset, u8 data); bool m_ext_crtc_write_unlock = false; u8 m_pr10_scratch = 0; + u8 m_egasw = 0; + u8 m_interlace_start = 0; + u8 m_interlace_end = 0; + bool m_interlace_mode = 0; + u8 m_pr15 = 0; +}; + +class wd90c11a_vga_device : public wd90c00_vga_device +{ +public: + wd90c11a_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + wd90c11a_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void sequencer_map(address_map &map) override; + virtual void device_reset() override; + + memory_view m_ext_seq_view; +private: + virtual u8 sequencer_data_r(offs_t offset) override; + virtual void sequencer_data_w(offs_t offset, u8 data) override; + + u8 ext_seq_status_r(offs_t offset); + void ext_seq_unlock_w(offs_t offset, u8 data); + u8 sys_if_control_r(offs_t offset); + void sys_if_control_w(offs_t offset, u8 data); + + bool m_ext_seq_unlock = false; + u8 m_pr31 = 0; }; DECLARE_DEVICE_TYPE(PVGA1A, pvga1a_vga_device) DECLARE_DEVICE_TYPE(WD90C00, wd90c00_vga_device) +DECLARE_DEVICE_TYPE(WD90C11A, wd90c11a_vga_device) #endif // MAME_VIDEO_PC_VGA_PARADISE_H