// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
voodoo_2.h
3dfx Voodoo Graphics SST-1/2 emulator.
***************************************************************************/
#ifndef MAME_VIDEO_VOODOO_2_H
#define MAME_VIDEO_VOODOO_2_H
#pragma once
#include "voodoo.h"
// forward declarations
class voodoo_2_device;
//**************************************************************************
// INTERNAL CLASSES
//**************************************************************************
namespace voodoo
{
// ======================> command_fifo
// command_fifo is a more intelligent FIFO that was introduced with the Voodoo-2
class command_fifo
{
public:
// construction
command_fifo(voodoo_2_device &device);
// initialization
void init(u8 *ram, u32 size) { m_ram = (u32 *)ram; m_mask = (size / 4) - 1; }
// state saving
void register_save(save_registrar &save);
// getters
bool enabled() const { return m_enable; }
u32 address_min() const { return m_address_min; }
u32 address_max() const { return m_address_max; }
u32 read_pointer() const { return m_read_index * 4; }
u32 depth() const { return m_depth; }
u32 holes() const { return m_holes; }
// setters
void set_enable(bool enabled) { m_enable = enabled; }
void set_count_holes(bool count) { m_count_holes = count; }
void set_base(u32 base) { m_ram_base = base; }
void set_end(u32 end) { m_ram_end = end; }
void set_size(u32 size) { m_ram_end = m_ram_base + size; }
void set_read_pointer(u32 ptr) { m_read_index = ptr / 4; }
void set_address_min(u32 addr) { m_address_min = addr; }
void set_address_max(u32 addr) { m_address_max = addr; }
void set_depth(u32 depth) { m_depth = depth; }
void set_holes(u32 holes) { m_holes = holes; }
// operations
u32 execute_if_ready();
// write to the FIFO if within the address range
bool write_if_in_range(offs_t addr, u32 data)
{
if (m_enable && addr >= m_ram_base && addr < m_ram_end)
{
write(addr, data);
return true;
}
return false;
}
// write directly to the FIFO, relative to the base
void write_direct(offs_t offset, u32 data)
{
write(m_ram_base + offset * 4, data);
}
private:
// internal helpers
void consume(u32 words) { m_read_index += words; m_depth -= words; }
u32 peek_next() { return m_ram[m_read_index & m_mask]; }
u32 read_next() { u32 result = peek_next(); consume(1); return result; }
float read_next_float() { float result = *(float *)&m_ram[m_read_index & m_mask]; consume(1); return result; }
// internal operations
u32 words_needed(u32 command);
void write(offs_t addr, u32 data);
// packet handlers
using packet_handler = u32 (command_fifo::*)(u32);
u32 packet_type_0(u32 command);
u32 packet_type_1(u32 command);
u32 packet_type_2(u32 command);
u32 packet_type_3(u32 command);
u32 packet_type_4(u32 command);
u32 packet_type_5(u32 command);
u32 packet_type_unknown(u32 command);
// internal state
voodoo_2_device &m_device; // reference to our device
u32 *m_ram; // base of RAM
u32 m_mask; // mask for RAM accesses
bool m_enable; // enabled?
bool m_count_holes; // count holes?
u32 m_ram_base; // base address in framebuffer RAM
u32 m_ram_end; // end address in framebuffer RAM
u32 m_read_index; // current read index into 32-bit RAM
u32 m_address_min; // minimum address
u32 m_address_max; // maximum address
u32 m_depth; // current depth
u32 m_holes; // number of holes
static packet_handler s_packet_handler[8];
};
// ======================> setup_vertex
// setup_vertex a set of coordinates managed by the triangle setup engine
// that was introduced with the Voodoo-2
struct setup_vertex
{
// state saving
void register_save(save_registrar &save)
{
save.reg(NAME(x));
save.reg(NAME(y));
save.reg(NAME(z));
save.reg(NAME(wb));
save.reg(NAME(r));
save.reg(NAME(g));
save.reg(NAME(b));
save.reg(NAME(a));
save.reg(NAME(s0));
save.reg(NAME(t0));
save.reg(NAME(w0));
save.reg(NAME(s1));
save.reg(NAME(t1));
save.reg(NAME(w1));
}
float x, y; // X, Y coordinates
float z, wb; // Z and broadcast W values
float r, g, b, a; // A, R, G, B values
float s0, t0, w0; // W, S, T for TMU 0
float s1, t1, w1; // W, S, T for TMU 1
};
}
//**************************************************************************
// VOODOO 2 DEVICE
//**************************************************************************
DECLARE_DEVICE_TYPE(VOODOO_2, voodoo_2_device)
// ======================> voodoo_2_device
// voodoo_2_device represents the 2nd generation of 3dfx Voodoo Graphics devices;
// these are pretty similar in architecture to the first generation, with the
// addition of command FIFOs and several other smaller features
class voodoo_2_device : public voodoo_1_device
{
friend class voodoo::command_fifo;
protected:
// internal construction
voodoo_2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, voodoo::voodoo_model model);
public:
// nominal clock value
static constexpr u32 NOMINAL_CLOCK = 90'000'000;
// construction
voodoo_2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
voodoo_2_device(mconfig, VOODOO_2, tag, owner, clock, voodoo::voodoo_model::VOODOO_2) { }
// address map and read/write helpers
virtual void core_map(address_map &map) override;
virtual u32 read(offs_t offset, u32 mem_mask = ~0) override;
virtual void write(offs_t offset, u32 data, u32 mem_mask = ~0) override;
protected:
// device-level overrides
virtual void device_start() override;
// system management
virtual void soft_reset() override;
virtual void register_save(u32 total_allocation) override;
// mapped writes
void map_register_w(offs_t offset, u32 data, u32 mem_mask = ~0);
// read/write and FIFO helpers
virtual u32 execute_fifos() override;
// register read accessors
u32 reg_hvretrace_r(u32 chipmask, u32 regnum);
u32 reg_cmdfifoptr_r(u32 chipmask, u32 regnum);
u32 reg_cmdfifodepth_r(u32 chipmask, u32 regnum);
u32 reg_cmdfifoholes_r(u32 chipmask, u32 regnum);
// register write accessors
u32 reg_intrctrl_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_video2_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_sargb_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_userintr_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_cmdfifo_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_cmdfifoptr_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_cmdfifodepth_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_cmdfifoholes_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_fbiinit5_7_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_draw_tri_w(u32 chipmask, u32 regnum, u32 data);
u32 reg_begin_tri_w(u32 chipmask, u32 regnum, u32 data);
// command FIFO-specific write handlers
virtual u32 cmdfifo_register_w(u32 offset, u32 data);
virtual u32 cmdfifo_2d_w(u32 offset, u32 data);
// VBLANK timing
virtual void vblank_start(void *ptr, s32 param) override;
virtual void vblank_stop(void *ptr, s32 param) override;
// video timing and updates
virtual void recompute_video_memory() override;
// rendering
s32 begin_triangle();
s32 draw_triangle();
s32 setup_and_draw_triangle();
// internal state
u8 m_sverts = 0; // number of vertices ready
voodoo::setup_vertex m_svert[3]; // 3 setup vertices
voodoo::command_fifo m_cmdfifo; // command FIFO
// register table
static voodoo::static_register_table_entry<voodoo_2_device> const s_register_table[256];
};
#endif // MAME_VIDEO_VOODOO_2_H