// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*************************************************************************
Midway Zeus2 Video
**************************************************************************/
#ifndef MAME_VIDEO_ZEUS2_H
#define MAME_VIDEO_ZEUS2_H
#pragma once
#include "video/poly.h"
#include "video/rgbutil.h"
#include "cpu/tms32031/tms32031.h"
/*************************************
* Constants
*************************************/
#define ZEUS2_VIDEO_CLOCK XTAL(66'666'700)
#define DUMP_WAVE_RAM 0
#define TRACK_REG_USAGE 0
#define PRINT_TEX_INFO 0
#define WAVERAM0_WIDTH 1024
#define WAVERAM0_HEIGHT 2048
#define WAVERAM1_WIDTH 512
#define WAVERAM1_HEIGHT 1024
/*************************************
* Type definitions
*************************************/
struct zeus2_poly_extra_data
{
const void * palbase;
const void * texbase;
uint16_t solidcolor;
uint16_t transcolor;
uint16_t texwidth;
uint16_t color;
uint32_t srcAlpha;
uint32_t dstAlpha;
uint32_t ctrl_word;
uint32_t ucode_src;
uint32_t tex_src;
bool texture_alpha;
bool texture_rgb555;
bool blend_enable;
int32_t zbuf_min;
bool depth_min_enable;
bool depth_test_enable;
bool depth_write_enable;
bool depth_clear_enable;
uint8_t(*get_texel)(const void *, int, int, int);
uint8_t(*get_alpha)(const void *, int, int, int);
};
/*************************************
* Macros
*************************************/
#define WAVERAM_BLOCK0(blocknum) ((void *)((uint8_t *)waveram + 8 * (blocknum)))
#define WAVERAM_BLOCK0_EXT(blocknum) ((void *)((uint8_t *)m_state->waveram + 8 * (blocknum)))
#define WAVERAM_PTR8(base, bytenum) ((uint8_t *)(base) + BYTE4_XOR_LE(bytenum))
#define WAVERAM_READ8(base, bytenum) (*WAVERAM_PTR8(base, bytenum))
#define WAVERAM_WRITE8(base, bytenum, data) do { *WAVERAM_PTR8(base, bytenum) = (data); } while (0)
#define WAVERAM_PTR16(base, wordnum) ((uint16_t *)(base) + BYTE_XOR_LE(wordnum))
#define WAVERAM_READ16(base, wordnum) (*WAVERAM_PTR16(base, wordnum))
#define WAVERAM_WRITE16(base, wordnum, data) do { *WAVERAM_PTR16(base, wordnum) = (data); } while (0)
#define WAVERAM_PTR32(base, dwordnum) ((uint32_t *)(base) + (dwordnum))
#define WAVERAM_READ32(base, dwordnum) (*WAVERAM_PTR32(base, dwordnum))
#define WAVERAM_WRITE32(base, dwordnum, data) do { *WAVERAM_PTR32(base, dwordnum) = (data); } while (0)
/*************************************
* Polygon renderer
*************************************/
class zeus2_device;
class zeus2_renderer : public poly_manager<float, zeus2_poly_extra_data, 4, 10000>
{
public:
zeus2_renderer(zeus2_device *state);
void render_poly_8bit(int32_t scanline, const extent_t& extent, const zeus2_poly_extra_data& object, int threadid);
void zeus2_draw_quad(const uint32_t *databuffer, uint32_t texdata, int logit);
private:
zeus2_device* m_state;
};
typedef zeus2_renderer::vertex_t z2_poly_vertex;
typedef zeus2_renderer::extent_t z2_poly_extent;
/*************************************
* Zeus2 Video Device
*************************************/
#define MCFG_ZEUS2_VBLANK_CB(_devcb) \
devcb = &downcast<zeus2_device &>(*device).set_vblank_callback(DEVCB_##_devcb);
#define MCFG_ZEUS2_IRQ_CB(_devcb) \
devcb = &downcast<zeus2_device &>(*device).set_irq_callback(DEVCB_##_devcb);
#define MCFG_ZEUS2_FLOAT_MODE(_mode) \
downcast<zeus2_device *>(device)->set_float_mode(_mode);
class zeus2_device : public device_t, public device_video_interface
{
public:
zeus2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_READ32_MEMBER( zeus2_r );
DECLARE_WRITE32_MEMBER( zeus2_w );
TIMER_CALLBACK_MEMBER(display_irq_off);
TIMER_CALLBACK_MEMBER(display_irq);
template <class Object> devcb_base &set_vblank_callback(Object &&cb) { return m_vblank.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_irq_callback(Object &&cb) { return m_irq.set_callback(std::forward<Object>(cb)); }
devcb_write_line m_vblank;
devcb_write_line m_irq;
void set_float_mode(int mode) { m_atlantis = mode; }
int m_atlantis; // Used to switch to using IEEE754 floating point format for atlantis
uint32_t m_zeusbase[0x80];
uint32_t m_renderRegs[0x50];
zeus2_renderer* poly;
rectangle zeus_cliprect;
int m_palSize;
float zeus_matrix[3][3];
float zeus_trans[4];
float zeus_light[3];
uint32_t zeus_texbase;
int zeus_quad_size;
bool m_useZOffset;
uint32_t *waveram;
std::unique_ptr<uint32_t[]> m_frameColor;
std::unique_ptr<int32_t[]> m_frameDepth;
uint32_t m_pal_table[0x100];
uint32_t m_ucode[0x200];
uint32_t m_curUCodeSrc;
uint32_t m_curPalTableSrc;
uint32_t m_texmodeReg;
emu_timer *int_timer;
emu_timer *vblank_timer;
int yoffs;
int texel_width;
float zbase;
enum { THEGRID, CRUSNEXO, MWSKINS };
int m_system;
#if PRINT_TEX_INFO
void check_tex(uint32_t &texmode, float &zObj, float &zMat, float &zOff);
std::string tex_info(void);
#endif
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_stop() override;
private:
TIMER_CALLBACK_MEMBER(int_timer_callback);
void zeus2_register32_w(offs_t offset, uint32_t data, int logit);
void zeus2_register_update(offs_t offset, uint32_t oldval, int logit);
bool zeus2_fifo_process(const uint32_t *data, int numwords);
void zeus2_pointer_write(uint8_t which, uint32_t value, int logit);
void load_pal_table(void *wavePtr, uint32_t ctrl, int type, int logit);
void load_ucode(void *wavePtr, uint32_t ctrl, int logit);
void zeus2_draw_model(uint32_t baseaddr, uint16_t count, int logit);
void log_fifo_command(const uint32_t *data, int numwords, const char *suffix);
void print_fifo_command(const uint32_t *data, int numwords, const char *suffix);
void log_render_info(uint32_t texdata);
/*************************************
* Member variables
*************************************/
uint8_t log_fifo;
uint32_t zeus_fifo[20];
uint8_t zeus_fifo_words;
uint32_t m_fill_color;
int32_t m_fill_depth;
int m_yScale;
#if PRINT_TEX_INFO
std::map<uint32_t, std::string> tex_map;
#endif
#if TRACK_REG_USAGE
struct reg_info
{
struct reg_info *next;
uint32_t value;
};
reg_info *regdata[0x80];
int regdata_count[0x80];
int regread_count[0x80];
int regwrite_count[0x80];
reg_info *subregdata[0x100];
int subregdata_count[0x80];
int subregwrite_count[0x100];
#endif
public:
/*************************************
* Inlines for block addressing
*************************************/
inline float convert_float(uint32_t val)
{
if (m_atlantis) {
return reinterpret_cast<float&>(val);
}
else
return tms3203x_device::fp_to_float(val);
}
inline uint32_t frame_addr_from_xy(uint32_t x, uint32_t y, bool render)
{
uint32_t addr;
if (render) {
// Rendering is y location
addr = m_renderRegs[0x4] << (9 + m_yScale);
}
else {
// y.16:x.16 row/col
// Ignore col for now
addr = m_zeusbase[0x38] >> (16 - 9 - 2 * m_yScale);
}
//uint32_t addr = render ? frame_addr_from_phys_addr(m_renderRegs[0x4] << (15 + m_yScale))
// : frame_addr_from_phys_addr((m_zeusbase[0x38] >> 1) << (m_yScale << 1));
addr += (y << (9 + m_yScale)) + x;
return addr;
}
// Convert 0xRRRRCCCC to frame buffer address
//inline uint32_t frame_addr_from_expanded_addr(uint32_t addr)
//{
// return (((addr & 0x3ff0000) >> (16 - 9 + 1)) | (addr & 0x1ff)) << 1;
//}
// Convert Physical 0xRRRRCCCC to frame buffer address
// Based on address reg 51 (no scaling)
inline uint32_t frame_addr_from_phys_addr(uint32_t physAddr)
{
uint32_t addr = (((physAddr & 0x3ff0000) >> (16 - 9)) | (physAddr & 0x1ff)) << 1;
return addr;
}
// Read from frame buffer
inline void frame_read()
{
uint32_t addr = frame_addr_from_phys_addr(m_zeusbase[0x51]);
m_zeusbase[0x58] = m_frameColor[addr];
m_zeusbase[0x59] = m_frameColor[addr + 1];
m_zeusbase[0x5a] = *(uint32_t*)&m_frameDepth[addr];
if (m_zeusbase[0x5e] & 0x40)
{
m_zeusbase[0x51]++;
m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7;
m_zeusbase[0x51] &= ~0xfe00;
}
}
// Write to frame buffer
inline void frame_write()
{
uint32_t addr = frame_addr_from_phys_addr(m_zeusbase[0x51]);
if (m_zeusbase[0x57] & 0x1)
m_frameColor[addr] = m_zeusbase[0x58];
if (m_zeusbase[0x5e] & 0x20) {
if (m_zeusbase[0x57] & 0x4)
m_frameColor[addr + 1] = m_zeusbase[0x5a];
} else
{
if (m_zeusbase[0x57] & 0x4)
m_frameColor[addr + 1] = m_zeusbase[0x59];
if (m_zeusbase[0x57] & 0x10)
*(uint32_t*)&m_frameDepth[addr] = m_zeusbase[0x5a];
}
if (m_zeusbase[0x5e] & 0x40)
{
m_zeusbase[0x51]++;
m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7;
m_zeusbase[0x51] &= ~0xfe00;
}
}
inline void *waveram0_ptr_from_expanded_addr(uint32_t addr)
{
uint32_t blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
return WAVERAM_BLOCK0(blocknum);
}
#ifdef UNUSED_FUNCTION
inline void *waveram0_ptr_from_texture_addr(uint32_t addr, int width)
{
uint32_t blocknum = ((addr & ~1) * width) / 8;
return WAVERAM_BLOCK0(blocknum);
}
#endif
/*************************************
* Inlines for rendering
*************************************/
inline uint32_t conv_rgb555_to_rgb32(uint16_t color)
{
return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x1f) << 3);
}
inline uint32_t conv_rgb565_to_rgb32(uint16_t color)
{
return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x8000) >> 5) | ((color & 0x1f) << 3);
}
inline uint32_t conv_rgb332_to_rgb32(uint8_t color)
{
uint32_t result;
result = ((((color) >> 0) & 0xe0) | (((color) >> 3) & 0x1c) | (((color) >> 6) & 0x03)) << 16;
result |= ((((color) << 3) & 0xe0) | (((color) >> 0) & 0x1c) | (((color) >> 3) & 0x03)) << 8;
result |= ((((color) << 6) & 0xc0) | (((color) << 4) & 0x30) | (((color) << 2) & 0x0c) | (((color) << 0) & 0x03)) << 0;
return result;
}
#ifdef UNUSED_FUNCTION
inline void WAVERAM_plot(int y, int x, uint32_t color)
{
if (zeus_cliprect.contains(x, y))
WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
}
#endif
#ifdef UNUSED_FUNCTION
inline void waveram_plot_depth(int y, int x, uint32_t color, uint16_t depth)
{
if (zeus_cliprect.contains(x, y))
{
WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
WAVERAM_WRITEDEPTH(zeus_renderbase, y, x, depth);
}
}
#endif
#ifdef UNUSED_FUNCTION
inline void waveram_plot_check_depth(int y, int x, uint32_t color, uint16_t depth)
{
if (zeus_cliprect.contains(x, y))
{
uint16_t *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x);
if (depth <= *depthptr)
{
WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
*depthptr = depth;
}
}
}
#endif
#ifdef UNUSED_FUNCTION
inline void waveram_plot_check_depth_nowrite(int y, int x, uint32_t color, uint16_t depth)
{
if (zeus_cliprect.contains(x, y))
{
uint16_t *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x);
if (depth <= *depthptr)
WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
}
}
#endif
/*************************************
* Inlines for texel accesses
*************************************/
// 4x2 block size
static inline uint8_t get_texel_4bit_4x2(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 8) << 3) + ((y & 1) << 2) + ((x / 2) & 3);
return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
}
static inline uint8_t get_texel_8bit_4x2(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 4) << 3) + ((y & 1) << 2) + (x & 3);
return WAVERAM_READ8(base, byteoffs);
}
// 2x2 block size within 32 bits, 2 2x2 blocks stacked in y in 64 bits
static inline uint8_t get_texel_4bit_2x2(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 4) * (width * 4) + ((x / 4) << 3) + ((y & 3) << 1) + ((x / 2) & 1);
return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
}
static inline uint8_t get_texel_8bit_2x2(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 4) * (width * 4) + ((x / 2) << 3) + ((y & 3) << 1) + (x & 1);
return WAVERAM_READ8(base, byteoffs);
}
// 2x2 block size of texel, alpha in 64 bits
// 8 Bit texel, 8 bit alpha
static inline uint8_t get_texel_8bit_2x2_alpha(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
// Only grab RGB value for now
byteoffs <<= 1;
return WAVERAM_READ8(base, byteoffs + 0);
}
static inline uint8_t get_alpha_8bit_2x2_alpha(const void *base, int y, int x, int width)
{
uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
// Only grab Alpha value for now
byteoffs <<= 1;
return WAVERAM_READ8(base, byteoffs + 1);
}
// 2x2 block size of r5g5r5 in 64 bits
static inline uint32_t get_rgb555(const void *base, int y, int x, int width)
{
uint32_t wordoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
uint16_t color = WAVERAM_READ16(base, wordoffs);
return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x1f) << 3);
}
};
// device type definition
DECLARE_DEVICE_TYPE(ZEUS2, zeus2_device)
#endif // MAME_VIDEO_ZEUS2