From f6efe2921f2a7f201d402967b1d0b849cac8ce82 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sun, 18 Nov 2018 23:11:16 +0100 Subject: add HP98550 high-res color graphic card Used in the high end HP9000/300 machines. Provides a resolution of 1280x1024 @ 8bpp. It also provides two overlay planes and one phantom plane. Each plane contains two window movers that are used for copying characters and tiles on the screen. It also has a RUG for line/vector drawing. The current state implements everything that is required to have a working HP Visual user environment in MAME. Working: - window mover - pixel replacement rules - window replacement rules - f0 tripple replacement rule (copy src or keep destination depending on pattern register) - VRAM bit access mode - solid line drawing Not implemented yet: - drawing circles - linetype vector/circles - rectangles - filling areas - tripple replacement rules other than f0 --- scripts/src/bus.lua | 2 + scripts/src/video.lua | 12 + src/devices/bus/hp_dio/hp98550.cpp | 234 +++++++ src/devices/bus/hp_dio/hp98550.h | 78 +++ src/devices/bus/hp_dio/hp_dio.cpp | 3 + src/devices/video/catseye.cpp | 1224 ++++++++++++++++++++++++++++++++++++ src/devices/video/catseye.h | 369 +++++++++++ src/emu/xtal.cpp | 1 + src/mame/drivers/hp9k_3xx.cpp | 10 +- src/mame/layout/hp9k_3xx.lay | 56 +- 10 files changed, 1950 insertions(+), 39 deletions(-) create mode 100644 src/devices/bus/hp_dio/hp98550.cpp create mode 100644 src/devices/bus/hp_dio/hp98550.h create mode 100644 src/devices/video/catseye.cpp create mode 100644 src/devices/video/catseye.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 198c4283c04..7fbc4448458 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -910,6 +910,8 @@ if (BUSES["HPDIO"]~=null) then MAME_DIR .. "src/devices/bus/hp_dio/hp98543.h", MAME_DIR .. "src/devices/bus/hp_dio/hp98544.cpp", MAME_DIR .. "src/devices/bus/hp_dio/hp98544.h", + MAME_DIR .. "src/devices/bus/hp_dio/hp98550.cpp", + MAME_DIR .. "src/devices/bus/hp_dio/hp98550.h", MAME_DIR .. "src/devices/bus/hp_dio/hp98603a.cpp", MAME_DIR .. "src/devices/bus/hp_dio/hp98603a.h", MAME_DIR .. "src/devices/bus/hp_dio/hp98603b.cpp", diff --git a/scripts/src/video.lua b/scripts/src/video.lua index fa529660ab1..6db6cd104e1 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -1104,6 +1104,18 @@ if (VIDEOS["TOPCAT"]~=null) then } end +-------------------------------------------------- +-- +--@src/devices/video/catseye.h,VIDEOS["CATSEYE"] = true +-------------------------------------------------- +if (VIDEOS["CATSEYE"]~=null) then + files { + MAME_DIR .. "src/devices/video/catseye.cpp", + MAME_DIR .. "src/devices/video/catseye.h", + } +end + + -------------------------------------------------- -- --@src/devices/video/nereid.h,VIDEOS["NEREID"] = true diff --git a/src/devices/bus/hp_dio/hp98550.cpp b/src/devices/bus/hp_dio/hp98550.cpp new file mode 100644 index 00000000000..8ec1660d5ce --- /dev/null +++ b/src/devices/bus/hp_dio/hp98550.cpp @@ -0,0 +1,234 @@ +// License:BSD-3-Clause +// copyright-holders:Sven Schnelle +/*************************************************************************** + +HP98550 high-resolution color board + +1280x1024 @ 60Hz, 8 bpp + +***************************************************************************/ + +#include "emu.h" +#include "hp98550.h" +#include "screen.h" +#include "video/nereid.h" +#include "video/catseye.h" +#include "machine/ram.h" + +//#define VERBOSE 1 +#include "logmacro.h" + +ROM_START(hp98550) + ROM_REGION(0x8000, "hp98550a_rom", 0) + ROM_LOAD("98550a.bin", 0x000000, 0x008000, CRC(9d639233) SHA1(d6b23a34850f24525ca5fb36de3deb91196d2dc5)) +ROM_END + +DEFINE_DEVICE_TYPE_NS(HPDIO_98550, bus::hp_dio, dio32_98550_device, "dio98550", "HP98550 high-res color DIO video card") + +namespace bus { namespace hp_dio { + +void dio32_98550_device::device_add_mconfig(machine_config &config) +{ + screen_device &screen(SCREEN(config, "hp98550_screen", SCREEN_TYPE_RASTER)); + screen.set_screen_update(FUNC(dio32_98550_device::screen_update)); + screen.screen_vblank().set(FUNC(dio32_98550_device::vblank_w)); + screen.set_raw(XTAL(108'108'000), 1689, 0, m_h_pix, 1066, 0, m_v_pix); + + for (int i = 0; i < CATSEYE_COUNT; i++) { + CATSEYE(config, m_catseye[i], XTAL(108'108'000)); + m_catseye[i]->set_fb_width(m_fb_width); + m_catseye[i]->set_fb_height(m_v_pix); + m_catseye[i]->set_plane(i); + m_catseye[i]->irq_out_cb().set(FUNC(dio32_98550_device::int_w)); + } + + NEREID(config, m_nereid, 0); +} + +const tiny_rom_entry *dio32_98550_device::device_rom_region() const +{ + return ROM_NAME(hp98550); +} + +void dio32_98550_device::map(address_map& map) +{ + map(0, 0x3fffff).ram().share("vram_video"); + map(0x400000, 0x7fffff).ram().share("vram_overlay"); +} + +device_memory_interface::space_config_vector dio32_98550_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(0, &m_space_config) + }; +} + +dio32_98550_device::dio32_98550_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + dio32_98550_device(mconfig, HPDIO_98550, tag, owner, clock) +{ +} + +dio32_98550_device::dio32_98550_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, type, tag, owner, clock), + device_dio16_card_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_nereid(*this, "nereid"), + m_catseye(*this, "catseye%d", 0), + m_space_config("vram", ENDIANNESS_BIG, 8, 23, 0, address_map_constructor(FUNC(dio32_98550_device::map), this)), + m_rom(*this, "hp98550a_rom"), + m_vram(*this, { "vram_video", "vram_overlay"}) +{ +} + +void dio32_98550_device::device_start() +{ + save_item(NAME(m_intreg)); + save_item(NAME(m_ints)); + + dio().install_memory( + 0x200000, 0x3fffff, + read16_delegate(FUNC(dio32_98550_device::vram_r), this), + write16_delegate(FUNC(dio32_98550_device::vram_w), this)); + + dio().install_memory( + 0x560000, 0x56ffff, + read16_delegate(FUNC(dio32_98550_device::rom_r), this), + write16_delegate(FUNC(dio32_98550_device::rom_w), this)); + + dio().install_memory( + 0x564000, 0x5648ff, + read16_delegate(FUNC(dio32_98550_device::catseye_r), this), + write16_delegate(FUNC(dio32_98550_device::catseye_w), this)); + + dio().install_memory( + 0x566000, 0x5660ff, + read16_delegate(FUNC(nereid_device::ctrl_r), &(*m_nereid)), + write16_delegate(FUNC(nereid_device::ctrl_w), &(*m_nereid))); +} + +void dio32_98550_device::device_reset() +{ + m_intreg = 0; + m_ints = 0; +} + +READ16_MEMBER(dio32_98550_device::rom_r) +{ + LOG("%s: %04x\n", __func__, offset); + + if (offset == 1) + return m_intreg; + + return 0xff00 | m_rom[offset]; +} + +WRITE16_MEMBER(dio32_98550_device::rom_w) +{ + switch (offset) { + case 0: + reset(); + break; + + case 1: + m_intreg = data; + break; + + default: + logerror("%s: %04x = %04x (mask %04x)\n", __func__, offset << 1, data, mem_mask); + break; + } +} + +READ16_MEMBER(dio32_98550_device::catseye_r) +{ + uint16_t ret = 0; + + for (auto &ce: m_catseye) + ret |= ce->ctrl_r(space, offset, mem_mask); + LOG("%s: %04X = %04X\n", __func__, offset << 1, ret); + return ret; +} + +WRITE16_MEMBER(dio32_98550_device::catseye_w) +{ + LOG("%s: %04X = %04X\n", __func__, offset << 1, data); + for (auto &ce: m_catseye) + ce->ctrl_w(space, offset, data, mem_mask); +} + +READ16_MEMBER(dio32_98550_device::vram_r) +{ + uint16_t ret = 0; + + for (auto &ce: m_catseye) + ret |= ce->vram_r(space, offset, mem_mask); + + return ret; +} + +WRITE16_MEMBER(dio32_98550_device::vram_w) +{ + for (auto &ce: m_catseye) + ce->vram_w(space, offset, data, mem_mask); +} + +WRITE_LINE_MEMBER(dio32_98550_device::vblank_w) +{ + for (auto &ce: m_catseye) + ce->vblank_w(state); +} + +WRITE8_MEMBER(dio32_98550_device::int_w) +{ + LOG("%s: plane%d = %s\n", __func__, offset, data ? "assert" : "deassert"); + m_ints &= ~(1 << offset); + m_ints |= data; + update_int(); +} + +void dio32_98550_device::update_int() +{ + bool state = m_ints; + int line = (m_intreg >> 3) & 7; + + if (!(m_intreg & 0x80)) + state = false; + + irq1_out(line == 1 && state); + irq2_out(line == 2 && state); + irq3_out(line == 3 && state); + irq4_out(line == 4 && state); + irq5_out(line == 5 && state); + irq6_out(line == 6 && state); + irq7_out(line == 7 && state); +} + +uint32_t dio32_98550_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + bool changed = false; + uint8_t mask = 0; + + for (auto &ce: m_catseye) + changed |= ce->has_changed(); + + if (!changed) + return UPDATE_HAS_NOT_CHANGED; + + for (auto &ce: m_catseye) + mask |= ce->plane_enabled(); + + for (int y = 0; y < m_v_pix; y++) { + uint32_t *scanline = &bitmap.pix32(y); + + for (int x = 0; x < m_h_pix; x++) { + const int offset = y * m_fb_width +x; + uint8_t tmp = m_vram[0][offset] & mask; + uint8_t ovl = m_vram[1][offset] & mask; + *scanline++ = m_nereid->map_color(tmp, ovl); + } + } + return 0; +} + +} // namespace bus::hp_dio +} // namespace bus diff --git a/src/devices/bus/hp_dio/hp98550.h b/src/devices/bus/hp_dio/hp98550.h new file mode 100644 index 00000000000..47057f6da70 --- /dev/null +++ b/src/devices/bus/hp_dio/hp98550.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle + +#ifndef MAME_BUS_HPDIO_98550_H +#define MAME_BUS_HPDIO_98550_H + +#pragma once + +#include "hp_dio.h" +#include "video/catseye.h" +#include "video/nereid.h" +#include "machine/ram.h" + +namespace bus { + namespace hp_dio { +class dio32_98550_device : + public device_t, + public device_dio16_card_interface, + public device_memory_interface +{ +public: + dio32_98550_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ16_MEMBER(rom_r); + DECLARE_WRITE16_MEMBER(rom_w); + + DECLARE_READ16_MEMBER(topcat_r); + DECLARE_WRITE16_MEMBER(topcat_w); + DECLARE_READ16_MEMBER(catseye_r); + DECLARE_WRITE16_MEMBER(catseye_w); + + DECLARE_READ16_MEMBER(vram_r); + DECLARE_WRITE16_MEMBER(vram_w); + + static constexpr int CATSEYE_COUNT = 8; + + + uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); +protected: + required_device m_nereid; + required_device_array m_catseye; + + dio32_98550_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override; + virtual void device_reset() override; + + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual space_config_vector memory_space_config() const override; + + DECLARE_WRITE_LINE_MEMBER(vblank_w); + DECLARE_WRITE8_MEMBER(int_w); + + const address_space_config m_space_config; + void map(address_map &map); + void update_int(); + + static constexpr int m_fb_width = 2048; + static constexpr int m_h_pix = 1280; + static constexpr int m_v_pix = 1024; + + required_region_ptr m_rom; + required_shared_ptr_array m_vram; + + uint16_t m_plane_mask; + uint8_t m_intreg; + uint8_t m_ints; +}; + +} // namespace bus::hp_dio +} // namespace bus + +// device type definition +DECLARE_DEVICE_TYPE_NS(HPDIO_98550, bus::hp_dio, dio32_98550_device) + +#endif // MAME_BUS_HPDIO_98550_H diff --git a/src/devices/bus/hp_dio/hp_dio.cpp b/src/devices/bus/hp_dio/hp_dio.cpp index 899b7be0c00..ed553d6ea05 100644 --- a/src/devices/bus/hp_dio/hp_dio.cpp +++ b/src/devices/bus/hp_dio/hp_dio.cpp @@ -11,6 +11,7 @@ #include "hp98265a.h" #include "hp98543.h" #include "hp98544.h" +#include "hp98550.h" #include "hp98603a.h" #include "hp98603b.h" #include "hp98620.h" @@ -365,6 +366,8 @@ void dio16_cards(device_slot_interface & device) void dio32_cards(device_slot_interface & device) { + dio16_cards(device); device.option_add("98265a", HPDIO_98265A); device.option_add("98620", HPDIO_98620); + device.option_add("98550", HPDIO_98550); } diff --git a/src/devices/video/catseye.cpp b/src/devices/video/catseye.cpp new file mode 100644 index 00000000000..c79e3b246f5 --- /dev/null +++ b/src/devices/video/catseye.cpp @@ -0,0 +1,1224 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle + +#include "emu.h" +#include "catseye.h" + +#define LOG_VRAM (LOG_GENERAL << 1) +#define LOG_REG (LOG_GENERAL << 2) +#define LOG_WMOVE (LOG_GENERAL << 3) + +//#define VERBOSE (LOG_WMOVE|LOG_REG|LOG_GENERAL) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(CATSEYE, catseye_device, "catseye", "HP Catseye ASIC") + +catseye_device::catseye_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_vram(*this, { "^vram_video", "^vram_overlay"}), + m_int_write_func(*this), + m_blink_timer(nullptr) +{ +} + +catseye_device::catseye_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + catseye_device(mconfig, CATSEYE, tag, owner, clock) +{ +} + + +void catseye_device::device_start() +{ + m_int_write_func.resolve_safe(); + + m_blink_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(catseye_device::blink_callback), this)); + m_blink_timer->adjust(attotime::from_hz(3)); + + save_item(NAME(m_changed)); + save_item(NAME(m_blink_state)); + save_item(NAME(m_write_enable), 2); + save_item(NAME(m_read_enable), 2); + save_item(NAME(m_fb_enable), 2); + save_item(NAME(m_display_enable)); + save_item(NAME(m_blink_enable)); + save_item(NAME(m_sync_enable)); + save_item(NAME(m_in_vblank)); + save_item(NAME(m_wm_int_pending)); + save_item(NAME(m_wm_int_enable)); + save_item(NAME(m_vblank_int_enable)); + save_item(NAME(m_vblank_int_pending)); + save_item(NAME(m_rugsc)); + save_item(NAME(m_misc)); + save_item(NAME(m_wmx)); + save_item(NAME(m_wmwidth)); + save_item(NAME(m_wmheight)); + save_item(NAME(m_wmsourcex)); + save_item(NAME(m_wmsourcey)); + save_item(NAME(m_wmdestx)); + save_item(NAME(m_wmdesty)); + save_item(NAME(m_wmclipleft)); + save_item(NAME(m_wmclipright)); + save_item(NAME(m_wmcliptop)); + save_item(NAME(m_wmclipbottom)); + save_item(NAME(m_patterns)); + save_item(NAME(m_linepath)); + save_item(NAME(m_linetype)); + save_item(NAME(m_prr), 2); + save_item(NAME(m_wrr), 2); + save_item(NAME(m_trr), 2); + save_item(NAME(m_trrctl), 2); + save_item(NAME(m_color), 2); + save_item(NAME(m_vb), 2); + save_item(NAME(m_acntrl)); + save_item(NAME(m_planemode), 2); + save_item(NAME(m_status)); +} + +void catseye_device::device_reset() +{ + LOG("%s\n", __func__); + + for(int i = 0; i < 2; i++) { + m_read_enable[i] = 0; + m_write_enable[i] = 0; + m_fb_enable[i] = 0; + + m_prr[i] = 0; + m_wrr[i] = 0; + m_trr[i] = 0; + m_trrctl[i] = 0; + m_color[i] = 0; + m_vb[i] = 0; + m_planemode[i] = 0; + std::fill(m_patterns[i].begin(), m_patterns[i].end(), 0); + } + m_acntrl = 0; + m_blink_enable = 0; + m_display_enable = m_plane_mask_h; + m_rugsc = 0; + m_wmwidth = 0; + m_wmheight = 0; + m_wmsourcex = 0; + m_wmsourcey = 0; + m_wmdestx = 0; + m_wmdesty = 0; + m_wmclipleft = 0; + m_wmclipright = 0; + m_wmcliptop = 0; + m_wmclipbottom = 0; + + m_linepath = 0; + m_linetype = 0; +} + +void catseye_device::update_int() +{ + LOG("%s: pending %d, enabled %d\n", __func__, m_wm_int_pending, m_wm_int_enable); + if ((m_wm_int_enable && m_wm_int_pending ) || + (m_vblank_int_enable && m_vblank_int_pending)) + m_int_write_func(m_plane); + else + m_int_write_func(0); +} + +TIMER_CALLBACK_MEMBER(catseye_device::blink_callback) +{ + m_blink_timer->adjust(attotime::from_hz(5)); + m_blink_state ^= true; + m_changed = true; +} + +void catseye_device::execute_rule(const bool src, const int rule, bool &dst) const +{ + switch (rule & 0x0f) { + case CATSEYE_REPLACE_RULE_CLEAR: + dst = false; + break; + + case CATSEYE_REPLACE_RULE_SRC_AND_DST: + dst &= src; + break; + + case CATSEYE_REPLACE_RULE_SRC_AND_NOT_DST: + dst = !dst & src; + break; + + case CATSEYE_REPLACE_RULE_SRC: + dst = src; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC_AND_DST: + dst &= !src; + break; + + case CATSEYE_REPLACE_RULE_NOP: + break; + + case CATSEYE_REPLACE_RULE_SRC_XOR_DST: + dst ^= src; + break; + + case CATSEYE_REPLACE_RULE_SRC_OR_DST: + dst |= src; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC_AND_NOT_DST: + dst = !dst & !src; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC_XOR_DST: + dst ^= !src; + break; + + case CATSEYE_REPLACE_RULE_NOT_DST: + dst ^= true; + break; + + case CATSEYE_REPLACE_RULE_SRC_OR_NOT_DST: + dst = src | !dst; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC: + dst = !src; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC_OR_DST: + dst |= !src; + break; + + case CATSEYE_REPLACE_RULE_NOT_SRC_OR_NOT_DST: + dst = !src | !dst; + break; + + case CATSEYE_REPLACE_RULE_SET: + dst = true; + break; + + } +} + +template +void catseye_device::window_move() +{ + + if (!m_fb_enable[idx]) + return; + + LOGMASKED(LOG_WMOVE, "%s%d: %3ux%3u -> %3ux%3u / %3ux%3u planemode %04x wrr %04x, trr %04x m_trrctl %04x acntr %04x\n", + __func__, idx, m_wmsourcex, m_wmsourcey, m_wmdestx, m_wmdesty, m_wmwidth, m_wmheight, m_planemode[idx], + m_wrr[idx], m_trr[idx], m_trrctl[idx], m_acntrl); + + int line, endline, lineincr; + + if (m_wmdesty > m_wmsourcey) { + /* move down */ + line = m_wmheight-1; + endline = -1; + lineincr = -1; + } else { + /* move up */ + line = 0; + endline = m_wmheight; + lineincr = 1; + } + + int startcolumn, endcolumn, columnincr; + if (m_wmdestx > m_wmsourcex) { + /* move right */ + startcolumn = m_wmwidth-1; + endcolumn = -1; + columnincr = -1; + } else { + /* move left */ + startcolumn = 0; + endcolumn = m_wmwidth; + columnincr = 1; + } + + for ( ; line != endline; line += lineincr) { + for (int column = startcolumn; column != endcolumn; column += columnincr) { + const int sx = m_wmsourcex + column; + const int sy = m_wmsourcey + line; + const int dx = m_wmdestx + column; + const int dy = m_wmdesty + line; + + if ((m_misc & CATSEYE_MISC_ENABLE_CLIP) && + (dy < m_wmcliptop || + (dy > m_wmclipbottom) || + (dx < m_wmclipleft) || + (dx > m_wmclipright))) { + continue; + } + + bool dst = false; + + if (m_trrctl[idx] & 0x0100) { + bool bit = m_patterns[idx][(m_plane << 4) | (dy & 0xf)] & (1 << (dx & 0xf)); + switch (m_trr[idx] >> 8) { + + case 0xf0: + dst = bit; + break; + + default: + logerror("%s: unknown trr %02x\n", __func__, m_trr[idx] >> 8); + break; + } + } else { + bool const src = get_vram_pixel_plane(sx, sy); + dst = get_vram_pixel(dx, dy); + execute_rule(src, m_wrr[idx] & 0x0f, dst); + } + modify_vram(dx, dy, dst); + } + } +} + + +template +void catseye_device::draw_pixel(int x, int y, int color) +{ + if ((m_misc & CATSEYE_MISC_ENABLE_CLIP) && + (x < m_wmclipleft || + x > m_wmclipright || + y < m_wmcliptop || + y > m_wmclipbottom)) + return; + + bool src = color & m_plane_mask_l; + bool dst = get_vram_pixel(x, y); + execute_rule(src, (m_prr[idx] >> 8) & 0x0f, dst); + modify_vram(x, y, dst); + m_status |= CATSEYE_STATUS_UNCLIPPED; +} + +template +void catseye_device::draw_line() +{ + const int color = m_color[idx] >> 8; + int x1 = m_wmsourcex; + int y1 = m_wmsourcey; + int x2 = m_wmdestx; + int y2 = m_wmdesty; + int dx, dy, t, e, x, y, incy, diago, horiz; + bool c1; + + LOGMASKED(LOG_WMOVE, "%s%d %dx%d -> %dx%d, color %d\n", + __func__, idx, m_wmsourcex, m_wmsourcey, m_wmdestx, m_wmdesty, color); + + c1 = false; + incy = 1; + + if (x2 > x1) + dx = x2 - x1; + else + dx = x1 - x2; + + if (y2 > y1) + dy = y2 - y1; + else + dy = y1 - y2; + + if (dy > dx) { + t = y2; + y2 = x2; + x2 = t; + + t = y1; + y1 = x1; + x1 = t; + + t = dx; + dx = dy; + dy = t; + + c1 = true; + } + + if (x1 > x2) { + t = y2; + y2 = y1; + y1 = t; + + t = x1; + x1 = x2; + x2 = t; + } + + horiz = dy << 1; + diago = (dy - dx) << 1; + e = (dy << 1) - dx; + + if (y1 <= y2) + incy = 1; + else + incy = -1; + + x = x1; + y = y1; + + if (c1) { + do { + draw_pixel(y, x, color); + + if (e > 0) { + y += incy; + e += diago; + } else { + e += horiz; + } + x++; + } while (x <= x2); + } else { + do { + draw_pixel(x, y, color); + if (e > 0) { + y += incy; + e += diago; + } else { + e += horiz; + } + x++; + } while (x <= x2); + } + +} + +template +void catseye_device::trigger_wm() +{ + if (!m_fb_enable[idx]) + return; + + if ((m_vb[idx] & CATSEYE_VB_VECTOR) && (m_rugsc == 0x10)) + draw_line(); + else if (m_rugsc == 0x90) + window_move(); + else + logerror("%s: unsupported rugcmd: %04x vb %04x\n", __func__, m_rugsc, m_vb[idx]); +} + +template +u16 catseye_device::vram_r_bit(offs_t offset) +{ + u16 ret = 0; + + offset &= ~0x7; + + for(int i = 0; i < 16; i++) + ret |= get_vram_offset_plane(offset * 2 + 15 - i) ? (1 << i) : 0; + return ret; +} + +template +u16 catseye_device::vram_r_word(offs_t offset, u16 mem_mask) +{ + u16 ret = 0; + + if (mem_mask & m_plane_mask_l) + ret |= get_vram_offset(offset * 2 + 1); + + if (mem_mask & m_plane_mask_h) + ret |= get_vram_offset(offset * 2) << 8; + + return ret; +} + +template +u16 catseye_device::vram_r(offs_t offset, u16 mem_mask) +{ + if (m_acntrl & 0x100) + return vram_r_bit(offset); + else + return vram_r_word(offset, mem_mask); +} + +READ16_MEMBER(catseye_device::vram_r) +{ + uint16_t ret = 0; + + if (m_acntrl & 0x200) + ret = vram_r(offset, mem_mask); + else + ret = vram_r(offset, mem_mask); + + LOGMASKED(LOG_VRAM, "%s: %04x: %04x(%04x)\n", __func__, offset << 1, ret, mem_mask); + return ret; +} + +template +void catseye_device::vram_w_bit(offs_t offset, u16 data, u16 mem_mask) +{ + offset &= ~0x7; + + for (int i = 0; i < 16; i++) { + + const int bit = (1 << i); + + if (!(mem_mask & bit)) + continue; + + bool dst = get_vram_offset(offset * 2 + 15 - i); + execute_rule(data & bit, (m_prr[idx] >> 8) & 0x0f, dst); + modify_vram_offset(offset * 2 + 15 - i, dst); + } +} + +template +void catseye_device::vram_w_word(offs_t offset, u16 data, u16 mem_mask) +{ + if (mem_mask & m_plane_mask_l) { + const bool src = data & m_plane_mask_l; + bool dst = get_vram_offset(offset * 2 + 1); + execute_rule(src, (m_prr[idx] >> 8) & 0x0f, dst); + modify_vram_offset(offset * 2 + 1, dst); + } + + if (mem_mask & m_plane_mask_h) { + const bool src = data & m_plane_mask_h; + bool dst = get_vram_offset(offset * 2); + execute_rule(src, (m_prr[idx] >> 8) & 0x0f, dst); + modify_vram_offset(offset * 2, dst); + } +} + +template +void catseye_device::vram_w(offs_t offset, u16 data, u16 mem_mask) +{ + if (m_acntrl & 0x100) + vram_w_bit(offset, data, mem_mask); + else + vram_w_word(offset, data, mem_mask); +} + +WRITE16_MEMBER(catseye_device::vram_w) +{ + LOGMASKED(LOG_VRAM, "%s: %04x: %04x(%04x)\n", __func__, offset << 1, data, mem_mask); + + if (m_fb_enable[0]) + vram_w(offset, data, mem_mask); + + if (m_fb_enable[1]) + vram_w(offset, data, mem_mask); +} + +WRITE16_MEMBER(catseye_device::ctrl_w) +{ + bool trigger = false; + + if (m_write_enable[0] && offset >= 0x200 && offset < 0x280) { + COMBINE_DATA(&m_patterns[0][offset - 0x200]); + LOGMASKED(LOG_REG, "W PATTERNS1[%03d] = %04x\n", offset - 0x200, m_patterns[0][offset - 0x200]); + return; + } + + if (m_write_enable[1] && offset >= 0x300 && offset < 0x380) { + COMBINE_DATA(&m_patterns[1][offset - 0x300]); + LOGMASKED(LOG_REG, "W PATTERNS2[%03d] = %04x\n", offset - 0x300, m_patterns[1][offset - 0x300]); + return; + } + + switch(offset) { + case TOPCAT_REG_ENABLE_BLINK_PLANES: + if (mem_mask & 0xff00) + m_blink_enable = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "enable blink plane: %04x\n", m_blink_enable); + break; + + case TOPCAT_REG_DISPLAY_PLANE_ENABLE: + if (mem_mask & 0xff00) + m_display_enable = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "display enable %04x\n", m_display_enable); + break; + + case TOPCAT_REG_SYNC_ENABLE: + if (mem_mask & 0xff00) + m_sync_enable = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "sync enable: %04x\n", m_sync_enable); + break; + + case TOPCAT_REG_WMOVE_INTRQ: + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMOVE_INTRQ = %04x\n", data); + m_wm_int_pending = 0; + update_int(); + break; + + case TOPCAT_REG_WMOVE_IE: + if (mem_mask & 0xff00) + m_wm_int_enable = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMOVE_IE = %04x\n", m_wm_int_enable); + update_int(); + break; + + case TOPCAT_REG_VBLANK_IE: + if (mem_mask & 0xff00) + m_vblank_int_enable = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMOVE_IE = %04x\n", m_vblank_int_enable); + update_int(); + break; + + case CATSEYE_REG_WMX: + COMBINE_DATA(&m_wmx); + COMBINE_DATA(&m_wmsourcex); + COMBINE_DATA(&m_wmdestx); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMX = %04x\n", m_wmx); + break; + + case CATSEYE_REG_RUG_SC: + COMBINE_DATA(&m_rugsc); + LOGMASKED(LOG_REG, "W CATSEYE_REG_RUG_SC = %04x\n", m_rugsc); + break; + + case TOPCAT_REG_WMWIDTH: + case CATSEYE_REG_WMWIDTH: + COMBINE_DATA(&m_wmwidth); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMWIDTH = %04x\n", m_wmwidth); + break; + + case TOPCAT_REG_WMHEIGHT: + case CATSEYE_REG_WMHEIGHT: + COMBINE_DATA(&m_wmheight); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMHEIGHT = %04x\n", m_wmheight); + break; + + case CATSEYE_REG_LINEPATH: + COMBINE_DATA(&m_linepath); + LOGMASKED(LOG_REG, "W CATSEYE_REG_LINEPATH = %04x\n", m_linepath); + break; + + case CATSEYE_REG_LINETYPE: + COMBINE_DATA(&m_linetype); + LOGMASKED(LOG_REG, "W CATSEYE_REG_LINETYPE = %04x\n", m_linetype); + break; + + + case TOPCAT_REG_WMSOURCEX: + case CATSEYE_REG_WMSOURCEX: + COMBINE_DATA(&m_wmsourcex); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMSOURCEX = %04x\n", m_wmsourcex); + break; + + case TOPCAT_REG_WMSOURCEY: + case CATSEYE_REG_WMSOURCEY: + COMBINE_DATA(&m_wmsourcey); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMSOURCEY = %04x\n", m_wmsourcey); + break; + + case TOPCAT_REG_WMDESTX: + case CATSEYE_REG_WMDESTX: + COMBINE_DATA(&m_wmdestx); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMDESTX = %04x\n", m_wmdestx); + break; + + case TOPCAT_REG_WMDESTY: + case CATSEYE_REG_WMDESTY: + COMBINE_DATA(&m_wmdesty); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMDESTY = %04x\n", m_wmdesty); + break; + + case CATSEYE_REG_WMCLIPLEFT: + COMBINE_DATA(&m_wmclipleft); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMCLIPLEFT = %04x\n", m_wmclipleft); + break; + + case CATSEYE_REG_WMCLIPRIGHT: + COMBINE_DATA(&m_wmclipright); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMCLIPRIGHT = %04x\n", m_wmclipright); + break; + + case CATSEYE_REG_WMCLIPTOP: + COMBINE_DATA(&m_wmcliptop); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMCLIPTOP = %04x\n", m_wmcliptop); + break; + + case CATSEYE_REG_WMCLIPBOTTOM: + COMBINE_DATA(&m_wmclipbottom); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WMCLIPBOTTOM = %04x\n", m_wmclipbottom); + break; + + case CATSEYE_REG_TWMWIDTH: + COMBINE_DATA(&m_wmwidth); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMWIDTH = %04x\n", m_wmwidth); + trigger = true; + break; + + case CATSEYE_REG_TWMHEIGHT: + COMBINE_DATA(&m_wmheight); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMHEIGHT = %04x\n", m_wmheight); + trigger = true; + break; + + case CATSEYE_REG_TWMSOURCEX: + COMBINE_DATA(&m_wmsourcex); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMSOURCEX = %04x\n", m_wmsourcex); + trigger = true; + break; + + case CATSEYE_REG_TWMSOURCEY: + COMBINE_DATA(&m_wmsourcey); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMSOURCEY = %04x\n", m_wmsourcey); + trigger = true; + break; + + case CATSEYE_REG_TWMDESTX: + COMBINE_DATA(&m_wmdestx); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMDESTX = %04x\n", m_wmdestx); + trigger = true; + break; + + case CATSEYE_REG_TWMDESTY: + COMBINE_DATA(&m_wmdesty); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TWMDESTY = %04x\n", m_wmdesty); + trigger = true; + break; + + case TOPCAT_REG_START_WMOVE: + if (m_write_enable[0]) { + LOGMASKED(LOG_REG, "W TOPCAT_REG_START_WMOVE = %04x\n", data); + window_move<0>(); + if (m_wm_int_enable) { + m_wm_int_pending = m_plane_mask_h; + update_int(); + } + } + break; + + case CATSEYE_REG_STATUS: + COMBINE_DATA(&m_status); + LOGMASKED(LOG_REG, "W CATSEYE_REG_STATUS = %04x\n", m_status); + break; + + case CATSEYE_REG_STATUS+1: + case CATSEYE_REG_STATUS+2: + // unknown + break; + + + // TC 1 registers + case TOPCAT_REG_READ_ENABLE_PLANE: + case CATSEYE_REG_TCREN1: + if (mem_mask & m_plane_mask_h) + m_read_enable[0] = data & m_plane_mask_l; + LOGMASKED(LOG_REG, "W CATSEYE_REG_READ_ENABLE1 = %04x\n", m_read_enable[0]); + break; + + case TOPCAT_REG_WRITE_ENABLE_PLANE: + case CATSEYE_REG_TCWEN1: + if (mem_mask & m_plane_mask_h) + m_write_enable[0] = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_WRITE_ENABLE1 = %04x\n", m_write_enable[0]); + break; + + case TOPCAT_REG_FB_WRITE_ENABLE: + case CATSEYE_REG_FBEN1: + if (mem_mask & m_plane_mask_h) + m_fb_enable[0] = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_FBEN1 = %04x\n", m_fb_enable[0]); + break; + + case TOPCAT_REG_PRR: + case CATSEYE_REG_PRR1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_prr[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_PRR1 = %04x\n", m_prr[0]); + break; + + case TOPCAT_REG_WRR: + case CATSEYE_REG_WRR1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_wrr[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WRR1 = %04x\n", m_wrr[0]); + break; + + case CATSEYE_REG_TRR1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_trr[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TRR1 = %04x\n", m_trr[0]); + break; + + case CATSEYE_REG_VB1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_vb[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_VB1 = %04x\n", m_vb[0]); + break; + + case CATSEYE_REG_COLOR1: + COMBINE_DATA(&m_color[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_COLOR1 = %04x\n", m_color[0]); + break; + + case CATSEYE_REG_TRRCTL1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_trrctl[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TRRCTL1 = %04x\n", m_trrctl[0]); + break; + + case CATSEYE_REG_ACNTL1: + if (!m_write_enable[0]) + break; + COMBINE_DATA(&m_acntrl); + LOGMASKED(LOG_REG, "W CATSEYE_REG_ACNTL1 = %04x\n", m_acntrl); + break; + + case CATSEYE_REG_PLANEMODE1: + COMBINE_DATA(&m_planemode[0]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_PLANEMODE1 = %04x\n", m_planemode[0]); + break; + + // TC 2 registers + case CATSEYE_REG_TCREN2: + if (mem_mask & 0xff00) + m_read_enable[1] = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_READ_ENABLE2 = %04x\n", m_read_enable[1]); + break; + + case CATSEYE_REG_TCWEN2: + if (mem_mask & 0xff00) + m_write_enable[1] = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_READ_ENABLE2 = %04x\n", m_write_enable[1]); + break; + + case CATSEYE_REG_FBEN2: + if (mem_mask & 0xff00) + m_fb_enable[1] = data & m_plane_mask_h; + LOGMASKED(LOG_REG, "W CATSEYE_REG_READ_ENABLE2 = %04x\n", m_fb_enable[1]); + break; + + case CATSEYE_REG_PRR2: + if (!m_write_enable[1]) + break; + COMBINE_DATA(&m_prr[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_PRR2 = %04x\n", m_prr[1]); + break; + + case CATSEYE_REG_WRR2: + if (!m_write_enable[1]) + break; + COMBINE_DATA(&m_wrr[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_WRR2 = %04x\n", m_wrr[1]); + break; + + case CATSEYE_REG_TRR2: + if (!m_write_enable[1]) + break; + COMBINE_DATA(&m_trr[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TRR2 = %04x\n", m_trr[1]); + break; + + case CATSEYE_REG_VB2: + if (!m_write_enable[1]) + break; + + COMBINE_DATA(&m_vb[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_VB2 = %04x\n", m_vb[1]); + break; + + case CATSEYE_REG_COLOR2: + COMBINE_DATA(&m_color[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_COLOR2 = %04x\n", m_color[1]); + break; + + case CATSEYE_REG_TRRCTL2: + if (!m_write_enable[1]) + break; + + COMBINE_DATA(&m_trrctl[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_TRRCTL2 = %04x\n", m_trrctl[1]); + break; + + case CATSEYE_REG_ACNTL2: + if (!m_write_enable[1]) + break; + + COMBINE_DATA(&m_acntrl); + LOGMASKED(LOG_REG, "W CATSEYE_REG_ACNTL2 = %04x\n", m_acntrl); + break; + + case CATSEYE_REG_PLANEMODE2: + if (!m_write_enable[1]) + break; + + COMBINE_DATA(&m_planemode[1]); + LOGMASKED(LOG_REG, "W CATSEYE_REG_PLANEMODE2 = %04x\n", m_planemode[1]); + break; + case CATSEYE_REG_RUG_REV: + COMBINE_DATA(&m_misc); + LOGMASKED(LOG_REG, "W CATSEYE_REG_MISC = %04x\n", m_misc); + break; + default: + logerror("%s: unknown: %04x = %04x (mask %04x)\n", __func__, offset << 1, data, mem_mask); + return; + } + + if (m_fb_enable[0] && trigger) + trigger_wm(); + + if (m_fb_enable[1] && trigger) + trigger_wm(); + +} + +READ16_MEMBER(catseye_device::ctrl_r) +{ + uint16_t ret; + + if (offset >= 0x200 && offset < 0x280) { + LOGMASKED(LOG_REG, "R PATTERNS1[%03d] = %04x\n", offset - 0x200, m_patterns[0][offset - 0x200]); + return m_patterns[0][offset - 0x200]; + } + + if (offset >= 0x300 && offset < 0x380) { + LOGMASKED(LOG_REG, "R PATTERNS2[%03d] = %04x\n", offset - 0x300, m_patterns[1][offset - 0x300]); + return m_patterns[1][offset - 0x300]; + } + + switch(offset) { + case TOPCAT_REG_ENABLE_BLINK_PLANES: + ret = m_blink_enable; + break; + + case TOPCAT_REG_SYNC_ENABLE: + ret = m_sync_enable; + break; + + case TOPCAT_REG_DISPLAY_PLANE_ENABLE: + ret = m_display_enable; + break; + + case TOPCAT_REG_VBLANK: + ret = m_in_vblank; + LOGMASKED(LOG_REG, "R VBLANK = %04x\n", ret); + break; + + case TOPCAT_REG_WMOVE_INTRQ: + ret = m_wm_int_pending; + LOGMASKED(LOG_REG, "R WMOVE_INTRQ = %04x\n", ret); + break; + + case TOPCAT_REG_VBLANK_INTRQ: + ret = m_vblank_int_pending; + LOGMASKED(LOG_REG, "R VBLANK_INTRQ = %04x\n", ret); + break; + + case TOPCAT_REG_WMOVE_IE: + ret = m_wm_int_enable; + LOGMASKED(LOG_REG, "R WMOVE_IE = %04x\n", ret); + break; + + case TOPCAT_REG_VBLANK_IE: + ret = m_vblank_int_enable; + LOGMASKED(LOG_REG, "R VBLANK_IE = %04x\n", ret); + break; + + case CATSEYE_REG_RUG_SC: + ret = m_rugsc; + LOGMASKED(LOG_REG, "R CATSEYE_REG_RUG_SC = %04x\n", ret); + break; + + case TOPCAT_REG_WMWIDTH: + case CATSEYE_REG_WMWIDTH: + ret = m_wmwidth; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMWIDTH = %04x\n", ret); + break; + + case TOPCAT_REG_WMHEIGHT: + case CATSEYE_REG_WMHEIGHT: + ret = m_wmheight; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMHEIGHT = %04x\n", ret); + break; + + case CATSEYE_REG_LINEPATH: + ret = m_linepath; + LOGMASKED(LOG_REG, "R CATSEYE_REG_LINEPATH = %04x\n", ret); + break; + + case CATSEYE_REG_LINETYPE: + ret = m_linetype; + LOGMASKED(LOG_REG, "R CATSEYE_REG_LINETYPE = %04x\n", ret); + break; + + case TOPCAT_REG_WMSOURCEX: + case CATSEYE_REG_WMSOURCEX: + ret = m_wmsourcex; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMSOURCEX = %04x\n", ret); + break; + + case TOPCAT_REG_WMSOURCEY: + case CATSEYE_REG_WMSOURCEY: + ret = m_wmsourcey; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMSOURCEY = %04x\n", ret); + break; + + case TOPCAT_REG_WMDESTX: + case CATSEYE_REG_WMDESTX: + ret = m_wmdestx; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMDESTX = %04x\n", ret); + break; + + case TOPCAT_REG_WMDESTY: + case CATSEYE_REG_WMDESTY: + ret = m_wmdesty; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMDESTY = %04x\n", ret); + break; + + case CATSEYE_REG_WMCLIPLEFT: + ret = m_wmclipleft; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMCLIPLEFT = %04x\n", ret); + break; + + case CATSEYE_REG_WMCLIPRIGHT: + ret = m_wmclipright; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMCLIPRIGHT = %04x\n", ret); + break; + + case CATSEYE_REG_WMCLIPTOP: + ret = m_wmcliptop; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMCLIPTOP = %04x\n", ret); + break; + + case CATSEYE_REG_WMCLIPBOTTOM: + ret = m_wmclipbottom; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WMCLIPBOTTOM = %04x\n", ret); + break; + + case CATSEYE_REG_TWMWIDTH: + ret = m_wmwidth; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMWIDTH = %04x\n", ret); + break; + + case CATSEYE_REG_TWMHEIGHT: + ret = m_wmheight; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMHEIGHT = %04x\n", ret); + break; + + case CATSEYE_REG_TWMSOURCEX: + ret = m_wmsourcex; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMSOURCEX = %04x\n", ret); + break; + + case CATSEYE_REG_TWMSOURCEY: + ret = m_wmsourcey; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMSOURCEY = %04x\n", ret); + break; + + case CATSEYE_REG_TWMDESTX: + ret = m_wmdestx; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMDESTX = %04x\n", ret); + break; + + case CATSEYE_REG_TWMDESTY: + ret = m_wmdesty; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TWMDESTY = %04x\n", ret); + break; + + case CATSEYE_REG_STATUS: + ret = CATSEYE_STATUS_READY | CATSEYE_STATUS_NO_DAUGHTERBOARD; + ret |= m_status & ~CATSEYE_STATUS_VBLANK; + if (m_in_vblank) + ret |= CATSEYE_STATUS_VBLANK; + + LOGMASKED(LOG_REG, "R CATSEYE_REG_STATUS = %04x\n", ret); + break; + + case CATSEYE_REG_STATUS+1: + case CATSEYE_REG_STATUS+2: + // unknown + ret = 0; + break; + + case TOPCAT_REG_START_WMOVE: + m_wm_int_pending = 0; + update_int(); + ret = 0; + break; + + case CATSEYE_REG_RUG_REV: + ret = m_misc; + LOGMASKED(LOG_REG, "R CATSEYE_REG_RUG_REV = %04x\n", ret); + break; + + // TC1 + case TOPCAT_REG_FB_WRITE_ENABLE: + case CATSEYE_REG_FBEN1: + ret = m_fb_enable[0]; + break; + + case TOPCAT_REG_READ_ENABLE_PLANE: + case CATSEYE_REG_TCREN1: + ret = m_read_enable[0]; + break; + + case TOPCAT_REG_WRITE_ENABLE_PLANE: + case CATSEYE_REG_TCWEN1: + ret = m_write_enable[0]; + break; + + case TOPCAT_REG_PRR: + case CATSEYE_REG_PRR1: + if (m_read_enable[0]) + return 0; + + ret = m_prr[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_PRR1 = %04x\n", ret); + break; + + case TOPCAT_REG_WRR: + case CATSEYE_REG_WRR1: + if (m_read_enable[0]) + return 0; + + ret = m_wrr[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WRR1 = %04x\n", ret); + break; + + case CATSEYE_REG_TRR1: + if (m_read_enable[0]) + return 0; + + ret = m_trr[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TRR1 = %04x\n", ret); + break; + + case CATSEYE_REG_COLOR1: + if (m_read_enable[0]) + return 0; + + ret = m_color[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_COLOR1 = %04x\n", ret); + break; + + case CATSEYE_REG_VB1: + if (m_read_enable[0]) + return 0; + + ret = m_vb[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_VB1 = %04x\n", ret); + break; + + case CATSEYE_REG_TRRCTL1: + if (m_read_enable[0]) + return 0; + + ret = m_trrctl[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TRRCTL1 = %04x\n", ret); + break; + + case CATSEYE_REG_ACNTL1: + if (m_read_enable[0]) + return 0; + + ret = m_acntrl; + LOGMASKED(LOG_REG, "R CATSEYE_REG_ACNTL1 = %04x\n", ret); + break; + + case CATSEYE_REG_PLANEMODE1: + if (m_read_enable[0]) + return 0; + + ret = m_planemode[0]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_PLANEMODE1 = %04x\n", ret); + break; + + case CATSEYE_REG_BARC_REV1: + ret = 0x0100; + break; + + // TC2 + case CATSEYE_REG_FBEN2: + ret = m_fb_enable[1]; + break; + + case CATSEYE_REG_TCREN2: + ret = m_read_enable[1]; + break; + + case CATSEYE_REG_TCWEN2: + ret = m_write_enable[1]; + break; + + case CATSEYE_REG_PRR2: + if (m_read_enable[1]) + return 0; + + ret = m_prr[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_PRR2 = %04x\n", ret); + break; + + case CATSEYE_REG_WRR2: + if (m_read_enable[1]) + return 0; + + ret = m_wrr[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_WRR2 = %04x\n", ret); + break; + + case CATSEYE_REG_TRR2: + if (m_read_enable[1]) + return 0; + + ret = m_trr[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TRR2 = %04x\n", ret); + break; + + case CATSEYE_REG_COLOR2: + if (m_read_enable[1]) + return 0; + + ret = m_color[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_COLOR2 = %04x\n", ret); + break; + + case CATSEYE_REG_VB2: + if (m_read_enable[1]) + return 0; + + ret = m_vb[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_VB2 = %04x\n", ret); + break; + + case CATSEYE_REG_TRRCTL2: + if (m_read_enable[1]) + return 0; + + ret = m_trrctl[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_TRRCTL2 = %04x\n", ret); + break; + + case CATSEYE_REG_ACNTL2: + if (m_read_enable[1]) + return 0; + + ret = m_acntrl; + LOGMASKED(LOG_REG, "R CATSEYE_REG_ACNTL2 = %04x\n", ret); + break; + + case CATSEYE_REG_PLANEMODE2: + if (m_read_enable[1]) + return 0; + + ret = m_planemode[1]; + LOGMASKED(LOG_REG, "R CATSEYE_REG_PLANEMODE2 = %04x\n", ret); + break; + + case CATSEYE_REG_BARC_REV2: + ret = 0x0100; + break; + + default: + logerror("%s: unknown: %04x (mask %04x)\n", __func__, offset << 1, mem_mask); + return space.unmap(); + } + return ret; +} + +WRITE_LINE_MEMBER(catseye_device::vblank_w) +{ + m_in_vblank = state ? m_plane_mask_h : 0; + if (state && m_vblank_int_enable) + m_vblank_int_pending = m_plane_mask_h; +} diff --git a/src/devices/video/catseye.h b/src/devices/video/catseye.h new file mode 100644 index 00000000000..257ae13f3ee --- /dev/null +++ b/src/devices/video/catseye.h @@ -0,0 +1,369 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle +#ifndef MAME_VIDEO_CATSEYE_H +#define MAME_VIDEO_CATSEYE_H + +#pragma once + +class catseye_device: public device_t +{ +public: + catseye_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ16_MEMBER(vram_r); + DECLARE_WRITE16_MEMBER(vram_w); + DECLARE_READ16_MEMBER(ctrl_r); + DECLARE_WRITE16_MEMBER(ctrl_w); + DECLARE_WRITE_LINE_MEMBER(vblank_w); + + void set_fb_width(int width) { m_fb_width = width; } + void set_fb_height(int height) { m_fb_height = height; } + void set_plane(const u8 plane) { + m_plane_mask_l = (1 << plane); + m_plane_mask_h = (0x100 << plane); + m_plane = plane; + } + + bool has_changed() { + bool ret = m_changed; + m_changed = false; + return ret; + }; + + u8 plane_enabled() const { + if (!m_display_enable || (m_blink_enable && !m_blink_state)) + return 0; + return m_plane_mask_l; + } + + auto irq_out_cb() { return m_int_write_func.bind(); } + +protected: + + required_shared_ptr_array m_vram; + catseye_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + devcb_write8 m_int_write_func; + TIMER_CALLBACK_MEMBER(blink_callback); + + virtual void device_start() override; + virtual void device_reset() override; + + void execute_rule(const bool src, const int rule, bool &dst) const; + void update_int(); + + template void window_move(); + template void draw_line(); + template void trigger_wm(); + template void draw_pixel(int x, int y, int color); + template void vram_w(offs_t offset, u16 data, u16 mem_mask); + template void vram_w_bit(offs_t offset, u16 data, u16 mem_mask); + template void vram_w_word(offs_t offset, u16 data, u16 mem_mask); + template u16 vram_r(offs_t offset, u16 mem_mask); + template u16 vram_r_bit(offs_t offset); + template u16 vram_r_word(offs_t offset, u16 mem_mask); + + int get_plane_from_idx(const int idx) const { + if (idx == VRAM_VIDEO_PLANE) { + if (m_acntrl == 0x0200) + return VRAM_OVERLAY_PLANE; + else + return VRAM_VIDEO_PLANE; + } else { + if (m_acntrl == 0x0200) + return VRAM_VIDEO_PLANE; + else + return VRAM_OVERLAY_PLANE; + } + } + + template + void modify_vram(int x, int y, bool state) { + m_changed = true; + m_status |= CATSEYE_STATUS_UNCLIPPED; + const int offset = y * m_fb_width + x; + if (state) + m_vram[idx][offset] |= m_plane_mask_l; + else + m_vram[idx][offset] &= ~m_plane_mask_l; + } + + template + void modify_vram_offset(int offset, bool state) { + m_changed = true; + m_status |= CATSEYE_STATUS_UNCLIPPED; + if (state) + m_vram[idx][offset] |= m_plane_mask_l; + else + m_vram[idx][offset] &= ~m_plane_mask_l; + } + + template + u8 get_vram_offset_plane(int offset) const { + const int plane = (m_planemode[idx] >> 8) & 0x0f; + if (!m_planemode[idx]) + return m_vram[idx][offset] & m_plane_mask_l; + else if (plane < 8) + return m_vram[idx][offset] & (1 << plane); + else + return m_vram[idx][offset] & (1 << (plane-8)); + } + + + template + u8 get_vram_offset(int offset) const { + return m_vram[idx][offset] & m_plane_mask_l; + } + + template + bool get_vram_pixel(int x, int y) const { + return m_vram[get_plane_from_idx(idx)][y * m_fb_width + x] & m_plane_mask_l; + } + + template + bool get_vram_pixel_plane(int x, int y) const { + const int plane = (m_planemode[idx] >> 8) & 0x0f; + const int offset = y * m_fb_width + x; + if (!(m_planemode[idx] & (1 << 12))) + return m_vram[idx][offset] & m_plane_mask_l; + else if (plane < 8) + return m_vram[0][offset] & (1 << plane); + else + return m_vram[1][offset] & (1 << (plane-8)); + } + + static constexpr int CATSEYE_REPLACE_RULE_CLEAR = 0; + static constexpr int CATSEYE_REPLACE_RULE_SRC_AND_DST = 1; + static constexpr int CATSEYE_REPLACE_RULE_SRC_AND_NOT_DST = 2; + static constexpr int CATSEYE_REPLACE_RULE_SRC = 3; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC_AND_DST = 4; + static constexpr int CATSEYE_REPLACE_RULE_NOP = 5; + static constexpr int CATSEYE_REPLACE_RULE_SRC_XOR_DST = 6; + static constexpr int CATSEYE_REPLACE_RULE_SRC_OR_DST = 7; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC_AND_NOT_DST = 8; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC_XOR_DST = 9; + static constexpr int CATSEYE_REPLACE_RULE_NOT_DST = 10; + static constexpr int CATSEYE_REPLACE_RULE_SRC_OR_NOT_DST = 11; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC = 12; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC_OR_DST = 13; + static constexpr int CATSEYE_REPLACE_RULE_NOT_SRC_OR_NOT_DST = 14; + static constexpr int CATSEYE_REPLACE_RULE_SET = 15; + + // registers compatible to topcat + static constexpr int TOPCAT_REG_VBLANK=0x20; + static constexpr int TOPCAT_REG_WMOVE_ACTIVE=0x22; + static constexpr int TOPCAT_REG_VBLANK_INTRQ=0x24; + static constexpr int TOPCAT_REG_WMOVE_INTRQ=0x26; + static constexpr int TOPCAT_REG_DISPLAY_PLANE_ENABLE=0x40; + static constexpr int TOPCAT_REG_SYNC_ENABLE=0x42; + static constexpr int TOPCAT_REG_WRITE_ENABLE_PLANE=0x44; + static constexpr int TOPCAT_REG_READ_ENABLE_PLANE=0x46; + static constexpr int TOPCAT_REG_FB_WRITE_ENABLE=0x48; + static constexpr int TOPCAT_REG_WMOVE_IE=0x4a; + static constexpr int TOPCAT_REG_VBLANK_IE=0x4c; + static constexpr int TOPCAT_REG_START_WMOVE=0x4e; + static constexpr int TOPCAT_REG_ENABLE_BLINK_PLANES=0x50; + static constexpr int TOPCAT_REG_ENABLE_ALT_FRAME=0x54; + static constexpr int TOPCAT_REG_PRR=0x75; + static constexpr int TOPCAT_REG_WRR=0x77; + static constexpr int TOPCAT_REG_WMSOURCEX=0x79; + static constexpr int TOPCAT_REG_WMSOURCEY=0x7b; + static constexpr int TOPCAT_REG_WMDESTX=0x7d; + static constexpr int TOPCAT_REG_WMDESTY=0x7f; + static constexpr int TOPCAT_REG_WMWIDTH=0x81; + static constexpr int TOPCAT_REG_WMHEIGHT=0x83; + + // catseye specific registers + static constexpr int CATSEYE_REG_WMX=0x100; + static constexpr int CATSEYE_REG_RUG_REV=0x102; + static constexpr int CATSEYE_REG_RUG_SC=0x103; + static constexpr int CATSEYE_REG_WMWIDTH=0x104; + static constexpr int CATSEYE_REG_WMHEIGHT=0x105; + static constexpr int CATSEYE_REG_LINEPATH=0x106; + static constexpr int CATSEYE_REG_LINETYPE=0x107; + static constexpr int CATSEYE_REG_WMSOURCEX=0x108; + static constexpr int CATSEYE_REG_WMSOURCEY=0x109; + static constexpr int CATSEYE_REG_WMDESTX=0x10a; + static constexpr int CATSEYE_REG_WMDESTY=0x10b; + static constexpr int CATSEYE_REG_WMCLIPLEFT=0x10c; + static constexpr int CATSEYE_REG_WMCLIPRIGHT=0x10d; + static constexpr int CATSEYE_REG_WMCLIPTOP=0x10e; + static constexpr int CATSEYE_REG_WMCLIPBOTTOM=0x10f; + static constexpr int CATSEYE_REG_TWMWIDTH=0x184; + static constexpr int CATSEYE_REG_TWMHEIGHT=0x185; + static constexpr int CATSEYE_REG_TWMSOURCEX=0x188; + static constexpr int CATSEYE_REG_TWMSOURCEY=0x189; + static constexpr int CATSEYE_REG_TWMDESTX=0x18a; + static constexpr int CATSEYE_REG_TWMDESTY=0x18b; + + // Window mover 1 registers + static constexpr int CATSEYE_REG_PATTERNS1=0x200; + static constexpr int CATSEYE_REG_FBEN1=0x280; + static constexpr int CATSEYE_REG_PRR1=0x281; + static constexpr int CATSEYE_REG_TCREN1=0x282; + static constexpr int CATSEYE_REG_WRR1=0x283; + static constexpr int CATSEYE_REG_TCWEN1=0x284; + static constexpr int CATSEYE_REG_BARC_REV1=0x285; + static constexpr int CATSEYE_REG_TRR1=0x286; + static constexpr int CATSEYE_REG_COLOR1=0x287; + static constexpr int CATSEYE_REG_VB1=0x288; + static constexpr int CATSEYE_REG_TRRCTL1=0x289; + static constexpr int CATSEYE_REG_ACNTL1=0x28a; + static constexpr int CATSEYE_REG_PLANEMODE1=0x28b; + + // Window mover 2 registers + static constexpr int CATSEYE_REG_PATTERNS2=0x300; + static constexpr int CATSEYE_REG_FBEN2=0x380; + static constexpr int CATSEYE_REG_PRR2=0x381; + static constexpr int CATSEYE_REG_TCREN2=0x382; + static constexpr int CATSEYE_REG_WRR2=0x383; + static constexpr int CATSEYE_REG_TCWEN2=0x384; + static constexpr int CATSEYE_REG_BARC_REV2=0x385; + static constexpr int CATSEYE_REG_TRR2=0x386; + static constexpr int CATSEYE_REG_COLOR2=0x387; + static constexpr int CATSEYE_REG_VB2=0x388; + static constexpr int CATSEYE_REG_TRRCTL2=0x389; + static constexpr int CATSEYE_REG_ACNTL2=0x38a; + static constexpr int CATSEYE_REG_PLANEMODE2=0x38b; + + static constexpr int CATSEYE_REG_STATUS=0x400; + + static constexpr u16 CATSEYE_STATUS_READY = 0x02; + static constexpr u16 CATSEYE_STATUS_UNCLIPPED = 0x04; + static constexpr u16 CATSEYE_STATUS_NO_DAUGHTERBOARD = 0x08; + static constexpr u16 CATSEYE_STATUS_VBLANK = 0x10; + + // bit definitions for various registers + static constexpr u16 CATSEYE_VB_VECTOR = 0x100; + static constexpr u16 CATSEYE_MISC_ENABLE_CLIP = 0x80; + static constexpr int VRAM_VIDEO_PLANE = 0; + static constexpr int VRAM_OVERLAY_PLANE = 1; + + emu_timer *m_blink_timer; + + // set when screen contents have changed + bool m_changed; + + // keeps track of visibility when plane is enabled for blinking + bool m_blink_state; + + // configuration settings + int m_fb_width; + int m_fb_height; + int m_plane; + + // we keep the plane mask twice - once for matching the lower byte, + // and once for matching the higher byte. + u16 m_plane_mask_l; + u16 m_plane_mask_h; + + // registers are enabled to be written by host cpu + u16 m_write_enable[2]; + + // registers are enabled to be read by host cpu + u16 m_read_enable[2]; + + // enables writing to plane from window mover + u16 m_fb_enable[2]; + + // plane is visible on screen + u16 m_display_enable; + + // plane is blinking + u16 m_blink_enable; + + // sync output to monitor is enabled (ignored) + u16 m_sync_enable; + + // video output is blanked due to vert retrace + u16 m_in_vblank; + + // interrupt status & enable + u16 m_wm_int_pending; + u16 m_vblank_int_pending; + u16 m_wm_int_enable; + u16 m_vblank_int_enable; + + // RUGCMD: + // bit 7-6: 0 - solid vector/circle + // 1 - linetype vector/circle + // 2 - blit mode + // 3 - fill mode + // bit 5: 1 - draw circle, 0 - draw vector + // bit 4: 1 - RUG is allowed to write to framebuffer + + u16 m_rugsc; + + // unknown, bit 7 enables window mover clipping + u16 m_misc; + + // WMX register allows to set SOURCEX and DESTX register + // in the window mover at the same time + u16 m_wmx; + + // co-ordinates for window mover + u16 m_wmwidth; + u16 m_wmheight; + u16 m_wmsourcex; + u16 m_wmsourcey; + u16 m_wmdestx; + u16 m_wmdesty; + + // limits for window mover + // (pixels outside of this range will not be drawn) + u16 m_wmclipleft; + u16 m_wmclipright; + u16 m_wmcliptop; + u16 m_wmclipbottom; + + // patterns for tripple replacement rules + std::array, 2> m_patterns; + + // 16 bit pattern for lines drawn + u16 m_linepath; + + // bit 11-8: repeat length + // bit 7-4: current pattern bit + // bit 3-0: current repeat count + u16 m_linetype; + + // Pixel replacement rule, applied when writing to VRAM from host CPU + u16 m_prr[2]; + + // Window replacement rule, applied by window mover + u16 m_wrr[2]; + + // Tripple replacement rule, used together with the patterns register + u16 m_trr[2]; + + // bit 8: 1 - enable tripple replacement rule + u16 m_trrctl[2]; + + // color used for drawing vectors + u16 m_color[2]; + + // unknown, bit 8: 1 - vector mode, 0 - bitblt mode + u16 m_vb[2]; + + // bit 1: 1 - VRAM is accessed in bit-mode by host CPU + // 2 bytes are expanded to 16 bytes, with 1 bit per byte information + // bit 2: 1 - host CPU reads overlay plane via host interface + u16 m_acntrl; + + // source plane for window mover operations + // bit 4: 1 - source plane is given in bit 3-0 + // 0 - current plane is source for move + u16 m_planemode[2]; + + // bit 0: 1 - window mover busy + // bit 1: 1 - registers ready for host CPU + // bit 2: 1 - pixels generated by RUG + // bit 3: 1 - no daughter board present + // bit 4: 1 - in vertical blank + // bit 4: 1 - in horizontal sync + u16 m_status; + +}; + +DECLARE_DEVICE_TYPE(CATSEYE, catseye_device) +#endif // MAME_VIDEO_CATSEYE_H diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp index 1310fc1b000..7b46160bb58 100644 --- a/src/emu/xtal.cpp +++ b/src/emu/xtal.cpp @@ -378,6 +378,7 @@ const double XTAL::known_xtals[] = { 87'183'360, /* 87.18336_MHz_XTAL AT&T 630 MTG */ 100'000'000, /* 100_MHz_XTAL PSX-based Namco System 12, Vegas, Sony ZN1-2-based */ 101'491'200, /* 101.4912_MHz_XTAL PSX-based Namco System 10 */ + 108'108'000, /* 108.108_MHz_XTAL HP 98550 high-res color card */ 200'000'000 /* 200_MHz_XTAL Base SH4 CPU (Naomi, Hikaru etc.) */ }; diff --git a/src/mame/drivers/hp9k_3xx.cpp b/src/mame/drivers/hp9k_3xx.cpp index 29061c95c82..4ccf982dd4c 100644 --- a/src/mame/drivers/hp9k_3xx.cpp +++ b/src/mame/drivers/hp9k_3xx.cpp @@ -357,13 +357,13 @@ MACHINE_CONFIG_START(hp9k3xx_state::hp9k320) hp9k300(config); add_dio32_bus(config); - DIO32_SLOT(config, "sl0", 0, "diobus", dio16_cards, "human_interface", true); - DIO32_SLOT(config, "sl1", 0, "diobus", dio16_cards, "98543", false); - DIO32_SLOT(config, "sl2", 0, "diobus", dio16_cards, "98603b", false); - DIO32_SLOT(config, "sl3", 0, "diobus", dio16_cards, "98644", false); + DIO32_SLOT(config, "sl0", 0, "diobus", dio32_cards, "human_interface", true); + DIO32_SLOT(config, "sl1", 0, "diobus", dio32_cards, "98543", false); + DIO32_SLOT(config, "sl2", 0, "diobus", dio32_cards, "98603b", false); + DIO32_SLOT(config, "sl3", 0, "diobus", dio32_cards, "98644", false); DIO32_SLOT(config, "sl4", 0, "diobus", dio32_cards, "98620", false); DIO32_SLOT(config, "sl5", 0, "diobus", dio32_cards, "98265a", false); - DIO32_SLOT(config, "sl6", 0, "diobus", dio16_cards, nullptr, false); + DIO32_SLOT(config, "sl6", 0, "diobus", dio32_cards, nullptr, false); MACHINE_CONFIG_END MACHINE_CONFIG_START(hp9k3xx_state::hp9k330) diff --git a/src/mame/layout/hp9k_3xx.lay b/src/mame/layout/hp9k_3xx.lay index 5ea470b0156..e52ea316517 100644 --- a/src/mame/layout/hp9k_3xx.lay +++ b/src/mame/layout/hp9k_3xx.lay @@ -15,45 +15,33 @@ Hewlett-Packard 9000/3xx Layout + + + + + - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + - + + - + -- cgit v1.2.3