diff options
Diffstat (limited to 'src/devices/bus/nubus/laserview.cpp')
-rw-r--r-- | src/devices/bus/nubus/laserview.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/devices/bus/nubus/laserview.cpp b/src/devices/bus/nubus/laserview.cpp new file mode 100644 index 00000000000..4ced40e7935 --- /dev/null +++ b/src/devices/bus/nubus/laserview.cpp @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + Sigma Designs fixed-resolution monochrome video card + 1664x1200 or 832x600 according to the ad, but more modes exist + in the dumped v3.0 declaration ROM. + + VRAM at Fs000000, mirrored at Fs900000. + Fs0BFFEC: write 0x04 to enable VBL, 0x01 to ack VBL + + Card has one ASIC, a Sigma Designs 53C280A. This is shared with the PC ISA + "LaserView Plus" card. + + Crystals: + 160.00 MHz + 122.925 MHz + 99.108 MHz + 16.0 MHz + + Modes in the declaration ROM shown by SlotsParse are: + 832x600 + 1664x1200 + 640x480 + 1280x960 + 512x384 + 1024x768 + + TODO: Figure out how to set the other modes. A software driver, possibly? + +***************************************************************************/ + +#include "emu.h" + +#include "laserview.h" + +#include "emupal.h" +#include "screen.h" + +#include <algorithm> + +static constexpr u32 VRAM_SIZE = 0x40000; // ROM tests for 512K, but card has 8x uPD41264 (64K x 4 bit) = 256 KiB +namespace { + + class nubus_laserview_device : public device_t, + public device_nubus_card_interface + { + public: + // construction/destruction + nubus_laserview_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // optional information overrides + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + + private: + u8 regs_r(offs_t offset); + void regs_w(offs_t offset, u8 data); + + u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + void vbl_w(int state); + + required_device<screen_device> m_screen; + + std::unique_ptr<u32[]> m_vram; + u16 m_htotal, m_hvis, m_vtotal, m_vvis, m_stride; + u32 m_vbl_disable; + u8 m_prot_latch; + }; + +ROM_START( laserview ) + ROM_REGION(0x8000, "declrom", 0) + ROM_LOAD( "lva-m2-00020_v3.00.bin", 0x000000, 0x008000, CRC(569d1fb7) SHA1(fd505505226abb5fea7c10ed14e8841077ef1be6) ) +ROM_END + +void nubus_laserview_device::device_add_mconfig(machine_config &config) +{ + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_screen_update(FUNC(nubus_laserview_device::screen_update)); + m_screen->set_raw(99108000/2, 1008, 0, 832, 622, 0, 600); + m_screen->set_palette("palette"); + m_screen->screen_vblank().set(FUNC(nubus_laserview_device::vbl_w)); + + PALETTE(config, "palette", palette_device::MONOCHROME_INVERTED); +} + +//------------------------------------------------- +// rom_region - device-specific ROM region +//------------------------------------------------- + +const tiny_rom_entry *nubus_laserview_device::device_rom_region() const +{ + return ROM_NAME( laserview ); +} + +nubus_laserview_device::nubus_laserview_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : + device_t(mconfig, NUBUS_LASERVIEW, tag, owner, clock), + device_nubus_card_interface(mconfig, *this), + m_screen(*this, "screen"), + m_htotal(0), m_hvis(0), m_vtotal(0), m_vvis(0), + m_vbl_disable(1), m_prot_latch(0) +{ +} + +void nubus_laserview_device::device_start() +{ + const u32 slotspace = get_slotspace(); + + install_declaration_rom("declrom", true); + + m_vram = std::make_unique<u32[]>(VRAM_SIZE / sizeof(u32)); + install_bank(slotspace, slotspace + VRAM_SIZE - 1, &m_vram[0]); + install_bank(slotspace+0x900000, slotspace+0x900000+VRAM_SIZE-1, &m_vram[0]); + + nubus().install_device(slotspace+0xB0000, slotspace+0xBFFFF, emu::rw_delegate(*this, FUNC(nubus_laserview_device::regs_r)), emu::rw_delegate(*this, FUNC(nubus_laserview_device::regs_w))); + + save_item(NAME(m_htotal)); + save_item(NAME(m_hvis)); + save_item(NAME(m_vtotal)); + save_item(NAME(m_vvis)); + save_item(NAME(m_vbl_disable)); + save_item(NAME(m_prot_latch)); + save_pointer(NAME(m_vram), VRAM_SIZE / sizeof(u32)); +} + +void nubus_laserview_device::device_reset() +{ + m_vbl_disable = 1; + std::fill_n(&m_vram[0], VRAM_SIZE / sizeof(u32), 0); +} + +u32 nubus_laserview_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + auto const vram8 = util::big_endian_cast<u8 const>(&m_vram[0]); + for (int y = 0; y < m_vvis; y++) + { + u16 *scanline = &bitmap.pix(y); + for (int x = 0; x < m_hvis/8; x++) + { + u8 const pixels = vram8[(y * (m_stride >> 4)) + x + 0x20]; + + *scanline++ = BIT(pixels, 7); + *scanline++ = BIT(pixels, 6); + *scanline++ = BIT(pixels, 5); + *scanline++ = BIT(pixels, 4); + *scanline++ = BIT(pixels, 3); + *scanline++ = BIT(pixels, 2); + *scanline++ = BIT(pixels, 1); + *scanline++ = BIT(pixels, 0); + } + } + return 0; +} + +void nubus_laserview_device::vbl_w(int state) +{ + if ((state) && (!m_vbl_disable)) + { + raise_slot_irq(); + } +} + +void nubus_laserview_device::regs_w(offs_t offset, u8 data) +{ + switch (offset) + { + case 0x00f9: + m_prot_latch = data ^ 0xff; + break; + + case 0x08ff: + if (data == 0xc1) + { + const rectangle visarea(0, (m_hvis / 2) - 1, 0, (m_vvis / 2) - 1); + m_screen->configure(m_htotal / 2, m_vtotal / 2, visarea, attotime::from_ticks((m_htotal / 2) * (m_vtotal / 2), 160000000 / 2).as_attoseconds()); + } + break; + + case 0x20f9: + m_prot_latch = data; + break; + + case 0xffef: + if ((data & 0xff) == 0x04) + { + m_vbl_disable = 0; + } + else if ((data & 0xff) == 1) + { + lower_slot_irq(); + } + else + { + m_vbl_disable = 1; + lower_slot_irq(); + } + break; + + default: + // the code to set the CRTC params dirties up bits 8-15 of the address, so ignore it + switch (offset & 0xff) + { + case 0x81: + m_htotal = (m_htotal & 0xff00) | data; + break; + + case 0x83: + m_htotal = (m_htotal & 0xff) | (data << 8); + break; + + case 0x85: + m_hvis = (m_hvis & 0xff00) | data; + break; + + case 0x87: + m_hvis = (m_hvis & 0xff) | (data << 8); + break; + + case 0x89: + m_stride = (m_stride & 0xff00) | data; + break; + + case 0x8b: + m_stride = (m_stride & 0xff) | (data << 8); + break; + + case 0x91: + m_vtotal = (m_vtotal & 0xff00) | data; + break; + + case 0x93: + m_vtotal = (m_vtotal & 0xff) | (data << 8); + break; + + case 0x95: + m_vvis = (m_vvis & 0xff00) | data; + break; + + case 0x97: + m_vvis = (m_vvis & 0xff) | (data << 8); + break; + } + break; + } +} + +u8 nubus_laserview_device::regs_r(offs_t offset) +{ + switch (offset) + { + case 0xff04: // vblank status + return m_screen->vblank(); + + case 0xff08: + return m_prot_latch; + + // monitor sense? DIP switches? + case 0xfffc: + return 0xe4; + } + + return 0xff; +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_LASERVIEW, device_nubus_card_interface, nubus_laserview_device, "nb_laserview", "Sigma Designs LaserView video card") |