diff options
Diffstat (limited to 'src/devices/machine/sis630_gui.cpp')
-rw-r--r-- | src/devices/machine/sis630_gui.cpp | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/devices/machine/sis630_gui.cpp b/src/devices/machine/sis630_gui.cpp new file mode 100644 index 00000000000..e7696b54dd4 --- /dev/null +++ b/src/devices/machine/sis630_gui.cpp @@ -0,0 +1,327 @@ +// license: BSD-3-Clause +// copyright-holders: Angelo Salese +/************************************************************************************************** + + SiS 630 Video GUI portion (SVGA-based) & 301 video bridge + + - 630 core is SVGA based: + \- has two sets of extended CRTC ($3c4) regs; + \- a dedicated MPEG-2 video playback interface; + \- a digital video interface to 301; + - 301 draws to a separate monitor, and it was originally tied to a SiS300 AGP card, + (which we don't have a dump of at the time of this writing): + \- can select VGA, NTSC, PAL or LCD sources; + \- Has separate set of VGA and RAMDAC regs; + \- Has TV encoder; + \- Has macrovision regs; + - GUI is the 630 PCI/AGP i/f + \- it's actually internal to the rest of 630; + \- 301 is external but closely tied to it: the digital i/f ports (RIO+$4) selects where it + should start drawing/sync etc. while the "VGA2 regs" (RIO+$14) seems to be a custom set + rather than be related at all (i.e. it most likely be just capable to have VGA-like + resolutions). + - sis_main.c portions refers to the correlated Linux driver at + https://github.com/torvalds/linux/blob/master/drivers/video/fbdev/sis/sis_main.c + + TODO: + - Backward port '630 GUI/PCI implementation to '300 and other flavours + (needs VGA mods to do this properly); + - 2d acceleration; + - Turbo queue stuff; + - AGP; + - xubuntu 6.10 splash screen is decentered (zooming?) + - xubuntu 6.10 splash screen text is unreadable or not visible depending on res selected; + - Interface with '301 bridge (a lovely can of worms); + +**************************************************************************************************/ + +#include "emu.h" +#include "sis630_gui.h" + +#define LOG_IO (1U << 1) // log PCI register accesses +#define LOG_TODO (1U << 2) // log unimplemented registers +#define LOG_MAP (1U << 3) // log full remaps +#define LOG_AGP (1U << 4) // log AGP + +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_AGP) +//#define LOG_OUTPUT_FUNC osd_printf_info + +#include "logmacro.h" + +#define LOGIO(...) LOGMASKED(LOG_IO, __VA_ARGS__) +#define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__) +#define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__) +#define LOGAGP(...) LOGMASKED(LOG_AGP, __VA_ARGS__) + +/***************************** + * + * 630 GUI PCI implementation + * + ****************************/ + +DEFINE_DEVICE_TYPE(SIS630_GUI, sis630_gui_device, "sis630_gui", "SiS 630 GUI") + +sis630_gui_device::sis630_gui_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_device(mconfig, SIS630_GUI, tag, owner, clock) + , m_vga(*this, "svga") + , m_gui_rom(*this, "gui_rom") +{ + set_ids(0x10396300, 0x00, 0x030000, 0x00); +} + +ROM_START( sis630gui ) + ROM_REGION32_LE( 0xc000, "gui_rom", ROMREGION_ERASEFF ) + // TODO: why the OEM ROM is 0xc000 in size? + // 0x8000-0xbfff mostly contains a charset, may be either programmable via a dedicated interface + // or the dump above is half size. + // gamecstl dump ver. 2.06.50 + // (which actually writes to VRAM with the actual expansion ROM enabled, uh?) + ROM_SYSTEM_BIOS( 0, "2.06.50", "Ver. 2.06.50 OEM" ) + ROMX_LOAD( "oemrom.bin", 0x0000, 0xc000, BAD_DUMP CRC(03d8df9d) SHA1(8fb80a2bf4067d9bebc90fb498448869ae795b2b), ROM_BIOS(0) ) + + // "SiS 630 (Ver. 2.02.1c) [AGP VGA] (Silicon Integrated Systems Corp.).bin" + ROM_SYSTEM_BIOS( 1, "2.02.1c", "Ver. 2.02.1c" ) + ROMX_LOAD( "sis630.bin", 0x0000, 0x8000, BAD_DUMP CRC(f04ef9b0) SHA1(2396a79cd4045362bfc511090b146daa85902b4d), ROM_BIOS(1) ) +ROM_END + +const tiny_rom_entry *sis630_gui_device::device_rom_region() const +{ + return ROM_NAME(sis630gui); +} + +void sis630_gui_device::device_add_mconfig(machine_config &config) +{ + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_raw(XTAL(25'174'800), 900, 0, 640, 526, 0, 480); + screen.set_screen_update(m_vga, FUNC(sis630_vga_device::screen_update)); + + SIS630_VGA(config, m_vga, 0); + m_vga->set_screen("screen"); + // 64MB according to POST + // documentation claims 128MB, assume being wrong + m_vga->set_vram_size(64*1024*1024); +} + +void sis630_gui_device::config_map(address_map &map) +{ + pci_device::config_map(map); + map(0x2c, 0x2d).r(FUNC(sis630_gui_device::subvendor_r)); + map(0x2e, 0x2f).r(FUNC(sis630_gui_device::subsystem_r)); + map(0x2c, 0x2f).w(FUNC(sis630_gui_device::subvendor_w)); + +// map(0x3c, 0x3d) irq line/pin + + map(0x34, 0x34).r(FUNC(sis630_gui_device::capptr_r)); + + map(0x50, 0x53).r(FUNC(sis630_gui_device::agp_id_r)); + map(0x54, 0x57).r(FUNC(sis630_gui_device::agp_status_r)); + map(0x58, 0x5b).rw(FUNC(sis630_gui_device::agp_command_r), FUNC(sis630_gui_device::agp_command_w)); + map(0x5c, 0x5c).lr8(NAME([] () { return 0; })); // NULL terminator +} + +u8 sis630_gui_device::capptr_r() +{ + return 0x50; +} + +// TODO: move to specific interface +u32 sis630_gui_device::agp_id_r() +{ + LOGAGP("Read AGP ID [$50]\n"); + // bits 23-16 AGP v1.0 + // bits 15-8 0x5c NEXT_PTR (which goes to NULL terminator) + // bits 7-0 CAP_ID (0x02 for AGP) + return 0x00105c02; +} + +u32 sis630_gui_device::agp_status_r() +{ + LOGAGP("Read AGP status [$54]\n"); + // RQ (1 + 1), 2X and 1X capable + return 0x01000003; +} + +u32 sis630_gui_device::agp_command_r(offs_t offset, uint32_t mem_mask) +{ + LOGAGP("Read AGP command [$58] %d %d %08x\n", m_agp.enable, m_agp.data_rate, mem_mask); + // TODO: enable gets cleared by AGP_RESET, or even from PCI RST# + return m_agp.enable << 8 | (m_agp.data_rate & 7); +} + +void sis630_gui_device::agp_command_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGAGP("Write AGP command [$c8] %08x & %08x\n", data, mem_mask); + + if (ACCESSING_BITS_8_15) + { + m_agp.enable = bool(BIT(m_agp.enable, 8)); + LOGAGP("- AGP_ENABLE = %d\n", m_agp.enable); + } + + if (ACCESSING_BITS_0_7) + { + // quick checker, to be translated into an AGP interface + std::map<u8, std::string> agp_transfer_rates = { + { 0, "(illegal 0)" }, + { 1, "1X" }, + { 2, "2X" }, + { 3, "(illegal 3)" } + }; + + // make sure the AGP DATA_RATE specs are honored + const u8 data_rate = data & 3; + LOGAGP("- DATA_RATE = %s enabled=%d\n", agp_transfer_rates.at(data_rate), m_agp.enable); + m_agp.data_rate = data_rate; + } +} + +// TODO: may be common to PCI base interface, verify +void sis630_gui_device::subvendor_w(offs_t offset, u32 data, u32 mem_mask) +{ + // write once + if (m_subsystem_logger_mask & mem_mask) + { + LOG("Warning: subvendor ID possible rewrite! old=%08x & %08x data=%08x & %08x\n" + , subsystem_id + , m_subsystem_logger_mask + , data + , mem_mask + ); + } + m_subsystem_logger_mask |= mem_mask; + + COMBINE_DATA(&subsystem_id); + LOGIO("subsystem ID write [$2c] %08x & %08x (%08x)\n", data, mem_mask, subsystem_id); +} + +void sis630_gui_device::memory_map(address_map &map) +{ + map(0x0000000, 0x3ffffff).rw(m_vga, FUNC(sis630_vga_device::mem_linear_r), FUNC(sis630_vga_device::mem_linear_w)); +} + +void sis630_gui_device::io_map(address_map &map) +{ + +} + +// "Relocate I/O" -> RIO +void sis630_gui_device::space_io_map(address_map &map) +{ + // RIO + 0x00: video capture regs on '300, omitted or missing on '630 + // RIO + 0x02: MPEG-2 video playback + // RIO + 0x04: digital video interface (to '301 only?) + // RIO + 0x10: 301 TV encoder + // RIO + 0x12: 301 macrovision regs + // RIO + 0x14: 301 VGA2 regs + // RIO + 0x16: 301 RAMDAC + // RIO + 0x30/+0x40/+0x50: omitted, legacy '300/'630 VGA regs? + // (gamecstl definitely tries to access 0x44 index 5 for readback extension ID) + map(0x30, 0x5f).m(m_vga, FUNC(sis630_vga_device::io_map)); +} + +void sis630_gui_device::legacy_memory_map(address_map &map) +{ + map(0xa0000, 0xbffff).rw(FUNC(sis630_gui_device::vram_r), FUNC(sis630_gui_device::vram_w)); +} + +void sis630_gui_device::legacy_io_map(address_map &map) +{ + map(0x03b0, 0x03df).m(m_vga, FUNC(sis630_vga_device::io_map)); +} + +void sis630_gui_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, + uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) +{ + +} + +void sis630_gui_device::device_start() +{ + pci_device::device_start(); + + add_map(64*1024*1024, M_MEM, FUNC(sis630_gui_device::memory_map)); + // claims 128KB, which goes outside the pentium range. + // Assume memory mapped, given the size should be yet another VGA memory compatible window. + add_map(128*1024, M_MEM, FUNC(sis630_gui_device::io_map)); + add_map(128, M_IO, FUNC(sis630_gui_device::space_io_map)); + + add_rom((u8 *)m_gui_rom->base(), m_gui_rom->bytes()); + + // INTA# + intr_pin = 1; +} + +void sis630_gui_device::device_reset() +{ + pci_device::device_reset(); + + command = 0x0004; + status = 0x0220; + + m_subsystem_logger_mask = 0; +} + +// TODO: remove these trampolines +uint8_t sis630_gui_device::vram_r(offs_t offset) +{ + return downcast<sis630_vga_device *>(m_vga.target())->mem_r(offset); +} + +void sis630_gui_device::vram_w(offs_t offset, uint8_t data) +{ + downcast<sis630_vga_device *>(m_vga.target())->mem_w(offset, data); +} + +/***************************** + * + * 630 bridge PCI implementation + * + ****************************/ + +DEFINE_DEVICE_TYPE(SIS630_BRIDGE, sis630_bridge_device, "sis630_bridge", "SiS 630 Virtual PCI-to-PCI bridge") + +sis630_bridge_device::sis630_bridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : pci_bridge_device(mconfig, SIS630_BRIDGE, tag, owner, clock) + , m_vga(*this, finder_base::DUMMY_TAG) +{ + +} + +void sis630_bridge_device::map_extra( + uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, + uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space +) +{ + // command extensions + // VGA control - forward legacy VGA addresses to AGP + // TODO: doc implies that is unaffected by base and limit? + if (BIT(bridge_control, 3)) + { + memory_space->install_device(0, 0xfffff, *m_vga, &sis630_gui_device::legacy_memory_map); + io_space->install_device(0, 0x0fff, *m_vga, &sis630_gui_device::legacy_io_map); + } + + // TODO: ISA control + // forward to "primary PCI" (host & LPC?) for A8 or A9 blocks for each 1KB blocks in I/O spaces, + // (i.e. $100-$3ff, $500-$7ff, $900-$bff etc.) + // even if I/O range is inside base and limits +// if (BIT(bridge_control, 2)) + // ... +} + +void sis630_bridge_device::bridge_control_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + pci_bridge_device::bridge_control_w(offset, data, mem_mask); + LOGMAP("- %s VGA control\n", bridge_control & 8 ? "Enable" : "Disable"); + remap_cb(); +} + +void sis630_bridge_device::device_start() +{ + pci_bridge_device::device_start(); +} + +void sis630_bridge_device::device_reset() +{ + pci_bridge_device::device_reset(); +} |