nubus/nubus_cb264.cpp: Modernization pass [R. Belmont]

* Raster timings should be accurate now
* Modernized types, usage of palette_device, and more
* VBL status register now returns the correct value
This commit is contained in:
arbee 2023-12-11 20:21:38 -05:00
parent 9dba0050e6
commit cf93bd66f9
2 changed files with 117 additions and 124 deletions

View File

@ -4,71 +4,85 @@
RasterOps ColorBoard 264 NuBus video card emulation RasterOps ColorBoard 264 NuBus video card emulation
fixed resolution 640x480 NuBus video card, 1/4/8/16/24 bit color fixed resolution 640x480 NuBus video card, 1/2/4/8/24 bit color
1.5? MB of VRAM (tests up to 0x1fffff), Bt473 RAMDAC, and two custom gate arrays. 1.5 MiB of VRAM, Bt473 RAMDAC, and two custom gate arrays.
0xfsff6004 is color depth: 0 for 1bpp, 1 for 2bpp, 2 for 4bpp, 3 for 8bpp, 4 for 24bpp 0xfsff6004 is color depth: 0 for 1bpp, 1 for 2bpp, 2 for 4bpp, 3 for 8bpp, 4 for 24bpp
0xfsff6014 is VBL ack: write 1 to ack 0xfsff6014 is VBL ack: write 1 to ack
0xfsff603c is VBL disable: write 1 to disable, 0 to enable 0xfsff603c is VBL disable: write 1 to disable, 0 to enable
Crystal (pixel clock) is 30.24 MHz
TODO:
- Figure out the vertical part of the CRTC registers and make the mode dynamic.
- Figure out how 24 bpp mode fits in 1.5 MiB. Stride is 4096 bytes, each
scanline is 640 pixels at 4 bytes each, which comes to just below 2 MiB.
***************************************************************************/ ***************************************************************************/
#include "emu.h" #include "emu.h"
#include "emupal.h"
#include "nubus_cb264.h" #include "nubus_cb264.h"
#include "screen.h" #include "screen.h"
#include <algorithm> #include <algorithm>
namespace {
#define CB264_SCREEN_NAME "cb264_screen" static constexpr u32 VRAM_SIZE = 0x200000; // 12x TC524256J (256K x 4 bit VRAM), so 1.5 MiB total
#define CB264_ROM_REGION "cb264_rom" class nubus_cb264_device : public device_t,
public device_nubus_card_interface
{
public:
// construction/destruction
nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
#define VRAM_SIZE (0x200000) // 2 megs, maxed out protected:
nubus_cb264_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// optional information overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
uint32_t cb264_r(offs_t offset, uint32_t mem_mask = ~0);
void cb264_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t cb264_ramdac_r(offs_t offset);
void cb264_ramdac_w(offs_t offset, uint32_t data);
private:
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
std::unique_ptr<u32[]> m_vram;
uint32_t m_cb264_mode, m_cb264_vbl_disable;
uint32_t m_colors[3], m_count, m_clutoffs;
};
ROM_START( cb264 ) ROM_START( cb264 )
ROM_REGION(0x4000, CB264_ROM_REGION, 0) ROM_REGION(0x4000, "cb264_rom", 0)
ROM_LOAD16_BYTE( "264-1915.bin", 0x000000, 0x002000, CRC(26c19ee5) SHA1(2b2853d04cc6b0258e85eccd23ebfd4f4f63a084) ) ROM_LOAD16_BYTE( "264-1915.bin", 0x000000, 0x002000, CRC(26c19ee5) SHA1(2b2853d04cc6b0258e85eccd23ebfd4f4f63a084) )
ROM_LOAD16_BYTE( "264-1914.bin", 0x000001, 0x002000, CRC(d5fbd5ad) SHA1(98d35ed3fb0bca4a9bee1cdb2af0d3f22b379386) ) ROM_LOAD16_BYTE( "264-1914.bin", 0x000001, 0x002000, CRC(d5fbd5ad) SHA1(98d35ed3fb0bca4a9bee1cdb2af0d3f22b379386) )
ROM_END ROM_END
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
DEFINE_DEVICE_TYPE(NUBUS_CB264, nubus_cb264_device, "nb_c264", "RasterOps ColorBoard 264 video card")
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void nubus_cb264_device::device_add_mconfig(machine_config &config) void nubus_cb264_device::device_add_mconfig(machine_config &config)
{ {
screen_device &screen(SCREEN(config, CB264_SCREEN_NAME, SCREEN_TYPE_RASTER)); screen_device &screen(SCREEN(config, "cb264_screen", SCREEN_TYPE_RASTER));
screen.set_screen_update(FUNC(nubus_cb264_device::screen_update)); screen.set_screen_update(FUNC(nubus_cb264_device::screen_update));
screen.set_raw(25175000, 800, 0, 640, 525, 0, 480); screen.set_raw(30240000, 860, 0, 640, 524, 0, 480);
screen.set_size(1024, 768);
screen.set_visarea(0, 640-1, 0, 480-1);
}
//------------------------------------------------- PALETTE(config, m_palette).set_entries(256);
// rom_region - device-specific ROM region }
//-------------------------------------------------
const tiny_rom_entry *nubus_cb264_device::device_rom_region() const const tiny_rom_entry *nubus_cb264_device::device_rom_region() const
{ {
return ROM_NAME( cb264 ); return ROM_NAME( cb264 );
} }
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// nubus_cb264_device - constructor
//-------------------------------------------------
nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
nubus_cb264_device(mconfig, NUBUS_CB264, tag, owner, clock) nubus_cb264_device(mconfig, NUBUS_CB264, tag, owner, clock)
{ {
@ -77,7 +91,9 @@ nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, const char
nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : nubus_cb264_device::nubus_cb264_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_t(mconfig, type, tag, owner, clock),
device_nubus_card_interface(mconfig, *this), device_nubus_card_interface(mconfig, *this),
m_cb264_mode(0), m_cb264_vbl_disable(0), m_cb264_toggle(0), m_count(0), m_clutoffs(0) m_screen(*this, "cb264_screen"),
m_palette(*this, "cb264_palette"),
m_cb264_mode(0), m_cb264_vbl_disable(0), m_count(0), m_clutoffs(0)
{ {
} }
@ -87,19 +103,22 @@ nubus_cb264_device::nubus_cb264_device(const machine_config &mconfig, device_typ
void nubus_cb264_device::device_start() void nubus_cb264_device::device_start()
{ {
uint32_t slotspace; u32 slotspace = get_slotspace();
install_declaration_rom(CB264_ROM_REGION); install_declaration_rom("cb264_rom");
slotspace = get_slotspace(); m_vram = std::make_unique<u32[]>(VRAM_SIZE / sizeof(u32));
install_bank(slotspace, slotspace + VRAM_SIZE - 1, &m_vram[0]);
// printf("[cb264 %p] slotspace = %x\n", this, slotspace);
m_vram.resize(VRAM_SIZE / sizeof(uint32_t));
install_bank(slotspace, slotspace+VRAM_SIZE-1, &m_vram[0]);
nubus().install_device(slotspace+0xff6000, slotspace+0xff60ff, read32s_delegate(*this, FUNC(nubus_cb264_device::cb264_r)), write32s_delegate(*this, FUNC(nubus_cb264_device::cb264_w))); nubus().install_device(slotspace+0xff6000, slotspace+0xff60ff, read32s_delegate(*this, FUNC(nubus_cb264_device::cb264_r)), write32s_delegate(*this, FUNC(nubus_cb264_device::cb264_w)));
nubus().install_device(slotspace+0xff7000, slotspace+0xff70ff, read32sm_delegate(*this, FUNC(nubus_cb264_device::cb264_ramdac_r)), write32sm_delegate(*this, FUNC(nubus_cb264_device::cb264_ramdac_w))); nubus().install_device(slotspace+0xff7000, slotspace+0xff70ff, read32sm_delegate(*this, FUNC(nubus_cb264_device::cb264_ramdac_r)), write32sm_delegate(*this, FUNC(nubus_cb264_device::cb264_ramdac_w)));
save_item(NAME(m_cb264_mode));
save_item(NAME(m_cb264_vbl_disable));
save_item(NAME(m_colors));
save_item(NAME(m_count));
save_item(NAME(m_clutoffs));
save_pointer(NAME(m_vram), VRAM_SIZE / sizeof(u32));
} }
//------------------------------------------------- //-------------------------------------------------
@ -108,21 +127,13 @@ void nubus_cb264_device::device_start()
void nubus_cb264_device::device_reset() void nubus_cb264_device::device_reset()
{ {
m_cb264_toggle = 0;
m_count = 0; m_count = 0;
m_clutoffs = 0; m_clutoffs = 0;
m_cb264_vbl_disable = 1; m_cb264_vbl_disable = 1;
m_cb264_mode = 0; m_cb264_mode = 0;
std::fill(m_vram.begin(), m_vram.end(), 0); std::fill_n(&m_vram[0], VRAM_SIZE / sizeof(u32), 0);
memset(m_palette, 0, sizeof(m_palette));
} }
/***************************************************************************
ColorBoard 264 section
***************************************************************************/
uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{ {
if (!m_cb264_vbl_disable) if (!m_cb264_vbl_disable)
@ -130,25 +141,27 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
raise_slot_irq(); raise_slot_irq();
} }
auto const vram8 = util::big_endian_cast<uint8_t const>(&m_vram[0]); auto const vram8 = util::big_endian_cast<u8 const>(&m_vram[0]);
const pen_t *pens = m_palette->pens();
switch (m_cb264_mode) switch (m_cb264_mode)
{ {
case 0: // 1 bpp case 0: // 1 bpp
for (int y = 0; y < 480; y++) for (int y = 0; y < 480; y++)
{ {
uint32_t *scanline = &bitmap.pix(y); u32 *scanline = &bitmap.pix(y);
for (int x = 0; x < 640/8; x++) for (int x = 0; x < 640/8; x++)
{ {
uint8_t const pixels = vram8[(y * 1024) + x]; u8 const pixels = vram8[(y * 1024) + x];
*scanline++ = m_palette[pixels&0x80]; *scanline++ = pens[pixels&0x80];
*scanline++ = m_palette[(pixels<<1)&0x80]; *scanline++ = pens[(pixels<<1)&0x80];
*scanline++ = m_palette[(pixels<<2)&0x80]; *scanline++ = pens[(pixels<<2)&0x80];
*scanline++ = m_palette[(pixels<<3)&0x80]; *scanline++ = pens[(pixels<<3)&0x80];
*scanline++ = m_palette[(pixels<<4)&0x80]; *scanline++ = pens[(pixels<<4)&0x80];
*scanline++ = m_palette[(pixels<<5)&0x80]; *scanline++ = pens[(pixels<<5)&0x80];
*scanline++ = m_palette[(pixels<<6)&0x80]; *scanline++ = pens[(pixels<<6)&0x80];
*scanline++ = m_palette[(pixels<<7)&0x80]; *scanline++ = pens[(pixels<<7)&0x80];
} }
} }
break; break;
@ -156,15 +169,15 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
case 1: // 2 bpp (3f/7f/bf/ff) case 1: // 2 bpp (3f/7f/bf/ff)
for (int y = 0; y < 480; y++) for (int y = 0; y < 480; y++)
{ {
uint32_t *scanline = &bitmap.pix(y); u32 *scanline = &bitmap.pix(y);
for (int x = 0; x < 640/4; x++) for (int x = 0; x < 640/4; x++)
{ {
uint8_t const pixels = vram8[(y * 1024) + x]; u8 const pixels = vram8[(y * 1024) + x];
*scanline++ = m_palette[pixels&0xc0]; *scanline++ = pens[pixels&0xc0];
*scanline++ = m_palette[(pixels<<2)&0xc0]; *scanline++ = pens[(pixels<<2)&0xc0];
*scanline++ = m_palette[(pixels<<4)&0xc0]; *scanline++ = pens[(pixels<<4)&0xc0];
*scanline++ = m_palette[(pixels<<6)&0xc0]; *scanline++ = pens[(pixels<<6)&0xc0];
} }
} }
break; break;
@ -172,13 +185,13 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
case 2: // 4 bpp case 2: // 4 bpp
for (int y = 0; y < 480; y++) for (int y = 0; y < 480; y++)
{ {
uint32_t *scanline = &bitmap.pix(y); u32 *scanline = &bitmap.pix(y);
for (int x = 0; x < 640/2; x++) for (int x = 0; x < 640/2; x++)
{ {
uint8_t const pixels = vram8[(y * 1024) + x]; u8 const pixels = vram8[(y * 1024) + x];
*scanline++ = m_palette[pixels&0xf0]; *scanline++ = pens[pixels&0xf0];
*scanline++ = m_palette[(pixels<<4)&0xf0]; *scanline++ = pens[(pixels<<4)&0xf0];
} }
} }
break; break;
@ -186,11 +199,11 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
case 3: // 8 bpp case 3: // 8 bpp
for (int y = 0; y < 480; y++) for (int y = 0; y < 480; y++)
{ {
uint32_t *scanline = &bitmap.pix(y); u32 *scanline = &bitmap.pix(y);
for (int x = 0; x < 640; x++) for (int x = 0; x < 640; x++)
{ {
uint8_t const pixels = vram8[(y * 1024) + x]; u8 const pixels = vram8[(y * 1024) + x];
*scanline++ = m_palette[pixels]; *scanline++ = pens[pixels];
} }
} }
break; break;
@ -210,7 +223,7 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
return 0; return 0;
} }
void nubus_cb264_device::cb264_w(offs_t offset, uint32_t data, uint32_t mem_mask) void nubus_cb264_device::cb264_w(offs_t offset, u32 data, u32 mem_mask)
{ {
switch (offset) switch (offset)
{ {
@ -226,13 +239,28 @@ void nubus_cb264_device::cb264_w(offs_t offset, uint32_t data, uint32_t mem_mask
m_cb264_vbl_disable = data; m_cb264_vbl_disable = data;
break; break;
/*
CRTC, but vertical doesn't make sense.
Vertical:
40: 2 - first line of active display?
44: 209 - last line of active display?
48: 20c - vtotal (524)
4c: f
Horizontal:
50: 27 - start of active display
54: c7 - end of active display (0xc7 - 0x27 = 160, 160 * 4 = 640)
58: d7 - htotal (860)
5c: 6b
*/
default: default:
// printf("%s cb264_w: %x to reg %x (mask %x)\n", machine().describe_context().c_str(), data, offset*4, mem_mask); //printf("%s cb264_w: %x to reg %x (mask %x)\n", machine().describe_context().c_str(), data, offset*4, mem_mask);
break; break;
} }
} }
uint32_t nubus_cb264_device::cb264_r(offs_t offset, uint32_t mem_mask) u32 nubus_cb264_device::cb264_r(offs_t offset, u32 mem_mask)
{ {
switch (offset) switch (offset)
{ {
@ -241,8 +269,7 @@ uint32_t nubus_cb264_device::cb264_r(offs_t offset, uint32_t mem_mask)
break; break;
case 0x34/4: case 0x34/4:
m_cb264_toggle ^= 1; return m_screen->vblank(); // bit 0 is vblank
return m_cb264_toggle; // bit 0 is vblank?
default: default:
logerror("cb264_r: reg %x (mask %x %s)\n", offset*4, mem_mask, machine().describe_context()); logerror("cb264_r: reg %x (mask %x %s)\n", offset*4, mem_mask, machine().describe_context());
@ -252,7 +279,7 @@ uint32_t nubus_cb264_device::cb264_r(offs_t offset, uint32_t mem_mask)
return 0; return 0;
} }
void nubus_cb264_device::cb264_ramdac_w(offs_t offset, uint32_t data) void nubus_cb264_device::cb264_ramdac_w(offs_t offset, u32 data)
{ {
switch (offset) switch (offset)
{ {
@ -266,7 +293,9 @@ void nubus_cb264_device::cb264_ramdac_w(offs_t offset, uint32_t data)
if (m_count == 3) if (m_count == 3)
{ {
m_palette[m_clutoffs] = rgb_t(m_colors[0], m_colors[1], m_colors[2]); m_palette->set_pen_red_level(m_clutoffs, m_colors[0]);
m_palette->set_pen_green_level(m_clutoffs, m_colors[1]);
m_palette->set_pen_blue_level(m_clutoffs, m_colors[2]);
m_clutoffs++; m_clutoffs++;
m_count = 0; m_count = 0;
} }
@ -278,7 +307,11 @@ void nubus_cb264_device::cb264_ramdac_w(offs_t offset, uint32_t data)
} }
} }
uint32_t nubus_cb264_device::cb264_ramdac_r(offs_t offset) u32 nubus_cb264_device::cb264_ramdac_r(offs_t offset)
{ {
return 0; return 0;
} }
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(NUBUS_CB264, device_nubus_card_interface, nubus_cb264_device, "nb_c264", "RasterOps ColorBoard 264 video card")

View File

@ -7,46 +7,6 @@
#include "nubus.h" #include "nubus.h"
//************************************************************************** DECLARE_DEVICE_TYPE(NUBUS_CB264, device_nubus_card_interface)
// TYPE DEFINITIONS
//**************************************************************************
// ======================> nubus_cb264_device
class nubus_cb264_device :
public device_t,
public device_nubus_card_interface
{
public:
// construction/destruction
nubus_cb264_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
nubus_cb264_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// optional information overrides
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
uint32_t cb264_r(offs_t offset, uint32_t mem_mask = ~0);
void cb264_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t cb264_ramdac_r(offs_t offset);
void cb264_ramdac_w(offs_t offset, uint32_t data);
private:
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
std::vector<uint32_t> m_vram;
uint32_t m_cb264_mode, m_cb264_vbl_disable, m_cb264_toggle;
uint32_t m_palette[256], m_colors[3], m_count, m_clutoffs;
};
// device type definition
DECLARE_DEVICE_TYPE(NUBUS_CB264, nubus_cb264_device)
#endif // MAME_BUS_NUBUS_NUBUS_CB264_H #endif // MAME_BUS_NUBUS_NUBUS_CB264_H