video/pc_vga_paradise.cpp: preliminary implementation of WD90C11A, add basic Extended CRTC to WD90C00

* Can setup VESA modes 100h to 104h
This commit is contained in:
angelosa 2023-07-10 00:14:33 +02:00
parent 7197c02726
commit d812485217
4 changed files with 297 additions and 20 deletions

View File

@ -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);
}

View File

@ -291,7 +291,6 @@ protected:
address_space_config m_seq_space_config;
address_space_config m_atc_space_config;
private:
bool m_ioas = false;
};

View File

@ -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) <reserved>
}
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-- ---- <reserved>
* --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;
}

View File

@ -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