From e5f6eb6dd9e65ff1ce9b9e3621c5eb86e3d11734 Mon Sep 17 00:00:00 2001 From: mooglyguy Date: Sun, 23 Dec 2018 09:52:58 +0100 Subject: Split m2_te_device declaration into its own header file, and cleaned up some underscore usage in M2-related #defines. Fixes single-driver builds. nw --- scripts/target/mame/arcade.lua | 1 + src/devices/cpu/dspp/dspp.h | 6 +- src/devices/cpu/dspp/dsppdasm.h | 6 +- src/mame/machine/3dom2.cpp | 8 +- src/mame/machine/3dom2.h | 404 +--- src/mame/machine/3dom2_defs.h | 695 ------- src/mame/machine/3dom2_te.cpp | 3959 -------------------------------------- src/mame/video/3dom2_te.cpp | 3960 +++++++++++++++++++++++++++++++++++++++ src/mame/video/3dom2_te.h | 421 +++++ 9 files changed, 4398 insertions(+), 5062 deletions(-) delete mode 100644 src/mame/machine/3dom2_defs.h delete mode 100644 src/mame/machine/3dom2_te.cpp create mode 100644 src/mame/video/3dom2_te.cpp create mode 100644 src/mame/video/3dom2_te.h diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index edf91749eda..2f572ff7cca 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -2364,6 +2364,7 @@ files { MAME_DIR .. "src/mame/machine/3dom2.cpp", MAME_DIR .. "src/mame/machine/3dom2.h", MAME_DIR .. "src/mame/machine/3dom2_te.cpp", + MAME_DIR .. "src/mame/machine/3dom2_te.h", MAME_DIR .. "src/mame/drivers/konblands.cpp", MAME_DIR .. "src/mame/drivers/konmedal.cpp", MAME_DIR .. "src/mame/drivers/konmedal68k.cpp", diff --git a/src/devices/cpu/dspp/dspp.h b/src/devices/cpu/dspp/dspp.h index 155ba4acbd1..b99940e24aa 100644 --- a/src/devices/cpu/dspp/dspp.h +++ b/src/devices/cpu/dspp/dspp.h @@ -10,8 +10,8 @@ #pragma once -#ifndef __DSPP_H__ -#define __DSPP_H__ +#ifndef DEVICES_CPU_DSPP_DSPP_H +#define DEVICES_CPU_DSPP_DSPP_H #include "cpu/drcfe.h" #include "cpu/drcuml.h" @@ -334,4 +334,4 @@ public: // TODO DECLARE_DEVICE_TYPE(DSPP, dspp_device); -#endif /* __DSPP_H__ */ +#endif // DEVICES_CPU_DSPP_DSPP_H diff --git a/src/devices/cpu/dspp/dsppdasm.h b/src/devices/cpu/dspp/dsppdasm.h index 7f0c526e18a..0ceae9b117b 100644 --- a/src/devices/cpu/dspp/dsppdasm.h +++ b/src/devices/cpu/dspp/dsppdasm.h @@ -4,8 +4,8 @@ DSPP disassembler shim */ -#ifndef MAME_CPU_DSPP_DSPPDASM_H -#define MAME_CPU_DSPP_DSPPDASM_H +#ifndef DEVICES_CPU_DSPP_DSPPDASM_H +#define DEVICES_CPU_DSPP_DSPPDASM_H #pragma once @@ -19,4 +19,4 @@ public: virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; }; -#endif +#endif // DEVICES_CPU_DSPP_DSPPDASM_H diff --git a/src/mame/machine/3dom2.cpp b/src/mame/machine/3dom2.cpp index 42ec38f04e9..245117ce0d5 100644 --- a/src/mame/machine/3dom2.cpp +++ b/src/mame/machine/3dom2.cpp @@ -188,7 +188,7 @@ DEFINE_DEVICE_TYPE(M2_CDE, m2_cde_device, "m2cde", "3DO M2 CDE ASIC") SUPPORT FUNCTIONS ***************************************************************************/ -static void write_m2_reg(uint32_t ®, uint32_t data, reg_wmode mode) +static void write_m2_reg(uint32_t ®, uint32_t data, m2_reg_wmode mode) { switch (mode) { @@ -952,7 +952,7 @@ READ32_MEMBER( m2_vdu_device::read ) WRITE32_MEMBER( m2_vdu_device::write ) { uint32_t byte_offs = offset << 2; - reg_wmode wmode = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE; + m2_reg_wmode wmode = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE; // logerror("%s: VDU WRITE: %03x %08x %x\n", machine().describe_context(), byte_offs, data, mem_mask); byte_offs &= ~0x400; @@ -1751,8 +1751,8 @@ WRITE32_MEMBER( m2_cde_device::write ) uint32_t byte_offs = offset << 2; uint32_t dmach = byte_offs & 0x20 ? 1 : 0; - reg_wmode wm_cw = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE; - reg_wmode wm_cs = byte_offs & 0x400 ? REG_CLEAR : REG_SET; + m2_reg_wmode wm_cw = byte_offs & 0x400 ? REG_CLEAR : REG_WRITE; + m2_reg_wmode wm_cs = byte_offs & 0x400 ? REG_CLEAR : REG_SET; byte_offs &= ~0x400; diff --git a/src/mame/machine/3dom2.h b/src/mame/machine/3dom2.h index f0a95aac24d..8942b515064 100644 --- a/src/mame/machine/3dom2.h +++ b/src/mame/machine/3dom2.h @@ -10,12 +10,13 @@ #pragma once -#ifndef _3DOM2_H_ -#define _3DOM2_H_ +#ifndef MAME_MACHINE_3DOM2_H +#define MAME_MACHINE_3DOM2_H #include "emu.h" #include "cpu/dspp/dspp.h" #include "cpu/powerpc/ppc.h" +#include "video/3dom2_te.h" #include "screen.h" #define M2_BAD_TIMING 0 // HACK @@ -77,7 +78,7 @@ enum bdaint_line BDAINT_TRIWINCLIP_LINE = 31, }; -enum reg_wmode +enum m2_reg_wmode { REG_WRITE, REG_INVALID, @@ -88,14 +89,13 @@ enum reg_wmode /*************************************************************************** - DEVICE CONFIGURATION MACROS + FORWARD DECLARATIONS ***************************************************************************/ class m2_bda_device; class m2_powerbus_device; class m2_memctl_device; class m2_vdu_device; -class m2_te_device; class m2_ctrlport_device; class m2_mpeg_device; class m2_cde_device; @@ -474,397 +474,6 @@ private: -/*************************************************************************** - TRIANGLE ENGINE DEVICE -***************************************************************************/ - -class m2_te_device : public device_t -{ -public: - m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // Static configuration helpers - auto general_int_handler() { return m_general_int_handler.bind(); } - auto dfinstr_int_handler() { return m_dfinstr_int_handler.bind(); } - auto iminstr_int_handler() { return m_iminstr_int_handler.bind(); } - auto listend_int_handler() { return m_listend_int_handler.bind(); } - auto winclip_int_handler() { return m_winclip_int_handler.bind(); } - - DECLARE_READ32_MEMBER(read); - DECLARE_WRITE32_MEMBER(write); - - uint32_t *tram_ptr() const { return m_tram; } - -protected: - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_post_load() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - -private: - - enum te_state - { - TE_STOPPED, - TE_PAUSED, - TE_RUNNING, - }; - - enum misc - { - PIP_RAM_WORDS = 256, - TEXTURE_RAM_WORDS = 4096, - PIP_RAM_BYTEMASK = PIP_RAM_WORDS * 4 - 1, - TEXTURE_RAM_BYTEMASK = TEXTURE_RAM_WORDS * 4 - 1, - }; - - enum inst_type - { - INST_WRITE_REG = 0x10000000, - INST_VTX_SHORT = 0x20000000, - INST_VTX_LONG = 0x30000000, - INST_VTX_POINT = 0x40000000, - INST_MASK = 0xf0000000, - }; - - enum vtx_flag - { - VTX_FLAG_SHAD = 0x00010000, - VTX_FLAG_TEXT = 0x00020000, - VTX_FLAG_PRSP = 0x00040000, - VTX_FLAG_NEW = 0x00080000, - VTX_FLAG_RM = 0x00100000, - }; - - struct se_vtx - { - float x, y; - float r, g, b, a; - float w; - float uw, vw; - float iv[8]; - }; - - struct slope_params - { - float y23; - float y31; - float y12; - float x23; - float x31; - float x12; - float xstep_long; - float iAria; - }; - - struct rgba { uint8_t r, g, b, a; }; - - void set_interrupt(uint32_t mask); - void update_interrupts(); - - void teicntl_w(uint32_t data, reg_wmode wmode); - void tedcntl_w(uint32_t data, reg_wmode wmode); - void master_mode_w(uint32_t data, reg_wmode wmode); - - void execute(); - void illegal_inst(); - uint32_t irp_fetch(); - float irp_fetch_float(); - - void add_vertex(const se_vtx &vtx, uint32_t flags); - void log_triangle(uint32_t flags); - void setup_triangle(uint32_t flags); - void calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out); - void walk_edges(uint32_t wrange); - void walk_span(uint32_t wrange, bool omit_right, uint32_t y, uint32_t xs, uint32_t xe, int32_t r, int32_t g, int32_t b, int32_t a, uint32_t uw, uint32_t vw, uint32_t w); - - void texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w, - uint32_t & uo, uint32_t & vo, uint32_t & wo); - - uint32_t lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1); - - uint32_t get_tram_bitdepth(); - - void addr_calc(uint32_t u, uint32_t v, uint32_t lod, - uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth); - - void get_texture_color(uint32_t u, uint32_t v, uint32_t lod, - uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s); - - void get_texel(uint32_t u, uint32_t v, uint32_t lod, - uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti); - - void texture_fetch(uint32_t texaddr, uint32_t texbit, uint32_t tdepth, - uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti); - - void select_lerp(uint32_t sel, - uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, - uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, - uint32_t & ar, uint32_t & ag, uint32_t & ab ); - - void select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt, - uint32_t & a ); - - void texture_blend(uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, - uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, - uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo); - - void destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb); - - uint8_t color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc, - uint8_t dm10, uint8_t dm11, - uint8_t dm20, uint8_t dm21); - - void select_alpha_dsb(); - uint8_t get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1); - uint8_t get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1); - uint8_t dither(uint8_t in, uint8_t dithval); - uint8_t alu_calc(uint16_t a, uint16_t b); - void select_src_pixel(); - void select_tex_pixel(); - void write_dst_pixel(); - - uint8_t read_tram8(offs_t address) const; - uint16_t read_tram16(offs_t address) const; - uint32_t read_tram32(offs_t address) const; - void write_tram8(offs_t address, uint8_t data); - void write_tram16(offs_t address, uint16_t data); - void write_tram32(offs_t address, uint32_t data); - - uint8_t read_pipram8(offs_t address) const; - uint16_t read_pipram16(offs_t address) const; - uint32_t read_pipram32(offs_t address) const; - void write_pipram32(offs_t address, uint32_t data); - - uint32_t readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits); - void load_texture(); - - m2_bda_device *m_bda; - const address_space_config m_space_config; // TODO: Why is this still here? - - devcb_write_line m_general_int_handler; - devcb_write_line m_dfinstr_int_handler; - devcb_write_line m_iminstr_int_handler; - devcb_write_line m_listend_int_handler; - devcb_write_line m_winclip_int_handler; - - // Registers - union - { - struct - { - uint32_t te_master_mode; - uint32_t reserved; - uint32_t teicntl_data; - uint32_t teicntl; - uint32_t tedcntl_data; - uint32_t tedcntl; - uint32_t iwp; - uint32_t irp; - uint32_t int_enable; - uint32_t int_status; - uint32_t vertex_ctrl; - }; - uint32_t m_regs[11]; - } m_gc; - - union - { - struct - { - se_vtx vertices[3]; - uint32_t reserved[16]; - uint32_t vertex_state; - }; - uint32_t m_regs[65]; - } m_se; - - struct - { - union - { - struct - { - uint32_t es_cntl; - uint32_t es_capaddr; - uint32_t es_capdata; - }; - uint32_t m_regs[3]; - }; - union - { - struct - { - uint32_t x1; - uint32_t y1; - uint32_t r1; - uint32_t g1; - uint32_t b1; - uint32_t a1; - uint32_t w1; - uint32_t uw1; - uint32_t vw1; - uint32_t x2; - uint32_t y2; - uint32_t y3; - uint32_t xstep_0; - uint32_t xstep_1; - uint32_t xstep_long; - uint32_t xystep_0; - uint32_t xystep_1; - uint32_t xystep_long; - uint32_t dy_0; - uint32_t dy_1; - uint32_t dy_long; - uint32_t ddx_r; - uint32_t ddx_g; - uint32_t ddx_b; - uint32_t ddx_a; - uint32_t ddx_w; - uint32_t ddx_uw; - uint32_t ddx_vw; - uint32_t slope_r; - uint32_t slope_g; - uint32_t slope_b; - uint32_t slope_a; - uint32_t slope_uw; - uint32_t slope_vw; - uint32_t slope_w; - uint32_t r2l; - }; - uint32_t m_buffer_regs[36]; - }; - } m_es; - - union - { - struct - { - uint32_t tex_cntl; - uint32_t texld_cntl; - uint32_t tex_addr_cntl; - uint32_t tex_pip_cntl; - uint32_t tex_tab_cntl; - union - { - uint32_t tex_lod_base0; - uint32_t texld_dstbase; - uint32_t tex_mm_dstbase; - }; - uint32_t tex_lod_base1; - uint32_t tex_lod_base2; - uint32_t tex_lod_base3; - union - { - uint32_t texld_srcbase; - uint32_t tex_mm_srcbase; - }; - union - { - uint32_t tex_bytecnt; - uint32_t tex_rowcnt; - uint32_t tex_texcnt; - }; - uint32_t uv_max; - uint32_t uv_mask; - uint32_t tex_srctype01; - uint32_t tex_srctype23; - uint32_t tex_exptype; - union - { - uint32_t tex_srcconst0; - uint32_t tex_clrconst; - uint32_t tex_catconst0; - }; - union - { - uint32_t tex_srcconst1; - uint32_t tex_pipconst1; - }; - union - { - uint32_t tex_srcconst2; - uint32_t tex_catiConst0; - }; - union - { - uint32_t tex_srcconst3; - uint32_t tex_caticonst1; - }; - uint32_t tex_srcexp; - }; - uint32_t m_regs[21]; - } m_tm; - - union - { - struct - { - uint32_t snoop; - uint32_t supergen_ctrl; - uint32_t usergen_ctrl; - uint32_t discard_ctrl; - uint32_t status; - uint32_t int_ctrl; - uint32_t fbclip; - uint32_t x_winclip; - uint32_t y_winclip; - uint32_t dst_ctrl; - uint32_t dst_baseaddr; - uint32_t dst_xstride; - uint32_t src_ctrl; - uint32_t src_baseaddr; - uint32_t src_xstride; - uint32_t src_offset; - uint32_t z_ctrl; - uint32_t z_baseaddr; - uint32_t z_offset; - uint32_t z_clip; - uint32_t ssbdsb_ctrl; - uint32_t const_in; - uint32_t txt_mult_cntl; - uint32_t txt_coef_const0; - uint32_t txt_coef_const1; - uint32_t src_mult_cntl; - uint32_t src_coef_const0; - uint32_t src_coef_const1; - uint32_t alu_ctrl; - uint32_t src_alpha_ctrl; - uint32_t dst_alpha_ctrl; - uint32_t dst_alpha_const; - uint32_t dither_mat_a; - uint32_t dither_mat_b; - }; - uint32_t m_regs[34]; - } m_db; - - // Destination blender state - struct - { - uint32_t x; - uint32_t y; - uint32_t w; - - rgba ti; - uint8_t ssb; - - rgba src; - uint8_t dsb; - - rgba srcpath; - rgba texpath; - rgba blend; - rgba dst; - } m_dbstate; - - te_state m_state; - - uint32_t *m_pipram; - uint32_t *m_tram; -}; - - - /*************************************************************************** MPEG DEVICE ***************************************************************************/ @@ -1132,6 +741,5 @@ DECLARE_DEVICE_TYPE(M2_VDU, m2_vdu_device) DECLARE_DEVICE_TYPE(M2_CTRLPORT, m2_ctrlport_device) DECLARE_DEVICE_TYPE(M2_MPEG, m2_mpeg_device) DECLARE_DEVICE_TYPE(M2_CDE, m2_cde_device) -DECLARE_DEVICE_TYPE(M2_TE, m2_te_device) -#endif // _3DOM2_H_ +#endif // MAME_MACHINE_3DOM2_H diff --git a/src/mame/machine/3dom2_defs.h b/src/mame/machine/3dom2_defs.h deleted file mode 100644 index 4019e5087ce..00000000000 --- a/src/mame/machine/3dom2_defs.h +++ /dev/null @@ -1,695 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Philip Bennett -/*************************************************************************** - - 3DO M2 - -***************************************************************************/ - -#pragma once - -#ifndef MACHINE_3DOM2_DEFS_H -#define MACHINE_3DOM2_DEFS_H - -/*************************************************************************** - ENUMERATIONS -***************************************************************************/ - -#define M2_SYSCFG_VIDEO_NTSC (0x00000000U) -#define M2_SYSCFG_VIDEO_PAL (0x00000001U) - -#define M2_SYSCFG_VIDEO_ENCODER_MEIENC (0x00000000U) // NTSC by default -#define M2_SYSCFG_VIDEO_ENCODER_VP536 (0x00000004U) // NTSC by default -#define M2_SYSCFG_VIDEO_ENCODER_BT9103 (0x00000008U) // PAL by default -#define M2_SYSCFG_VIDEO_ENCODER_DENC (0x0000000CU) // PAL by default - -#define M2_SYSCFG_REGION_UK (0x00000800U) -#define M2_SYSCFG_REGION_JAPAN (0x00001000U) -#define M2_SYSCFG_REGION_US (0x00001800U) - -#if 0 // Console -#define M2_SYSCFG_AUDIO_CS4216 (0xA0000000U) -#define M2_SYSCFG_AUDIO_ASASHI (0xE0000000U) -#else -#define M2_SYSCFG_AUDIO_CS4216 (0x20000000U) -#define M2_SYSCFG_AUDIO_ASASHI (0x60000000U) -#endif -#define M2_SYSCFG_BOARD_AC_DEVCARD (0x00040000U) -#define M2_SYSCFG_BOARD_AC_COREBOARD (0x00058000U) -#define M2_SYSCFG_BOARD_DEVCARD (0x00060000U) -#define M2_SYSCFG_BOARD_UPGRADE (0x00070000U) -#define M2_SYSCFG_BOARD_MULTIPLAYER (0x00078000U) - -#define M2_SYSCONFIG_ARCADE (0x03600000 | SYSCFG_BOARD_AC_COREBOARD | SYSCFG_AUDIO_ASASHI | SYSCFG_REGION_JAPAN | SYSCFG_VIDEO_ENCODER_MEIENC | SYSCFG_VIDEO_NTSCU) - - -#define M2_MEMBASE_POWERBUS (0x00010000U) -#define M2_MEMBASE_MEMCTL (0x00020000U) -#define M2_MEMBASE_VDU (0x00030000U) -#define M2_MEMBASE_TE (0x00040000U) -#define M2_MEMBASE_DSP (0x00060000U) -#define M2_MEMBASE_CTRLPORT (0x00070000U) -#define M2_MEMBASE_MPEG (0x00080000U) -#define M2_MEMBASE_TE_TRAM (0x000c0000U) -#define M2_MEMBASE_SLOT1 (0x01000000U) -#define M2_MEMBASE_SLOT2 (0x02000000U) -#define M2_MEMBASE_SLOT3 (0x03000000U) -#define M2_MEMBASE_SLOT4 (0x04000000U) -#define M2_MEMBASE_SLOT5 (0x05000000U) -#define M2_MEMBASE_SLOT6 (0x06000000U) -#define M2_MEMBASE_SLOT7 (0x07000000U) -#define M2_MEMBASE_SLOT8 (0x08000000U) -#define M2_MEMBASE_CPUID (0x10000000U) -#define M2_MEMBASE_RAM (0x40000000U) - -enum dev_mask -{ - DEVICE_MASK (0x0000ffffU) - SLOT_MASK (0x00ffffffU) - TE_TRAM_MASK (0x00003fffU) -}; - - enum reg_offs - { -#define M2_BDAPCTL_DEVID (0x00U) -#define M2_BDAPCTL_PBCONTROL (0x10U) -#define M2_BDAPCTL_PBINTENSET (0x40U) -#define M2_BDAPCTL_PBINTSTAT (0x50U) -#define M2_BDAPCTL_ERRSTAT (0x60U) -#define M2_BDAPCTL_ERRADDR (0x70U) - - - enum reg_offs - { - MCTL_MCONFIG (0x0U) - MCTL_MREF (0x4U) - MCTL_MCNTL (0x8U) - MCTL_MRESET (0xcU) - }; - -#define M2_MCFG_LDIA_MASK (0x07000000U) -#define M2_MCFG_LDIA_SHIFT (24U) -#define M2_MCFG_LDOA_MASK (0x00c00000U) -#define M2_MCFG_LDOA_SHIFT (22U) -#define M2_MCFG_RC_MASK (0x003c0000U) -#define M2_MCFG_RC_SHIFT (18U) -#define M2_MCFG_RCD_MASK (0x00030000U) -#define M2_MCFG_RCD_SHIFT (16U) -#define M2_MCFG_SS1_MASK (0x0000e000U) -#define M2_MCFG_SS1_SHIFT (13U) -#define M2_MCFG_SS0_MASK (0x00001c00U) -#define M2_MCFG_SS0_SHIFT (10U) -#define M2_MCFG_CL_MASK (0x00000030U) -#define M2_MCFG_CL_SHIFT (4U) - -#define M2_MREF_DEBUGADDR (0x7F000000U) /* Selector if GPIOx_GP =(0 */ -#define M2_MREF_GPIO3_GP (0x00800000U) /* General purpose or debug out */ -#define M2_MREF_GPIO3_OUT (0x00400000U) /* Output or input */ -#define M2_MREF_GPIO3_VALUE (0x00200000U) /* Value if GPIOx_GP =(1 */ -#define M2_MREF_GPIO2_GP (0x00100000U) /* General purpose or debug out */ -#define M2_MREF_GPIO2_OUT (0x00080000U) /* Output or input */ -#define M2_MREF_GPIO2_VALUE (0x00040000U) /* Value if GPIOx_GP =(1 */ -#define M2_MREF_GPIO1_GP (0x00020000U) /* General purpose or debug out */ -#define M2_MREF_GPIO1_OUT (0x00010000U) /* Output or input */ -#define M2_MREF_GPIO1_VALUE (0x00008000U) /* Value if GPIOx_GP =(1 */ -#define M2_MREF_GPIO0_GP (0x00004000U) /* General purpose or debug out */ -#define M2_MREF_GPIO0_OUT (0x00002000U) /* Output or input */ -#define M2_MREF_GPIO0_VALUE (0x00001000U) /* Value if GPIOx_GP =(1 */ -#define M2_MREF_REFRESH (0x00000FFFU) /* Memory refresh count */ - - - enum CDE_REGS - // Miscellaneous - CDE_DEVICE_ID (0x000U) - CDE_VERSION (0x004U) - CDE_SDBG_CNTL (0x00C, // Serial debug control register - CDE_SDBG_RD (0x010, // Serial debug read data - CDE_SDBG_WRT (0x014, // Serial debug write data - CDE_INT_STS (0x018, // offset for status reg - CDE_INT_ENABLE (0x01CU) - CDE_RESET_CNTL (0x020U) - CDE_ROM_DISABLE (0x024U) - CDE_CD_CMD_WRT (0x028U) - CDE_CD_STS_RD (0x02CU) - CDE_GPIO1 (0x030, // GPIO1 control register (UART interrupt) - CDE_GPIO2 (0x034, // GPIO1 control register - - // BIO Bus - CDE_DEV_DETECT (0x200U) - CDE_BBLOCK (0x204U) - CDE_BBLOCK_EN (0x208, // Blocking enable register - CDE_DEV5_CONF (0x20CU) - CDE_DEV_STATE (0x210U) - CDE_DEV6_CONF (0x214U) - CDE_DEV5_VISA_CONF (0x218U) - CDE_DEV6_VISA_CONF (0x21CU) - CDE_UNIQ_ID_CMD (0x220U) - CDE_UNIQ_ID_RD (0x224U) - CDE_DEV_ERROR (0x228U) - CDE_DEV7_CONF (0x22CU) - CDE_DEV7_VISA_CONF (0x230U) - CDE_DEV0_SETUP (0x240U) - CDE_DEV0_CYCLE_TIME (0x244U) - CDE_DEV1_SETUP (0x248U) - CDE_DEV1_CYCLE_TIME (0x24CU) - CDE_DEV2_SETUP (0x250U) - CDE_DEV2_CYCLE_TIME (0x254U) - CDE_DEV3_SETUP (0x258U) - CDE_DEV3_CYCLE_TIME (0x25CU) - CDE_DEV4_SETUP (0x260U) - CDE_DEV4_CYCLE_TIME (0x264U) - CDE_DEV5_SETUP (0x268U) - CDE_DEV5_CYCLE_TIME (0x26CU) - CDE_DEV6_SETUP (0x270U) - CDE_DEV6_CYCLE_TIME (0x274U) - CDE_DEV7_SETUP (0x278U) - CDE_DEV7_CYCLE_TIME (0x27CU) - CDE_SYSTEM_CONF (0x280U) - CDE_VISA_DIS (0x284U) - M2_CDE_MICRO_RWS (0x290U) - M2_CDE_MICRO_WI (0x294U) - M2_CDE_MICRO_WOB (0x298U) - M2_CDE_MICRO_WO (0x29CU) - M2_CDE_MICRO_STATUS (0x2A0U) - - // CD DMA - M2_CDE_CD_DMA1_CNTL (0x300U) - M2_CDE_CD_DMA1_CPAD (0x308U) - M2_CDE_CD_DMA1_CCNT (0x30CU) - M2_CDE_CD_DMA1_NPAD (0x318U) - M2_CDE_CD_DMA1_NCNT (0x31CU) - M2_CDE_CD_DMA2_CNTL (0x320U) - M2_CDE_CD_DMA2_CPAD (0x328U) - M2_CDE_CD_DMA2_CCNT (0x32CU) - M2_CDE_CD_DMA2_NPAD (0x338U) - M2_CDE_CD_DMA2_NCNT (0x33CU) - - // BioBus DMA - M2_CDE_DMA1_CNTL (0x1000U) - M2_CDE_DMA1_CBAD (0x1004U) - M2_CDE_DMA1_CPAD (0x1008U) - M2_CDE_DMA1_CCNT (0x100CU) - M2_CDE_DMA1_NBAD (0x1014U) - M2_CDE_DMA1_NPAD (0x1018U) - M2_CDE_DMA1_NCNT (0x101CU) - M2_CDE_DMA2_CNTL (0x1020U) - M2_CDE_DMA2_CBAD (0x1024U) - M2_CDE_DMA2_CPAD (0x1028U) - M2_CDE_DMA2_CCNT (0x102CU) - M2_CDE_DMA2_NBAD (0x1034U) - M2_CDE_DMA2_NPAD (0x1038U) - M2_CDE_DMA2_NCNT (0x103CU) - }; - - enum cde_int - { - M2_CDE_INT_SENT (0x80000000U) - M2_CDE_SDBG_WRT_DONE (0x10000000U) - M2_CDE_SDBG_RD_DONE (0x08000000U) - M2_CDE_DIPIR (0x04000000U) - M2_CDE_ARM_BOUNDS (0x01000000U) - M2_CDE_DMA2_BLOCKED (0x00400000U) - M2_CDE_DMA1_BLOCKED (0x00200000U) - M2_CDE_ID_READY (0x00100000U) - M2_CDE_ARM_FENCE (0x00080000U) - M2_CDE_EXT_INT (0x00040000, // Added by Phil - M2_CDE_3DO_CARD_INT (0x00020000U) - M2_CDE_ARM_INT (0x00010000U) - M2_CDE_CD_DMA2_OF (0x00004000U) - M2_CDE_CD_DMA1_OF (0x00002000U) - M2_CDE_ARM_ABORT (0x00001000U) - M2_CDE_CD_DMA2_DONE (0x00000800U) - M2_CDE_CD_DMA1_DONE (0x00000400U) - M2_CDE_DMA2_DONE (0x00000100U) - M2_CDE_DMA1_DONE (0x00000080U) - M2_CDE_PBUS_ERROR (0x00000040U) - M2_CDE_CD_CMD_WRT_DONE (0x00000020U) - M2_CDE_CD_STS_RD_DONE (0x00000010U) - M2_CDE_CD_STS_FL_DONE (0x00000008U) - M2_CDE_GPIO1_INT (0x00000004U) - M2_CDE_GPIO2_INT (0x00000002U) - M2_CDE_BBUS_ERROR (0x00000001U) - }; - - enum cde_dma_cntl - { - M2_CDE_DMA_DIRECTION (0x00000400, /* PowerBus to BioBus if set */ - M2_CDE_DMA_RESET (0x00000200, /* Reset engine if set */ - M2_CDE_DMA_GLOBAL (0x00000100, /* snoopable trans if set */ - M2_CDE_DMA_CURR_VALID (0x00000080, /* current setup valid if set */ - M2_CDE_DMA_NEXT_VALID (0x00000040, /* next setup valid if set */ - M2_CDE_DMA_GO_FOREVER (0x00000020, /* copy next to current if set*/ - M2_CDE_PB_CHANNEL_MASK (0x0000001F, /* powerbus channel to use */ - }; - -// CDE -#define M2_CDE_WRITEN_HOLD (0x00000003U) -#define M2_CDE_WRITEN_SETUP (0x0000001CU) -#define M2_CDE_READ_HOLD (0x00000060U) -#define M2_CDE_READ_SETUP (0x00000380U) -#define M2_CDE_PAGEMODE (0x00000400U) -#define M2_CDE_DATAWIDTH (0x00001800U) -#define M2_CDE_DATAWIDTH_8 (0x00000000U) -#define M2_CDE_DATAWIDTH_16 (0x00000800U) -#define M2_CDE_READ_SETUP_IO (0x0000E000U) -#define M2_CDE_MODEA (0x00010000U) -#define M2_CDE_HIDEA (0x00020000U) - - -// TE - -/*************************************************************************** - REGISTER DEFINITIONS - ***************************************************************************/ -//------------------------------------------------- -// General Control -//------------------------------------------------- - -// Triangle Engine Master Mode -#define M2_TE_MASTER_MODE_RESET (0x00000001U) -#define M2_TE_MASTER_MODE_DTEXT (0x00000002U) -#define M2_TE_MASTER_MODE_DSHADE (0x00000004U) -#define M2_TE_MASTER_MODE_DBLEND (0x00000008U) -#define M2_TE_MASTER_MODE_DZBUF (0x00000010U) -#define M2_TE_MASTER_MODE_DDITH (0x00000020U) - -// Triangle Engine Immediate Control -#define M2_TE_TEICNTL_INT (0x00000001U) -#define M2_TE_TEICNTL_STEP (0x00000002U) -#define M2_TE_TEICNTL_STPL (0x00000004U) -#define M2_TE_TEICNTL_STPI (0x00000008U) -#define M2_TE_TEICNTL_RSTRT (0x00000010U) -#define M2_TE_TEICNTL_STRT (0x00000020U) - -#define M2_TE_TEDCNTL_TLD (0x00000001U) -#define M2_TE_TEDCNTL_JA (0x00000002U) -#define M2_TE_TEDCNTL_JR (0x00000004U) -#define M2_TE_TEDCNTL_INT (0x00000008U) -#define M2_TE_TEDCNTL_PSE (0x00000010U) -#define M2_TE_TEDCNTL_SYNC (0x00000020U) - -#define M2_TE_INTSTAT_DEFERRED_INSTR (0x00000100U) -#define M2_TE_INTSTAT_IMMEDIATE_INSTR (0x00000200U) -#define M2_TE_INTSTAT_LIST_END (0x00000400U) -#define M2_TE_INTSTAT_WINDOW_CLIP (0x00000800U) -#define M2_TE_INTSTAT_SPECIAL_INSTR (0x00001000U) -#define M2_TE_INTSTAT_UNIMPLEMENTED_INSTR (0x00002000U) -#define M2_TE_INTSTAT_SUPERVISOR (0x00004000U) -#define M2_TE_INTSTAT_ANY_RENDER (0x00008000U) -#define M2_TE_INTSTAT_Z_FUNC (0x00010000U) -#define M2_TE_INTSTAT_ALU_STATUS (0x00020000U) -#define M2_TE_INTSTAT_FB_CLIP (0x00040000U) -#define M2_TE_INTSTAT_IMMEDIATE (0x00080000U) - -// IWP -// IRP -// Interrupt Enable -// Interrupt Status -// Vertex Control - - - -//------------------------------------------------- -// Setup Engine -//------------------------------------------------- - - // Vertex State -#define M2_TE_VERTEXSTATE_TSORT_MASK (0x00000007U) -#define M2_TE_VERTEXSTATE_TSORT_OMN (0x00000001U) -#define M2_TE_VERTEXSTATE_TSORT_MNO (0x00000002U) -#define M2_TE_VERTEXSTATE_TSORT_ONM (0x00000003U) -#define M2_TE_VERTEXSTATE_TSORT_NOM (0x00000004U) -#define M2_TE_VERTEXSTATE_TSORT_MON (0x00000005U) -#define M2_TE_VERTEXSTATE_TSORT_NMO (0x00000006U) - -#define M2_TE_VERTEXSTATE_VCNT_SHIFT (3U) -#define M2_TE_VERTEXSTATE_VCNT_MASK (0x00000018U) - - - //------------------------------------------------- - // Edge Walker - //------------------------------------------------- - - // Edge and Span Walker Control -#define ESCNTL_DSPOFF (0x00000001U) -#define ESCNTL_DUSCAN (0x00000002U) -#define ESCNTL_PERSPECTIVEOFF (0x00000004U) - - - //------------------------------------------------- - // Texture Mapper - //------------------------------------------------- - - // Texture Mapper Master Control (0x00046400) -#define M2_TE_TXTCNTL_MMDMA_TRAM_ON (0x00000004U) -#define M2_TE_TXTCNTL_MMDMA_PIP_ON (0x00000008U) -#define M2_TE_TXTCNTL_SNOOP_ON (0x00000020U) - - // Texture Load Control (0x00046404) -#define M2_TE_TXTLDCNTL_SRCBITOFFS (0x00000007U) -#define M2_TE_TXTLDCNTL_LDMODE_MASK (0x00000300U) -#define M2_TE_TXTLDCNTL_LDMODE_TEXLOAD (0x00000000U) -#define M2_TE_TXTLDCNTL_LDMODE_MMDMA (0x00000100U) -#define M2_TE_TXTLDCNTL_LDMODE_PIPLOAD (0x00000200U) -#define M2_TE_TXTLDCNTL_LDMODE_RESERVED (0x00000300U) -#define M2_TE_TXTLDCNTL_COMPRESSED (0x00000400U) - - // Address Control (0x00046408) -#define M2_TE_TXTADDRCNTL_LODMAX_MASK (0x0000000fU) -#define M2_TE_TXTADDRCNTL_FILTERSEL_MASK (0x00000003U) -#define M2_TE_TXTADDRCNTL_FILTERSEL_POINT (0x00000000U) -#define M2_TE_TXTADDRCNTL_FILTERSEL_LINEAR (0x00000001U) -#define M2_TE_TXTADDRCNTL_FILTERSEL_BILINEAR (0x00000002U) -#define M2_TE_TXTADDRCNTL_FILTERSEL_QUASITRI (0x00000003U) -#define M2_TE_TXTADDRCNTL_R12FILTERSEL_SHIFT (4U) -#define M2_TE_TXTADDRCNTL_R3FILTERSEL_SHIFT (7U) -#define M2_TE_TXTADDRCNTL_R45FILTERSEL_SHIFT (10U) -#define M2_TE_TXTADDRCNTL_LOOKUP_EN (0x00002000U) - - // PIP Control (0x0004640C) -#define M2_TE_TXTPIPCNTL_INDEX_OFFSET (0x000000ffU) -#define M2_TE_TXTPIPCNTL_COLORSEL_MASK (0x00000700U) -#define M2_TE_TXTPIPCNTL_COLORSEL_SHIFT (8U) -#define M2_TE_TXTPIPCNTL_ALPHASEL_MASK (0x00003800U) -#define M2_TE_TXTPIPCNTL_ALPHASEL_SHIFT (11U) -#define M2_TE_TXTPIPCNTL_SSBSEL_MASK (0x0001c000U) -#define M2_TE_TXTPIPCNTL_SSBSEL_SHIFT (14U) - -#define M2_TE_TXTPIPCNTL_SEL_CONSTANT 0 -#define M2_TE_TXTPIPCNTL_SEL_TRAM 1 -#define M2_TE_TXTPIPCNTL_SEL_PIP 2 - - // Texture Application Control (0x00046410) -#define M2_TE_TXTTABCNTL_C_ASEL_MASK 0x00000007 -#define M2_TE_TXTTABCNTL_C_ASEL_SHIFT 0 -#define M2_TE_TXTTABCNTL_C_BSEL_MASK 0x00000038 -#define M2_TE_TXTTABCNTL_C_BSEL_SHIFT 3 -#define M2_TE_TXTTABCNTL_C_TSEL_MASK 0x000001c0 -#define M2_TE_TXTTABCNTL_C_TSEL_SHIFT 6 - -#define M2_TE_TXTTABCNTL_C_ABTSEL_AITER 0 -#define M2_TE_TXTTABCNTL_C_ABTSEL_CITER 1 -#define M2_TE_TXTTABCNTL_C_ABTSEL_AT 2 -#define M2_TE_TXTTABCNTL_C_ABTSEL_CT 3 -#define M2_TE_TXTTABCNTL_C_ABTSEL_ACONST 4 -#define M2_TE_TXTTABCNTL_C_ABTSEL_CCONST 5 - -#define M2_TE_TXTTABCNTL_C_OSEL_MASK 0x00000600 -#define M2_TE_TXTTABCNTL_C_OSEL_SHIFT 9 - -#define M2_TE_TXTTABCNTL_CO_SEL_CITER 0 -#define M2_TE_TXTTABCNTL_CO_SEL_CT 1 -#define M2_TE_TXTTABCNTL_CO_SEL_BLEND 2 -#define M2_TE_TXTTABCNTL_CO_SEL_RESERVED 3 - -#define M2_TE_TXTTABCNTL_A_ASEL_MASK 0x00001800 -#define M2_TE_TXTTABCNTL_A_ASEL_SHIFT 11 -#define M2_TE_TXTTABCNTL_A_BSEL_MASK 0x00006000 -#define M2_TE_TXTTABCNTL_A_BSEL_SHIFT 13 - -#define M2_TE_TXTTABCNTL_A_ABSEL_AITER 0 -#define M2_TE_TXTTABCNTL_A_ABSEL_AT 1 -#define M2_TE_TXTTABCNTL_A_ABSEL_ACONST 2 - -#define M2_TE_TXTTABCNTL_A_OSEL_MASK 0x00018000 -#define M2_TE_TXTTABCNTL_A_OSEL_SHIFT 15 - -#define M2_TE_TXTTABCNTL_AO_SEL_AITER 0 -#define M2_TE_TXTTABCNTL_AO_SEL_AT 1 -#define M2_TE_TXTTABCNTL_AO_SEL_BLEND 2 -#define M2_TE_TXTTABCNTL_AO_SEL_RESERVED 3 - -#define M2_TE_TXTTABCNTL_BLENDOP_MASK 0x00010000 -#define M2_TE_TXTTABCNTL_BLENDOP_SHIFT 16 -#define M2_TE_TXTTABCNTL_BLENDOP_LERP 0 -#define M2_TE_TXTTABCNTL_BLENDOP_MULT 1 - - // TAB Constants -#define M2_TE_TXTTABCONST_BLUE 0x000000ff -#define M2_TE_TXTTABCONST_BLUE_SHIFT 0 -#define M2_TE_TXTTABCONST_GREEN 0x0000ff00 -#define M2_TE_TXTTABCONST_GREEN_SHIFT 8 -#define M2_TE_TXTTABCONST_RED 0x00ff0000 -#define M2_TE_TXTTABCONST_RED_SHIFT 16 -#define M2_TE_TXTTABCONST_ALPHA 0x7f000000 -#define M2_TE_TXTTABCONST_ALPHA_SHIFT 24 -#define M2_TE_TXTTABCONST_SSB 0x80000000 - - // Texture Loader Destination Base (0x00046414) -#define M2_TE_TXTLDDSTBASE_ADDR 0x00003ffc - - // Texture Lod Base 0 (0x00046414) - // Texture Lod Base 1 (0x00046418) - // Texture Lod Base 2 (0x0004641C) - // Texture Lod Base 3 (0x00046420) -#define M2_TE_TXTLODBASE_MASK 0x00003ffc - - // Texture Loader Source Base (0x00046424) -#define M2_TE_TXTLDSRCBASE_ADDR 0x00003fff - - // Texture Loader Counts (0x00046428) -#define M2_TE_TXTLDBYTECNT_COUNT 0x0fffffff -#define M2_TE_TXTLDROWCNT_COUNT 0x0fffffff -#define M2_TE_TXTLDTEXCNT_COUNT 0x0fffffff - - // Texture Loader Width (0x00046428) -#define M2_TE_TxTLDWIDTH_SRCROW 0x0000ffff -#define M2_TE_TxTLDWIDTH_DSTROW_SHIFT 16 -#define M2_TE_TxTLDWIDTH_DSTROW 0xffff0000 - - // Texture Size (0x0004642C) -#define M2_TE_TXTUVMAX_VMAX_MASK 0x000003ff -#define M2_TE_TXTUVMAX_VMAX_SHIFT 0 -#define M2_TE_TXTUVMAX_UMAX_MASK 0x03ff0000 -#define M2_TE_TXTUVMAX_UMAX_SHIFT 16 - - // Texture Mask (0x00046430) -#define M2_TE_TXTUVMASK_VMASK_MASK 0x000003ff -#define M2_TE_TXTUVMASK_VMASK_SHIFT 0 -#define M2_TE_TXTUVMASK_UMASK_MASK 0x03ff0000 -#define M2_TE_TXTUVMASK_UMASK_SHIFT 16 - - // TRAM Format (0x0004643C) - // TODO: Expansion formats -#define M2_TE_TXTEXPFORM_CDEPTH_MASK 0x0000000f -#define M2_TE_TXTEXPFORM_CDEPTH_SHIFT 0 -#define M2_TE_TXTEXPFORM_IDEPTH_MASK 0x0000000f -#define M2_TE_TXTEXPFORM_IDEPTH_SHIFT 0 -#define M2_TE_TXTEXPFORM_ADEPTH_MASK 0x000000f0 -#define M2_TE_TXTEXPFORM_ADEPTH_SHIFT 4 -#define M2_TE_TXTEXPFORM_TRANSPARENT 0x00000100 -#define M2_TE_TXTEXPFORM_SSBON 0x00000200 -#define M2_TE_TXTEXPFORM_COLORON 0x00000400 -#define M2_TE_TXTEXPFORM_INDEXON 0x00000400 -#define M2_TE_TXTEXPFORM_ALPHAON 0x00000800 -#define M2_TE_TXTEXPFORM_LITERAL 0x00001000 - - - // Format Registers - - - //------------------------------------------------- - // Destination Blender - //------------------------------------------------- - - // Snoop (0x0048000) -#define M2_TE_DBSNOOP_DESTWRSNOOP 0x00000001 -#define M2_TE_DBSNOOP_SRCRDSNOOP 0x00000002 -#define M2_TE_DBSNOOP_ZWRSNOOP 0x00000004 -#define M2_TE_DBSNOOP_ZRDSNOOP 0x00000008 - - // Supervisor General Control (0x0048004) -#define M2_TE_DBSUPERGENCTL_DESTOUTEN 0x00000001 -#define M2_TE_DBSUPERGENCTL_DESTWR16BEN 0x00000002 -#define M2_TE_DBSUPERGENCTL_ZWR16BEN 0x00000004 - - // User General Control (0x0048008) -#define M2_TE_DBUSERGENCTL_DESTOUT_MASK 0x0000000f -#define M2_TE_DBUSERGENCTL_DITHEREN 0x00000010 -#define M2_TE_DBUSERGENCTL_SRCINEN 0x00000020 -#define M2_TE_DBUSERGENCTL_BLENDEN 0x00000040 -#define M2_TE_DBUSERGENCTL_WCLIPOUTEN 0x00000080 -#define M2_TE_DBUSERGENCTL_WCLIPINEN 0x00000100 -#define M2_TE_DBUSERGENCTL_ZOUTEN 0x00000200 -#define M2_TE_DBUSERGENCTL_ZBUFEN 0x00000400 - - // Discard Control (0x004800C) -#define M2_TE_DBDISCARDCTL_ADISEN 0x00000001 -#define M2_TE_DBDISCARDCTL_RGBDISEN 0x00000002 -#define M2_TE_DBDISCARDCTL_SSBDISEN 0x00000004 -#define M2_TE_DBDISCARDCTL_ZCLIPDISEN 0x00000008 - - // Status (0x0048010) -#define M2_TE_DBSTATUS_ANYREND 0x00000001 -#define M2_TE_DBSTATUS_ZFUNC_GT 0x00000002 -#define M2_TE_DBSTATUS_ZFUNC_EQ 0x00000004 -#define M2_TE_DBSTATUS_ZFUNC_LT 0x00000008 -#define DBSTATUS_ALUSTAT_BLUE_GT 0x00000010 -#define DBSTATUS_ALUSTAT_BLUE_EQ 0x00000020 -#define DBSTATUS_ALUSTAT_BLUE_LT 0x00000040 -#define DBSTATUS_ALUSTAT_GREEN_GT 0x00000080 -#define DBSTATUS_ALUSTAT_GREEN_EQ 0x00000100 -#define DBSTATUS_ALUSTAT_GREEN_LT 0x00000200 -#define DBSTATUS_ALUSTAT_RED_GT 0x00000400 -#define DBSTATUS_ALUSTAT_RED_EQ 0x00000800 -#define DBSTATUS_ALUSTAT_RED_LT 0x00001000 -#define M2_TE_DBSTATUS_ZCLIP 0x00002000 -#define M2_TE_DBSTATUS_WINCLIP 0x00004000 -#define M2_TE_DBSTATUS_FBCLIP 0x00008000 - - // Interrupt Control (0x00048014) -#define M2_TE_DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 -#define M2_TE_DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 - - // Framebuffer XY Clip Control (0x00048018) -#define M2_TE_DBFBCLIP_YFBCLIP_MASK 0x000007ff -#define M2_TE_DBFBCLIP_YFBCLIP_SHIFT 0 -#define M2_TE_DBFBCLIP_XFBCLIP_MASK 0x07ff0000 -#define M2_TE_DBFBCLIP_XFBCLIP_SHIFT 16 - - // Window X Clip Control (0x0004801C) -#define M2_TE_DBFBXWINCLIP_XMAX_MASK 0x000007ff -#define M2_TE_DBFBXWINCLIP_XMAX_SHIFT 0 -#define M2_TE_DBFBXWINCLIP_XMIN_MASK 0x07ff0000 -#define M2_TE_DBFBXWINCLIP_XMIN_SHIFT 16 - - // Window Y Clip Control (0x00048020) -#define M2_TE_DBFBYWINCLIP_YMAX_MASK 0x000007ff -#define M2_TE_DBFBYWINCLIP_YMAX_SHIFT 0 -#define M2_TE_DBFBYWINCLIP_YMIN_MASK 0x07ff0000 -#define M2_TE_DBFBYWINCLIP_YMIN_SHIFT 16 - - // Destination Write Control (0x0048024) -#define M2_TE_DBDESTCNTL_32BPP 0x00000001 - - // Destination Write Base Address (0x0048028) - - // Destination X Stride (0x004802C) -#define M2_TE_DBDEST_XSTRIDE 0x000007ff - - // Source Read Control (0x00048030) -#define M2_TE_DBSRCCNTL_32BPP 0x00000001 -#define M2_TE_DBSRCCNTL_MSBREP 0x00000002 - - // Source Read Base Address (0x00048034) - - // Source X Stride (0x00048038) -#define M2_TE_DBSRCXSTRIDE 0x000007ff - - // Source XY Offset (0x0004803C) -#define M2_TE_DBSRCOFFS_YOFFS_MASK 0x00000fff -#define M2_TE_DBSRCOFFS_YOFFS_SHIFT 0 -#define M2_TE_DBSRCOFFS_XOFFS_MASK 0x0fff0000 -#define M2_TE_DBSRCOFFS_XOFFS_SHIFT 16 - - // Z Buffer Control (0x00048040) -#define M2_TE_DBZCNTL_ZFUNCCNTL_MASK 0x0000003f -#define M2_TE_DBZCNTL_ZPIXOUT_LT 0x00000001 -#define M2_TE_DBZCNTL_ZBUFOUT_LT 0x00000002 -#define M2_TE_DBZCNTL_ZPIXOUT_EQ 0x00000004 -#define M2_TE_DBZCNTL_ZBUFOUT_EQ 0x00000008 -#define M2_TE_DBZCNTL_ZPIXOUT_GT 0x00000010 -#define M2_TE_DBZCNTL_ZBUFOUT_GT 0x00000020 - - // Z Buffer Base Address (0x00048044) -#define M2_TE_DBZBASEADDR_MASK 0x00ffffff - - // Z Buffer XY Offset (0x00048048) -#define M2_TE_DBZOFFS_YOFFS_MASK 0x00000fff -#define M2_TE_DBZOFFS_YOFFS_SHIFT 0 -#define M2_TE_DBZOFFS_XOFFS_MASK 0x0fff0000 -#define M2_TE_DBZOFFS_XOFFS_SHIFT 16 - - // Z Buffer Clip (0x0004804C) -#define M2_TE_DBZCLIP_YCLIP_MASK 0x000007ff -#define M2_TE_DBZCLIP_YCLIP_SHIFT 0 -#define M2_TE_DBZCLIP_XCLIP_MASK 0x07ff0000 -#define M2_TE_DBZCLIP_XCLIP_SHIFT 16 - - // SSB/DSB Control (0x00048050) -#define M2_TE_DBSSBDSBCNTL_DSBSELECT_MASK 0x00000007 -#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SHIFT 0 -#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SSB 0 -#define M2_TE_DBSSBDSBCNTL_DSBSELECT_CONSTANT 1 -#define M2_TE_DBSSBDSBCNTL_DSBSELECT_SRC 2 - -#define M2_TE_DBSSBDSBCNTL_DSBCONST 0x00000004 - - // RGB constants (0x00048054) -#define M2_TE_DBCONSTIN_B_MASK 0x000000ff -#define M2_TE_DBCONSTIN_B_SHIFT 0 -#define M2_TE_DBCONSTIN_G_MASK 0x0000ff00 -#define M2_TE_DBCONSTIN_G_SHIFT 8 -#define M2_TE_DBCONSTIN_R_MASK 0x00ff0000 -#define M2_TE_DBCONSTIN_R_SHIFT 16 - - // Texture Multiplication Control (0x00048058) -#define M2_TE_DBTXTMULTCNTL_TXTRJUST 0x00000001 -#define M2_TE_DBTXTMULTCNTL_TXTCOEFCMP 0x00000002 - -#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_MASK 0x0000000c -#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT 2 -#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB 0 -#define M2_TE_DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB 1 - -#define M2_TE_DBTXTMULTCNTL_COEFSEL_MASK 0x00000030 -#define M2_TE_DBTXTMULTCNTL_COEFSEL_SHIFT 4 -#define M2_TE_DBTXTMULTCNTL_COEFSEL_ATI 0 -#define M2_TE_DBTXTMULTCNTL_COEFSEL_ASRC 1 -#define M2_TE_DBTXTMULTCNTL_COEFSEL_CONSTANT 2 -#define M2_TE_DBTXTMULTCNTL_COEFSEL_CSRC 3 - -#define M2_TE_DBTXTMULTCNTL_INSEL_MASK 0x000000c0 -#define M2_TE_DBTXTMULTCNTL_INSEL_SHIFT 6 -#define M2_TE_DBTXTMULTCNTL_INSEL_CTI 0 -#define M2_TE_DBTXTMULTCNTL_INSEL_CONSTANT 1 -#define M2_TE_DBTXTMULTCNTL_INSEL_COMPSRC 2 -#define M2_TE_DBTXTMULTCNTL_INSEL_ATI 3 - - // Source Multiplication Control (0x00048058) -#define M2_TE_DBSRCMULTCNTL_SRCRJUST 0x00000001 -#define M2_TE_DBSRCMULTCNTL_SRCCOEFCMP 0x00000002 - -#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_MASK 0x0000000c -#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT 2 -#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB 0 -#define M2_TE_DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB 1 - -#define M2_TE_DBSRCMULTCNTL_COEFSEL_MASK 0x00000030 -#define M2_TE_DBSRCMULTCNTL_COEFSEL_SHIFT 4 -#define M2_TE_DBSRCMULTCNTL_COEFSEL_ATI 0 -#define M2_TE_DBSRCMULTCNTL_COEFSEL_ASRC 1 -#define M2_TE_DBSRCMULTCNTL_COEFSEL_CONSTANT 2 -#define M2_TE_DBSRCMULTCNTL_COEFSEL_CTI 3 - -#define M2_TE_DBSRCMULTCNTL_INSEL_MASK 0x000000c0 -#define M2_TE_DBSRCMULTCNTL_INSEL_SHIFT 6 -#define M2_TE_DBSRCMULTCNTL_INSEL_SRC 0 -#define M2_TE_DBSRCMULTCNTL_INSEL_CONSTANT 1 -#define M2_TE_DBSRCMULTCNTL_INSEL_COMPCTI 2 -#define M2_TE_DBSRCMULTCNTL_INSEL_TEXALPHA 3 - -// ALU Control (0x00048070) -#define M2_TE_DBALUCNTL_FINALDIVIDE_MASK 0x00000007 -#define M2_TE_DBALUCNTL_FINALDIVIDE_SHIFT 0 - -#define M2_TE_DBALUCNTL_ALUOP_MASK 0x000000f8 -#define M2_TE_DBALUCNTL_ALUOP_SHIFT 5 - -// Source Alpha Control (0x00048074) -#define M2_TE_DBDSTACNTL_ADESTSEL_MASK 0x00000003 -#define M2_TE_DBDSTACNTL_ADESTSEL_SHIFT 0 -#define M2_TE_DBDSTACNTL_ADESTCONSTCNTL_MASK 0x0000000c -#define M2_TE_DBDSTACNTL_ADESTCONSTCNTL_SHIFT 2 - -#define M2_TE_DBDSTALPHACONST_CONST1_MASK 0x000000ff -#define M2_TE_DBDSTALPHACONST_CONST1_SHIFT 0 -#define M2_TE_DBDSTALPHACONST_CONST0_MASK 0x00ff0000 -#define M2_TE_DBDSTALPHACONST_CONST0_SHIFT 16 - -#define M2_TE_DBSSBDSBCNTL_DSBSEL_MASK 0x00000003 -#define M2_TE_DBSSBDSBCNTL_DSBSEL_SHIFT 0 -#define M2_TE_DBSSBDSBCNTL_DSBCONST_MASK 0x00000004 -#define M2_TE_DBSSBDSBCNTL_DSBCONST_SHIFT 2 - -#endif // MACHINE_3DOM2_DEFS_H diff --git a/src/mame/machine/3dom2_te.cpp b/src/mame/machine/3dom2_te.cpp deleted file mode 100644 index 9757e966da4..00000000000 --- a/src/mame/machine/3dom2_te.cpp +++ /dev/null @@ -1,3959 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Philip Bennett -/*************************************************************************** - - 3DO M2 BDA Triangle Engine - -***************************************************************************/ - -#include "math.h" -#include "3dom2.h" - -/* - TODO: - - VTX_FLAGS do not get passed to the TMAPPER: Should use master control - bits to disable shading and texturing. - - - Evil Night attract mode sky is missing. Why? - - What is 1/w when 0? - - What do we do about RL flat-topped triangles? - - Heat of 11 color check has dodgy pixels <- HAS IT? - - Polystar blending is incorrect (intro) -*/ - -#define TEST_TIMING 1 - -#if TEST_TIMING -enum -{ - STAT_TRIANGLES_PROCESSED, - STAT_TEXEL_LOADS, - STAT_TEXEL_READS, - STAT_PIXELS_PROCESSED, - STAT_PIXEL_LOADS, - STAT_PIXEL_STORES, - STAT_TEXEL_BYTES, - STAT_ZBUFFER_LOADS, - STAT_ZBUFFER_STORES, -}; -static uint32_t g_statistics[16]; -#endif - -static bool g_debug = false; // TODO - -//************************************************************************** -// MACROS / CONSTANTS -//************************************************************************** - -// Device type definition -DEFINE_DEVICE_TYPE(M2_TE, m2_te_device, "m2te", "BDA Triangle Engine") - - - -//static const uint32_t fixed_bits = 23; - -static const uint32_t xy_bits = 11; -static const uint32_t color_bits = 8; -static const uint32_t text_bits[] = { 10, 7, 4, 1 }; -static const int32_t depth_bits[] = { 0, -3, -6, -9 }; - -// For right-aligning -static const uint32_t xy_rshift = 12; -static const uint32_t color_rshift = 4; - - -// 11.0 format -static const uint32_t xy_one = 1; - - -/*************************************************************************** - REGISTER DEFINITIONS - ***************************************************************************/ - -// TODO: SUFFIX bits with _BIT? -// Move to another file? - -//------------------------------------------------- -// General Control -//------------------------------------------------- - -// Triangle Engine Master Mode -#define TEMASTER_MODE_RESET 0x00000001 -#define TEMASTER_MODE_DTEXT 0x00000002 -#define TEMASTER_MODE_DSHADE 0x00000004 -#define TEMASTER_MODE_DBLEND 0x00000008 -#define TEMASTER_MODE_DZBUF 0x00000010 -#define TEMASTER_MODE_DDITH 0x00000020 - -// Triangle Engine Immediate Control -#define TEICNTL_INT 0x00000001 -#define TEICNTL_STEP 0x00000002 -#define TEICNTL_STPL 0x00000004 -#define TEICNTL_STPI 0x00000008 -#define TEICNTL_RSTRT 0x00000010 -#define TEICNTL_STRT 0x00000020 - -#define TEDCNTL_TLD 0x00000001 -#define TEDCNTL_JA 0x00000002 -#define TEDCNTL_JR 0x00000004 -#define TEDCNTL_INT 0x00000008 -#define TEDCNTL_PSE 0x00000010 -#define TEDCNTL_SYNC 0x00000020 - -#define INTSTAT_DEFERRED_INSTR 0x00000100 -#define INTSTAT_IMMEDIATE_INSTR 0x00000200 -#define INTSTAT_LIST_END 0x00000400 -#define INTSTAT_WINDOW_CLIP 0x00000800 -#define INTSTAT_SPECIAL_INSTR 0x00001000 -#define INTSTAT_UNIMPLEMENTED_INSTR 0x00002000 -#define INTSTAT_SUPERVISOR 0x00004000 -#define INTSTAT_ANY_RENDER 0x00008000 -#define INTSTAT_Z_FUNC 0x00010000 -#define INTSTAT_ALU_STATUS 0x00020000 -#define INTSTAT_FB_CLIP 0x00040000 -#define INTSTAT_IMMEDIATE 0x00080000 - -// IWP -// IRP -// Interrupt Enable -// Interrupt Status -// Vertex Control - - - -//------------------------------------------------- -// Setup Engine -//------------------------------------------------- - -// Vertex State -#define VERTEXSTATE_TSORT_MASK 0x00000007 -#define VERTEXSTATE_TSORT_OMN 0x00000001 -#define VERTEXSTATE_TSORT_MNO 0x00000002 -#define VERTEXSTATE_TSORT_ONM 0x00000003 -#define VERTEXSTATE_TSORT_NOM 0x00000004 -#define VERTEXSTATE_TSORT_MON 0x00000005 -#define VERTEXSTATE_TSORT_NMO 0x00000006 - -#define VERTEXSTATE_VCNT_SHIFT 3 -#define VERTEXSTATE_VCNT_MASK 0x00000018 - - -//------------------------------------------------- -// Edge Walker -//------------------------------------------------- - -// Edge and Span Walker Control -#define ESCNTL_DSPOFF 0x00000001 -#define ESCNTL_DUSCAN 0x00000002 -#define ESCNTL_PERSPECTIVEOFF 0x00000004 - - -//------------------------------------------------- -// Texture Mapper -//------------------------------------------------- - -// Texture Mapper Master Control (0x00046400) -#define TXTCNTL_MMDMA_TRAM_ON 0x00000004 -#define TXTCNTL_MMDMA_PIP_ON 0x00000008 -#define TXTCNTL_SNOOP_ON 0x00000020 - -// Texture Load Control (0x00046404) -#define TXTLDCNTL_SRCBITOFFS 0x00000007 -#define TXTLDCNTL_LDMODE_MASK 0x00000300 -#define TXTLDCNTL_LDMODE_TEXLOAD 0x00000000 -#define TXTLDCNTL_LDMODE_MMDMA 0x00000100 -#define TXTLDCNTL_LDMODE_PIPLOAD 0x00000200 -#define TXTLDCNTL_LDMODE_RESERVED 0x00000300 -#define TXTLDCNTL_COMPRESSED 0x00000400 - -// Address Control (0x00046408) -#define TXTADDRCNTL_LODMAX_MASK 0x0000000f -#define TXTADDRCNTL_FILTERSEL_MASK 0x00000003 -#define TXTADDRCNTL_FILTERSEL_POINT 0x00000000 -#define TXTADDRCNTL_FILTERSEL_LINEAR 0x00000001 -#define TXTADDRCNTL_FILTERSEL_BILINEAR 0x00000002 -#define TXTADDRCNTL_FILTERSEL_QUASITRI 0x00000003 -#define TXTADDRCNTL_R12FILTERSEL_SHIFT 4 -#define TXTADDRCNTL_R3FILTERSEL_SHIFT 7 -#define TXTADDRCNTL_R45FILTERSEL_SHIFT 10 -#define TXTADDRCNTL_LOOKUP_EN 0x00002000 - -// PIP Control (0x0004640C) -#define TXTPIPCNTL_INDEX_OFFSET 0x000000ff -#define TXTPIPCNTL_COLORSEL_MASK 0x00000700 -#define TXTPIPCNTL_COLORSEL_SHIFT 8 -#define TXTPIPCNTL_ALPHASEL_MASK 0x00003800 -#define TXTPIPCNTL_ALPHASEL_SHIFT 11 -#define TXTPIPCNTL_SSBSEL_MASK 0x0001c000 -#define TXTPIPCNTL_SSBSEL_SHIFT 14 - -#define TXTPIPCNTL_SEL_CONSTANT 0 -#define TXTPIPCNTL_SEL_TRAM 1 -#define TXTPIPCNTL_SEL_PIP 2 - -// Texture Application Control (0x00046410) -#define TXTTABCNTL_C_ASEL_MASK 0x00000007 -#define TXTTABCNTL_C_ASEL_SHIFT 0 -#define TXTTABCNTL_C_BSEL_MASK 0x00000038 -#define TXTTABCNTL_C_BSEL_SHIFT 3 -#define TXTTABCNTL_C_TSEL_MASK 0x000001c0 -#define TXTTABCNTL_C_TSEL_SHIFT 6 - -#define TXTTABCNTL_C_ABTSEL_AITER 0 -#define TXTTABCNTL_C_ABTSEL_CITER 1 -#define TXTTABCNTL_C_ABTSEL_AT 2 -#define TXTTABCNTL_C_ABTSEL_CT 3 -#define TXTTABCNTL_C_ABTSEL_ACONST 4 -#define TXTTABCNTL_C_ABTSEL_CCONST 5 - -#define TXTTABCNTL_C_OSEL_MASK 0x00000600 -#define TXTTABCNTL_C_OSEL_SHIFT 9 - -#define TXTTABCNTL_CO_SEL_CITER 0 -#define TXTTABCNTL_CO_SEL_CT 1 -#define TXTTABCNTL_CO_SEL_BLEND 2 -#define TXTTABCNTL_CO_SEL_RESERVED 3 - -#define TXTTABCNTL_A_ASEL_MASK 0x00001800 -#define TXTTABCNTL_A_ASEL_SHIFT 11 -#define TXTTABCNTL_A_BSEL_MASK 0x00006000 -#define TXTTABCNTL_A_BSEL_SHIFT 13 - -#define TXTTABCNTL_A_ABSEL_AITER 0 -#define TXTTABCNTL_A_ABSEL_AT 1 -#define TXTTABCNTL_A_ABSEL_ACONST 2 - -#define TXTTABCNTL_A_OSEL_MASK 0x00018000 -#define TXTTABCNTL_A_OSEL_SHIFT 15 - -#define TXTTABCNTL_AO_SEL_AITER 0 -#define TXTTABCNTL_AO_SEL_AT 1 -#define TXTTABCNTL_AO_SEL_BLEND 2 -#define TXTTABCNTL_AO_SEL_RESERVED 3 - -#define TXTTABCNTL_BLENDOP_MASK 0x00010000 -#define TXTTABCNTL_BLENDOP_SHIFT 16 -#define TXTTABCNTL_BLENDOP_LERP 0 -#define TXTTABCNTL_BLENDOP_MULT 1 - -// TAB Constants -#define TXTTABCONST_BLUE 0x000000ff -#define TXTTABCONST_BLUE_SHIFT 0 -#define TXTTABCONST_GREEN 0x0000ff00 -#define TXTTABCONST_GREEN_SHIFT 8 -#define TXTTABCONST_RED 0x00ff0000 -#define TXTTABCONST_RED_SHIFT 16 -#define TXTTABCONST_ALPHA 0x7f000000 -#define TXTTABCONST_ALPHA_SHIFT 24 -#define TXTTABCONST_SSB 0x80000000 - -// Texture Loader Destination Base (0x00046414) -#define TXTLDDSTBASE_ADDR 0x00003ffc - -// Texture Lod Base 0 (0x00046414) -// Texture Lod Base 1 (0x00046418) -// Texture Lod Base 2 (0x0004641C) -// Texture Lod Base 3 (0x00046420) -#define TXTLODBASE_MASK 0x00003ffc - -// Texture Loader Source Base (0x00046424) -#define TXTLDSRCBASE_ADDR 0x00003fff - -// Texture Loader Counts (0x00046428) -#define TXTLDBYTECNT_COUNT 0x0fffffff -#define TXTLDROWCNT_COUNT 0x0fffffff -#define TXTLDTEXCNT_COUNT 0x0fffffff - -// Texture Loader Width (0x00046428) -#define TxTLDWIDTH_SRCROW 0x0000ffff -#define TxTLDWIDTH_DSTROW_SHIFT 16 -#define TxTLDWIDTH_DSTROW 0xffff0000 - -// Texture Size (0x0004642C) -#define TXTUVMAX_VMAX_MASK 0x000003ff -#define TXTUVMAX_VMAX_SHIFT 0 -#define TXTUVMAX_UMAX_MASK 0x03ff0000 -#define TXTUVMAX_UMAX_SHIFT 16 - -// Texture Mask (0x00046430) -#define TXTUVMASK_VMASK_MASK 0x000003ff -#define TXTUVMASK_VMASK_SHIFT 0 -#define TXTUVMASK_UMASK_MASK 0x03ff0000 -#define TXTUVMASK_UMASK_SHIFT 16 - -// TRAM Format (0x0004643C) -// TODO: Expansion formats -#define TXTEXPFORM_CDEPTH_MASK 0x0000000f -#define TXTEXPFORM_CDEPTH_SHIFT 0 -#define TXTEXPFORM_IDEPTH_MASK 0x0000000f -#define TXTEXPFORM_IDEPTH_SHIFT 0 -#define TXTEXPFORM_ADEPTH_MASK 0x000000f0 -#define TXTEXPFORM_ADEPTH_SHIFT 4 -#define TXTEXPFORM_TRANSPARENT 0x00000100 -#define TXTEXPFORM_SSBON 0x00000200 -#define TXTEXPFORM_COLORON 0x00000400 -#define TXTEXPFORM_INDEXON 0x00000400 -#define TXTEXPFORM_ALPHAON 0x00000800 -#define TXTEXPFORM_LITERAL 0x00001000 - - -// Format Registers - - -//------------------------------------------------- -// Destination Blender -//------------------------------------------------- - -// Snoop (0x0048000) -#define DBSNOOP_DESTWRSNOOP 0x00000001 -#define DBSNOOP_SRCRDSNOOP 0x00000002 -#define DBSNOOP_ZWRSNOOP 0x00000004 -#define DBSNOOP_ZRDSNOOP 0x00000008 - -// Supervisor General Control (0x0048004) -#define DBSUPERGENCTL_DESTOUTEN 0x00000001 -#define DBSUPERGENCTL_DESTWR16BEN 0x00000002 -#define DBSUPERGENCTL_ZWR16BEN 0x00000004 - -// User General Control (0x0048008) -#define DBUSERGENCTL_DESTOUT_MASK 0x0000000f -#define DBUSERGENCTL_DITHEREN 0x00000010 -#define DBUSERGENCTL_SRCINEN 0x00000020 -#define DBUSERGENCTL_BLENDEN 0x00000040 -#define DBUSERGENCTL_WCLIPOUTEN 0x00000080 -#define DBUSERGENCTL_WCLIPINEN 0x00000100 -#define DBUSERGENCTL_ZOUTEN 0x00000200 -#define DBUSERGENCTL_ZBUFEN 0x00000400 - -// Discard Control (0x004800C) -#define DBDISCARDCTL_ADISEN 0x00000001 -#define DBDISCARDCTL_RGBDISEN 0x00000002 -#define DBDISCARDCTL_SSBDISEN 0x00000004 -#define DBDISCARDCTL_ZCLIPDISEN 0x00000008 - -// Status (0x0048010) -#define DBSTATUS_ANYREND 0x00000001 -#define DBSTATUS_ZFUNC_GT 0x00000002 -#define DBSTATUS_ZFUNC_EQ 0x00000004 -#define DBSTATUS_ZFUNC_LT 0x00000008 -#define DBSTATUS_ALUSTAT_BLUE_GT 0x00000010 -#define DBSTATUS_ALUSTAT_BLUE_EQ 0x00000020 -#define DBSTATUS_ALUSTAT_BLUE_LT 0x00000040 -#define DBSTATUS_ALUSTAT_GREEN_GT 0x00000080 -#define DBSTATUS_ALUSTAT_GREEN_EQ 0x00000100 -#define DBSTATUS_ALUSTAT_GREEN_LT 0x00000200 -#define DBSTATUS_ALUSTAT_RED_GT 0x00000400 -#define DBSTATUS_ALUSTAT_RED_EQ 0x00000800 -#define DBSTATUS_ALUSTAT_RED_LT 0x00001000 -#define DBSTATUS_ZCLIP 0x00002000 -#define DBSTATUS_WINCLIP 0x00004000 -#define DBSTATUS_FBCLIP 0x00008000 - -// Interrupt Control (0x00048014) -#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 -#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 - -// Framebuffer XY Clip Control (0x00048018) -#define DBFBCLIP_YFBCLIP_MASK 0x000007ff -#define DBFBCLIP_YFBCLIP_SHIFT 0 -#define DBFBCLIP_XFBCLIP_MASK 0x07ff0000 -#define DBFBCLIP_XFBCLIP_SHIFT 16 - -// Window X Clip Control (0x0004801C) -#define DBFBXWINCLIP_XMAX_MASK 0x000007ff -#define DBFBXWINCLIP_XMAX_SHIFT 0 -#define DBFBXWINCLIP_XMIN_MASK 0x07ff0000 -#define DBFBXWINCLIP_XMIN_SHIFT 16 - -// Window Y Clip Control (0x00048020) -#define DBFBYWINCLIP_YMAX_MASK 0x000007ff -#define DBFBYWINCLIP_YMAX_SHIFT 0 -#define DBFBYWINCLIP_YMIN_MASK 0x07ff0000 -#define DBFBYWINCLIP_YMIN_SHIFT 16 - -// Destination Write Control (0x0048024) -#define DBDESTCNTL_32BPP 0x00000001 - -// Destination Write Base Address (0x0048028) - -// Destination X Stride (0x004802C) -#define DBDEST_XSTRIDE 0x000007ff - -// Source Read Control (0x00048030) -#define DBSRCCNTL_32BPP 0x00000001 -#define DBSRCCNTL_MSBREP 0x00000002 - -// Source Read Base Address (0x00048034) - -// Source X Stride (0x00048038) -#define DBSRCXSTRIDE 0x000007ff - -// Source XY Offset (0x0004803C) -#define DBSRCOFFS_YOFFS_MASK 0x00000fff -#define DBSRCOFFS_YOFFS_SHIFT 0 -#define DBSRCOFFS_XOFFS_MASK 0x0fff0000 -#define DBSRCOFFS_XOFFS_SHIFT 16 - -// Z Buffer Control (0x00048040) -#define DBZCNTL_ZFUNCCNTL_MASK 0x0000003f -#define DBZCNTL_ZPIXOUT_LT 0x00000001 -#define DBZCNTL_ZBUFOUT_LT 0x00000002 -#define DBZCNTL_ZPIXOUT_EQ 0x00000004 -#define DBZCNTL_ZBUFOUT_EQ 0x00000008 -#define DBZCNTL_ZPIXOUT_GT 0x00000010 -#define DBZCNTL_ZBUFOUT_GT 0x00000020 - -// Z Buffer Base Address (0x00048044) -#define DBZBASEADDR_MASK 0x00ffffff - -// Z Buffer XY Offset (0x00048048) -#define DBZOFFS_YOFFS_MASK 0x00000fff -#define DBZOFFS_YOFFS_SHIFT 0 -#define DBZOFFS_XOFFS_MASK 0x0fff0000 -#define DBZOFFS_XOFFS_SHIFT 16 - -// Z Buffer Clip (0x0004804C) -#define DBZCLIP_YCLIP_MASK 0x000007ff -#define DBZCLIP_YCLIP_SHIFT 0 -#define DBZCLIP_XCLIP_MASK 0x07ff0000 -#define DBZCLIP_XCLIP_SHIFT 16 - -// SSB/DSB Control (0x00048050) -#define DBSSBDSBCNTL_DSBSELECT_MASK 0x00000007 -#define DBSSBDSBCNTL_DSBSELECT_SHIFT 0 -#define DBSSBDSBCNTL_DSBSELECT_SSB 0 -#define DBSSBDSBCNTL_DSBSELECT_CONSTANT 1 -#define DBSSBDSBCNTL_DSBSELECT_SRC 2 - -#define DBSSBDSBCNTL_DSBCONST 0x00000004 - -// RGB constants (0x00048054) -#define DBCONSTIN_B_MASK 0x000000ff -#define DBCONSTIN_B_SHIFT 0 -#define DBCONSTIN_G_MASK 0x0000ff00 -#define DBCONSTIN_G_SHIFT 8 -#define DBCONSTIN_R_MASK 0x00ff0000 -#define DBCONSTIN_R_SHIFT 16 - -// Texture Multiplication Control (0x00048058) -#define DBTXTMULTCNTL_TXTRJUST 0x00000001 -#define DBTXTMULTCNTL_TXTCOEFCMP 0x00000002 - -#define DBTXTMULTCNTL_TXTCONSTCNTL_MASK 0x0000000c -#define DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT 2 -#define DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB 0 -#define DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB 1 - -#define DBTXTMULTCNTL_COEFSEL_MASK 0x00000030 -#define DBTXTMULTCNTL_COEFSEL_SHIFT 4 -#define DBTXTMULTCNTL_COEFSEL_ATI 0 -#define DBTXTMULTCNTL_COEFSEL_ASRC 1 -#define DBTXTMULTCNTL_COEFSEL_CONSTANT 2 -#define DBTXTMULTCNTL_COEFSEL_CSRC 3 - -#define DBTXTMULTCNTL_INSEL_MASK 0x000000c0 -#define DBTXTMULTCNTL_INSEL_SHIFT 6 -#define DBTXTMULTCNTL_INSEL_CTI 0 -#define DBTXTMULTCNTL_INSEL_CONSTANT 1 -#define DBTXTMULTCNTL_INSEL_COMPSRC 2 -#define DBTXTMULTCNTL_INSEL_ATI 3 - -// Source Multiplication Control (0x00048058) -#define DBSRCMULTCNTL_SRCRJUST 0x00000001 -#define DBSRCMULTCNTL_SRCCOEFCMP 0x00000002 - -#define DBSRCMULTCNTL_SRCCONSTCNTL_MASK 0x0000000c -#define DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT 2 -#define DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB 0 -#define DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB 1 - -#define DBSRCMULTCNTL_COEFSEL_MASK 0x00000030 -#define DBSRCMULTCNTL_COEFSEL_SHIFT 4 -#define DBSRCMULTCNTL_COEFSEL_ATI 0 -#define DBSRCMULTCNTL_COEFSEL_ASRC 1 -#define DBSRCMULTCNTL_COEFSEL_CONSTANT 2 -#define DBSRCMULTCNTL_COEFSEL_CTI 3 - -#define DBSRCMULTCNTL_INSEL_MASK 0x000000c0 -#define DBSRCMULTCNTL_INSEL_SHIFT 6 -#define DBSRCMULTCNTL_INSEL_SRC 0 -#define DBSRCMULTCNTL_INSEL_CONSTANT 1 -#define DBSRCMULTCNTL_INSEL_COMPCTI 2 -#define DBSRCMULTCNTL_INSEL_TEXALPHA 3 - -// ALU Control (0x00048070) TODO -#define DBALUCNTL_FINALDIVIDE_MASK 0x00000007 -#define DBALUCNTL_FINALDIVIDE_SHIFT 0 - -#define DBALUCNTL_ALUOP_MASK 0x000000f8 -#define DBALUCNTL_ALUOP_SHIFT 5 - -// Source Alpha Control (0x00048074) -#define DBDSTACNTL_ADESTSEL_MASK 0x00000003 -#define DBDSTACNTL_ADESTSEL_SHIFT 0 -#define DBDSTACNTL_ADESTCONSTCNTL_MASK 0x0000000c -#define DBDSTACNTL_ADESTCONSTCNTL_SHIFT 2 - -#define DBDSTALPHACONST_CONST1_MASK 0x000000ff -#define DBDSTALPHACONST_CONST1_SHIFT 0 -#define DBDSTALPHACONST_CONST0_MASK 0x00ff0000 -#define DBDSTALPHACONST_CONST0_SHIFT 16 - -#define DBSSBDSBCNTL_DSBSEL_MASK 0x00000003 -#define DBSSBDSBCNTL_DSBSEL_SHIFT 0 -#define DBSSBDSBCNTL_DSBCONST_MASK 0x00000004 -#define DBSSBDSBCNTL_DSBCONST_SHIFT 2 - - - -//************************************************************************** -// SUPPORT FUNCTIONS -//************************************************************************** - -static inline float int_trunc(float x) -{ - return (float)(int)x; -} - -static inline uint8_t extract_exp(float x) -{ - uint32_t u32 = *reinterpret_cast(&x); - return (u32 >> 23) & 0xff; -} - -// Convert a regular float to sign-magnitude fixed point -static int32_t ieee754_to_tefix(float f, int32_t bits) -{ - float format = powf(2.0f, bits); - float tmp1 = format * 2.0f; - - // Check to see if number is within range - float tmp2 = fmodf(fabsf(f), tmp1); - float tmp3 = (tmp2 >= format) ? tmp2 : tmp2 + format; - - // Extract the result - uint32_t res = *reinterpret_cast(&tmp3) & 0x007fffff; - - // What is this? - if (tmp2 >= format || tmp3 == tmp1) - res |= 0x00800000; - - // Negate - if (f < 0.0f) - res = -res; - - return res; -} - -static void write_te_reg(uint32_t ®, uint32_t data, reg_wmode mode) -{ - switch (mode) - { - case REG_WRITE: - { - reg = data; - break; - } - case REG_SET: - { - reg |= data; - break; - } - case REG_CLEAR: - { - reg &= ~data; - break; - } - default: - assert_always(false, "Bad register write mode"); - } -} - -#if 0 -static const char *get_reg_name(uint32_t unit, uint32_t reg) -{ - static const char *gc_regs[] = - { - "TEMasterMode", - "Reserved", - "TEICntlData", - "TEICntl", - "TEDCntlData", - "TEDCntl", - "IWP", - "IRP", - "IntEn", - "IntStat", - "Vertex Control", - }; - - static const char *db_regs[] = - { - "Snoop", - "SuperGenControl", - "usergen_ctrl", - "Discard Control", - "Status", - "Int Cntl", - "FBClip", - "XWinClip", - "YWinClip", - "DestCntl", - "DestBaseAddr", - "DestXStride", - "SrcCntl", - "SrcBaseAddr", - "SrcXStride", - "SrcOffset", - "ZCntl", - "ZBaseAddr", - "ZOffset", - "ZClip", - "SSBDSBCntl", - "ConstIn", - "DBTXTMULTCNTL", - "TxtCoefConst0", - "TxtCoefConst1", - "src_mult_cntl", - "SrcCoefConst0", - "SrcCoefConst1", - "src_mult_cntl", - "SrcCoefconst0", - "SrcCoefconst1", - "ALUCntl", - "SrcAlphaCntl", - "DestAlphaCntl", - "DestAlphaConst", - "DitherMatA", - "DitherMatB", - }; - - static const char *es_regs[] = - { - "ESCntl", - "ESCapAddr", - "ESCapData", - }; - - static char buffer[128]; - - switch (unit) - { - case 0: - { - if (reg < sizeof(gc_regs)) - { - sprintf(buffer, "GC:%s", gc_regs[reg]); - return buffer; - } - break; - } - case 1: - { - sprintf(buffer, "SE:????"); - return buffer; - } - case 2: - { - if (reg < sizeof(es_regs)) - { - sprintf(buffer, "ES:%s", es_regs[reg]); - return buffer; - } - break; - } - case 3: - { -// if (reg < sizeof(tm_regs)) - { - sprintf(buffer, "TM:????"); - return buffer; - } - break; - } - case 4: - { - if (reg < sizeof(db_regs)) - { - sprintf(buffer, "DB:%s", db_regs[reg]); - return buffer; - } - break; - } - } - - return "????"; -} -#endif -//************************************************************************** -// TRIANGLE ENGINE DEVICE -//************************************************************************** - -//------------------------------------------------- -// m2_te_device - constructor -//------------------------------------------------- - -m2_te_device::m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, M2_TE, tag, owner, clock), - m_general_int_handler(*this), - m_dfinstr_int_handler(*this), - m_iminstr_int_handler(*this), - m_listend_int_handler(*this), - m_winclip_int_handler(*this) -{ -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void m2_te_device::device_start() -{ - // Find our parent - m_bda = downcast(owner()); - - // Resolve callbacks - m_general_int_handler.resolve_safe(); - m_dfinstr_int_handler.resolve_safe(); - m_iminstr_int_handler.resolve_safe(); - m_listend_int_handler.resolve_safe(); - m_winclip_int_handler.resolve_safe(); - - // Allocate texture RAM - m_tram = auto_alloc_array(machine(), uint32_t, TEXTURE_RAM_WORDS); - - // Allocate PIP RAM - m_pipram = auto_alloc_array(machine(), uint32_t, PIP_RAM_WORDS); - - // TODO - memset(&m_gc, 0, sizeof(m_gc)); - memset(&m_se, 0, sizeof(m_se)); - memset(&m_es, 0, sizeof(m_es)); - memset(&m_tm, 0, sizeof(m_tm)); - memset(&m_db, 0, sizeof(m_db)); - - - // Register state for saving - save_pointer(NAME(m_tram), TEXTURE_RAM_WORDS); - save_pointer(NAME(m_pipram), PIP_RAM_WORDS); - - save_item(NAME(m_gc.m_regs)); - save_item(NAME(m_se.m_regs)); - save_item(NAME(m_es.m_regs)); - save_item(NAME(m_tm.m_regs)); - save_item(NAME(m_db.m_regs)); -} - - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void m2_te_device::device_reset() -{ - m_state = TE_STOPPED; - - // TODO -} - - -//------------------------------------------------- -// device_post_load - device-specific post-load -//------------------------------------------------- - -void m2_te_device::device_post_load() -{ - -} - - - -/*************************************************************************** - PUBLIC FUNCTIONS -***************************************************************************/ - -READ32_MEMBER( m2_te_device::read ) -{ - uint32_t unit = (offset >> 11) & 7; - uint32_t reg = offset & 0x1ff; - - logerror("%s: TE R[%x]\n", machine().describe_context(), 0x00040000 + (offset << 2)); - - switch (unit) - { - case 0: - { - if (reg < sizeof(m_gc) / 4) - return m_gc.m_regs[reg]; - - break; - } - case 1: - { - if (reg < sizeof(m_se) / 4) - return m_se.m_regs[reg]; - - break; - } - case 2: - { - if (reg < sizeof(m_es) / 4) - return m_es.m_regs[reg]; - - break; - } - case 3: - { - if (reg < 0x400/4) - { - return m_pipram[reg]; - } - else if ((reg - 0x400) < sizeof(m_tm) / 4) - { - return m_tm.m_regs[reg]; - } - - break; - } - case 4: - { - if (reg < sizeof(m_db) / 4) - return m_db.m_regs[reg]; - - break; - } - } - - logerror("%s: Unknown TE register read from %d:[%x]", machine().describe_context(), unit, reg); - return 0; -} - -WRITE32_MEMBER( m2_te_device::write ) -{ - uint32_t unit = (offset >> 11) & 7; - uint32_t reg = offset & 0x1ff; - reg_wmode wmode = static_cast((offset >> 9) & 3); - -// logerror("%s: TE W[%.8x] (%s) %.8x\n", machine().describe_context(), 0x00040000 + (offset << 2), get_reg_name(unit, reg), data); - - switch (unit) - { - case 0: - { - switch (reg) - { - case 0: - { - master_mode_w(data, wmode); - return; - } - case 0x0c/4: - { - teicntl_w(data, wmode); - return; - } - case 0x14/4: - { - tedcntl_w(data, wmode); - return; - } - case 0x24/4: - { - write_te_reg(m_gc.int_status, data, wmode); - update_interrupts(); - return; - } - default: - { - if (reg < sizeof(m_gc) / 4) - { - write_te_reg(m_gc.m_regs[reg], data, wmode); - return; - } - } - } - break; - } - case 1: - { - if (reg < sizeof(m_se) / 4) - { - write_te_reg(m_se.m_regs[reg], data, wmode); - return; - } - break; - } - case 2: - { - if (reg < sizeof(m_es) / 4) - { - write_te_reg(m_es.m_regs[reg], data, wmode); - return; - } - break; - } - case 3: - { - if (reg < 0x400 / 4) - { - m_pipram[reg] = data; - return; - } - else if ((reg - 0x400 / 4) < sizeof(m_tm) / 4) - { - write_te_reg(m_tm.m_regs[reg - 0x400 / 4], data, wmode); - return; - } - break; - } - case 4: - { - if (reg < sizeof(m_db) / 4) - { - write_te_reg(m_db.m_regs[reg], data, wmode); - return; - } - break; - } - } - - logerror("%s: Unknown TE register write to %d:[%x] with %x\n", machine().describe_context(), unit, reg, data); -} - - - -/*************************************************************************** - PRIVATE FUNCTIONS -***************************************************************************/ - -/*************************************************************************** - INTERRUPTS -***************************************************************************/ - -//------------------------------------------------- -// set_interrupt - -//------------------------------------------------- - -void m2_te_device::set_interrupt(uint32_t mask) -{ - m_gc.int_status |= mask; - update_interrupts(); -} - - -//------------------------------------------------- -// update_interrupts - -//------------------------------------------------- - -void m2_te_device::update_interrupts() -{ - bool gen_int = ((m_gc.int_status & m_gc.int_enable) & 0x0000ff00) != 0; - - // TODO: ALU status and FB clip are controlled by dest blender - m_general_int_handler(gen_int); - - // From DBL (Page 265) - // FBClip - // WinClip - // ZClip - // ALUStat - // ZFuncStat - - // Page 43 - - // PAGE 26 - m_dfinstr_int_handler((m_gc.int_status >> 8) & 1); - m_iminstr_int_handler((m_gc.int_status >> 9) & 1); - m_listend_int_handler((m_gc.int_status >> 10) & 1); - m_winclip_int_handler((m_gc.int_status >> 11) & 1); -} - - - -/*************************************************************************** - SPECIAL REGISTER WRITES -***************************************************************************/ - -//------------------------------------------------- -// master_mode_w - -//------------------------------------------------- - -void m2_te_device::master_mode_w(uint32_t data, reg_wmode wmode) -{ - write_te_reg(m_gc.te_master_mode, data, wmode); - - if (m_gc.te_master_mode & TEMASTER_MODE_RESET) - device_reset(); -} - - -//------------------------------------------------- -// teicntl_w - -//------------------------------------------------- - -void m2_te_device::teicntl_w(uint32_t data, reg_wmode wmode) -{ - uint32_t newreg = 0; - - write_te_reg(newreg, data, wmode); - write_te_reg(m_gc.te_master_mode, data, wmode); - - if (newreg & TEICNTL_STRT) - { - m_gc.irp = m_gc.teicntl_data; - m_state = TE_RUNNING; - execute(); - } - else if (newreg & TEICNTL_RSTRT) - { - m_state = TE_RUNNING; - execute(); - } -} - - -//------------------------------------------------- -// tedcntl_w - -//------------------------------------------------- - -void m2_te_device::tedcntl_w(uint32_t data, reg_wmode wmode) -{ - write_te_reg(m_gc.tedcntl, data, wmode); - - if (m_gc.tedcntl & TEDCNTL_SYNC) - { - // TODO - } - else if (m_gc.tedcntl & TEDCNTL_PSE) - { - m_state = TE_PAUSED; - } - else if (m_gc.tedcntl & TEDCNTL_INT) - { - set_interrupt(INTSTAT_IMMEDIATE); - } - else if (m_gc.tedcntl & TEDCNTL_JR) - { - m_gc.irp += m_gc.tedcntl_data; - } - else if (m_gc.tedcntl & TEDCNTL_JA) - { - m_gc.irp = m_gc.tedcntl_data; - } - else if (m_gc.tedcntl & TEDCNTL_TLD) - { - load_texture(); - } -} - - - -/*************************************************************************** - VERTEX PROCESSING -***************************************************************************/ - -//------------------------------------------------- -// add_vertex - -//------------------------------------------------- - -void m2_te_device::add_vertex(const se_vtx &vtx, uint32_t flags) -{ - uint32_t tsort; - uint32_t vcnt; - - if (flags & VTX_FLAG_NEW) - { - // Reset state for a new triangle - tsort = 0; - vcnt = 0; - } - else - { - // Continue current triangle - tsort = m_se.vertex_state & VERTEXSTATE_TSORT_MASK; - vcnt = (m_se.vertex_state & VERTEXSTATE_VCNT_MASK) >> VERTEXSTATE_VCNT_SHIFT; - } - - if (vcnt < 3) - { - // Add vertex to incomplete triangle - m_se.vertices[vcnt++] = vtx; - - // Are we now complete? - if (vcnt == 3) - tsort = VERTEXSTATE_TSORT_OMN; - } - else - { - // Replace an existing vertex - if (flags & VTX_FLAG_RM) - { - // Triangle fan mode - switch (tsort) - { - case VERTEXSTATE_TSORT_OMN: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break; - case VERTEXSTATE_TSORT_MNO: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break; - case VERTEXSTATE_TSORT_ONM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break; - case VERTEXSTATE_TSORT_NOM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break; - case VERTEXSTATE_TSORT_MON: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break; - case VERTEXSTATE_TSORT_NMO: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break; - } - } - else - { - // Triangle strip mode - switch (tsort) - { - case VERTEXSTATE_TSORT_OMN: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break; - case VERTEXSTATE_TSORT_MNO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break; - case VERTEXSTATE_TSORT_ONM: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break; - case VERTEXSTATE_TSORT_NOM: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break; - case VERTEXSTATE_TSORT_MON: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break; - case VERTEXSTATE_TSORT_NMO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break; - } - } - - } - - // Update fields - m_se.vertex_state = (vcnt << VERTEXSTATE_VCNT_SHIFT) | tsort; - - // Do we have three valid vertices? - if (vcnt == 3) - { - // Send the triangle to the setup engine - setup_triangle(flags); - } -} - - -//------------------------------------------------- -// calculate_slope - -//------------------------------------------------- - -void m2_te_device::calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out) -{ - float detx = q1 * sp.y23 + q2 * sp.y31 + q3 * sp.y12; - float dety = q1 * sp.x23 + q2 * sp.x31 + q3 * sp.x12; - float detxy = sp.xstep_long * detx - dety; - - slope_out = detxy * sp.iAria; - ddx_out = detx * sp.iAria; -} - - -//------------------------------------------------- -// log_triangle - -//------------------------------------------------- - -void m2_te_device::log_triangle(uint32_t flags) -{ - logerror("[Triangle]\n"); - - for (uint32_t i = 0; i < 3; ++i) - { - char s[64]; - char t[64]; - char p[64]; - - s[0] = '\0'; - t[0] = '\0'; - p[0] = '\0'; - - const se_vtx &vtx = m_se.vertices[i]; - - if (flags & VTX_FLAG_SHAD) - sprintf(s, "COLR[R:%.6f G:%.6f B:%.6f A:%.6f]", vtx.r, vtx.g, vtx.b, vtx.a); - - if (flags & VTX_FLAG_TEXT) - sprintf(t, "TEXT[UW:%.6f VW:%.6f]", vtx.uw, vtx.vw); - - if (flags & VTX_FLAG_PRSP) - sprintf(p, "PRSP[W:%.6f]", vtx.w); - - logerror("V%d: X:%.6f Y:%.6f %s %s %s\n", i, vtx.x, vtx.y, s, t, p); - } -} - - -//------------------------------------------------- -// setup_triangle - -//------------------------------------------------- - -void m2_te_device::setup_triangle(uint32_t flags) -{ -// log_triangle(flags); - - se_vtx va = m_se.vertices[0]; - se_vtx vb = m_se.vertices[1]; - se_vtx vc = m_se.vertices[2]; - - // Truncate XY coordinates to integers - va.x = int_trunc(va.x); - vb.x = int_trunc(vb.x); - vc.x = int_trunc(vc.x); - - va.y = int_trunc(va.y); - vb.y = int_trunc(vb.y); - vc.y = int_trunc(vc.y); - - - // Scale and truncate colors - if (flags & VTX_FLAG_SHAD) - { - va.r = int_trunc(va.r * 255.0f); - va.g = int_trunc(va.g * 255.0f); - va.b = int_trunc(va.b * 255.0f); - va.a = int_trunc(va.a * 255.0f); - - vb.r = int_trunc(vb.r * 255.0f); - vb.g = int_trunc(vb.g * 255.0f); - vb.b = int_trunc(vb.b * 255.0f); - vb.a = int_trunc(vb.a * 255.0f); - - vc.r = int_trunc(vc.r * 255.0f); - vc.g = int_trunc(vc.g * 255.0f); - vc.b = int_trunc(vc.b * 255.0f); - vc.a = int_trunc(vc.a * 255.0f); - } - - // Sort the vertices into top, middle and bottom - uint32_t a = 0; - - if ((va.y - vb.y) < 0.0f) a |= 4; - if ((vb.y - vc.y) < 0.0f) a |= 2; - if ((vc.y - va.y) < 0.0f) a |= 1; - - const se_vtx *v1 = NULL; - const se_vtx *v2 = NULL; - const se_vtx *v3 = NULL; - - switch (a) - { - case 1: v1 = &vc; v2 = &vb; v3 = &va; break; - case 2: v1 = &vb; v2 = &va; v3 = &vc; break; - case 3: v1 = &vb; v2 = &vc; v3 = &va; break; - case 4: v1 = &va; v2 = &vc; v3 = &vb; break; - case 5: v1 = &vc; v2 = &va; v3 = &vb; break; - case 6: v1 = &va; v2 = &vb; v3 = &vc; break; - default: - return; // Reject degenerates - } - - - // Determine the W range for depth and texture values - uint32_t wrange = 0; - - if (flags & VTX_FLAG_PRSP) - { - const uint8_t exp_zero = 0x7f; - const uint8_t wexp0 = exp_zero - 3; - const uint8_t wexp1 = exp_zero - 6; - const uint8_t wexp2 = exp_zero - 9; - - uint8_t w1exp = extract_exp(v1->w); - uint8_t w2exp = extract_exp(v2->w); - uint8_t w3exp = extract_exp(v3->w); - - if (w1exp >= wexp0 || w2exp >= wexp0 || w3exp >= wexp0) - wrange = 0; - else if (w1exp >= wexp1 || w2exp >= wexp1 || w3exp >= wexp1) - wrange = 1; - else if (w1exp >= wexp2 || w2exp >= wexp2 || w3exp >= wexp2) - wrange = 2; - else - wrange = 3; - } - - // Calculate the coordinate deltas - float x12 = v1->x - v2->x; - float x23 = v2->x - v3->x; - float x31 = v3->x - v1->x; - float y12 = v1->y - v2->y; - float y23 = v2->y - v3->y; - float y31 = v3->y - v1->y; - - // Calculate the triangle area - float aria = v1->x * y23 + v2->x * y31 + v3->x * y12; - - // Reject degenerates - if (aria == 0.0f) - return; - - float iaria = 1.0f / aria; - - // Determine scan direction - bool scan_lr = aria > 0.0f; - - // Calculate vertex slopes - float abs_y12 = fabs(y12); - float abs_y23 = fabs(y23); - float abs_y31 = fabs(y31); - - - // Avoid division by zero - float xslope_0 = (abs_y12 > 0.0f) ? (-x12 / abs_y12) : 0.0f; - float xslope_1 = (abs_y23 > 0.0f) ? (-x23 / abs_y23) : 0.0f; - float xslope_long = (abs_y31 > 0.0f) ? (x31 / abs_y31) : 0.0f; - - - // Calculate x steps - float xstep_long; - float xstep_0; - float xstep_1; - - if (scan_lr) - { - xstep_long = floor(xslope_long); - xstep_0 = ceil(xslope_0); - xstep_1 = ceil(xslope_1); - } - else - { - xstep_long = ceil(xslope_long); - xstep_0 = floor(xslope_0); - xstep_1 = floor(xslope_1); - } - - float xystep_0 = x12 - xstep_0 * y12; - float xystep_1 = x23 - xstep_1 * y23; - float xystep_long = x31 - xstep_long * y31; - - float dy_0 = -y12; - float dy_1 = -y23; - float dy_long = -y31; - - - // Calculate color and texture slopes - slope_params sparams = { y23, y31, y12, x23, x31, x12, xstep_long, iaria }; - - float r_slope = 0.0f, r_ddx = 0.0f; - float g_slope = 0.0f, g_ddx = 0.0f; - float b_slope = 0.0f, b_ddx = 0.0f; - float a_slope = 0.0f, a_ddx = 0.0f; - float w_slope = 0.0f, w_ddx = 0.0f; - float uw_slope = 0.0f, uw_ddx = 0.0f; - float vw_slope = 0.0f, vw_ddx = 0.0f; - - if (flags & VTX_FLAG_SHAD) - { - calculate_slope(sparams, v1->r, v2->r, v3->r, r_slope, r_ddx); - calculate_slope(sparams, v1->g, v2->g, v3->g, g_slope, g_ddx); - calculate_slope(sparams, v1->b, v2->b, v3->b, b_slope, b_ddx); - calculate_slope(sparams, v1->a, v2->a, v3->a, a_slope, a_ddx); - } - - if (flags & VTX_FLAG_TEXT) - { - calculate_slope(sparams, v1->uw, v2->uw, v3->uw, uw_slope, uw_ddx); - calculate_slope(sparams, v1->vw, v2->vw, v3->vw, vw_slope, vw_ddx); - } - - if (flags & VTX_FLAG_PRSP) - { - calculate_slope(sparams, v1->w, v2->w, v3->w, w_slope, w_ddx); - } - - const uint32_t textbits = text_bits[wrange]; - const uint32_t depthbits = depth_bits[wrange]; - - // Convert everything to fixed point and pass to the edge walker - - /* - NOT SURE THESE ARE RIGHT. See P209 - - XY 12.0 - SL s12.0 - RGBA 9.0 - RGBA SLOPES = s9.11 - TEX: 11.13 - DEPTH: 1.23 - TEX SLOPES: s11.13 - DEPTH SLOPES: s1.23 - AREA : s23.0 - - Numbers output to the edge walker are 24 bits - - IEE: 1.8.23 - BDA: 1.7.24 (includes hidden bit) - - However, we're using 23 bits. - */ - - - // XY: 0000 0000 0iii iiii iiii 0000 0000 0000 - // Colors: 0000 0000 0iii iiii ifff ffff ffff 0000 - // UV: - // W: 0000 0000 0iii iiii iiii iiii iiii iiii - - - // Converted numbers are left-aligned into the mantissa - // However, we want them right-aligned for convenience - // TODO: Is there a better way to do this? - m_es.x1 = ieee754_to_tefix(v1->x, xy_bits) >> xy_rshift; - m_es.y1 = ieee754_to_tefix(v1->y, xy_bits) >> xy_rshift; - m_es.x2 = ieee754_to_tefix(v2->x, xy_bits) >> xy_rshift; - m_es.y2 = ieee754_to_tefix(v2->y, xy_bits) >> xy_rshift; - m_es.y3 = ieee754_to_tefix(v3->y, xy_bits) >> xy_rshift; - - m_es.xstep_0 = ieee754_to_tefix(xstep_0, xy_bits) >> xy_rshift; - m_es.xstep_1 = ieee754_to_tefix(xstep_1, xy_bits) >> xy_rshift; - m_es.xstep_long = ieee754_to_tefix(xstep_long, xy_bits) >> xy_rshift; - m_es.xystep_0 = ieee754_to_tefix(xystep_0, xy_bits) >> xy_rshift; - m_es.xystep_1 = ieee754_to_tefix(xystep_1, xy_bits) >> xy_rshift; - m_es.xystep_long = ieee754_to_tefix(xystep_long, xy_bits) >> xy_rshift; - m_es.dy_0 = ieee754_to_tefix(dy_0, xy_bits) >> xy_rshift; - m_es.dy_1 = ieee754_to_tefix(dy_1, xy_bits) >> xy_rshift; - m_es.dy_long = ieee754_to_tefix(dy_long, xy_bits) >> xy_rshift; - - m_es.r1 = ieee754_to_tefix(v1->r, color_bits) >> color_rshift; - m_es.g1 = ieee754_to_tefix(v1->g, color_bits) >> color_rshift; - m_es.b1 = ieee754_to_tefix(v1->b, color_bits) >> color_rshift; - m_es.a1 = ieee754_to_tefix(v1->a, color_bits) >> color_rshift; - m_es.ddx_r = ieee754_to_tefix(r_ddx, color_bits) >> color_rshift; - m_es.ddx_g = ieee754_to_tefix(g_ddx, color_bits) >> color_rshift; - m_es.ddx_b = ieee754_to_tefix(b_ddx, color_bits) >> color_rshift; - m_es.ddx_a = ieee754_to_tefix(a_ddx, color_bits) >> color_rshift; - m_es.slope_r = ieee754_to_tefix(r_slope, color_bits) >> color_rshift; - m_es.slope_g = ieee754_to_tefix(g_slope, color_bits) >> color_rshift; - m_es.slope_b = ieee754_to_tefix(b_slope, color_bits) >> color_rshift; - m_es.slope_a = ieee754_to_tefix(a_slope, color_bits) >> color_rshift; - - // No need to shift these - m_es.uw1 = ieee754_to_tefix(v1->uw, textbits); - m_es.vw1 = ieee754_to_tefix(v1->vw, textbits); - m_es.w1 = ieee754_to_tefix(v1->w, depthbits); - m_es.ddx_uw = ieee754_to_tefix(uw_ddx, textbits); - m_es.ddx_vw = ieee754_to_tefix(vw_ddx, textbits); - m_es.ddx_w = ieee754_to_tefix(w_ddx, depthbits); - m_es.slope_uw = ieee754_to_tefix(uw_slope, textbits); - m_es.slope_vw = ieee754_to_tefix(vw_slope, textbits); - m_es.slope_w = ieee754_to_tefix(w_slope, depthbits); - - m_es.r2l = !scan_lr; - -#if TEST_TIMING - g_statistics[STAT_TRIANGLES_PROCESSED]++; -#endif - - // Proceed to walk the edges - walk_edges(wrange); -} - -static inline bool ins(bool lr, int32_t v) -{ - return lr ? v <= 0 : v >= 0; -} - -static inline bool ein(bool lr, int32_t v) -{ - return lr ? v < 0 : v > 0; -} - -static const uint8_t m_nr_rom[128] = -{ - 127, 125, 123, 121, 119, 118, - 116, 114, 112, 110, 109, 107, - 105, 104, 102, 100, 99, 97, - 96, 94, 93, 91, 90, 88, - 87, 86, 84, 83, 81, 80, - 79, 78, 76, 75, 74, 73, - 71, 70, 69, 68, 67, 65, - 64, 63, 62, 61, 60, 59, - 58, 57, 56, 55, 54, 53, - 52, 51, 50, 49, 48, 47, - 46, 45, 44, 43, 42, 41, - 40, 40, 39, 38, 37, 36, - 35, 35, 34, 33, 32, 31, - 31, 30, 29, 28, 28, 27, - 26, 25, 25, 24, 23, 23, - 22, 21, 21,20, 19, 19, - 18, 17, 17, 16, 15, 15, - 14, 13, 13, 12, 12, 11, - 11, 10, 9, 9, 8, 8, - 7, 7, 6, 5, 5, 4, - 4, 3, 3, 2, 2, 1, - 1, 0 -}; - - -//------------------------------------------------- -// nr_invert - Newton Rhapson reciprocal -//------------------------------------------------- - -uint32_t nr_invert(uint32_t num, uint32_t & shift_amount) -{ - uint32_t original; - uint32_t first_guess; - uint32_t m; - uint32_t shfnum; - - // TODO: Unconfirmed but seems sensible - if (num == 0) - { - shift_amount = 0; - return 0; - } - - shift_amount = -1; - while ((num << ++shift_amount) < 0x800000); - - shfnum = num << shift_amount; - original = shfnum >> 8; - first_guess = m_nr_rom[(shfnum >> 16) & ((1 << 7) - 1)]; - first_guess = first_guess + 128; - m = first_guess * original; - m = (1 << 24) - m; - m = m >> 3; - m = first_guess * m; - m = m >> 8; - - return m; -} - - -//------------------------------------------------- -// clamp - -//------------------------------------------------- - -uint32_t clamp(int32_t v, int32_t min, int32_t max) -{ - if (v < min) - return min; - else if (v > max) - return max; - - return v; -} - - -//------------------------------------------------- -// walk_edges - -//------------------------------------------------- - -void m2_te_device::walk_edges(uint32_t wrange) -{ - bool dsp_off = m_es.es_cntl & ESCNTL_DSPOFF; - bool du_scan = m_es.es_cntl & ESCNTL_DUSCAN; - bool omit_right = true; - bool scan_lr = m_es.r2l == false; - - uint32_t cf_long = 0; - uint32_t cf_short = 0; - uint32_t xystep; - uint32_t xstep; - uint32_t dy; - uint32_t xs; - uint32_t xe; - - int32_t r, g, b, a; - int32_t uw, vw; - int32_t w; - - // Determine starting values - uint32_t y = m_es.y1; - - // Flat-top triangles are a special case - if (m_es.y1 == m_es.y2) - { - xystep = m_es.xystep_1; - xstep = m_es.xstep_1; - dy = m_es.dy_1; - - if (scan_lr ^ (m_es.x1 < m_es.x2)) - { - // TODO: Is this possible? - assert_always(false, "SPECIAL CASE: WHAT DO?"); - r = m_es.r1; // Where do the colors come from? - g = m_es.g1; - b = m_es.b1; - a = m_es.a1; - uw = m_es.uw1; - vw = m_es.vw1; - w = m_es.w1; - - xs = m_es.x2; - xe = m_es.x1; - } - else - { - r = m_es.r1; - g = m_es.g1; - b = m_es.b1; - a = m_es.a1; - uw = m_es.uw1; - vw = m_es.vw1; - w = m_es.w1; - - xs = m_es.x1; - xe = m_es.x2; - } - } - else - { - // Regular triangles - xystep = m_es.xystep_0; - xstep = m_es.xstep_0; - dy = m_es.dy_0; - r = m_es.r1; - g = m_es.g1; - b = m_es.b1; - a = m_es.a1; - uw = m_es.uw1; - vw = m_es.vw1; - w = m_es.w1; - - xs = m_es.x1; - xe = xs; - } - - do - { - // Render the pixels from this span - walk_span(wrange, omit_right, y, xs, xe, r, g, b, a, uw, vw, w); - - // Now update the values - omit_right = false; - cf_short += xystep; - cf_long += m_es.xystep_long; - - bool step_back = false; - - if (scan_lr) - { - xs += m_es.xstep_long; - xe += xstep; - - if (!ins(scan_lr, cf_long)) - { - step_back = true; - cf_long += m_es.dy_long; - xs += xy_one; - } - - if (dsp_off ? !ins(scan_lr, cf_short) : !ein(scan_lr, cf_short)) - { - cf_short -= dy; - xe -= xy_one; - } - } - else - { - xe += xstep; - xs += m_es.xstep_long; - - if (!ins(scan_lr, cf_short)) - { - cf_short += dy; - xe += xy_one; - } - - if (dsp_off ? !ins(scan_lr, cf_long) : !ein(scan_lr, cf_long)) - { - step_back = true; - cf_long -= m_es.dy_long; - xs -= xy_one; - } - } - - // Update the color values - if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE)) - { - if (scan_lr) - { - r += step_back ? m_es.slope_r + m_es.ddx_r : m_es.slope_r; - g += step_back ? m_es.slope_g + m_es.ddx_g : m_es.slope_g; - b += step_back ? m_es.slope_b + m_es.ddx_b : m_es.slope_b; - a += step_back ? m_es.slope_a + m_es.ddx_a : m_es.slope_a; - } - else - { - r += step_back ? m_es.slope_r - m_es.ddx_r : m_es.slope_r; - g += step_back ? m_es.slope_g - m_es.ddx_g : m_es.slope_g; - b += step_back ? m_es.slope_b - m_es.ddx_b : m_es.slope_b; - a += step_back ? m_es.slope_a - m_es.ddx_a : m_es.slope_a; - } - - // Clamp to 8.11 - r = clamp(r, 0, 0x0007ffff); - g = clamp(g, 0, 0x0007ffff); - b = clamp(b, 0, 0x0007ffff); - a = clamp(a, 0, 0x0007ffff); - } - - if (!(m_es.es_cntl & TEMASTER_MODE_DTEXT)) - { - if (scan_lr) - { - uw += step_back ? m_es.slope_uw + m_es.ddx_uw : m_es.slope_uw; - vw += step_back ? m_es.slope_vw + m_es.ddx_vw : m_es.slope_vw; - } - else - { - uw += step_back ? m_es.slope_uw - m_es.ddx_uw : m_es.slope_uw; - vw += step_back ? m_es.slope_vw - m_es.ddx_vw : m_es.slope_vw; - } - - // Clamp to 10.13 - uw = clamp(uw, 0, 0x007fffff); - vw = clamp(vw, 0, 0x007fffff); - } - - if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF)) - { - if (scan_lr) - w += step_back ? m_es.slope_w + m_es.ddx_w : m_es.slope_w; - else - w += step_back ? m_es.slope_w - m_es.ddx_w : m_es.slope_w; - - // Clamp to 0.23 - w = clamp(w, 0, 0x007fffff); - } - - // Update Y - uint32_t next_y = y + (du_scan ? -xy_one : xy_one); - - if (next_y == m_es.y2) - { - cf_short = 0; - xystep = m_es.xystep_1; - xstep = m_es.xstep_1; - dy = m_es.dy_1; - xe = m_es.x2; - - if (scan_lr) - omit_right = true; - } - - y = next_y; - - } while (y != m_es.y3); -} - - - -//------------------------------------------------- -// texcoord_gen - -//------------------------------------------------- - -void m2_te_device::texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w, - uint32_t & uo, uint32_t & vo, uint32_t & wo) -{ - - // Perspective correction - if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF)) - { - uint32_t wshift; - - // Calculate the inverse of 1/w. Output is 0.20 - uint32_t winv = nr_invert(w, wshift); - - // 10.13 normalize then reduce to 10.6 - // Normalization occurs by detecting leading zeroes and - // left-shifting until 1 in MSB - - uint32_t uwshift = 0; - uint32_t vwshift = 0; - - while ((uw < 0x00400000) && uwshift < 7) - { - uw <<= 1; - ++uwshift; - } - - while ((vw < 0x00400000) && vwshift < 7) - { - vw <<= 1; - ++vwshift; - } - - uint32_t normalized_uw = uw >> 7; - uint32_t normalized_vw = vw >> 7; - - // 10.6 * 0.20 = 10.26 - uint64_t ur = (uint64_t)normalized_uw * winv; - uint64_t vr = (uint64_t)normalized_vw * winv; - - // De-normalize - if (uwshift > wshift) - ur >>= (uwshift - wshift); - else - ur <<= (wshift - uwshift); - - if (vwshift > wshift) - vr >>= (vwshift - wshift); - else - vr <<= (wshift - vwshift); - - // Reduce from 10.26 to 10.6 - uo = ur >> 20; - vo = vr >> 20; - } - else - { - // Reduce from 10.13 to 10.6 - // TODO: Is this actually correct? - uo = uw >> (7 + (10 - text_bits[wrange])); - vo = vw >> (7 + (10 - text_bits[wrange])); - } - - // Output to texture mapper is 10.4 - uo = uo >> 2; - vo = vo >> 2; -} - - -//------------------------------------------------- -// lod_calc - -//------------------------------------------------- - -uint32_t m2_te_device::lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1) -{ - return 0; -} - - -//------------------------------------------------- -// get_tram_bitdepth -//------------------------------------------------- - -uint32_t m2_te_device::get_tram_bitdepth() -{ - // TODO: Could cache this - const uint32_t tex_type = m_tm.tex_exptype; - - uint32_t bitdepth = 0; - - if (tex_type & TXTEXPFORM_COLORON) - bitdepth += (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; - if (tex_type & TXTEXPFORM_ALPHAON) - bitdepth += (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; - if (tex_type & TXTEXPFORM_SSBON) - ++bitdepth; - - return bitdepth; -} - - -//------------------------------------------------- -// get_texture_color - -//------------------------------------------------- -void m2_te_device::get_texture_color(uint32_t u, uint32_t v, uint32_t lod, - uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s) -{ - uint32_t texaddr; - uint32_t texbit; - uint32_t texdepth = get_tram_bitdepth(); - - // TODO: Multiple LODs - uint32_t filter = (m_tm.tex_addr_cntl >> TXTADDRCNTL_R12FILTERSEL_SHIFT) & TXTADDRCNTL_FILTERSEL_MASK; - - switch (filter) - { - case TXTADDRCNTL_FILTERSEL_POINT: - case TXTADDRCNTL_FILTERSEL_LINEAR: // TODO - { - addr_calc(u, v, lod, texaddr, texbit, texdepth); - get_texel(texaddr, texbit, texdepth, r, g, b, a, s); - break; - } - - case TXTADDRCNTL_FILTERSEL_BILINEAR: - case TXTADDRCNTL_FILTERSEL_QUASITRI: // TODO - { - // See p170 for implemenation - uint32_t r0, g0, b0, a0, s0; - uint32_t r1, g1, b1, a1, s1; - uint32_t r2, g2, b2, a2, s2; - uint32_t r3, g3, b3, a3, s3; - - addr_calc(u, v, lod, texaddr, texbit, texdepth); - get_texel(texaddr, texbit, texdepth, r0, g0, b0, a0, s0); - addr_calc(u + 0x10, v, lod, texaddr, texbit, texdepth); - get_texel(texaddr, texbit, texdepth, r1, g1, b1, a1, s1); - addr_calc(u, v + 0x10, lod, texaddr, texbit, texdepth); - get_texel(texaddr, texbit, texdepth, r2, g2, b2, a2, s2); - addr_calc(u + 0x10, v + 0x10, lod, texaddr, texbit, texdepth); - get_texel(texaddr, texbit, texdepth, r3, g3, b3, a3, s3); - - // LERP - uint32_t ufrac = u & 0xf; - uint32_t vfrac = v & 0xf; - uint32_t om_ufrac = 0x10 - ufrac; - uint32_t om_vfrac = 0x10 - vfrac; - - // This is probably wrong - s0 = s0 * 0xff; - s1 = s1 * 0xff; - s2 = s2 * 0xff; - s3 = s3 * 0xff; - - // 8.0 * 1.4 + 8.0 * 1.4 = 9.4 - uint32_t rl = r0 * (om_ufrac) + r1 * ufrac; - uint32_t gl = g0 * (om_ufrac) + g1 * ufrac; - uint32_t bl = b0 * (om_ufrac) + b1 * ufrac; - uint32_t al = a0 * (om_ufrac) + a1 * ufrac; - uint32_t sl = s0 * (om_ufrac) + s1 * ufrac; - - uint32_t ru = r2 * (om_ufrac) + r3 * ufrac; - uint32_t gu = g2 * (om_ufrac) + g3 * ufrac; - uint32_t bu = b2 * (om_ufrac) + b3 * ufrac; - uint32_t au = a2 * (om_ufrac) + a3 * ufrac; - uint32_t su = s2 * (om_ufrac) + s3 * ufrac; - - // 9.4 * 0.4 + 9.4 * 0.4 = 10.8? - r = (rl * om_vfrac + ru * vfrac) >> 8; - g = (gl * om_vfrac + gu * vfrac) >> 8; - b = (bl * om_vfrac + bu * vfrac) >> 8; - a = (al * om_vfrac + au * vfrac) >> 8; - - s = ((sl * om_vfrac + su * vfrac) >> 10) ? 1 : 0; - break; - } - } -} - - -//------------------------------------------------- -// addr_calc - -//------------------------------------------------- -void m2_te_device::addr_calc(uint32_t u, uint32_t v, uint32_t lod, - uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth) -{ - uint32_t u_mask = (m_tm.uv_mask & TXTUVMASK_UMASK_MASK) >> TXTUVMASK_UMASK_SHIFT; - uint32_t v_mask = (m_tm.uv_mask & TXTUVMASK_VMASK_MASK) >> TXTUVMASK_VMASK_SHIFT; - uint32_t u_max = (m_tm.uv_max & TXTUVMAX_UMAX_MASK) >> TXTUVMAX_UMAX_SHIFT; - uint32_t v_max = (m_tm.uv_max & TXTUVMAX_VMAX_MASK) >> TXTUVMAX_VMAX_SHIFT; - - // Remove fractional parts (10.0) - uint32_t u0 = u >> 4; - uint32_t v0 = v >> 4; - - u0 = u0 & u_mask; - v0 = v0 & v_mask; - - u_max &= u_mask; - v_max &= v_mask; - - u0 = clamp(u0, 0, u_max); - v0 = clamp(v0, 0, v_max); - - // LOD - uint32_t lodmax = m_tm.tex_addr_cntl & TXTADDRCNTL_LODMAX_MASK; - uint32_t lod_shift = (lodmax - lod) & 3; - - // 20.0 - uint32_t voffset = (v0 * (u_max + 1)) << lod_shift; - uint32_t offset = (voffset + u0) >> lod_shift; - - offset = offset * tdepth; - - uint32_t base_addr = 0; - - switch (lod) - { - case 0: base_addr = m_tm.tex_lod_base0; break; - case 1: base_addr = m_tm.tex_lod_base1; break; - case 2: base_addr = m_tm.tex_lod_base2; break; - case 3: base_addr = m_tm.tex_lod_base3; break; - } - - uint32_t adsum = (base_addr << 3) + offset; - - texaddr = adsum / 32; - texbit = adsum & 31; -} - - -void m2_te_device::get_texel(uint32_t tex_addr, uint32_t tex_bit, uint32_t tdepth, - uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & ssb) -{ - const uint32_t tex_type = m_tm.tex_exptype; - - uint8_t rtex, gtex, btex, atex; - uint8_t ssbtex; - - uint8_t rpip, gpip, bpip, apip; - uint8_t ssbpip; - - // Page 127 - // See M2_2_7_part3_clt_ocrc.pdf page 95 for better expl. - - uint32_t tram_data = m_tram[tex_addr]; - -#if TEST_TIMING - g_statistics[STAT_TEXEL_READS]++; -#endif - - - // Align the texel - uint32_t texel = tram_data >> (tex_bit & ~7); - - // Align within byte (TODO: Fix for 32-bits!) - texel >>= (tex_bit ^ (8 - tdepth)) & 7; - - uint32_t c_depth = (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; - uint32_t a_depth = (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; - uint32_t i_depth = c_depth; - - // Color is either sourced from tram or PIP - if (tex_type & TXTEXPFORM_LITERAL) - { - if (tex_type & TXTEXPFORM_COLORON) - { - // Literal can only be 32-bit or 16bpp - uint32_t mask = (1 << c_depth) - 1; - - btex = texel & mask; - texel >>= c_depth; - gtex = texel & mask; - texel >>= c_depth; - rtex = texel & mask; - texel >>= c_depth; - } - else - { - rtex = gtex = btex = 0; - } - } - else - { - rtex = gtex = btex = 0; - } - - if (tex_type & TXTEXPFORM_INDEXON) - { - uint32_t pipidx = texel & ((1 << i_depth) - 1); - uint32_t pipaddr = (m_tm.tex_pip_cntl & TXTPIPCNTL_INDEX_OFFSET) + pipidx; - - uint32_t pipval = m_pipram[pipaddr & 0xff]; - - // Color, alpha and SSB always present in PIP - bpip = pipval & 0xff; - gpip = (pipval >> 8) & 0xff; - rpip = (pipval >> 16) & 0xff; - apip = (pipval >> 24) & 0x7f; - ssbpip = pipval >> 31; - - texel >>= i_depth; - } - else - { - // Nothing coming from the PIP - rpip = gpip = bpip = 0; - apip = ssbpip = 0; - } - - // Alpha and SSB could be present - if (tex_type & TXTEXPFORM_ALPHAON) - { - uint32_t mask = (1 << a_depth) - 1; - - atex = texel & mask; - - // Need to expand alpha if 4-bits - if (a_depth == 4) - atex = (atex << 3) | (atex >> 1); - - texel >>= a_depth; - } - else - { - atex = 0; - } - - if (tex_type & TXTEXPFORM_SSBON) - ssbtex = texel & 1; - else - ssbtex = 0; - - // Select the SSB - switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_SSBSEL_MASK) >> TXTPIPCNTL_SSBSEL_SHIFT) - { - case TXTPIPCNTL_SEL_CONSTANT: - { - uint32_t cnst = ssbtex ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; - ssb = cnst >> 31; - break; - } - case TXTPIPCNTL_SEL_TRAM: - { - ssb = ssbtex; - break; - } - case TXTPIPCNTL_SEL_PIP: - { - ssb = ssbpip; - break; - } - } - - // PIP color control - switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_COLORSEL_MASK) >> TXTPIPCNTL_COLORSEL_SHIFT) - { - case TXTPIPCNTL_SEL_CONSTANT: - { - uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; - r = (cnst >> 16) & 0xff; - g = (cnst >> 8) & 0xff; - b = (cnst >> 0) & 0xff; - break; - } - case TXTPIPCNTL_SEL_TRAM: - { - r = rtex; - g = gtex; - b = btex; - break; - } - case TXTPIPCNTL_SEL_PIP: - { - r = rpip; - g = gpip; - b = bpip; - break; - } - } - - // Alpha control - switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_ALPHASEL_MASK) >> TXTPIPCNTL_ALPHASEL_SHIFT) - { - case TXTPIPCNTL_SEL_CONSTANT: - { - uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; - a = (cnst >> 24) & 0x7f; - break; - } - case TXTPIPCNTL_SEL_TRAM: - { - a = atex; - break; - } - case TXTPIPCNTL_SEL_PIP: - { - a = apip; - break; - } - } - - // Expand alpha to 8-bits - a = (a << 1) | (a >> 6); -} - - -//------------------------------------------------- -// lerp -//------------------------------------------------- - -static inline uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) -{ - if (t == 255) - return b; - if (t == 0) - return a; - - return (((255 - t) * a) >> 8) + ((t * b) >> 8); -} - - -//------------------------------------------------- -// multiply -//------------------------------------------------- - -static inline uint8_t multiply(uint8_t a, uint8_t b) -{ - if (b == 255) - return a; - if (a == 255) - return b; - else - return (a * b) >> 8; -} - - -//------------------------------------------------- -// texture_blend - -//------------------------------------------------- - -void m2_te_device::texture_blend( - uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, - uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, - uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo) -{ - uint32_t rbl = 0, gbl = 0, bbl = 0, abl = 0; - - { - uint32_t ar, ab, ag, aa; - uint32_t br, bb, bg, ba; - uint32_t tr, tb, tg; - - select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_ASEL_MASK) >> TXTTABCNTL_C_ASEL_SHIFT, - ri, gi, bi, ai, - rt, gt, bt, at, ssbt, - ar, ag, ab ); - - select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_BSEL_MASK) >> TXTTABCNTL_C_BSEL_SHIFT, - ri, gi, bi, ai, - rt, gt, bt, at, ssbt, - br, bg, bb ); - - select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_TSEL_MASK) >> TXTTABCNTL_C_TSEL_SHIFT, - ri, gi, bi, ai, - rt, gt, bt, at, ssbt, - tr, tg, tb ); - - if (((m_tm.tex_tab_cntl & TXTTABCNTL_BLENDOP_MASK) >> TXTTABCNTL_BLENDOP_SHIFT) == TXTTABCNTL_BLENDOP_LERP) - { - rbl = lerp(ar, br, tr); - gbl = lerp(ag, bg, tg); - bbl = lerp(ab, bb, tb); - } - else - { - // TODO: CHECK ME - // Alpha is multiply only - select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_ASEL_MASK) >> TXTTABCNTL_A_ASEL_SHIFT, - ai, at, ssbt, - aa); - - select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_BSEL_MASK) >> TXTTABCNTL_A_BSEL_SHIFT, - ai, at, ssbt, - ba); - - rbl = multiply(ar, br); - gbl = multiply(ag, bg); - bbl = multiply(ab, bb); - abl = multiply(aa, ba); - } - } - - // Now select the output - switch ((m_tm.tex_tab_cntl & TXTTABCNTL_C_OSEL_MASK) >> TXTTABCNTL_C_OSEL_SHIFT) - { - case TXTTABCNTL_CO_SEL_CITER: - { - ro = ri; - go = gi; - bo = bi; - break; - } - case TXTTABCNTL_CO_SEL_CT: - { - ro = rt; - go = gt; - bo = bt; - break; - } - case TXTTABCNTL_CO_SEL_BLEND: - { - ro = rbl; - go = gbl; - bo = bbl; - break; - } - case TXTTABCNTL_CO_SEL_RESERVED: - { - ro = go = bo = 0; - break; - } - } - - // Select alpha output - switch ((m_tm.tex_tab_cntl & TXTTABCNTL_A_OSEL_MASK) >> TXTTABCNTL_A_OSEL_SHIFT) - { - case TXTTABCNTL_AO_SEL_AITER: - { - ao = ai; - break; - } - case TXTTABCNTL_AO_SEL_AT: - { - ao = at; - break; - } - case TXTTABCNTL_AO_SEL_BLEND: - { - ao = abl; - break; - } - case TXTTABCNTL_AO_SEL_RESERVED: - { - ao = 0; - break; - } - } -} - -void m2_te_device::select_lerp( uint32_t sel, - uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, - uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, - uint32_t & ar, uint32_t & ag, uint32_t & ab ) -{ - switch (sel) - { - case TXTTABCNTL_C_ABTSEL_AITER: - { - ar = ai; - ag = ai; - ab = ai; - break; - } - case TXTTABCNTL_C_ABTSEL_CITER: - { - ar = ri; - ag = gi; - ab = bi; - break; - } - case TXTTABCNTL_C_ABTSEL_AT: - { - ar = at; - ag = at; - ab = at; - break; - } - case TXTTABCNTL_C_ABTSEL_CT: - { - ar = rt; - ag = gt; - ab = bt; - break; - } - case TXTTABCNTL_C_ABTSEL_ACONST: - { - uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; - uint8_t aval = (cnst >> 24) & 0x7f; - - // Expand to 8-bit - aval = (aval << 1) | (aval >> 6); - - ar = aval; - ag = aval; - ab = aval; - break; - } - case TXTTABCNTL_C_ABTSEL_CCONST: - { - uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; - - ar = (cnst >> 24) & 0xff; - ag = (cnst >> 16) & 0xff; - ab = (cnst >> 0) & 0xff; - break; - } - default: - { - ar = 0; - ag = 0; - ab = 0; - break; - } - } -} - - -void m2_te_device::select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt, - uint32_t & a ) -{ - switch (sel) - { - case TXTTABCNTL_A_ABSEL_AITER: - { - a = ai; - break; - } - case TXTTABCNTL_A_ABSEL_AT: - { - a = at; - break; - } - case TXTTABCNTL_A_ABSEL_ACONST: - { - uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; - uint8_t aval = (cnst >> 24) & 0x7f; - - // Expand to 8-bit - a = (aval << 1) | (aval >> 6); - break; - } - default: - { - a = 0; - break; - } - } -} - - -//------------------------------------------------- -// write_dst_pixel - Write pixel to framebuffer -//------------------------------------------------- - -void m2_te_device::write_dst_pixel() -{ - uint32_t mask = m_db.usergen_ctrl & DBUSERGENCTL_DESTOUT_MASK; - - if (m_db.dst_ctrl & DBDESTCNTL_32BPP) - { - uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint32_t); - - uint32_t old = m_bda->read_bus32(dstaddr); - uint32_t out = 0; - - uint8_t sdsb_a = (old >> 24) & 0xff; - uint8_t sr = (old >> 16) & 0xff; - uint8_t sg = (old >> 8) & 0xff; - uint8_t sb = old & 0xff; - - out |= (mask & 8 ? (m_dbstate.dsb << 7) | (m_dbstate.dst.a >> 1) : sdsb_a) << 24; - out |= (mask & 4 ? m_dbstate.dst.r : sr) << 16; - out |= (mask & 2 ? m_dbstate.dst.g : sg) << 8; - out |= mask & 1 ? m_dbstate.dst.b : sb; - - m_bda->write_bus32(dstaddr, out); - } - else - { - uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint16_t); - - uint16_t old = m_bda->read_bus16(dstaddr); - uint16_t out = 0; - - uint8_t sdsb_a = (old >> 15) & 0x1; - uint8_t sr = (old >> 10) & 0x1f; - uint8_t sg = (old >> 5) & 0x1f; - uint8_t sb = old & 0x1f; - - out |= (mask & 8 ? m_dbstate.dsb : sdsb_a) << 15; - out |= (mask & 4 ? m_dbstate.dst.r >> 3 : sr) << 10; - out |= (mask & 2 ? m_dbstate.dst.g >> 3 : sg) << 5; - out |= mask & 1 ? m_dbstate.dst.b >> 3 : sb; - - m_bda->write_bus16(dstaddr, out); - } - -#if TEST_TIMING - g_statistics[STAT_PIXEL_STORES]++; -#endif -} - - -//------------------------------------------------- -// destination_blend - -//------------------------------------------------- - -void m2_te_device::destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb) -{ - m_dbstate.x = x; - m_dbstate.y = y; - m_dbstate.w = w; - m_dbstate.ti = ti_color; - m_dbstate.ssb = ssb; - - bool dis = false; - bool zpixout = true; - bool zbufout = true; - bool zclip = false; - bool zclipdis = false; - bool fbclipdis = false; - bool winclipdis = false; - - // Z Status - uint32_t zgel = 0; - - uint32_t zaddr; - - // FBCLIP - { - uint32_t xclip = (m_db.fbclip & DBFBCLIP_XFBCLIP_MASK) >> DBFBCLIP_XFBCLIP_SHIFT; - uint32_t yclip = (m_db.fbclip & DBFBCLIP_YFBCLIP_MASK) >> DBFBCLIP_YFBCLIP_SHIFT; - - fbclipdis = (x >= xclip) || (y >= yclip); - - if (fbclipdis) - m_db.status |= DBSTATUS_FBCLIP; - } - - // WINCLIP - { - uint32_t xmin = (m_db.x_winclip & DBFBXWINCLIP_XMIN_MASK) >> DBFBXWINCLIP_XMIN_SHIFT; - uint32_t xmax = (m_db.x_winclip & DBFBXWINCLIP_XMAX_MASK) >> DBFBXWINCLIP_XMAX_SHIFT; - uint32_t ymin = (m_db.y_winclip & DBFBYWINCLIP_YMIN_MASK) >> DBFBYWINCLIP_YMIN_SHIFT; - uint32_t ymax = (m_db.y_winclip & DBFBYWINCLIP_YMAX_MASK) >> DBFBYWINCLIP_YMAX_SHIFT; - - bool inside = (x >= xmin) && (x < xmax) && (y >= ymin) && (y < ymax); - - winclipdis = ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPINEN) && inside) || - ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPOUTEN) && !inside); - - if (winclipdis) - m_db.status |= DBSTATUS_WINCLIP; - } - - select_src_pixel(); - - select_tex_pixel(); - - select_alpha_dsb(); - - - { - uint8_t dm10, dm11, dm20, dm21; - uint32_t txtcnst0 = m_db.txt_coef_const0; - uint32_t txtcnst1 = m_db.txt_coef_const1; - uint32_t srccnst0 = m_db.src_coef_const0; - uint32_t srccnst1 = m_db.src_coef_const1; - - if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) - { - // Blue - dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8; - dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8; - dm20 = srccnst0 & 0xff; srccnst0 >>= 8; - dm21 = srccnst1 & 0xff; srccnst1 >>= 8; - m_dbstate.blend.b = color_blend(m_dbstate.texpath.b, m_dbstate.ti.b, m_dbstate.srcpath.b, m_dbstate.src.b, dm10, dm11, dm20, dm21); - - // TODO: ALURGEL for each - - // Green - dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8; - dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8; - dm20 = srccnst0 & 0xff; srccnst0 >>= 8; - dm21 = srccnst1 & 0xff; srccnst1 >>= 8; - m_dbstate.blend.g = color_blend(m_dbstate.texpath.g, m_dbstate.ti.g, m_dbstate.srcpath.g, m_dbstate.src.g, dm10, dm11, dm20, dm21); - - // Red - dm10 = txtcnst0 & 0xff; - dm11 = txtcnst1 & 0xff; - dm20 = srccnst0 & 0xff; - dm21 = srccnst1 & 0xff; - m_dbstate.blend.r = color_blend(m_dbstate.texpath.r, m_dbstate.ti.r, m_dbstate.srcpath.r, m_dbstate.src.r, dm10, dm11, dm20, dm21); - } - else - { - m_dbstate.blend.r = m_dbstate.ti.r; - m_dbstate.blend.g = m_dbstate.ti.g; - m_dbstate.blend.b = m_dbstate.ti.b; - } - - // Dithering - if (m_db.usergen_ctrl & DBUSERGENCTL_DITHEREN) - { - uint32_t dith_x = x & 3; - uint32_t dith_y = y & 3; - - uint32_t dith_mtx = dith_y & 2 ? m_db.dither_mat_b : m_db.dither_mat_a; - uint32_t idx = 7 ^ (((dith_y & 1) << 2) | dith_x); - uint8_t val = (dith_mtx >> (idx * 4)) & 0xf; - - m_dbstate.dst.r = dither(m_dbstate.blend.r, val); - m_dbstate.dst.g = dither(m_dbstate.blend.g, val); - m_dbstate.dst.b = dither(m_dbstate.blend.b, val); - } - else - { - m_dbstate.dst.r = m_dbstate.blend.r; - m_dbstate.dst.g = m_dbstate.blend.g; - m_dbstate.dst.b = m_dbstate.blend.b; - } - } - - - if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) && - (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN)) - { - int32_t x_offs = (m_db.z_offset & DBZOFFS_XOFFS_MASK) >> DBZOFFS_XOFFS_SHIFT; - int32_t y_offs = (m_db.z_offset & DBZOFFS_YOFFS_MASK) >> DBZOFFS_YOFFS_SHIFT; - - // Sign extend - x_offs = (x_offs << 20) >> 20; - y_offs = (x_offs << 20) >> 20; - - x_offs += m_dbstate.x; - y_offs += m_dbstate.y; - - uint32_t x_clip = (m_db.z_clip & DBZCLIP_XCLIP_MASK) >> DBZCLIP_XCLIP_SHIFT; - uint32_t y_clip = (m_db.z_clip & DBZCLIP_YCLIP_MASK) >> DBZCLIP_YCLIP_SHIFT; - - zclip = (x_offs < 0) || (y_offs < 0) || (x_offs >= x_clip) || (y_offs >= y_clip); - - zaddr = m_db.z_baseaddr + (x_offs + y_offs * m_db.dst_xstride) * 2; - } - else - { - zaddr = 0; - zclip = false; - } - - zclipdis = zclip && (m_db.discard_ctrl & DBDISCARDCTL_ZCLIPDISEN); - - if (zclipdis) - m_db.status |= DBSTATUS_ZCLIP; - - // Z-path - if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) && - (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN) && - !zclip) - { -#if TEST_TIMING - g_statistics[STAT_ZBUFFER_LOADS]++; -#endif - -#if 1 // TODO: Why are we using this? - int32_t zdiff = w - m_bda->read_bus16(zaddr); -#else - // Shift W back to 0.23 - uint16_t oldw = m_bda->read_bus16(zaddr); - uint32_t exp = (oldw & 0xc000) >> 14; - uint32_t man = (oldw & 0x3fff) << 17; - - uint32_t oldz = man >> (exp * 3); - - exp = (w & 0xc000) >> 14; - man = (w & 0x3fff) << 17; - uint32_t curz = man >> (exp * 3); - - int32_t zdiff = curz - oldz; -#endif - - // TODO: Why isn't this working? - // W vs Z? - if (zdiff > 0) - { - zpixout = m_db.z_ctrl & 1;//DBZCNTL_ZPIXOUT_GT; - zbufout = m_db.z_ctrl & 2;//DBZCNTL_ZBUFOUT_GT; - zgel |= 4; - m_db.status |= DBSTATUS_ZFUNC_GT; - } - else if (zdiff == 0) - { - zpixout = m_db.z_ctrl & DBZCNTL_ZPIXOUT_EQ; - zbufout = m_db.z_ctrl & DBZCNTL_ZBUFOUT_EQ; - zgel |= 2; - m_db.status |= DBSTATUS_ZFUNC_EQ; - } - else - { - zpixout = m_db.z_ctrl & 0x10;//DBZCNTL_ZPIXOUT_LT; - zbufout = m_db.z_ctrl & 0x20;//DBZCNTL_ZBUFOUT_LT; - zgel |= 1; - m_db.status |= DBSTATUS_ZFUNC_LT; - } - } - else - { - zpixout = true; - zbufout = false; - } - - // Discard logic - { - bool ssbdis = (m_db.discard_ctrl & DBDISCARDCTL_SSBDISEN) && (m_dbstate.ssb == 0); - - bool adis = (m_db.discard_ctrl & DBDISCARDCTL_ADISEN) && (m_dbstate.dst.a == 0); - - bool rgbdis = (m_db.discard_ctrl & DBDISCARDCTL_RGBDISEN) && - (m_dbstate.dst.r == 0) && (m_dbstate.dst.g == 0) && (m_dbstate.dst.b == 0); - - dis = fbclipdis || winclipdis || zclipdis || ssbdis || adis || rgbdis; - } - - // Write output depth and color - if (!dis) - { - // Z-buffer - if (zbufout && (m_db.usergen_ctrl & DBUSERGENCTL_ZOUTEN)) - { -#if TEST_TIMING - g_statistics[STAT_ZBUFFER_STORES]++; -#endif - m_bda->write_bus16(zaddr, w & 0xffff); - } - - // Color - if (zpixout && (m_db.supergen_ctrl & DBSUPERGENCTL_DESTOUTEN)) - { - write_dst_pixel(); - } - } - - // TODO: Status -/* - { - fbClipStat = fbClipDis - winClipStat = winClipDis - zClipStat = zClipDis - alurstat - alugstat - alubstat - zFuncStat - anyRender - set_interrupt - } -*/ -} - -// Select between texture unit and source pixel -void m2_te_device::select_tex_pixel() -{ - uint32_t cntl; - - // TODO: REGBITS - if (m_dbstate.ti.a == 0) - cntl = (m_db.src_alpha_ctrl >> 4) & 3; - else if (m_dbstate.ti.a == 255) - cntl = m_db.src_alpha_ctrl & 3; - else - cntl = (m_db.src_alpha_ctrl >> 2) & 3; - - switch (cntl) - { - case 0: m_dbstate.texpath.a = m_dbstate.ti.a; break; - case 1: m_dbstate.texpath.a = 255; break; - case 2: m_dbstate.texpath.a = 0; break; - } - - switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_INSEL_MASK) >> DBTXTMULTCNTL_INSEL_SHIFT) - { - case DBTXTMULTCNTL_INSEL_CTI: - { - m_dbstate.texpath.r = m_dbstate.ti.r; - m_dbstate.texpath.g = m_dbstate.ti.g; - m_dbstate.texpath.b = m_dbstate.ti.b; - break; - } - case DBTXTMULTCNTL_INSEL_CONSTANT: - { - uint32_t cnst = m_db.const_in; - m_dbstate.texpath.r = (cnst >> 16) & 0xff; - m_dbstate.texpath.g = (cnst >> 8) & 0xff; - m_dbstate.texpath.b = cnst & 0xff; - break; - } - case DBTXTMULTCNTL_INSEL_COMPSRC: - { - m_dbstate.texpath.r = ~m_dbstate.src.r; - m_dbstate.texpath.g = ~m_dbstate.src.g; - m_dbstate.texpath.b = ~m_dbstate.src.b; - break; - } - case DBTXTMULTCNTL_INSEL_ATI: - { - m_dbstate.texpath.r = m_dbstate.ti.a; - m_dbstate.texpath.g = m_dbstate.ti.a; - m_dbstate.texpath.b = m_dbstate.ti.a; - break; - } - } - - if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTRJUST) - { - m_dbstate.texpath.r >>= 3; - m_dbstate.texpath.g >>= 3; - m_dbstate.texpath.b >>= 3; - } -} - -void m2_te_device::select_src_pixel() -{ - if ((m_db.usergen_ctrl & DBUSERGENCTL_SRCINEN) - && (m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) - && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) - { - int32_t x_offs = (m_db.src_offset & DBSRCOFFS_XOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT; - int32_t y_offs = (m_db.src_offset & DBSRCOFFS_YOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT; - - // Sign extend - x_offs = (x_offs << 20) >> 20; - y_offs = (y_offs << 20) >> 20; - - x_offs += m_dbstate.x; - y_offs += m_dbstate.y; - - uint32_t addr = y_offs * m_db.src_xstride + x_offs; - - if (m_db.src_ctrl & DBSRCCNTL_32BPP) - { - uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint32_t); - uint32_t srcval = m_bda->read_bus32(srcaddr); - - m_dbstate.src.a = ((srcval >> 24) & 0x7f) << 1; - m_dbstate.src.r = (srcval >> 16) & 0xff; - m_dbstate.src.g = (srcval >> 8) & 0xff; - m_dbstate.src.b = (srcval >> 0) & 0xff; - - if (m_db.src_ctrl & DBSRCCNTL_MSBREP) - m_dbstate.src.a |= (m_dbstate.src.a >> 6) & 1; - - m_dbstate.dsb = (srcval >> 31) & 1; - } - else - { - uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint16_t); - uint32_t srcval = m_bda->read_bus16(srcaddr); - - m_dbstate.src.r = (srcval >> 10) & 0x1f; - m_dbstate.src.g = (srcval >> 5) & 0x1f; - m_dbstate.src.b = srcval & 0x1f; - m_dbstate.src.a = 0; - - m_dbstate.dsb = srcval & 0x8000; - m_dbstate.src.r <<= 3; - m_dbstate.src.g <<= 3; - m_dbstate.src.b <<= 3; - - if (m_db.src_ctrl & DBSRCCNTL_MSBREP) - { - m_dbstate.src.r |= (m_dbstate.src.r >> 5); - m_dbstate.src.g |= (m_dbstate.src.g >> 5); - m_dbstate.src.b |= (m_dbstate.src.b >> 5); - } - } -#if TEST_TIMING - g_statistics[STAT_PIXEL_LOADS]++; -#endif - } - else - { - // Source input disabled - m_dbstate.dsb = 0; - m_dbstate.src.r = 0; - m_dbstate.src.g = 0; - m_dbstate.src.b = 0; - m_dbstate.src.a = 0; - } - - // Now - switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_INSEL_MASK) >> DBSRCMULTCNTL_INSEL_SHIFT) - { - case DBSRCMULTCNTL_INSEL_SRC: - { - m_dbstate.srcpath.r = m_dbstate.src.r; - m_dbstate.srcpath.g = m_dbstate.src.g; - m_dbstate.srcpath.b = m_dbstate.src.b; - break; - } - case DBSRCMULTCNTL_INSEL_CONSTANT: - { - uint32_t cnst = m_db.const_in; - m_dbstate.srcpath.r = (cnst >> 16) & 0xff; - m_dbstate.srcpath.g = (cnst >> 8) & 0xff; - m_dbstate.srcpath.b = (cnst >> 0) & 0xff; - break; - } - case DBSRCMULTCNTL_INSEL_COMPCTI: - { - m_dbstate.srcpath.r = ~m_dbstate.ti.r; - m_dbstate.srcpath.g = ~m_dbstate.ti.g; - m_dbstate.srcpath.b = ~m_dbstate.ti.b; - break; - } - case DBSRCMULTCNTL_INSEL_TEXALPHA: - { - m_dbstate.srcpath.r = m_dbstate.src.a; - m_dbstate.srcpath.g = m_dbstate.src.a; - m_dbstate.srcpath.b = m_dbstate.src.a; - break; - } - } - - if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCRJUST) - { - m_dbstate.srcpath.r >>= 3; - m_dbstate.srcpath.g >>= 3; - m_dbstate.srcpath.b >>= 3; - } - - m_dbstate.srcpath.a = m_dbstate.src.a; -} - -uint8_t m2_te_device::dither(uint8_t in, uint8_t dithval) -{ - int32_t res; - int32_t sgn_val; - - if (dithval & 8) - sgn_val = -8 + (dithval & 7); - else - sgn_val = dithval; - - res = (int32_t)in + sgn_val; - - if (res > 255) - res = 255; - else if (res < 0) - res = 0; - - return (uint8_t)res; -} - -uint8_t m2_te_device::get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1) -{ - uint32_t sel=0; - uint8_t cnst, coef=0; - - switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCONSTCNTL_MASK) >> DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT) - { - case DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB: sel = m_dbstate.ssb; break; - case DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB: sel = m_dbstate.dsb; break; - } - - cnst = sel ? dm2const1 : dm2const0; - - switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_COEFSEL_MASK) >> DBSRCMULTCNTL_COEFSEL_SHIFT) - { - case DBSRCMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break; - case DBSRCMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break; - case DBSRCMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break; - case DBSRCMULTCNTL_COEFSEL_CTI: coef = cti; break; - } - - if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCOEFCMP) - return ~coef; - else - return coef; -} - -uint8_t m2_te_device::get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1) -{ - uint32_t sel=0; - uint8_t cnst, coef=0; - - // TODO: Make like src coefficient - uint32_t cntl = ((m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCONSTCNTL_MASK) >> DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT); - - if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB) - sel = m_dbstate.ssb; - else if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB) - sel = m_dbstate.dsb; - - cnst = sel ? dm1const1 : dm1const0; - - switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_COEFSEL_MASK) >> DBTXTMULTCNTL_COEFSEL_SHIFT) - { - case DBTXTMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break; - case DBTXTMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break; - case DBTXTMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break; - case DBTXTMULTCNTL_COEFSEL_CSRC: coef = cs; break; - } - - if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCOEFCMP) - return ~coef; - else - return coef; -} - -void m2_te_device::select_alpha_dsb() -{ - if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) - { - uint32_t sel = 0; - uint8_t aconst; - - switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTCONSTCNTL_MASK) >> DBDSTACNTL_ADESTCONSTCNTL_SHIFT) - { - case 0: sel = m_dbstate.ssb; break; - case 1: sel = m_dbstate.dsb; break; - } - - if (sel) - aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST1_MASK) >> DBDSTALPHACONST_CONST1_SHIFT; - else - aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST0_MASK) >> DBDSTALPHACONST_CONST0_SHIFT; - - switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTSEL_MASK) >> DBDSTACNTL_ADESTSEL_SHIFT) - { - case 0: m_dbstate.dst.a = m_dbstate.texpath.a; break; - case 1: m_dbstate.dst.a = aconst; break; - case 2: m_dbstate.dst.a = m_dbstate.srcpath.a; break; - case 3: m_dbstate.dst.a = m_dbstate.blend.r; break; - } - - switch ((m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBSEL_MASK) >> DBSSBDSBCNTL_DSBSEL_SHIFT) - { - case 0: m_dbstate.dsb = m_dbstate.ssb; break; - case 1: m_dbstate.dsb = (m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBCONST_MASK) >> DBSSBDSBCNTL_DSBCONST_SHIFT; break; - case 2: m_dbstate.dsb = m_dbstate.dsb; break; - } - } - else - { - m_dbstate.dst.a = m_dbstate.texpath.a; - m_dbstate.dsb = m_dbstate.ssb; - } -} - - -uint8_t m2_te_device::color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc, - uint8_t dm10, uint8_t dm11, - uint8_t dm20, uint8_t dm21) -{ - uint8_t tcoef, scoef; - uint16_t tm, sm; - - tcoef = get_tex_coef(csrc, dm10, dm11); - scoef = get_src_coef(cti, dm20, dm21); - - tm = (tcoef == 255) ? ct : ((ct == 255) ? tcoef : ((tcoef * ct) >> 8)); - sm = (scoef == 255) ? cs : ((cs == 255) ? scoef : ((scoef * cs) >> 8)); - - return alu_calc(tm, sm); -} - -#if 1 - -uint8_t m2_te_device::alu_calc(uint16_t a, uint16_t b) -{ - uint16_t cinv; - uint16_t c = 0; - uint32_t blendout; - uint32_t result; - uint32_t carry = 0; - uint32_t borrow = 0; - uint32_t cntl = (m_db.alu_ctrl & DBALUCNTL_ALUOP_MASK) >> DBALUCNTL_ALUOP_SHIFT; - - // p271 - - /* ALU */ - if ((cntl & 8) == 0) - { - if (!(cntl & 4)) - { - result = a + b; - } - else if (cntl & 2) - { - result = b - a; - if (result < 0) - borrow = 1; - } - else - { - result = a - b; - if (result < 0) - borrow = 1; - } - } - /* Boolean */ - else - { - cinv = 0; - int i, j; - - for (i = 0; i < 8; ++i) - { - j = (a & 1) *2 + (b & 1); - - switch (j) - { - case 0: cinv |= (cntl & 1); break; - case 1: cinv |= (cntl & 2) && 1; break; - case 2: cinv |= (cntl & 4) && 1; break; - case 3: cinv |= (cntl & 8) && 1; break; - } - - cinv <<= 1; - a >>= 1; - b >>= 1; - } - cinv >>= 1; - - for (i = 0; i < 8; ++i) - { - c |= cinv & 1; - c <<= 1; - cinv >>= 1; - } - - c >>= 1; - result = (int)c; - } - - result &= 0x1ff; - - switch ((m_db.alu_ctrl & DBALUCNTL_FINALDIVIDE_MASK) >> DBALUCNTL_FINALDIVIDE_SHIFT) - { - case 1: blendout = result << 1; break; - case 2: blendout = result << 2; break; - case 3: blendout = result << 3; break; - case 7: blendout = result >> 1; break; - case 6: blendout = result >> 2; break; - case 5: blendout = result >> 3; break; - default: blendout = result; break; - } - - if (blendout > 255) - carry = 1; - -#if 0 - int alugel; - // TODO: FIX ALUGEL - Needs to be propagated to ALU status - if (borrow == 1) - alugel = 1; - else if (blendout == 0) - alugel = 2; - else - alugel = 4; -#endif - - if ((cntl & 8) == 0) - { - /* Clamp? */ - if (!(cntl & 1)) - { - blendout = carry ? 255 : blendout; - blendout = borrow ? 0 : blendout; - } - else - { - if (cntl & 2) - { - blendout = carry ? 255 : blendout; - blendout = borrow ? 0 : blendout; - } - } - } - - return blendout & 0xff; -} - - - -#endif - -//------------------------------------------------- -// walk_span - -//------------------------------------------------- - -void m2_te_device::walk_span(uint32_t wrange, bool omit_right, - uint32_t y, uint32_t xs, uint32_t xe, - int32_t r, int32_t g, int32_t b, int32_t a, - uint32_t uw, uint32_t vw, - uint32_t w) -{ - bool scan_lr = !m_es.r2l; - - // TODO: Is this correct? - xe = scan_lr ? xe + 1 : xe - 1; - - /* - Edge to Span walker - X/Y 11.0 - RGBA 8.11 - U/W, V/W 10.13 - 1/W 0.23 - RGBA DDX s8.11 - UV DDX s10.13 - 1/W DDX s0.23 - - To destination blender: - X/Y 11.0 - W 0.16 - - To texture mapper: - RGBA 8.0 - UV 10.4 - */ - - if (omit_right) - { - if (scan_lr) - { - xe -= 1; - } - else - { - xs -= 1; - r -= m_es.ddx_r; - g -= m_es.ddx_g; - b -= m_es.ddx_b; - a -= m_es.ddx_a; - uw -= m_es.ddx_uw; - vw -= m_es.ddx_vw; - w -= m_es.ddx_w; - } - } - - if (g_debug) - { - g_debug = true; - } - - while (xs != xe) - { - uint32_t sx = xs; - uint32_t sy = y; - -#if 1 // DEBUG - if (sx == 320/2 && sy == 200) - { - ; - } -#endif - - // Fetch RGB and A - uint32_t rt, gt, bt, at, ssbt; - - uint32_t w16 = 0; - - // W - { - // Undo shifting that took place during setup and reduce 0.23 to 0.16 - uint32_t normalized_w = w >> -depth_bits[wrange]; - w16 = (normalized_w >> 7) & 0xffff; - } - - if (!(m_gc.te_master_mode & TEMASTER_MODE_DTEXT) && (m_tm.tex_addr_cntl & TXTADDRCNTL_LOOKUP_EN)) - { - uint32_t u, v; - - // UV and W - texcoord_gen(wrange, uw, vw, w, u, v, w16); - - // TODO: FIXME - uint32_t lod = lod_calc(u, v, u, v); - - get_texture_color(u, v, lod, rt, gt, bt, at, ssbt); - } - else - { - rt = gt = bt = at = ssbt = 0; - } - - uint32_t ri, gi, bi, ai; - - if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE)) - { - // Remove the fractional parts of iterated ARGB - ri = r >> 11; - gi = g >> 11; - bi = b >> 11; - ai = a >> 11; - } - else - { - ri = 0xff; - gi = 0xff; - bi = 0xff; - ai = 0xff; - } - - uint32_t ro, go, bo, ao; - - // Note: SSB may be overriden - uint32_t ssbo = ssbt; - - // Blend iterated RGB with texel - texture_blend(ri, gi, bi, ai, - rt, gt, bt, at, ssbt, - ro, go, bo, ao, ssbo); - - // Destination blend and write-out - // Interface: - // Span length - // Left 2 Right - // W0, W1 - - rgba texout; - texout.r = ro; - texout.g = go; - texout.b = bo; - texout.a = ao; - - destination_blend(sx, sy, w16, texout, ssbo); - - // Update interpolated paramters - if (scan_lr) - { - xs += 1; - r += m_es.ddx_r; - g += m_es.ddx_g; - b += m_es.ddx_b; - a += m_es.ddx_a; - uw += m_es.ddx_uw; - vw += m_es.ddx_vw; - w += m_es.ddx_w; - } - else - { - xs -= 1; - r -= m_es.ddx_r; - g -= m_es.ddx_g; - b -= m_es.ddx_b; - a -= m_es.ddx_a; - uw -= m_es.ddx_uw; - vw -= m_es.ddx_vw; - w -= m_es.ddx_w; - } - - // Clamp to 11.8 - r = clamp(r, 0, 0x0007ffff); - g = clamp(g, 0, 0x0007ffff); - b = clamp(b, 0, 0x0007ffff); - a = clamp(a, 0, 0x0007ffff); - - // Clamp to 10.13 - uw = clamp(uw, 0, 0x007fffff); - vw = clamp(vw, 0, 0x007fffff); - - // Clamp to 0.23 - w = clamp(w, 0, 0x007fffff); - -#if TEST_TIMING - g_statistics[STAT_PIXELS_PROCESSED]++; -#endif - } -} - - - -/*************************************************************************** - INSTRUCTION PROCESSING -***************************************************************************/ - -//------------------------------------------------- -// irp_fetch - -//------------------------------------------------- - -uint32_t m2_te_device::irp_fetch() -{ - uint32_t data = m_bda->read_bus32(m_gc.irp); - m_gc.irp += 4; - - return data; -} - - -//------------------------------------------------- -// irp_fetch_float - -//------------------------------------------------- - -float m2_te_device::irp_fetch_float() -{ - uint32_t data = m_bda->read_bus32(m_gc.irp); - m_gc.irp += 4; - - return *reinterpret_cast(&data); -} - - -//------------------------------------------------- -// illegal_inst - -//------------------------------------------------- - -void m2_te_device::illegal_inst() -{ - set_interrupt(INTSTAT_UNIMPLEMENTED_INSTR); - m_state = TE_STOPPED; -} - - -//------------------------------------------------- -// execute - -//------------------------------------------------- - -void m2_te_device::execute() -{ - address_space &space = machine().driver_data()->generic_space(); - -#if TEST_TIMING - memset(g_statistics, 0, sizeof(g_statistics)); -#endif - - while (m_state == TE_RUNNING) - { - uint32_t inst = irp_fetch(); - - switch (inst & INST_MASK) - { - case INST_WRITE_REG: - { - uint32_t offs = inst & 0xffff; - int32_t cnt = (inst >> 16) & 0xff; - - while (cnt-- >= 0) - { - write(space, offs >> 2, irp_fetch(), 0xffffffff); - offs += 4; - - if (m_state != TE_RUNNING) - break; - } - break; - } - - case INST_VTX_SHORT: - { - int32_t cnt = inst & 0xffff; - uint32_t flags = inst & 0x001f0000; - uint32_t ver = (inst >> 24) & 0xf; - - if (ver != 0) - { - illegal_inst(); - break; - } - - while (cnt-- >= 0) - { - se_vtx vtx = { 0 }; - - vtx.x = irp_fetch_float(); - vtx.y = irp_fetch_float(); - - if (flags & VTX_FLAG_SHAD) - { - vtx.r = irp_fetch_float(); - vtx.g = irp_fetch_float(); - vtx.b = irp_fetch_float(); - vtx.a = irp_fetch_float(); - } - if (flags & VTX_FLAG_PRSP) - { - vtx.w = irp_fetch_float(); - } - if (flags & VTX_FLAG_TEXT) - { - vtx.uw = irp_fetch_float(); - vtx.vw = irp_fetch_float(); - } - - // Send this vertex for processing - add_vertex(vtx, flags); - - // Clear the new triangle flag if set - flags &= ~VTX_FLAG_NEW; - } - - break; - } - case INST_VTX_LONG: - { - const uint32_t ver = (inst >> 24) & 0xf; - - if (ver != 0) - { - illegal_inst(); - break; - } - - fatalerror("Long format unimplemented"); - - break; - } - case INST_VTX_POINT: - { - const uint32_t ver = (inst >> 24) & 0xf; - - if (ver != 0) - { - illegal_inst(); - break; - } - - fatalerror("Point format unimplemented"); - - break; - } - default: - { - illegal_inst(); - break; - } - } - - // Stop or pause execution? - if (m_gc.irp == m_gc.iwp) - { - m_state = m_gc.te_master_mode & TEICNTL_STPL ? TE_STOPPED : TE_PAUSED; - set_interrupt(INTSTAT_LIST_END); - } - else if (m_gc.te_master_mode & (TEICNTL_STPI | TEICNTL_STEP)) - { - m_state = TE_STOPPED; - } - }; - -#if TEST_TIMING -/* - TESetup Engine: 600-700 triangles/sec (?) - - Pixel Rates: - Point - 132Mpix/s - Linear - 66Mpix/s - Bilin - 33Mpix - QTril - 22M - - No blend, no Z - 120MPix - Zbuffer - 66-120M pix - Bend - 66 M pix -*/ - - uint32_t total_cycles = (g_statistics[STAT_TRIANGLES_PROCESSED] * 100) + - (g_statistics[STAT_TEXEL_READS]) + -// (g_statistics[STAT_PIXELS_PROCESSED]) + - (g_statistics[STAT_PIXEL_LOADS]) + - (g_statistics[STAT_PIXEL_STORES]) + - (g_statistics[STAT_TEXEL_BYTES]/4) + - (g_statistics[STAT_ZBUFFER_LOADS]) + - (g_statistics[STAT_ZBUFFER_STORES]); -#if 0 - logerror(">>> END OF LIST <<<\n"); - logerror("Triangles: %u\n", g_statistics[STAT_TRIANGLES_PROCESSED]); - logerror("Texture samples: %u\n", g_statistics[STAT_TEXEL_READS]); - logerror("Texture bytes loaded: %u\n", g_statistics[STAT_TEXEL_BYTES]); - logerror("Pixels rasterized: %u\n", g_statistics[STAT_PIXELS_PROCESSED]); - logerror("Pixel reads: %u\n", g_statistics[STAT_PIXEL_LOADS]); - logerror("Pixel writes: %u\n", g_statistics[STAT_PIXEL_STORES]); - logerror("Z reads: %u\n", g_statistics[STAT_ZBUFFER_LOADS]); - logerror("Z writes: %u\n", g_statistics[STAT_ZBUFFER_STORES]); - logerror("Total: %u cycles (%fusec)\n", total_cycles, clocks_to_attotime(total_cycles).as_double()*1.0e6); -#endif - timer_set(clocks_to_attotime(total_cycles), 0); -#else - // Interrupt after stopping? - if (m_gc.te_master_mode & TEICNTL_INT) - { - set_interrupt(INTSTAT_IMMEDIATE_INSTR); - } -#endif -} - - - -/*************************************************************************** - TEXTURE RAM ACCESSORS -***************************************************************************/ - -uint8_t m2_te_device::read_tram8(offs_t address) const -{ - address &= TEXTURE_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + BYTE4_XOR_BE(address); - return *ptr; -} - -uint16_t m2_te_device::read_tram16(offs_t address) const -{ - address &= TEXTURE_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//WORD_XOR_BE(address); - return *reinterpret_cast(ptr); -} - -uint32_t m2_te_device::read_tram32(offs_t address) const -{ - address &= TEXTURE_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//DWORD_XOR_BE(address); - return *reinterpret_cast(ptr); -} - -void m2_te_device::write_tram8(offs_t address, uint8_t data) -{ - assert(address <= TEXTURE_RAM_WORDS * 4); - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//BYTE8_XOR_BE(address); - *ptr = data; -} - -void m2_te_device::write_tram16(offs_t address, uint16_t data) -{ - assert(address < TEXTURE_RAM_WORDS * 4); - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + WORD2_XOR_BE(address); - *reinterpret_cast(ptr) = data; -} - -void m2_te_device::write_tram32(offs_t address, uint32_t data) -{ - address &= TEXTURE_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//DWORD_XOR_BE(address); - *reinterpret_cast(ptr) = data; -} - - - -/*************************************************************************** - PIP RAM ACCESSORS -***************************************************************************/ - -uint8_t m2_te_device::read_pipram8(offs_t address) const -{ - address &= PIP_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//BYTE4_XOR_BE(address); - return *ptr; -} - -uint16_t m2_te_device::read_pipram16(offs_t address) const -{ - address &= PIP_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//WORD_XOR_BE(address); - return *reinterpret_cast(ptr); -} - -uint32_t m2_te_device::read_pipram32(offs_t address) const -{ - address &= PIP_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//DWORD_XOR_BE(address); - return *reinterpret_cast(ptr); -} - -void m2_te_device::write_pipram32(offs_t address, uint32_t data) -{ - address &= PIP_RAM_BYTEMASK; - - uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//DWORD_XOR_BE(address); - *reinterpret_cast(ptr) = data; -} - - -// For extracting bit fields from RAM -uint32_t m2_te_device::readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits) -{ - uint32_t src_val = m_bda->read_bus32(src_addr); - - if (((bit_offs & 31) + bits) > 32) - { - uint32_t src_val2 = m_bda->read_bus32(src_addr + 4); - - uint32_t r_bits = ((bit_offs & 31) + bits) - 32; - uint32_t l_bits = bits - r_bits; - - src_val &= (1 << l_bits) - 1; - src_val <<= r_bits; - - // Position the right hand side - src_val2 >>= (32 - r_bits); - src_val2 &= (1 << r_bits) - 1; - - src_val |= src_val2; - } - else - { - src_val = src_val >> (32 - (bits + (bit_offs & 31))); - } - - return src_val &= (1 << bits) - 1; -} - -void m2_te_device::load_texture() -{ - switch (m_tm.texld_cntl & TXTLDCNTL_LDMODE_MASK) - { - case TXTLDCNTL_LDMODE_TEXLOAD: - { - if (m_tm.texld_cntl & TXTLDCNTL_COMPRESSED) - { - // Source address is byte aligned - uint32_t src_addr = m_tm.texld_srcbase; - uint32_t bit_offs = m_tm.texld_cntl & TXTLDCNTL_SRCBITOFFS; - - // Destination address is dword-aligned - uint32_t dst_addr = m_tm.texld_dstbase << 3; - int32_t texels = m_tm.tex_bytecnt; - - uint32_t dst_type = m_tm.tex_exptype; - uint32_t dst_cdepth = (dst_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; - uint32_t dst_adepth = (dst_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; - uint32_t dst_bits = 0; - - if (dst_type & TXTEXPFORM_COLORON) - { - if (dst_type & TXTEXPFORM_LITERAL) - dst_bits += dst_cdepth * 3; - else - dst_bits += dst_cdepth; - } - - if (dst_type & TXTEXPFORM_SSBON) - ++dst_bits; - - if (dst_bits & TXTEXPFORM_ALPHAON) - dst_bits += dst_adepth; - - while (texels > 0) - { - uint8_t cntl = readbits_from_ram(src_addr, bit_offs, 8); - - uint32_t type = (cntl >> 6) & 3; - uint32_t cnst; - - // Select constant register - if (type == 0) - cnst = m_tm.tex_srcconst0; - else if (type == 1) - cnst = m_tm.tex_srcconst1; - else if (type == 2) - cnst = m_tm.tex_srcconst2; - else - cnst = m_tm.tex_srcconst3; - - // Select pixel type register - uint32_t src_type = type & 2 ? m_tm.tex_srctype23 : m_tm.tex_srctype01; - - if (type & 1) - src_type = src_type >> 16; - - const bool has_color = src_type & TXTEXPFORM_COLORON; - const bool has_alpha = src_type & TXTEXPFORM_ALPHAON; - const bool has_ssb = src_type & TXTEXPFORM_SSBON; - const bool is_transparent = src_type & TXTEXPFORM_TRANSPARENT; - const bool is_literal = src_type & TXTEXPFORM_LITERAL; - - uint32_t cnt = (cntl & (is_transparent ? 0x3f : 0x1f)) + 1; - - uint32_t src_cdepth = (src_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; - uint32_t src_adepth = (src_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; - uint32_t src_bits = 0; - - if (is_literal) - src_cdepth *= 3; - - uint32_t src_val = 0; - - if (is_transparent) - { - src_val = cnst; - } - else - { - src_bits += src_cdepth; - - if (has_ssb) - ++src_bits; - - if (has_alpha) - src_bits += src_adepth; - } - - // String - if (!is_transparent && (cntl & 0x20)) - { - for (uint32_t i = 0; i < cnt; ++i) - { - uint32_t dst_val = 0; - uint32_t src_ssb = 0; - uint32_t src_color = 0; - uint32_t src_alpha = 0; - uint32_t src_val = readbits_from_ram(src_addr, bit_offs, src_bits); - -#if TEST_TIMING // FIXME - g_statistics[STAT_TEXEL_BYTES] += 4; -#endif - - if (has_color) - { - src_color = src_val & ((1 << src_cdepth) - 1); - src_val >>= src_cdepth; - - // Indexed format - add an offset - if (!(src_type & TXTEXPFORM_INDEXON)) - src_color += cnst & 0xff; - } - - if (has_alpha) - { - if (is_transparent) - { - src_alpha = (cnst >> 24) & ((1 << src_adepth) - 1); - } - else - { - src_alpha = src_val & ((1 << src_adepth) - 1); - src_val >>= src_adepth; - } - } - - if (has_ssb) - { - if (is_transparent) - src_ssb = (cnst >> 31) & 1; - else - src_ssb = src_val & 1; - } - - // Now create the destination value - dst_val = src_color - | (src_alpha << src_cdepth) - | (src_ssb << (src_cdepth + src_adepth)); - - uint32_t oldval = m_tram[(dst_addr >> 3) >> 2]; - - // Clear out the old value - uint32_t shift = (32 - (dst_bits + (dst_addr & 31))); - oldval &= ~(((1 << dst_bits) - 1) << shift); - oldval |= dst_val << shift; - - m_tram[(dst_addr >> 3) >> 2] = oldval; - - //src_addr += src_bits; - dst_addr += dst_bits; - } - } - else - { - uint32_t dst_val; - - if (!is_transparent) - { - // Read one texel - src_val = readbits_from_ram(src_addr, bit_offs, src_bits); - -#if TEST_TIMING // FIXME - g_statistics[STAT_TEXEL_BYTES] += 4; -#endif - - // Indexed format - add an offset - if (!is_literal) - src_val += cnst & 0xff; - } - - // HACK: Bits don't match? - dst_val = src_val; - - for (uint32_t i = 0; i < cnt; ++i) - { - uint32_t oldval = m_tram[(dst_addr >> 3) & ~3]; - - // Clear out the old value - uint32_t shift = (32 - (dst_bits + (dst_addr & 31))); - oldval &= ~(((1 << dst_bits) - 1) << shift); - oldval |= dst_val << shift; - - m_tram[(dst_addr >> 3) >> 2] = oldval; - - dst_addr += dst_bits; - } - - // Copy - //src_addr += src_bits; - } - - texels -= cnt; - // assert if negative? - } - } - else - { - // Regular - fatalerror("REGULAR TEXTURE NOT SUPPORTED\n"); - } - - break; - } - - case TXTLDCNTL_LDMODE_MMDMA: - { - uint32_t srcaddr = m_tm.tex_mm_srcbase; - uint32_t dstaddr = m_tm.tex_mm_dstbase; - uint32_t bytes = m_tm.tex_bytecnt; - - // TODO: Do TRAM and PIPRAM only allow 32-bit accesses? - assert((bytes & 3) == 0); - - if (m_tm.tex_cntl & TXTCNTL_MMDMA_TRAM_ON) - { - // TRAM destination must be 32-bit aligned - assert((dstaddr & 3) == 0); - - while (bytes > 0) - { -#if 0 - uint32_t data = m_bda->read_bus32(srcaddr); - write_tram32(dstaddr, data); - dstaddr += 4; - srcaddr += 4; - bytes -= 4; -#else - uint32_t data = m_bda->read_bus8(srcaddr); - write_tram8(dstaddr, data); - dstaddr ++; - srcaddr ++; - bytes--; - -#if TEST_TIMING - g_statistics[STAT_TEXEL_BYTES]++; -#endif - -#endif - } - } - else if (m_tm.tex_cntl & TXTCNTL_MMDMA_PIP_ON) - { - // TODO: Should PIP destination be 32-bit aligned? - assert((dstaddr & 3) == 0); - - while (bytes > 0) - { - uint32_t data = m_bda->read_bus32(srcaddr); - write_pipram32(dstaddr, data); - dstaddr += 4; - srcaddr += 4; - bytes -= 4; - -#if TEST_TIMING - g_statistics[STAT_TEXEL_BYTES] += 4; -#endif - } - } - - break; - } - - case TXTLDCNTL_LDMODE_PIPLOAD: - { - // TODO: What is the difference between this and the MMDMA? - uint32_t srcaddr = m_tm.texld_srcbase; - uint32_t dstaddr = m_tm.texld_dstbase; - uint32_t bytes = m_tm.tex_bytecnt; - - // Assuming byte count must be aligned? - assert((m_tm.tex_bytecnt & 3) == 0); - - while (bytes > 0) - { - uint32_t data = m_bda->read_bus32(srcaddr); - write_pipram32(dstaddr, data); - dstaddr += 4; - srcaddr += 4; - bytes -= 4; -#if TEST_TIMING - g_statistics[STAT_TEXEL_BYTES] += 4; -#endif - } - - break; - } - - default: - { - logerror("UNHANDLED TEXTURE LOAD!\n"); - break; - } - } -} - - - -/*************************************************************************** - TIMERS -***************************************************************************/ - -void m2_te_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch (id) - { - case 0: - if (m_gc.te_master_mode & TEICNTL_INT) - set_interrupt(INTSTAT_IMMEDIATE_INSTR); - break; - } - -} diff --git a/src/mame/video/3dom2_te.cpp b/src/mame/video/3dom2_te.cpp new file mode 100644 index 00000000000..6dde9f57093 --- /dev/null +++ b/src/mame/video/3dom2_te.cpp @@ -0,0 +1,3960 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + 3DO M2 BDA Triangle Engine + +***************************************************************************/ + +#include "math.h" +#include "machine/3dom2.h" +#include "video/3dom2_te.h" + +/* + TODO: + + VTX_FLAGS do not get passed to the TMAPPER: Should use master control + bits to disable shading and texturing. + + - Evil Night attract mode sky is missing. Why? + - What is 1/w when 0? + - What do we do about RL flat-topped triangles? + - Heat of 11 color check has dodgy pixels <- HAS IT? + - Polystar blending is incorrect (intro) +*/ + +#define TEST_TIMING 1 + +#if TEST_TIMING +enum +{ + STAT_TRIANGLES_PROCESSED, + STAT_TEXEL_LOADS, + STAT_TEXEL_READS, + STAT_PIXELS_PROCESSED, + STAT_PIXEL_LOADS, + STAT_PIXEL_STORES, + STAT_TEXEL_BYTES, + STAT_ZBUFFER_LOADS, + STAT_ZBUFFER_STORES, +}; +static uint32_t g_statistics[16]; +#endif + +static bool g_debug = false; // TODO + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +// Device type definition +DEFINE_DEVICE_TYPE(M2_TE, m2_te_device, "m2te", "BDA Triangle Engine") + + + +//static const uint32_t fixed_bits = 23; + +static const uint32_t xy_bits = 11; +static const uint32_t color_bits = 8; +static const uint32_t text_bits[] = { 10, 7, 4, 1 }; +static const int32_t depth_bits[] = { 0, -3, -6, -9 }; + +// For right-aligning +static const uint32_t xy_rshift = 12; +static const uint32_t color_rshift = 4; + + +// 11.0 format +static const uint32_t xy_one = 1; + + +/*************************************************************************** + REGISTER DEFINITIONS + ***************************************************************************/ + +// TODO: SUFFIX bits with _BIT? +// Move to another file? + +//------------------------------------------------- +// General Control +//------------------------------------------------- + +// Triangle Engine Master Mode +#define TEMASTER_MODE_RESET 0x00000001 +#define TEMASTER_MODE_DTEXT 0x00000002 +#define TEMASTER_MODE_DSHADE 0x00000004 +#define TEMASTER_MODE_DBLEND 0x00000008 +#define TEMASTER_MODE_DZBUF 0x00000010 +#define TEMASTER_MODE_DDITH 0x00000020 + +// Triangle Engine Immediate Control +#define TEICNTL_INT 0x00000001 +#define TEICNTL_STEP 0x00000002 +#define TEICNTL_STPL 0x00000004 +#define TEICNTL_STPI 0x00000008 +#define TEICNTL_RSTRT 0x00000010 +#define TEICNTL_STRT 0x00000020 + +#define TEDCNTL_TLD 0x00000001 +#define TEDCNTL_JA 0x00000002 +#define TEDCNTL_JR 0x00000004 +#define TEDCNTL_INT 0x00000008 +#define TEDCNTL_PSE 0x00000010 +#define TEDCNTL_SYNC 0x00000020 + +#define INTSTAT_DEFERRED_INSTR 0x00000100 +#define INTSTAT_IMMEDIATE_INSTR 0x00000200 +#define INTSTAT_LIST_END 0x00000400 +#define INTSTAT_WINDOW_CLIP 0x00000800 +#define INTSTAT_SPECIAL_INSTR 0x00001000 +#define INTSTAT_UNIMPLEMENTED_INSTR 0x00002000 +#define INTSTAT_SUPERVISOR 0x00004000 +#define INTSTAT_ANY_RENDER 0x00008000 +#define INTSTAT_Z_FUNC 0x00010000 +#define INTSTAT_ALU_STATUS 0x00020000 +#define INTSTAT_FB_CLIP 0x00040000 +#define INTSTAT_IMMEDIATE 0x00080000 + +// IWP +// IRP +// Interrupt Enable +// Interrupt Status +// Vertex Control + + + +//------------------------------------------------- +// Setup Engine +//------------------------------------------------- + +// Vertex State +#define VERTEXSTATE_TSORT_MASK 0x00000007 +#define VERTEXSTATE_TSORT_OMN 0x00000001 +#define VERTEXSTATE_TSORT_MNO 0x00000002 +#define VERTEXSTATE_TSORT_ONM 0x00000003 +#define VERTEXSTATE_TSORT_NOM 0x00000004 +#define VERTEXSTATE_TSORT_MON 0x00000005 +#define VERTEXSTATE_TSORT_NMO 0x00000006 + +#define VERTEXSTATE_VCNT_SHIFT 3 +#define VERTEXSTATE_VCNT_MASK 0x00000018 + + +//------------------------------------------------- +// Edge Walker +//------------------------------------------------- + +// Edge and Span Walker Control +#define ESCNTL_DSPOFF 0x00000001 +#define ESCNTL_DUSCAN 0x00000002 +#define ESCNTL_PERSPECTIVEOFF 0x00000004 + + +//------------------------------------------------- +// Texture Mapper +//------------------------------------------------- + +// Texture Mapper Master Control (0x00046400) +#define TXTCNTL_MMDMA_TRAM_ON 0x00000004 +#define TXTCNTL_MMDMA_PIP_ON 0x00000008 +#define TXTCNTL_SNOOP_ON 0x00000020 + +// Texture Load Control (0x00046404) +#define TXTLDCNTL_SRCBITOFFS 0x00000007 +#define TXTLDCNTL_LDMODE_MASK 0x00000300 +#define TXTLDCNTL_LDMODE_TEXLOAD 0x00000000 +#define TXTLDCNTL_LDMODE_MMDMA 0x00000100 +#define TXTLDCNTL_LDMODE_PIPLOAD 0x00000200 +#define TXTLDCNTL_LDMODE_RESERVED 0x00000300 +#define TXTLDCNTL_COMPRESSED 0x00000400 + +// Address Control (0x00046408) +#define TXTADDRCNTL_LODMAX_MASK 0x0000000f +#define TXTADDRCNTL_FILTERSEL_MASK 0x00000003 +#define TXTADDRCNTL_FILTERSEL_POINT 0x00000000 +#define TXTADDRCNTL_FILTERSEL_LINEAR 0x00000001 +#define TXTADDRCNTL_FILTERSEL_BILINEAR 0x00000002 +#define TXTADDRCNTL_FILTERSEL_QUASITRI 0x00000003 +#define TXTADDRCNTL_R12FILTERSEL_SHIFT 4 +#define TXTADDRCNTL_R3FILTERSEL_SHIFT 7 +#define TXTADDRCNTL_R45FILTERSEL_SHIFT 10 +#define TXTADDRCNTL_LOOKUP_EN 0x00002000 + +// PIP Control (0x0004640C) +#define TXTPIPCNTL_INDEX_OFFSET 0x000000ff +#define TXTPIPCNTL_COLORSEL_MASK 0x00000700 +#define TXTPIPCNTL_COLORSEL_SHIFT 8 +#define TXTPIPCNTL_ALPHASEL_MASK 0x00003800 +#define TXTPIPCNTL_ALPHASEL_SHIFT 11 +#define TXTPIPCNTL_SSBSEL_MASK 0x0001c000 +#define TXTPIPCNTL_SSBSEL_SHIFT 14 + +#define TXTPIPCNTL_SEL_CONSTANT 0 +#define TXTPIPCNTL_SEL_TRAM 1 +#define TXTPIPCNTL_SEL_PIP 2 + +// Texture Application Control (0x00046410) +#define TXTTABCNTL_C_ASEL_MASK 0x00000007 +#define TXTTABCNTL_C_ASEL_SHIFT 0 +#define TXTTABCNTL_C_BSEL_MASK 0x00000038 +#define TXTTABCNTL_C_BSEL_SHIFT 3 +#define TXTTABCNTL_C_TSEL_MASK 0x000001c0 +#define TXTTABCNTL_C_TSEL_SHIFT 6 + +#define TXTTABCNTL_C_ABTSEL_AITER 0 +#define TXTTABCNTL_C_ABTSEL_CITER 1 +#define TXTTABCNTL_C_ABTSEL_AT 2 +#define TXTTABCNTL_C_ABTSEL_CT 3 +#define TXTTABCNTL_C_ABTSEL_ACONST 4 +#define TXTTABCNTL_C_ABTSEL_CCONST 5 + +#define TXTTABCNTL_C_OSEL_MASK 0x00000600 +#define TXTTABCNTL_C_OSEL_SHIFT 9 + +#define TXTTABCNTL_CO_SEL_CITER 0 +#define TXTTABCNTL_CO_SEL_CT 1 +#define TXTTABCNTL_CO_SEL_BLEND 2 +#define TXTTABCNTL_CO_SEL_RESERVED 3 + +#define TXTTABCNTL_A_ASEL_MASK 0x00001800 +#define TXTTABCNTL_A_ASEL_SHIFT 11 +#define TXTTABCNTL_A_BSEL_MASK 0x00006000 +#define TXTTABCNTL_A_BSEL_SHIFT 13 + +#define TXTTABCNTL_A_ABSEL_AITER 0 +#define TXTTABCNTL_A_ABSEL_AT 1 +#define TXTTABCNTL_A_ABSEL_ACONST 2 + +#define TXTTABCNTL_A_OSEL_MASK 0x00018000 +#define TXTTABCNTL_A_OSEL_SHIFT 15 + +#define TXTTABCNTL_AO_SEL_AITER 0 +#define TXTTABCNTL_AO_SEL_AT 1 +#define TXTTABCNTL_AO_SEL_BLEND 2 +#define TXTTABCNTL_AO_SEL_RESERVED 3 + +#define TXTTABCNTL_BLENDOP_MASK 0x00010000 +#define TXTTABCNTL_BLENDOP_SHIFT 16 +#define TXTTABCNTL_BLENDOP_LERP 0 +#define TXTTABCNTL_BLENDOP_MULT 1 + +// TAB Constants +#define TXTTABCONST_BLUE 0x000000ff +#define TXTTABCONST_BLUE_SHIFT 0 +#define TXTTABCONST_GREEN 0x0000ff00 +#define TXTTABCONST_GREEN_SHIFT 8 +#define TXTTABCONST_RED 0x00ff0000 +#define TXTTABCONST_RED_SHIFT 16 +#define TXTTABCONST_ALPHA 0x7f000000 +#define TXTTABCONST_ALPHA_SHIFT 24 +#define TXTTABCONST_SSB 0x80000000 + +// Texture Loader Destination Base (0x00046414) +#define TXTLDDSTBASE_ADDR 0x00003ffc + +// Texture Lod Base 0 (0x00046414) +// Texture Lod Base 1 (0x00046418) +// Texture Lod Base 2 (0x0004641C) +// Texture Lod Base 3 (0x00046420) +#define TXTLODBASE_MASK 0x00003ffc + +// Texture Loader Source Base (0x00046424) +#define TXTLDSRCBASE_ADDR 0x00003fff + +// Texture Loader Counts (0x00046428) +#define TXTLDBYTECNT_COUNT 0x0fffffff +#define TXTLDROWCNT_COUNT 0x0fffffff +#define TXTLDTEXCNT_COUNT 0x0fffffff + +// Texture Loader Width (0x00046428) +#define TxTLDWIDTH_SRCROW 0x0000ffff +#define TxTLDWIDTH_DSTROW_SHIFT 16 +#define TxTLDWIDTH_DSTROW 0xffff0000 + +// Texture Size (0x0004642C) +#define TXTUVMAX_VMAX_MASK 0x000003ff +#define TXTUVMAX_VMAX_SHIFT 0 +#define TXTUVMAX_UMAX_MASK 0x03ff0000 +#define TXTUVMAX_UMAX_SHIFT 16 + +// Texture Mask (0x00046430) +#define TXTUVMASK_VMASK_MASK 0x000003ff +#define TXTUVMASK_VMASK_SHIFT 0 +#define TXTUVMASK_UMASK_MASK 0x03ff0000 +#define TXTUVMASK_UMASK_SHIFT 16 + +// TRAM Format (0x0004643C) +// TODO: Expansion formats +#define TXTEXPFORM_CDEPTH_MASK 0x0000000f +#define TXTEXPFORM_CDEPTH_SHIFT 0 +#define TXTEXPFORM_IDEPTH_MASK 0x0000000f +#define TXTEXPFORM_IDEPTH_SHIFT 0 +#define TXTEXPFORM_ADEPTH_MASK 0x000000f0 +#define TXTEXPFORM_ADEPTH_SHIFT 4 +#define TXTEXPFORM_TRANSPARENT 0x00000100 +#define TXTEXPFORM_SSBON 0x00000200 +#define TXTEXPFORM_COLORON 0x00000400 +#define TXTEXPFORM_INDEXON 0x00000400 +#define TXTEXPFORM_ALPHAON 0x00000800 +#define TXTEXPFORM_LITERAL 0x00001000 + + +// Format Registers + + +//------------------------------------------------- +// Destination Blender +//------------------------------------------------- + +// Snoop (0x0048000) +#define DBSNOOP_DESTWRSNOOP 0x00000001 +#define DBSNOOP_SRCRDSNOOP 0x00000002 +#define DBSNOOP_ZWRSNOOP 0x00000004 +#define DBSNOOP_ZRDSNOOP 0x00000008 + +// Supervisor General Control (0x0048004) +#define DBSUPERGENCTL_DESTOUTEN 0x00000001 +#define DBSUPERGENCTL_DESTWR16BEN 0x00000002 +#define DBSUPERGENCTL_ZWR16BEN 0x00000004 + +// User General Control (0x0048008) +#define DBUSERGENCTL_DESTOUT_MASK 0x0000000f +#define DBUSERGENCTL_DITHEREN 0x00000010 +#define DBUSERGENCTL_SRCINEN 0x00000020 +#define DBUSERGENCTL_BLENDEN 0x00000040 +#define DBUSERGENCTL_WCLIPOUTEN 0x00000080 +#define DBUSERGENCTL_WCLIPINEN 0x00000100 +#define DBUSERGENCTL_ZOUTEN 0x00000200 +#define DBUSERGENCTL_ZBUFEN 0x00000400 + +// Discard Control (0x004800C) +#define DBDISCARDCTL_ADISEN 0x00000001 +#define DBDISCARDCTL_RGBDISEN 0x00000002 +#define DBDISCARDCTL_SSBDISEN 0x00000004 +#define DBDISCARDCTL_ZCLIPDISEN 0x00000008 + +// Status (0x0048010) +#define DBSTATUS_ANYREND 0x00000001 +#define DBSTATUS_ZFUNC_GT 0x00000002 +#define DBSTATUS_ZFUNC_EQ 0x00000004 +#define DBSTATUS_ZFUNC_LT 0x00000008 +#define DBSTATUS_ALUSTAT_BLUE_GT 0x00000010 +#define DBSTATUS_ALUSTAT_BLUE_EQ 0x00000020 +#define DBSTATUS_ALUSTAT_BLUE_LT 0x00000040 +#define DBSTATUS_ALUSTAT_GREEN_GT 0x00000080 +#define DBSTATUS_ALUSTAT_GREEN_EQ 0x00000100 +#define DBSTATUS_ALUSTAT_GREEN_LT 0x00000200 +#define DBSTATUS_ALUSTAT_RED_GT 0x00000400 +#define DBSTATUS_ALUSTAT_RED_EQ 0x00000800 +#define DBSTATUS_ALUSTAT_RED_LT 0x00001000 +#define DBSTATUS_ZCLIP 0x00002000 +#define DBSTATUS_WINCLIP 0x00004000 +#define DBSTATUS_FBCLIP 0x00008000 + +// Interrupt Control (0x00048014) +#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 +#define DBINTCNTL_ZFUNCSTATINTEN_MASK 0x00000003 + +// Framebuffer XY Clip Control (0x00048018) +#define DBFBCLIP_YFBCLIP_MASK 0x000007ff +#define DBFBCLIP_YFBCLIP_SHIFT 0 +#define DBFBCLIP_XFBCLIP_MASK 0x07ff0000 +#define DBFBCLIP_XFBCLIP_SHIFT 16 + +// Window X Clip Control (0x0004801C) +#define DBFBXWINCLIP_XMAX_MASK 0x000007ff +#define DBFBXWINCLIP_XMAX_SHIFT 0 +#define DBFBXWINCLIP_XMIN_MASK 0x07ff0000 +#define DBFBXWINCLIP_XMIN_SHIFT 16 + +// Window Y Clip Control (0x00048020) +#define DBFBYWINCLIP_YMAX_MASK 0x000007ff +#define DBFBYWINCLIP_YMAX_SHIFT 0 +#define DBFBYWINCLIP_YMIN_MASK 0x07ff0000 +#define DBFBYWINCLIP_YMIN_SHIFT 16 + +// Destination Write Control (0x0048024) +#define DBDESTCNTL_32BPP 0x00000001 + +// Destination Write Base Address (0x0048028) + +// Destination X Stride (0x004802C) +#define DBDEST_XSTRIDE 0x000007ff + +// Source Read Control (0x00048030) +#define DBSRCCNTL_32BPP 0x00000001 +#define DBSRCCNTL_MSBREP 0x00000002 + +// Source Read Base Address (0x00048034) + +// Source X Stride (0x00048038) +#define DBSRCXSTRIDE 0x000007ff + +// Source XY Offset (0x0004803C) +#define DBSRCOFFS_YOFFS_MASK 0x00000fff +#define DBSRCOFFS_YOFFS_SHIFT 0 +#define DBSRCOFFS_XOFFS_MASK 0x0fff0000 +#define DBSRCOFFS_XOFFS_SHIFT 16 + +// Z Buffer Control (0x00048040) +#define DBZCNTL_ZFUNCCNTL_MASK 0x0000003f +#define DBZCNTL_ZPIXOUT_LT 0x00000001 +#define DBZCNTL_ZBUFOUT_LT 0x00000002 +#define DBZCNTL_ZPIXOUT_EQ 0x00000004 +#define DBZCNTL_ZBUFOUT_EQ 0x00000008 +#define DBZCNTL_ZPIXOUT_GT 0x00000010 +#define DBZCNTL_ZBUFOUT_GT 0x00000020 + +// Z Buffer Base Address (0x00048044) +#define DBZBASEADDR_MASK 0x00ffffff + +// Z Buffer XY Offset (0x00048048) +#define DBZOFFS_YOFFS_MASK 0x00000fff +#define DBZOFFS_YOFFS_SHIFT 0 +#define DBZOFFS_XOFFS_MASK 0x0fff0000 +#define DBZOFFS_XOFFS_SHIFT 16 + +// Z Buffer Clip (0x0004804C) +#define DBZCLIP_YCLIP_MASK 0x000007ff +#define DBZCLIP_YCLIP_SHIFT 0 +#define DBZCLIP_XCLIP_MASK 0x07ff0000 +#define DBZCLIP_XCLIP_SHIFT 16 + +// SSB/DSB Control (0x00048050) +#define DBSSBDSBCNTL_DSBSELECT_MASK 0x00000007 +#define DBSSBDSBCNTL_DSBSELECT_SHIFT 0 +#define DBSSBDSBCNTL_DSBSELECT_SSB 0 +#define DBSSBDSBCNTL_DSBSELECT_CONSTANT 1 +#define DBSSBDSBCNTL_DSBSELECT_SRC 2 + +#define DBSSBDSBCNTL_DSBCONST 0x00000004 + +// RGB constants (0x00048054) +#define DBCONSTIN_B_MASK 0x000000ff +#define DBCONSTIN_B_SHIFT 0 +#define DBCONSTIN_G_MASK 0x0000ff00 +#define DBCONSTIN_G_SHIFT 8 +#define DBCONSTIN_R_MASK 0x00ff0000 +#define DBCONSTIN_R_SHIFT 16 + +// Texture Multiplication Control (0x00048058) +#define DBTXTMULTCNTL_TXTRJUST 0x00000001 +#define DBTXTMULTCNTL_TXTCOEFCMP 0x00000002 + +#define DBTXTMULTCNTL_TXTCONSTCNTL_MASK 0x0000000c +#define DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT 2 +#define DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB 0 +#define DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB 1 + +#define DBTXTMULTCNTL_COEFSEL_MASK 0x00000030 +#define DBTXTMULTCNTL_COEFSEL_SHIFT 4 +#define DBTXTMULTCNTL_COEFSEL_ATI 0 +#define DBTXTMULTCNTL_COEFSEL_ASRC 1 +#define DBTXTMULTCNTL_COEFSEL_CONSTANT 2 +#define DBTXTMULTCNTL_COEFSEL_CSRC 3 + +#define DBTXTMULTCNTL_INSEL_MASK 0x000000c0 +#define DBTXTMULTCNTL_INSEL_SHIFT 6 +#define DBTXTMULTCNTL_INSEL_CTI 0 +#define DBTXTMULTCNTL_INSEL_CONSTANT 1 +#define DBTXTMULTCNTL_INSEL_COMPSRC 2 +#define DBTXTMULTCNTL_INSEL_ATI 3 + +// Source Multiplication Control (0x00048058) +#define DBSRCMULTCNTL_SRCRJUST 0x00000001 +#define DBSRCMULTCNTL_SRCCOEFCMP 0x00000002 + +#define DBSRCMULTCNTL_SRCCONSTCNTL_MASK 0x0000000c +#define DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT 2 +#define DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB 0 +#define DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB 1 + +#define DBSRCMULTCNTL_COEFSEL_MASK 0x00000030 +#define DBSRCMULTCNTL_COEFSEL_SHIFT 4 +#define DBSRCMULTCNTL_COEFSEL_ATI 0 +#define DBSRCMULTCNTL_COEFSEL_ASRC 1 +#define DBSRCMULTCNTL_COEFSEL_CONSTANT 2 +#define DBSRCMULTCNTL_COEFSEL_CTI 3 + +#define DBSRCMULTCNTL_INSEL_MASK 0x000000c0 +#define DBSRCMULTCNTL_INSEL_SHIFT 6 +#define DBSRCMULTCNTL_INSEL_SRC 0 +#define DBSRCMULTCNTL_INSEL_CONSTANT 1 +#define DBSRCMULTCNTL_INSEL_COMPCTI 2 +#define DBSRCMULTCNTL_INSEL_TEXALPHA 3 + +// ALU Control (0x00048070) TODO +#define DBALUCNTL_FINALDIVIDE_MASK 0x00000007 +#define DBALUCNTL_FINALDIVIDE_SHIFT 0 + +#define DBALUCNTL_ALUOP_MASK 0x000000f8 +#define DBALUCNTL_ALUOP_SHIFT 5 + +// Source Alpha Control (0x00048074) +#define DBDSTACNTL_ADESTSEL_MASK 0x00000003 +#define DBDSTACNTL_ADESTSEL_SHIFT 0 +#define DBDSTACNTL_ADESTCONSTCNTL_MASK 0x0000000c +#define DBDSTACNTL_ADESTCONSTCNTL_SHIFT 2 + +#define DBDSTALPHACONST_CONST1_MASK 0x000000ff +#define DBDSTALPHACONST_CONST1_SHIFT 0 +#define DBDSTALPHACONST_CONST0_MASK 0x00ff0000 +#define DBDSTALPHACONST_CONST0_SHIFT 16 + +#define DBSSBDSBCNTL_DSBSEL_MASK 0x00000003 +#define DBSSBDSBCNTL_DSBSEL_SHIFT 0 +#define DBSSBDSBCNTL_DSBCONST_MASK 0x00000004 +#define DBSSBDSBCNTL_DSBCONST_SHIFT 2 + + + +//************************************************************************** +// SUPPORT FUNCTIONS +//************************************************************************** + +static inline float int_trunc(float x) +{ + return (float)(int)x; +} + +static inline uint8_t extract_exp(float x) +{ + uint32_t u32 = *reinterpret_cast(&x); + return (u32 >> 23) & 0xff; +} + +// Convert a regular float to sign-magnitude fixed point +static int32_t ieee754_to_tefix(float f, int32_t bits) +{ + float format = powf(2.0f, bits); + float tmp1 = format * 2.0f; + + // Check to see if number is within range + float tmp2 = fmodf(fabsf(f), tmp1); + float tmp3 = (tmp2 >= format) ? tmp2 : tmp2 + format; + + // Extract the result + uint32_t res = *reinterpret_cast(&tmp3) & 0x007fffff; + + // What is this? + if (tmp2 >= format || tmp3 == tmp1) + res |= 0x00800000; + + // Negate + if (f < 0.0f) + res = -res; + + return res; +} + +static void write_te_reg(uint32_t ®, uint32_t data, m2_te_device::te_reg_wmode mode) +{ + switch (mode) + { + case REG_WRITE: + { + reg = data; + break; + } + case REG_SET: + { + reg |= data; + break; + } + case REG_CLEAR: + { + reg &= ~data; + break; + } + default: + assert_always(false, "Bad register write mode"); + } +} + +#if 0 +static const char *get_reg_name(uint32_t unit, uint32_t reg) +{ + static const char *gc_regs[] = + { + "TEMasterMode", + "Reserved", + "TEICntlData", + "TEICntl", + "TEDCntlData", + "TEDCntl", + "IWP", + "IRP", + "IntEn", + "IntStat", + "Vertex Control", + }; + + static const char *db_regs[] = + { + "Snoop", + "SuperGenControl", + "usergen_ctrl", + "Discard Control", + "Status", + "Int Cntl", + "FBClip", + "XWinClip", + "YWinClip", + "DestCntl", + "DestBaseAddr", + "DestXStride", + "SrcCntl", + "SrcBaseAddr", + "SrcXStride", + "SrcOffset", + "ZCntl", + "ZBaseAddr", + "ZOffset", + "ZClip", + "SSBDSBCntl", + "ConstIn", + "DBTXTMULTCNTL", + "TxtCoefConst0", + "TxtCoefConst1", + "src_mult_cntl", + "SrcCoefConst0", + "SrcCoefConst1", + "src_mult_cntl", + "SrcCoefconst0", + "SrcCoefconst1", + "ALUCntl", + "SrcAlphaCntl", + "DestAlphaCntl", + "DestAlphaConst", + "DitherMatA", + "DitherMatB", + }; + + static const char *es_regs[] = + { + "ESCntl", + "ESCapAddr", + "ESCapData", + }; + + static char buffer[128]; + + switch (unit) + { + case 0: + { + if (reg < sizeof(gc_regs)) + { + sprintf(buffer, "GC:%s", gc_regs[reg]); + return buffer; + } + break; + } + case 1: + { + sprintf(buffer, "SE:????"); + return buffer; + } + case 2: + { + if (reg < sizeof(es_regs)) + { + sprintf(buffer, "ES:%s", es_regs[reg]); + return buffer; + } + break; + } + case 3: + { +// if (reg < sizeof(tm_regs)) + { + sprintf(buffer, "TM:????"); + return buffer; + } + break; + } + case 4: + { + if (reg < sizeof(db_regs)) + { + sprintf(buffer, "DB:%s", db_regs[reg]); + return buffer; + } + break; + } + } + + return "????"; +} +#endif +//************************************************************************** +// TRIANGLE ENGINE DEVICE +//************************************************************************** + +//------------------------------------------------- +// m2_te_device - constructor +//------------------------------------------------- + +m2_te_device::m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, M2_TE, tag, owner, clock), + m_general_int_handler(*this), + m_dfinstr_int_handler(*this), + m_iminstr_int_handler(*this), + m_listend_int_handler(*this), + m_winclip_int_handler(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void m2_te_device::device_start() +{ + // Find our parent + m_bda = downcast(owner()); + + // Resolve callbacks + m_general_int_handler.resolve_safe(); + m_dfinstr_int_handler.resolve_safe(); + m_iminstr_int_handler.resolve_safe(); + m_listend_int_handler.resolve_safe(); + m_winclip_int_handler.resolve_safe(); + + // Allocate texture RAM + m_tram = auto_alloc_array(machine(), uint32_t, TEXTURE_RAM_WORDS); + + // Allocate PIP RAM + m_pipram = auto_alloc_array(machine(), uint32_t, PIP_RAM_WORDS); + + // TODO + memset(&m_gc, 0, sizeof(m_gc)); + memset(&m_se, 0, sizeof(m_se)); + memset(&m_es, 0, sizeof(m_es)); + memset(&m_tm, 0, sizeof(m_tm)); + memset(&m_db, 0, sizeof(m_db)); + + + // Register state for saving + save_pointer(NAME(m_tram), TEXTURE_RAM_WORDS); + save_pointer(NAME(m_pipram), PIP_RAM_WORDS); + + save_item(NAME(m_gc.m_regs)); + save_item(NAME(m_se.m_regs)); + save_item(NAME(m_es.m_regs)); + save_item(NAME(m_tm.m_regs)); + save_item(NAME(m_db.m_regs)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void m2_te_device::device_reset() +{ + m_state = TE_STOPPED; + + // TODO +} + + +//------------------------------------------------- +// device_post_load - device-specific post-load +//------------------------------------------------- + +void m2_te_device::device_post_load() +{ + +} + + + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + +READ32_MEMBER( m2_te_device::read ) +{ + uint32_t unit = (offset >> 11) & 7; + uint32_t reg = offset & 0x1ff; + + logerror("%s: TE R[%x]\n", machine().describe_context(), 0x00040000 + (offset << 2)); + + switch (unit) + { + case 0: + { + if (reg < sizeof(m_gc) / 4) + return m_gc.m_regs[reg]; + + break; + } + case 1: + { + if (reg < sizeof(m_se) / 4) + return m_se.m_regs[reg]; + + break; + } + case 2: + { + if (reg < sizeof(m_es) / 4) + return m_es.m_regs[reg]; + + break; + } + case 3: + { + if (reg < 0x400/4) + { + return m_pipram[reg]; + } + else if ((reg - 0x400) < sizeof(m_tm) / 4) + { + return m_tm.m_regs[reg]; + } + + break; + } + case 4: + { + if (reg < sizeof(m_db) / 4) + return m_db.m_regs[reg]; + + break; + } + } + + logerror("%s: Unknown TE register read from %d:[%x]", machine().describe_context(), unit, reg); + return 0; +} + +WRITE32_MEMBER( m2_te_device::write ) +{ + uint32_t unit = (offset >> 11) & 7; + uint32_t reg = offset & 0x1ff; + te_reg_wmode wmode = static_cast((offset >> 9) & 3); + +// logerror("%s: TE W[%.8x] (%s) %.8x\n", machine().describe_context(), 0x00040000 + (offset << 2), get_reg_name(unit, reg), data); + + switch (unit) + { + case 0: + { + switch (reg) + { + case 0: + { + master_mode_w(data, wmode); + return; + } + case 0x0c/4: + { + teicntl_w(data, wmode); + return; + } + case 0x14/4: + { + tedcntl_w(data, wmode); + return; + } + case 0x24/4: + { + write_te_reg(m_gc.int_status, data, wmode); + update_interrupts(); + return; + } + default: + { + if (reg < sizeof(m_gc) / 4) + { + write_te_reg(m_gc.m_regs[reg], data, wmode); + return; + } + } + } + break; + } + case 1: + { + if (reg < sizeof(m_se) / 4) + { + write_te_reg(m_se.m_regs[reg], data, wmode); + return; + } + break; + } + case 2: + { + if (reg < sizeof(m_es) / 4) + { + write_te_reg(m_es.m_regs[reg], data, wmode); + return; + } + break; + } + case 3: + { + if (reg < 0x400 / 4) + { + m_pipram[reg] = data; + return; + } + else if ((reg - 0x400 / 4) < sizeof(m_tm) / 4) + { + write_te_reg(m_tm.m_regs[reg - 0x400 / 4], data, wmode); + return; + } + break; + } + case 4: + { + if (reg < sizeof(m_db) / 4) + { + write_te_reg(m_db.m_regs[reg], data, wmode); + return; + } + break; + } + } + + logerror("%s: Unknown TE register write to %d:[%x] with %x\n", machine().describe_context(), unit, reg, data); +} + + + +/*************************************************************************** + PRIVATE FUNCTIONS +***************************************************************************/ + +/*************************************************************************** + INTERRUPTS +***************************************************************************/ + +//------------------------------------------------- +// set_interrupt - +//------------------------------------------------- + +void m2_te_device::set_interrupt(uint32_t mask) +{ + m_gc.int_status |= mask; + update_interrupts(); +} + + +//------------------------------------------------- +// update_interrupts - +//------------------------------------------------- + +void m2_te_device::update_interrupts() +{ + bool gen_int = ((m_gc.int_status & m_gc.int_enable) & 0x0000ff00) != 0; + + // TODO: ALU status and FB clip are controlled by dest blender + m_general_int_handler(gen_int); + + // From DBL (Page 265) + // FBClip + // WinClip + // ZClip + // ALUStat + // ZFuncStat + + // Page 43 + + // PAGE 26 + m_dfinstr_int_handler((m_gc.int_status >> 8) & 1); + m_iminstr_int_handler((m_gc.int_status >> 9) & 1); + m_listend_int_handler((m_gc.int_status >> 10) & 1); + m_winclip_int_handler((m_gc.int_status >> 11) & 1); +} + + + +/*************************************************************************** + SPECIAL REGISTER WRITES +***************************************************************************/ + +//------------------------------------------------- +// master_mode_w - +//------------------------------------------------- + +void m2_te_device::master_mode_w(uint32_t data, te_reg_wmode wmode) +{ + write_te_reg(m_gc.te_master_mode, data, wmode); + + if (m_gc.te_master_mode & TEMASTER_MODE_RESET) + device_reset(); +} + + +//------------------------------------------------- +// teicntl_w - +//------------------------------------------------- + +void m2_te_device::teicntl_w(uint32_t data, te_reg_wmode wmode) +{ + uint32_t newreg = 0; + + write_te_reg(newreg, data, wmode); + write_te_reg(m_gc.te_master_mode, data, wmode); + + if (newreg & TEICNTL_STRT) + { + m_gc.irp = m_gc.teicntl_data; + m_state = TE_RUNNING; + execute(); + } + else if (newreg & TEICNTL_RSTRT) + { + m_state = TE_RUNNING; + execute(); + } +} + + +//------------------------------------------------- +// tedcntl_w - +//------------------------------------------------- + +void m2_te_device::tedcntl_w(uint32_t data, te_reg_wmode wmode) +{ + write_te_reg(m_gc.tedcntl, data, wmode); + + if (m_gc.tedcntl & TEDCNTL_SYNC) + { + // TODO + } + else if (m_gc.tedcntl & TEDCNTL_PSE) + { + m_state = TE_PAUSED; + } + else if (m_gc.tedcntl & TEDCNTL_INT) + { + set_interrupt(INTSTAT_IMMEDIATE); + } + else if (m_gc.tedcntl & TEDCNTL_JR) + { + m_gc.irp += m_gc.tedcntl_data; + } + else if (m_gc.tedcntl & TEDCNTL_JA) + { + m_gc.irp = m_gc.tedcntl_data; + } + else if (m_gc.tedcntl & TEDCNTL_TLD) + { + load_texture(); + } +} + + + +/*************************************************************************** + VERTEX PROCESSING +***************************************************************************/ + +//------------------------------------------------- +// add_vertex - +//------------------------------------------------- + +void m2_te_device::add_vertex(const se_vtx &vtx, uint32_t flags) +{ + uint32_t tsort; + uint32_t vcnt; + + if (flags & VTX_FLAG_NEW) + { + // Reset state for a new triangle + tsort = 0; + vcnt = 0; + } + else + { + // Continue current triangle + tsort = m_se.vertex_state & VERTEXSTATE_TSORT_MASK; + vcnt = (m_se.vertex_state & VERTEXSTATE_VCNT_MASK) >> VERTEXSTATE_VCNT_SHIFT; + } + + if (vcnt < 3) + { + // Add vertex to incomplete triangle + m_se.vertices[vcnt++] = vtx; + + // Are we now complete? + if (vcnt == 3) + tsort = VERTEXSTATE_TSORT_OMN; + } + else + { + // Replace an existing vertex + if (flags & VTX_FLAG_RM) + { + // Triangle fan mode + switch (tsort) + { + case VERTEXSTATE_TSORT_OMN: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break; + case VERTEXSTATE_TSORT_MNO: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break; + case VERTEXSTATE_TSORT_ONM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break; + case VERTEXSTATE_TSORT_NOM: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break; + case VERTEXSTATE_TSORT_MON: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break; + case VERTEXSTATE_TSORT_NMO: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break; + } + } + else + { + // Triangle strip mode + switch (tsort) + { + case VERTEXSTATE_TSORT_OMN: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NOM; break; + case VERTEXSTATE_TSORT_MNO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_OMN; break; + case VERTEXSTATE_TSORT_ONM: m_se.vertices[0] = vtx; tsort = VERTEXSTATE_TSORT_NMO; break; + case VERTEXSTATE_TSORT_NOM: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_MNO; break; + case VERTEXSTATE_TSORT_MON: m_se.vertices[1] = vtx; tsort = VERTEXSTATE_TSORT_ONM; break; + case VERTEXSTATE_TSORT_NMO: m_se.vertices[2] = vtx; tsort = VERTEXSTATE_TSORT_MON; break; + } + } + + } + + // Update fields + m_se.vertex_state = (vcnt << VERTEXSTATE_VCNT_SHIFT) | tsort; + + // Do we have three valid vertices? + if (vcnt == 3) + { + // Send the triangle to the setup engine + setup_triangle(flags); + } +} + + +//------------------------------------------------- +// calculate_slope - +//------------------------------------------------- + +void m2_te_device::calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out) +{ + float detx = q1 * sp.y23 + q2 * sp.y31 + q3 * sp.y12; + float dety = q1 * sp.x23 + q2 * sp.x31 + q3 * sp.x12; + float detxy = sp.xstep_long * detx - dety; + + slope_out = detxy * sp.iAria; + ddx_out = detx * sp.iAria; +} + + +//------------------------------------------------- +// log_triangle - +//------------------------------------------------- + +void m2_te_device::log_triangle(uint32_t flags) +{ + logerror("[Triangle]\n"); + + for (uint32_t i = 0; i < 3; ++i) + { + char s[64]; + char t[64]; + char p[64]; + + s[0] = '\0'; + t[0] = '\0'; + p[0] = '\0'; + + const se_vtx &vtx = m_se.vertices[i]; + + if (flags & VTX_FLAG_SHAD) + sprintf(s, "COLR[R:%.6f G:%.6f B:%.6f A:%.6f]", vtx.r, vtx.g, vtx.b, vtx.a); + + if (flags & VTX_FLAG_TEXT) + sprintf(t, "TEXT[UW:%.6f VW:%.6f]", vtx.uw, vtx.vw); + + if (flags & VTX_FLAG_PRSP) + sprintf(p, "PRSP[W:%.6f]", vtx.w); + + logerror("V%d: X:%.6f Y:%.6f %s %s %s\n", i, vtx.x, vtx.y, s, t, p); + } +} + + +//------------------------------------------------- +// setup_triangle - +//------------------------------------------------- + +void m2_te_device::setup_triangle(uint32_t flags) +{ +// log_triangle(flags); + + se_vtx va = m_se.vertices[0]; + se_vtx vb = m_se.vertices[1]; + se_vtx vc = m_se.vertices[2]; + + // Truncate XY coordinates to integers + va.x = int_trunc(va.x); + vb.x = int_trunc(vb.x); + vc.x = int_trunc(vc.x); + + va.y = int_trunc(va.y); + vb.y = int_trunc(vb.y); + vc.y = int_trunc(vc.y); + + + // Scale and truncate colors + if (flags & VTX_FLAG_SHAD) + { + va.r = int_trunc(va.r * 255.0f); + va.g = int_trunc(va.g * 255.0f); + va.b = int_trunc(va.b * 255.0f); + va.a = int_trunc(va.a * 255.0f); + + vb.r = int_trunc(vb.r * 255.0f); + vb.g = int_trunc(vb.g * 255.0f); + vb.b = int_trunc(vb.b * 255.0f); + vb.a = int_trunc(vb.a * 255.0f); + + vc.r = int_trunc(vc.r * 255.0f); + vc.g = int_trunc(vc.g * 255.0f); + vc.b = int_trunc(vc.b * 255.0f); + vc.a = int_trunc(vc.a * 255.0f); + } + + // Sort the vertices into top, middle and bottom + uint32_t a = 0; + + if ((va.y - vb.y) < 0.0f) a |= 4; + if ((vb.y - vc.y) < 0.0f) a |= 2; + if ((vc.y - va.y) < 0.0f) a |= 1; + + const se_vtx *v1 = NULL; + const se_vtx *v2 = NULL; + const se_vtx *v3 = NULL; + + switch (a) + { + case 1: v1 = &vc; v2 = &vb; v3 = &va; break; + case 2: v1 = &vb; v2 = &va; v3 = &vc; break; + case 3: v1 = &vb; v2 = &vc; v3 = &va; break; + case 4: v1 = &va; v2 = &vc; v3 = &vb; break; + case 5: v1 = &vc; v2 = &va; v3 = &vb; break; + case 6: v1 = &va; v2 = &vb; v3 = &vc; break; + default: + return; // Reject degenerates + } + + + // Determine the W range for depth and texture values + uint32_t wrange = 0; + + if (flags & VTX_FLAG_PRSP) + { + const uint8_t exp_zero = 0x7f; + const uint8_t wexp0 = exp_zero - 3; + const uint8_t wexp1 = exp_zero - 6; + const uint8_t wexp2 = exp_zero - 9; + + uint8_t w1exp = extract_exp(v1->w); + uint8_t w2exp = extract_exp(v2->w); + uint8_t w3exp = extract_exp(v3->w); + + if (w1exp >= wexp0 || w2exp >= wexp0 || w3exp >= wexp0) + wrange = 0; + else if (w1exp >= wexp1 || w2exp >= wexp1 || w3exp >= wexp1) + wrange = 1; + else if (w1exp >= wexp2 || w2exp >= wexp2 || w3exp >= wexp2) + wrange = 2; + else + wrange = 3; + } + + // Calculate the coordinate deltas + float x12 = v1->x - v2->x; + float x23 = v2->x - v3->x; + float x31 = v3->x - v1->x; + float y12 = v1->y - v2->y; + float y23 = v2->y - v3->y; + float y31 = v3->y - v1->y; + + // Calculate the triangle area + float aria = v1->x * y23 + v2->x * y31 + v3->x * y12; + + // Reject degenerates + if (aria == 0.0f) + return; + + float iaria = 1.0f / aria; + + // Determine scan direction + bool scan_lr = aria > 0.0f; + + // Calculate vertex slopes + float abs_y12 = fabs(y12); + float abs_y23 = fabs(y23); + float abs_y31 = fabs(y31); + + + // Avoid division by zero + float xslope_0 = (abs_y12 > 0.0f) ? (-x12 / abs_y12) : 0.0f; + float xslope_1 = (abs_y23 > 0.0f) ? (-x23 / abs_y23) : 0.0f; + float xslope_long = (abs_y31 > 0.0f) ? (x31 / abs_y31) : 0.0f; + + + // Calculate x steps + float xstep_long; + float xstep_0; + float xstep_1; + + if (scan_lr) + { + xstep_long = floor(xslope_long); + xstep_0 = ceil(xslope_0); + xstep_1 = ceil(xslope_1); + } + else + { + xstep_long = ceil(xslope_long); + xstep_0 = floor(xslope_0); + xstep_1 = floor(xslope_1); + } + + float xystep_0 = x12 - xstep_0 * y12; + float xystep_1 = x23 - xstep_1 * y23; + float xystep_long = x31 - xstep_long * y31; + + float dy_0 = -y12; + float dy_1 = -y23; + float dy_long = -y31; + + + // Calculate color and texture slopes + slope_params sparams = { y23, y31, y12, x23, x31, x12, xstep_long, iaria }; + + float r_slope = 0.0f, r_ddx = 0.0f; + float g_slope = 0.0f, g_ddx = 0.0f; + float b_slope = 0.0f, b_ddx = 0.0f; + float a_slope = 0.0f, a_ddx = 0.0f; + float w_slope = 0.0f, w_ddx = 0.0f; + float uw_slope = 0.0f, uw_ddx = 0.0f; + float vw_slope = 0.0f, vw_ddx = 0.0f; + + if (flags & VTX_FLAG_SHAD) + { + calculate_slope(sparams, v1->r, v2->r, v3->r, r_slope, r_ddx); + calculate_slope(sparams, v1->g, v2->g, v3->g, g_slope, g_ddx); + calculate_slope(sparams, v1->b, v2->b, v3->b, b_slope, b_ddx); + calculate_slope(sparams, v1->a, v2->a, v3->a, a_slope, a_ddx); + } + + if (flags & VTX_FLAG_TEXT) + { + calculate_slope(sparams, v1->uw, v2->uw, v3->uw, uw_slope, uw_ddx); + calculate_slope(sparams, v1->vw, v2->vw, v3->vw, vw_slope, vw_ddx); + } + + if (flags & VTX_FLAG_PRSP) + { + calculate_slope(sparams, v1->w, v2->w, v3->w, w_slope, w_ddx); + } + + const uint32_t textbits = text_bits[wrange]; + const uint32_t depthbits = depth_bits[wrange]; + + // Convert everything to fixed point and pass to the edge walker + + /* + NOT SURE THESE ARE RIGHT. See P209 + + XY 12.0 + SL s12.0 + RGBA 9.0 + RGBA SLOPES = s9.11 + TEX: 11.13 + DEPTH: 1.23 + TEX SLOPES: s11.13 + DEPTH SLOPES: s1.23 + AREA : s23.0 + + Numbers output to the edge walker are 24 bits + + IEE: 1.8.23 + BDA: 1.7.24 (includes hidden bit) + + However, we're using 23 bits. + */ + + + // XY: 0000 0000 0iii iiii iiii 0000 0000 0000 + // Colors: 0000 0000 0iii iiii ifff ffff ffff 0000 + // UV: + // W: 0000 0000 0iii iiii iiii iiii iiii iiii + + + // Converted numbers are left-aligned into the mantissa + // However, we want them right-aligned for convenience + // TODO: Is there a better way to do this? + m_es.x1 = ieee754_to_tefix(v1->x, xy_bits) >> xy_rshift; + m_es.y1 = ieee754_to_tefix(v1->y, xy_bits) >> xy_rshift; + m_es.x2 = ieee754_to_tefix(v2->x, xy_bits) >> xy_rshift; + m_es.y2 = ieee754_to_tefix(v2->y, xy_bits) >> xy_rshift; + m_es.y3 = ieee754_to_tefix(v3->y, xy_bits) >> xy_rshift; + + m_es.xstep_0 = ieee754_to_tefix(xstep_0, xy_bits) >> xy_rshift; + m_es.xstep_1 = ieee754_to_tefix(xstep_1, xy_bits) >> xy_rshift; + m_es.xstep_long = ieee754_to_tefix(xstep_long, xy_bits) >> xy_rshift; + m_es.xystep_0 = ieee754_to_tefix(xystep_0, xy_bits) >> xy_rshift; + m_es.xystep_1 = ieee754_to_tefix(xystep_1, xy_bits) >> xy_rshift; + m_es.xystep_long = ieee754_to_tefix(xystep_long, xy_bits) >> xy_rshift; + m_es.dy_0 = ieee754_to_tefix(dy_0, xy_bits) >> xy_rshift; + m_es.dy_1 = ieee754_to_tefix(dy_1, xy_bits) >> xy_rshift; + m_es.dy_long = ieee754_to_tefix(dy_long, xy_bits) >> xy_rshift; + + m_es.r1 = ieee754_to_tefix(v1->r, color_bits) >> color_rshift; + m_es.g1 = ieee754_to_tefix(v1->g, color_bits) >> color_rshift; + m_es.b1 = ieee754_to_tefix(v1->b, color_bits) >> color_rshift; + m_es.a1 = ieee754_to_tefix(v1->a, color_bits) >> color_rshift; + m_es.ddx_r = ieee754_to_tefix(r_ddx, color_bits) >> color_rshift; + m_es.ddx_g = ieee754_to_tefix(g_ddx, color_bits) >> color_rshift; + m_es.ddx_b = ieee754_to_tefix(b_ddx, color_bits) >> color_rshift; + m_es.ddx_a = ieee754_to_tefix(a_ddx, color_bits) >> color_rshift; + m_es.slope_r = ieee754_to_tefix(r_slope, color_bits) >> color_rshift; + m_es.slope_g = ieee754_to_tefix(g_slope, color_bits) >> color_rshift; + m_es.slope_b = ieee754_to_tefix(b_slope, color_bits) >> color_rshift; + m_es.slope_a = ieee754_to_tefix(a_slope, color_bits) >> color_rshift; + + // No need to shift these + m_es.uw1 = ieee754_to_tefix(v1->uw, textbits); + m_es.vw1 = ieee754_to_tefix(v1->vw, textbits); + m_es.w1 = ieee754_to_tefix(v1->w, depthbits); + m_es.ddx_uw = ieee754_to_tefix(uw_ddx, textbits); + m_es.ddx_vw = ieee754_to_tefix(vw_ddx, textbits); + m_es.ddx_w = ieee754_to_tefix(w_ddx, depthbits); + m_es.slope_uw = ieee754_to_tefix(uw_slope, textbits); + m_es.slope_vw = ieee754_to_tefix(vw_slope, textbits); + m_es.slope_w = ieee754_to_tefix(w_slope, depthbits); + + m_es.r2l = !scan_lr; + +#if TEST_TIMING + g_statistics[STAT_TRIANGLES_PROCESSED]++; +#endif + + // Proceed to walk the edges + walk_edges(wrange); +} + +static inline bool ins(bool lr, int32_t v) +{ + return lr ? v <= 0 : v >= 0; +} + +static inline bool ein(bool lr, int32_t v) +{ + return lr ? v < 0 : v > 0; +} + +static const uint8_t m_nr_rom[128] = +{ + 127, 125, 123, 121, 119, 118, + 116, 114, 112, 110, 109, 107, + 105, 104, 102, 100, 99, 97, + 96, 94, 93, 91, 90, 88, + 87, 86, 84, 83, 81, 80, + 79, 78, 76, 75, 74, 73, + 71, 70, 69, 68, 67, 65, + 64, 63, 62, 61, 60, 59, + 58, 57, 56, 55, 54, 53, + 52, 51, 50, 49, 48, 47, + 46, 45, 44, 43, 42, 41, + 40, 40, 39, 38, 37, 36, + 35, 35, 34, 33, 32, 31, + 31, 30, 29, 28, 28, 27, + 26, 25, 25, 24, 23, 23, + 22, 21, 21,20, 19, 19, + 18, 17, 17, 16, 15, 15, + 14, 13, 13, 12, 12, 11, + 11, 10, 9, 9, 8, 8, + 7, 7, 6, 5, 5, 4, + 4, 3, 3, 2, 2, 1, + 1, 0 +}; + + +//------------------------------------------------- +// nr_invert - Newton Rhapson reciprocal +//------------------------------------------------- + +uint32_t nr_invert(uint32_t num, uint32_t & shift_amount) +{ + uint32_t original; + uint32_t first_guess; + uint32_t m; + uint32_t shfnum; + + // TODO: Unconfirmed but seems sensible + if (num == 0) + { + shift_amount = 0; + return 0; + } + + shift_amount = -1; + while ((num << ++shift_amount) < 0x800000); + + shfnum = num << shift_amount; + original = shfnum >> 8; + first_guess = m_nr_rom[(shfnum >> 16) & ((1 << 7) - 1)]; + first_guess = first_guess + 128; + m = first_guess * original; + m = (1 << 24) - m; + m = m >> 3; + m = first_guess * m; + m = m >> 8; + + return m; +} + + +//------------------------------------------------- +// clamp - +//------------------------------------------------- + +uint32_t clamp(int32_t v, int32_t min, int32_t max) +{ + if (v < min) + return min; + else if (v > max) + return max; + + return v; +} + + +//------------------------------------------------- +// walk_edges - +//------------------------------------------------- + +void m2_te_device::walk_edges(uint32_t wrange) +{ + bool dsp_off = m_es.es_cntl & ESCNTL_DSPOFF; + bool du_scan = m_es.es_cntl & ESCNTL_DUSCAN; + bool omit_right = true; + bool scan_lr = m_es.r2l == false; + + uint32_t cf_long = 0; + uint32_t cf_short = 0; + uint32_t xystep; + uint32_t xstep; + uint32_t dy; + uint32_t xs; + uint32_t xe; + + int32_t r, g, b, a; + int32_t uw, vw; + int32_t w; + + // Determine starting values + uint32_t y = m_es.y1; + + // Flat-top triangles are a special case + if (m_es.y1 == m_es.y2) + { + xystep = m_es.xystep_1; + xstep = m_es.xstep_1; + dy = m_es.dy_1; + + if (scan_lr ^ (m_es.x1 < m_es.x2)) + { + // TODO: Is this possible? + assert_always(false, "SPECIAL CASE: WHAT DO?"); + r = m_es.r1; // Where do the colors come from? + g = m_es.g1; + b = m_es.b1; + a = m_es.a1; + uw = m_es.uw1; + vw = m_es.vw1; + w = m_es.w1; + + xs = m_es.x2; + xe = m_es.x1; + } + else + { + r = m_es.r1; + g = m_es.g1; + b = m_es.b1; + a = m_es.a1; + uw = m_es.uw1; + vw = m_es.vw1; + w = m_es.w1; + + xs = m_es.x1; + xe = m_es.x2; + } + } + else + { + // Regular triangles + xystep = m_es.xystep_0; + xstep = m_es.xstep_0; + dy = m_es.dy_0; + r = m_es.r1; + g = m_es.g1; + b = m_es.b1; + a = m_es.a1; + uw = m_es.uw1; + vw = m_es.vw1; + w = m_es.w1; + + xs = m_es.x1; + xe = xs; + } + + do + { + // Render the pixels from this span + walk_span(wrange, omit_right, y, xs, xe, r, g, b, a, uw, vw, w); + + // Now update the values + omit_right = false; + cf_short += xystep; + cf_long += m_es.xystep_long; + + bool step_back = false; + + if (scan_lr) + { + xs += m_es.xstep_long; + xe += xstep; + + if (!ins(scan_lr, cf_long)) + { + step_back = true; + cf_long += m_es.dy_long; + xs += xy_one; + } + + if (dsp_off ? !ins(scan_lr, cf_short) : !ein(scan_lr, cf_short)) + { + cf_short -= dy; + xe -= xy_one; + } + } + else + { + xe += xstep; + xs += m_es.xstep_long; + + if (!ins(scan_lr, cf_short)) + { + cf_short += dy; + xe += xy_one; + } + + if (dsp_off ? !ins(scan_lr, cf_long) : !ein(scan_lr, cf_long)) + { + step_back = true; + cf_long -= m_es.dy_long; + xs -= xy_one; + } + } + + // Update the color values + if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE)) + { + if (scan_lr) + { + r += step_back ? m_es.slope_r + m_es.ddx_r : m_es.slope_r; + g += step_back ? m_es.slope_g + m_es.ddx_g : m_es.slope_g; + b += step_back ? m_es.slope_b + m_es.ddx_b : m_es.slope_b; + a += step_back ? m_es.slope_a + m_es.ddx_a : m_es.slope_a; + } + else + { + r += step_back ? m_es.slope_r - m_es.ddx_r : m_es.slope_r; + g += step_back ? m_es.slope_g - m_es.ddx_g : m_es.slope_g; + b += step_back ? m_es.slope_b - m_es.ddx_b : m_es.slope_b; + a += step_back ? m_es.slope_a - m_es.ddx_a : m_es.slope_a; + } + + // Clamp to 8.11 + r = clamp(r, 0, 0x0007ffff); + g = clamp(g, 0, 0x0007ffff); + b = clamp(b, 0, 0x0007ffff); + a = clamp(a, 0, 0x0007ffff); + } + + if (!(m_es.es_cntl & TEMASTER_MODE_DTEXT)) + { + if (scan_lr) + { + uw += step_back ? m_es.slope_uw + m_es.ddx_uw : m_es.slope_uw; + vw += step_back ? m_es.slope_vw + m_es.ddx_vw : m_es.slope_vw; + } + else + { + uw += step_back ? m_es.slope_uw - m_es.ddx_uw : m_es.slope_uw; + vw += step_back ? m_es.slope_vw - m_es.ddx_vw : m_es.slope_vw; + } + + // Clamp to 10.13 + uw = clamp(uw, 0, 0x007fffff); + vw = clamp(vw, 0, 0x007fffff); + } + + if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF)) + { + if (scan_lr) + w += step_back ? m_es.slope_w + m_es.ddx_w : m_es.slope_w; + else + w += step_back ? m_es.slope_w - m_es.ddx_w : m_es.slope_w; + + // Clamp to 0.23 + w = clamp(w, 0, 0x007fffff); + } + + // Update Y + uint32_t next_y = y + (du_scan ? -xy_one : xy_one); + + if (next_y == m_es.y2) + { + cf_short = 0; + xystep = m_es.xystep_1; + xstep = m_es.xstep_1; + dy = m_es.dy_1; + xe = m_es.x2; + + if (scan_lr) + omit_right = true; + } + + y = next_y; + + } while (y != m_es.y3); +} + + + +//------------------------------------------------- +// texcoord_gen - +//------------------------------------------------- + +void m2_te_device::texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w, + uint32_t & uo, uint32_t & vo, uint32_t & wo) +{ + + // Perspective correction + if (!(m_es.es_cntl & ESCNTL_PERSPECTIVEOFF)) + { + uint32_t wshift; + + // Calculate the inverse of 1/w. Output is 0.20 + uint32_t winv = nr_invert(w, wshift); + + // 10.13 normalize then reduce to 10.6 + // Normalization occurs by detecting leading zeroes and + // left-shifting until 1 in MSB + + uint32_t uwshift = 0; + uint32_t vwshift = 0; + + while ((uw < 0x00400000) && uwshift < 7) + { + uw <<= 1; + ++uwshift; + } + + while ((vw < 0x00400000) && vwshift < 7) + { + vw <<= 1; + ++vwshift; + } + + uint32_t normalized_uw = uw >> 7; + uint32_t normalized_vw = vw >> 7; + + // 10.6 * 0.20 = 10.26 + uint64_t ur = (uint64_t)normalized_uw * winv; + uint64_t vr = (uint64_t)normalized_vw * winv; + + // De-normalize + if (uwshift > wshift) + ur >>= (uwshift - wshift); + else + ur <<= (wshift - uwshift); + + if (vwshift > wshift) + vr >>= (vwshift - wshift); + else + vr <<= (wshift - vwshift); + + // Reduce from 10.26 to 10.6 + uo = ur >> 20; + vo = vr >> 20; + } + else + { + // Reduce from 10.13 to 10.6 + // TODO: Is this actually correct? + uo = uw >> (7 + (10 - text_bits[wrange])); + vo = vw >> (7 + (10 - text_bits[wrange])); + } + + // Output to texture mapper is 10.4 + uo = uo >> 2; + vo = vo >> 2; +} + + +//------------------------------------------------- +// lod_calc - +//------------------------------------------------- + +uint32_t m2_te_device::lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1) +{ + return 0; +} + + +//------------------------------------------------- +// get_tram_bitdepth +//------------------------------------------------- + +uint32_t m2_te_device::get_tram_bitdepth() +{ + // TODO: Could cache this + const uint32_t tex_type = m_tm.tex_exptype; + + uint32_t bitdepth = 0; + + if (tex_type & TXTEXPFORM_COLORON) + bitdepth += (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; + if (tex_type & TXTEXPFORM_ALPHAON) + bitdepth += (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; + if (tex_type & TXTEXPFORM_SSBON) + ++bitdepth; + + return bitdepth; +} + + +//------------------------------------------------- +// get_texture_color - +//------------------------------------------------- +void m2_te_device::get_texture_color(uint32_t u, uint32_t v, uint32_t lod, + uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s) +{ + uint32_t texaddr; + uint32_t texbit; + uint32_t texdepth = get_tram_bitdepth(); + + // TODO: Multiple LODs + uint32_t filter = (m_tm.tex_addr_cntl >> TXTADDRCNTL_R12FILTERSEL_SHIFT) & TXTADDRCNTL_FILTERSEL_MASK; + + switch (filter) + { + case TXTADDRCNTL_FILTERSEL_POINT: + case TXTADDRCNTL_FILTERSEL_LINEAR: // TODO + { + addr_calc(u, v, lod, texaddr, texbit, texdepth); + get_texel(texaddr, texbit, texdepth, r, g, b, a, s); + break; + } + + case TXTADDRCNTL_FILTERSEL_BILINEAR: + case TXTADDRCNTL_FILTERSEL_QUASITRI: // TODO + { + // See p170 for implemenation + uint32_t r0, g0, b0, a0, s0; + uint32_t r1, g1, b1, a1, s1; + uint32_t r2, g2, b2, a2, s2; + uint32_t r3, g3, b3, a3, s3; + + addr_calc(u, v, lod, texaddr, texbit, texdepth); + get_texel(texaddr, texbit, texdepth, r0, g0, b0, a0, s0); + addr_calc(u + 0x10, v, lod, texaddr, texbit, texdepth); + get_texel(texaddr, texbit, texdepth, r1, g1, b1, a1, s1); + addr_calc(u, v + 0x10, lod, texaddr, texbit, texdepth); + get_texel(texaddr, texbit, texdepth, r2, g2, b2, a2, s2); + addr_calc(u + 0x10, v + 0x10, lod, texaddr, texbit, texdepth); + get_texel(texaddr, texbit, texdepth, r3, g3, b3, a3, s3); + + // LERP + uint32_t ufrac = u & 0xf; + uint32_t vfrac = v & 0xf; + uint32_t om_ufrac = 0x10 - ufrac; + uint32_t om_vfrac = 0x10 - vfrac; + + // This is probably wrong + s0 = s0 * 0xff; + s1 = s1 * 0xff; + s2 = s2 * 0xff; + s3 = s3 * 0xff; + + // 8.0 * 1.4 + 8.0 * 1.4 = 9.4 + uint32_t rl = r0 * (om_ufrac) + r1 * ufrac; + uint32_t gl = g0 * (om_ufrac) + g1 * ufrac; + uint32_t bl = b0 * (om_ufrac) + b1 * ufrac; + uint32_t al = a0 * (om_ufrac) + a1 * ufrac; + uint32_t sl = s0 * (om_ufrac) + s1 * ufrac; + + uint32_t ru = r2 * (om_ufrac) + r3 * ufrac; + uint32_t gu = g2 * (om_ufrac) + g3 * ufrac; + uint32_t bu = b2 * (om_ufrac) + b3 * ufrac; + uint32_t au = a2 * (om_ufrac) + a3 * ufrac; + uint32_t su = s2 * (om_ufrac) + s3 * ufrac; + + // 9.4 * 0.4 + 9.4 * 0.4 = 10.8? + r = (rl * om_vfrac + ru * vfrac) >> 8; + g = (gl * om_vfrac + gu * vfrac) >> 8; + b = (bl * om_vfrac + bu * vfrac) >> 8; + a = (al * om_vfrac + au * vfrac) >> 8; + + s = ((sl * om_vfrac + su * vfrac) >> 10) ? 1 : 0; + break; + } + } +} + + +//------------------------------------------------- +// addr_calc - +//------------------------------------------------- +void m2_te_device::addr_calc(uint32_t u, uint32_t v, uint32_t lod, + uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth) +{ + uint32_t u_mask = (m_tm.uv_mask & TXTUVMASK_UMASK_MASK) >> TXTUVMASK_UMASK_SHIFT; + uint32_t v_mask = (m_tm.uv_mask & TXTUVMASK_VMASK_MASK) >> TXTUVMASK_VMASK_SHIFT; + uint32_t u_max = (m_tm.uv_max & TXTUVMAX_UMAX_MASK) >> TXTUVMAX_UMAX_SHIFT; + uint32_t v_max = (m_tm.uv_max & TXTUVMAX_VMAX_MASK) >> TXTUVMAX_VMAX_SHIFT; + + // Remove fractional parts (10.0) + uint32_t u0 = u >> 4; + uint32_t v0 = v >> 4; + + u0 = u0 & u_mask; + v0 = v0 & v_mask; + + u_max &= u_mask; + v_max &= v_mask; + + u0 = clamp(u0, 0, u_max); + v0 = clamp(v0, 0, v_max); + + // LOD + uint32_t lodmax = m_tm.tex_addr_cntl & TXTADDRCNTL_LODMAX_MASK; + uint32_t lod_shift = (lodmax - lod) & 3; + + // 20.0 + uint32_t voffset = (v0 * (u_max + 1)) << lod_shift; + uint32_t offset = (voffset + u0) >> lod_shift; + + offset = offset * tdepth; + + uint32_t base_addr = 0; + + switch (lod) + { + case 0: base_addr = m_tm.tex_lod_base0; break; + case 1: base_addr = m_tm.tex_lod_base1; break; + case 2: base_addr = m_tm.tex_lod_base2; break; + case 3: base_addr = m_tm.tex_lod_base3; break; + } + + uint32_t adsum = (base_addr << 3) + offset; + + texaddr = adsum / 32; + texbit = adsum & 31; +} + + +void m2_te_device::get_texel(uint32_t tex_addr, uint32_t tex_bit, uint32_t tdepth, + uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & ssb) +{ + const uint32_t tex_type = m_tm.tex_exptype; + + uint8_t rtex, gtex, btex, atex; + uint8_t ssbtex; + + uint8_t rpip, gpip, bpip, apip; + uint8_t ssbpip; + + // Page 127 + // See M2_2_7_part3_clt_ocrc.pdf page 95 for better expl. + + uint32_t tram_data = m_tram[tex_addr]; + +#if TEST_TIMING + g_statistics[STAT_TEXEL_READS]++; +#endif + + + // Align the texel + uint32_t texel = tram_data >> (tex_bit & ~7); + + // Align within byte (TODO: Fix for 32-bits!) + texel >>= (tex_bit ^ (8 - tdepth)) & 7; + + uint32_t c_depth = (tex_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; + uint32_t a_depth = (tex_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; + uint32_t i_depth = c_depth; + + // Color is either sourced from tram or PIP + if (tex_type & TXTEXPFORM_LITERAL) + { + if (tex_type & TXTEXPFORM_COLORON) + { + // Literal can only be 32-bit or 16bpp + uint32_t mask = (1 << c_depth) - 1; + + btex = texel & mask; + texel >>= c_depth; + gtex = texel & mask; + texel >>= c_depth; + rtex = texel & mask; + texel >>= c_depth; + } + else + { + rtex = gtex = btex = 0; + } + } + else + { + rtex = gtex = btex = 0; + } + + if (tex_type & TXTEXPFORM_INDEXON) + { + uint32_t pipidx = texel & ((1 << i_depth) - 1); + uint32_t pipaddr = (m_tm.tex_pip_cntl & TXTPIPCNTL_INDEX_OFFSET) + pipidx; + + uint32_t pipval = m_pipram[pipaddr & 0xff]; + + // Color, alpha and SSB always present in PIP + bpip = pipval & 0xff; + gpip = (pipval >> 8) & 0xff; + rpip = (pipval >> 16) & 0xff; + apip = (pipval >> 24) & 0x7f; + ssbpip = pipval >> 31; + + texel >>= i_depth; + } + else + { + // Nothing coming from the PIP + rpip = gpip = bpip = 0; + apip = ssbpip = 0; + } + + // Alpha and SSB could be present + if (tex_type & TXTEXPFORM_ALPHAON) + { + uint32_t mask = (1 << a_depth) - 1; + + atex = texel & mask; + + // Need to expand alpha if 4-bits + if (a_depth == 4) + atex = (atex << 3) | (atex >> 1); + + texel >>= a_depth; + } + else + { + atex = 0; + } + + if (tex_type & TXTEXPFORM_SSBON) + ssbtex = texel & 1; + else + ssbtex = 0; + + // Select the SSB + switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_SSBSEL_MASK) >> TXTPIPCNTL_SSBSEL_SHIFT) + { + case TXTPIPCNTL_SEL_CONSTANT: + { + uint32_t cnst = ssbtex ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; + ssb = cnst >> 31; + break; + } + case TXTPIPCNTL_SEL_TRAM: + { + ssb = ssbtex; + break; + } + case TXTPIPCNTL_SEL_PIP: + { + ssb = ssbpip; + break; + } + } + + // PIP color control + switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_COLORSEL_MASK) >> TXTPIPCNTL_COLORSEL_SHIFT) + { + case TXTPIPCNTL_SEL_CONSTANT: + { + uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; + r = (cnst >> 16) & 0xff; + g = (cnst >> 8) & 0xff; + b = (cnst >> 0) & 0xff; + break; + } + case TXTPIPCNTL_SEL_TRAM: + { + r = rtex; + g = gtex; + b = btex; + break; + } + case TXTPIPCNTL_SEL_PIP: + { + r = rpip; + g = gpip; + b = bpip; + break; + } + } + + // Alpha control + switch ((m_tm.tex_pip_cntl & TXTPIPCNTL_ALPHASEL_MASK) >> TXTPIPCNTL_ALPHASEL_SHIFT) + { + case TXTPIPCNTL_SEL_CONSTANT: + { + uint32_t cnst = ssb ? m_tm.tex_srcconst1 : m_tm.tex_srcconst0; + a = (cnst >> 24) & 0x7f; + break; + } + case TXTPIPCNTL_SEL_TRAM: + { + a = atex; + break; + } + case TXTPIPCNTL_SEL_PIP: + { + a = apip; + break; + } + } + + // Expand alpha to 8-bits + a = (a << 1) | (a >> 6); +} + + +//------------------------------------------------- +// lerp +//------------------------------------------------- + +static inline uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) +{ + if (t == 255) + return b; + if (t == 0) + return a; + + return (((255 - t) * a) >> 8) + ((t * b) >> 8); +} + + +//------------------------------------------------- +// multiply +//------------------------------------------------- + +static inline uint8_t multiply(uint8_t a, uint8_t b) +{ + if (b == 255) + return a; + if (a == 255) + return b; + else + return (a * b) >> 8; +} + + +//------------------------------------------------- +// texture_blend - +//------------------------------------------------- + +void m2_te_device::texture_blend( + uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, + uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, + uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo) +{ + uint32_t rbl = 0, gbl = 0, bbl = 0, abl = 0; + + { + uint32_t ar, ab, ag, aa; + uint32_t br, bb, bg, ba; + uint32_t tr, tb, tg; + + select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_ASEL_MASK) >> TXTTABCNTL_C_ASEL_SHIFT, + ri, gi, bi, ai, + rt, gt, bt, at, ssbt, + ar, ag, ab ); + + select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_BSEL_MASK) >> TXTTABCNTL_C_BSEL_SHIFT, + ri, gi, bi, ai, + rt, gt, bt, at, ssbt, + br, bg, bb ); + + select_lerp( (m_tm.tex_tab_cntl & TXTTABCNTL_C_TSEL_MASK) >> TXTTABCNTL_C_TSEL_SHIFT, + ri, gi, bi, ai, + rt, gt, bt, at, ssbt, + tr, tg, tb ); + + if (((m_tm.tex_tab_cntl & TXTTABCNTL_BLENDOP_MASK) >> TXTTABCNTL_BLENDOP_SHIFT) == TXTTABCNTL_BLENDOP_LERP) + { + rbl = lerp(ar, br, tr); + gbl = lerp(ag, bg, tg); + bbl = lerp(ab, bb, tb); + } + else + { + // TODO: CHECK ME + // Alpha is multiply only + select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_ASEL_MASK) >> TXTTABCNTL_A_ASEL_SHIFT, + ai, at, ssbt, + aa); + + select_mul( (m_tm.tex_tab_cntl & TXTTABCNTL_A_BSEL_MASK) >> TXTTABCNTL_A_BSEL_SHIFT, + ai, at, ssbt, + ba); + + rbl = multiply(ar, br); + gbl = multiply(ag, bg); + bbl = multiply(ab, bb); + abl = multiply(aa, ba); + } + } + + // Now select the output + switch ((m_tm.tex_tab_cntl & TXTTABCNTL_C_OSEL_MASK) >> TXTTABCNTL_C_OSEL_SHIFT) + { + case TXTTABCNTL_CO_SEL_CITER: + { + ro = ri; + go = gi; + bo = bi; + break; + } + case TXTTABCNTL_CO_SEL_CT: + { + ro = rt; + go = gt; + bo = bt; + break; + } + case TXTTABCNTL_CO_SEL_BLEND: + { + ro = rbl; + go = gbl; + bo = bbl; + break; + } + case TXTTABCNTL_CO_SEL_RESERVED: + { + ro = go = bo = 0; + break; + } + } + + // Select alpha output + switch ((m_tm.tex_tab_cntl & TXTTABCNTL_A_OSEL_MASK) >> TXTTABCNTL_A_OSEL_SHIFT) + { + case TXTTABCNTL_AO_SEL_AITER: + { + ao = ai; + break; + } + case TXTTABCNTL_AO_SEL_AT: + { + ao = at; + break; + } + case TXTTABCNTL_AO_SEL_BLEND: + { + ao = abl; + break; + } + case TXTTABCNTL_AO_SEL_RESERVED: + { + ao = 0; + break; + } + } +} + +void m2_te_device::select_lerp( uint32_t sel, + uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, + uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, + uint32_t & ar, uint32_t & ag, uint32_t & ab ) +{ + switch (sel) + { + case TXTTABCNTL_C_ABTSEL_AITER: + { + ar = ai; + ag = ai; + ab = ai; + break; + } + case TXTTABCNTL_C_ABTSEL_CITER: + { + ar = ri; + ag = gi; + ab = bi; + break; + } + case TXTTABCNTL_C_ABTSEL_AT: + { + ar = at; + ag = at; + ab = at; + break; + } + case TXTTABCNTL_C_ABTSEL_CT: + { + ar = rt; + ag = gt; + ab = bt; + break; + } + case TXTTABCNTL_C_ABTSEL_ACONST: + { + uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; + uint8_t aval = (cnst >> 24) & 0x7f; + + // Expand to 8-bit + aval = (aval << 1) | (aval >> 6); + + ar = aval; + ag = aval; + ab = aval; + break; + } + case TXTTABCNTL_C_ABTSEL_CCONST: + { + uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; + + ar = (cnst >> 24) & 0xff; + ag = (cnst >> 16) & 0xff; + ab = (cnst >> 0) & 0xff; + break; + } + default: + { + ar = 0; + ag = 0; + ab = 0; + break; + } + } +} + + +void m2_te_device::select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt, + uint32_t & a ) +{ + switch (sel) + { + case TXTTABCNTL_A_ABSEL_AITER: + { + a = ai; + break; + } + case TXTTABCNTL_A_ABSEL_AT: + { + a = at; + break; + } + case TXTTABCNTL_A_ABSEL_ACONST: + { + uint32_t cnst = ssbt ? m_tm.tex_srcconst3 : m_tm.tex_srcconst2; + uint8_t aval = (cnst >> 24) & 0x7f; + + // Expand to 8-bit + a = (aval << 1) | (aval >> 6); + break; + } + default: + { + a = 0; + break; + } + } +} + + +//------------------------------------------------- +// write_dst_pixel - Write pixel to framebuffer +//------------------------------------------------- + +void m2_te_device::write_dst_pixel() +{ + uint32_t mask = m_db.usergen_ctrl & DBUSERGENCTL_DESTOUT_MASK; + + if (m_db.dst_ctrl & DBDESTCNTL_32BPP) + { + uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint32_t); + + uint32_t old = m_bda->read_bus32(dstaddr); + uint32_t out = 0; + + uint8_t sdsb_a = (old >> 24) & 0xff; + uint8_t sr = (old >> 16) & 0xff; + uint8_t sg = (old >> 8) & 0xff; + uint8_t sb = old & 0xff; + + out |= (mask & 8 ? (m_dbstate.dsb << 7) | (m_dbstate.dst.a >> 1) : sdsb_a) << 24; + out |= (mask & 4 ? m_dbstate.dst.r : sr) << 16; + out |= (mask & 2 ? m_dbstate.dst.g : sg) << 8; + out |= mask & 1 ? m_dbstate.dst.b : sb; + + m_bda->write_bus32(dstaddr, out); + } + else + { + uint32_t dstaddr = m_db.dst_baseaddr + (m_dbstate.y * m_db.dst_xstride + m_dbstate.x) * sizeof(uint16_t); + + uint16_t old = m_bda->read_bus16(dstaddr); + uint16_t out = 0; + + uint8_t sdsb_a = (old >> 15) & 0x1; + uint8_t sr = (old >> 10) & 0x1f; + uint8_t sg = (old >> 5) & 0x1f; + uint8_t sb = old & 0x1f; + + out |= (mask & 8 ? m_dbstate.dsb : sdsb_a) << 15; + out |= (mask & 4 ? m_dbstate.dst.r >> 3 : sr) << 10; + out |= (mask & 2 ? m_dbstate.dst.g >> 3 : sg) << 5; + out |= mask & 1 ? m_dbstate.dst.b >> 3 : sb; + + m_bda->write_bus16(dstaddr, out); + } + +#if TEST_TIMING + g_statistics[STAT_PIXEL_STORES]++; +#endif +} + + +//------------------------------------------------- +// destination_blend - +//------------------------------------------------- + +void m2_te_device::destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb) +{ + m_dbstate.x = x; + m_dbstate.y = y; + m_dbstate.w = w; + m_dbstate.ti = ti_color; + m_dbstate.ssb = ssb; + + bool dis = false; + bool zpixout = true; + bool zbufout = true; + bool zclip = false; + bool zclipdis = false; + bool fbclipdis = false; + bool winclipdis = false; + + // Z Status + uint32_t zgel = 0; + + uint32_t zaddr; + + // FBCLIP + { + uint32_t xclip = (m_db.fbclip & DBFBCLIP_XFBCLIP_MASK) >> DBFBCLIP_XFBCLIP_SHIFT; + uint32_t yclip = (m_db.fbclip & DBFBCLIP_YFBCLIP_MASK) >> DBFBCLIP_YFBCLIP_SHIFT; + + fbclipdis = (x >= xclip) || (y >= yclip); + + if (fbclipdis) + m_db.status |= DBSTATUS_FBCLIP; + } + + // WINCLIP + { + uint32_t xmin = (m_db.x_winclip & DBFBXWINCLIP_XMIN_MASK) >> DBFBXWINCLIP_XMIN_SHIFT; + uint32_t xmax = (m_db.x_winclip & DBFBXWINCLIP_XMAX_MASK) >> DBFBXWINCLIP_XMAX_SHIFT; + uint32_t ymin = (m_db.y_winclip & DBFBYWINCLIP_YMIN_MASK) >> DBFBYWINCLIP_YMIN_SHIFT; + uint32_t ymax = (m_db.y_winclip & DBFBYWINCLIP_YMAX_MASK) >> DBFBYWINCLIP_YMAX_SHIFT; + + bool inside = (x >= xmin) && (x < xmax) && (y >= ymin) && (y < ymax); + + winclipdis = ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPINEN) && inside) || + ((m_db.usergen_ctrl & DBUSERGENCTL_WCLIPOUTEN) && !inside); + + if (winclipdis) + m_db.status |= DBSTATUS_WINCLIP; + } + + select_src_pixel(); + + select_tex_pixel(); + + select_alpha_dsb(); + + + { + uint8_t dm10, dm11, dm20, dm21; + uint32_t txtcnst0 = m_db.txt_coef_const0; + uint32_t txtcnst1 = m_db.txt_coef_const1; + uint32_t srccnst0 = m_db.src_coef_const0; + uint32_t srccnst1 = m_db.src_coef_const1; + + if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) + { + // Blue + dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8; + dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8; + dm20 = srccnst0 & 0xff; srccnst0 >>= 8; + dm21 = srccnst1 & 0xff; srccnst1 >>= 8; + m_dbstate.blend.b = color_blend(m_dbstate.texpath.b, m_dbstate.ti.b, m_dbstate.srcpath.b, m_dbstate.src.b, dm10, dm11, dm20, dm21); + + // TODO: ALURGEL for each + + // Green + dm10 = txtcnst0 & 0xff; txtcnst0 >>= 8; + dm11 = txtcnst1 & 0xff; txtcnst1 >>= 8; + dm20 = srccnst0 & 0xff; srccnst0 >>= 8; + dm21 = srccnst1 & 0xff; srccnst1 >>= 8; + m_dbstate.blend.g = color_blend(m_dbstate.texpath.g, m_dbstate.ti.g, m_dbstate.srcpath.g, m_dbstate.src.g, dm10, dm11, dm20, dm21); + + // Red + dm10 = txtcnst0 & 0xff; + dm11 = txtcnst1 & 0xff; + dm20 = srccnst0 & 0xff; + dm21 = srccnst1 & 0xff; + m_dbstate.blend.r = color_blend(m_dbstate.texpath.r, m_dbstate.ti.r, m_dbstate.srcpath.r, m_dbstate.src.r, dm10, dm11, dm20, dm21); + } + else + { + m_dbstate.blend.r = m_dbstate.ti.r; + m_dbstate.blend.g = m_dbstate.ti.g; + m_dbstate.blend.b = m_dbstate.ti.b; + } + + // Dithering + if (m_db.usergen_ctrl & DBUSERGENCTL_DITHEREN) + { + uint32_t dith_x = x & 3; + uint32_t dith_y = y & 3; + + uint32_t dith_mtx = dith_y & 2 ? m_db.dither_mat_b : m_db.dither_mat_a; + uint32_t idx = 7 ^ (((dith_y & 1) << 2) | dith_x); + uint8_t val = (dith_mtx >> (idx * 4)) & 0xf; + + m_dbstate.dst.r = dither(m_dbstate.blend.r, val); + m_dbstate.dst.g = dither(m_dbstate.blend.g, val); + m_dbstate.dst.b = dither(m_dbstate.blend.b, val); + } + else + { + m_dbstate.dst.r = m_dbstate.blend.r; + m_dbstate.dst.g = m_dbstate.blend.g; + m_dbstate.dst.b = m_dbstate.blend.b; + } + } + + + if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) && + (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN)) + { + int32_t x_offs = (m_db.z_offset & DBZOFFS_XOFFS_MASK) >> DBZOFFS_XOFFS_SHIFT; + int32_t y_offs = (m_db.z_offset & DBZOFFS_YOFFS_MASK) >> DBZOFFS_YOFFS_SHIFT; + + // Sign extend + x_offs = (x_offs << 20) >> 20; + y_offs = (x_offs << 20) >> 20; + + x_offs += m_dbstate.x; + y_offs += m_dbstate.y; + + uint32_t x_clip = (m_db.z_clip & DBZCLIP_XCLIP_MASK) >> DBZCLIP_XCLIP_SHIFT; + uint32_t y_clip = (m_db.z_clip & DBZCLIP_YCLIP_MASK) >> DBZCLIP_YCLIP_SHIFT; + + zclip = (x_offs < 0) || (y_offs < 0) || (x_offs >= x_clip) || (y_offs >= y_clip); + + zaddr = m_db.z_baseaddr + (x_offs + y_offs * m_db.dst_xstride) * 2; + } + else + { + zaddr = 0; + zclip = false; + } + + zclipdis = zclip && (m_db.discard_ctrl & DBDISCARDCTL_ZCLIPDISEN); + + if (zclipdis) + m_db.status |= DBSTATUS_ZCLIP; + + // Z-path + if (!(m_gc.te_master_mode & TEMASTER_MODE_DZBUF) && + (m_db.usergen_ctrl & DBUSERGENCTL_ZBUFEN) && + !zclip) + { +#if TEST_TIMING + g_statistics[STAT_ZBUFFER_LOADS]++; +#endif + +#if 1 // TODO: Why are we using this? + int32_t zdiff = w - m_bda->read_bus16(zaddr); +#else + // Shift W back to 0.23 + uint16_t oldw = m_bda->read_bus16(zaddr); + uint32_t exp = (oldw & 0xc000) >> 14; + uint32_t man = (oldw & 0x3fff) << 17; + + uint32_t oldz = man >> (exp * 3); + + exp = (w & 0xc000) >> 14; + man = (w & 0x3fff) << 17; + uint32_t curz = man >> (exp * 3); + + int32_t zdiff = curz - oldz; +#endif + + // TODO: Why isn't this working? + // W vs Z? + if (zdiff > 0) + { + zpixout = m_db.z_ctrl & 1;//DBZCNTL_ZPIXOUT_GT; + zbufout = m_db.z_ctrl & 2;//DBZCNTL_ZBUFOUT_GT; + zgel |= 4; + m_db.status |= DBSTATUS_ZFUNC_GT; + } + else if (zdiff == 0) + { + zpixout = m_db.z_ctrl & DBZCNTL_ZPIXOUT_EQ; + zbufout = m_db.z_ctrl & DBZCNTL_ZBUFOUT_EQ; + zgel |= 2; + m_db.status |= DBSTATUS_ZFUNC_EQ; + } + else + { + zpixout = m_db.z_ctrl & 0x10;//DBZCNTL_ZPIXOUT_LT; + zbufout = m_db.z_ctrl & 0x20;//DBZCNTL_ZBUFOUT_LT; + zgel |= 1; + m_db.status |= DBSTATUS_ZFUNC_LT; + } + } + else + { + zpixout = true; + zbufout = false; + } + + // Discard logic + { + bool ssbdis = (m_db.discard_ctrl & DBDISCARDCTL_SSBDISEN) && (m_dbstate.ssb == 0); + + bool adis = (m_db.discard_ctrl & DBDISCARDCTL_ADISEN) && (m_dbstate.dst.a == 0); + + bool rgbdis = (m_db.discard_ctrl & DBDISCARDCTL_RGBDISEN) && + (m_dbstate.dst.r == 0) && (m_dbstate.dst.g == 0) && (m_dbstate.dst.b == 0); + + dis = fbclipdis || winclipdis || zclipdis || ssbdis || adis || rgbdis; + } + + // Write output depth and color + if (!dis) + { + // Z-buffer + if (zbufout && (m_db.usergen_ctrl & DBUSERGENCTL_ZOUTEN)) + { +#if TEST_TIMING + g_statistics[STAT_ZBUFFER_STORES]++; +#endif + m_bda->write_bus16(zaddr, w & 0xffff); + } + + // Color + if (zpixout && (m_db.supergen_ctrl & DBSUPERGENCTL_DESTOUTEN)) + { + write_dst_pixel(); + } + } + + // TODO: Status +/* + { + fbClipStat = fbClipDis + winClipStat = winClipDis + zClipStat = zClipDis + alurstat + alugstat + alubstat + zFuncStat + anyRender + set_interrupt + } +*/ +} + +// Select between texture unit and source pixel +void m2_te_device::select_tex_pixel() +{ + uint32_t cntl; + + // TODO: REGBITS + if (m_dbstate.ti.a == 0) + cntl = (m_db.src_alpha_ctrl >> 4) & 3; + else if (m_dbstate.ti.a == 255) + cntl = m_db.src_alpha_ctrl & 3; + else + cntl = (m_db.src_alpha_ctrl >> 2) & 3; + + switch (cntl) + { + case 0: m_dbstate.texpath.a = m_dbstate.ti.a; break; + case 1: m_dbstate.texpath.a = 255; break; + case 2: m_dbstate.texpath.a = 0; break; + } + + switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_INSEL_MASK) >> DBTXTMULTCNTL_INSEL_SHIFT) + { + case DBTXTMULTCNTL_INSEL_CTI: + { + m_dbstate.texpath.r = m_dbstate.ti.r; + m_dbstate.texpath.g = m_dbstate.ti.g; + m_dbstate.texpath.b = m_dbstate.ti.b; + break; + } + case DBTXTMULTCNTL_INSEL_CONSTANT: + { + uint32_t cnst = m_db.const_in; + m_dbstate.texpath.r = (cnst >> 16) & 0xff; + m_dbstate.texpath.g = (cnst >> 8) & 0xff; + m_dbstate.texpath.b = cnst & 0xff; + break; + } + case DBTXTMULTCNTL_INSEL_COMPSRC: + { + m_dbstate.texpath.r = ~m_dbstate.src.r; + m_dbstate.texpath.g = ~m_dbstate.src.g; + m_dbstate.texpath.b = ~m_dbstate.src.b; + break; + } + case DBTXTMULTCNTL_INSEL_ATI: + { + m_dbstate.texpath.r = m_dbstate.ti.a; + m_dbstate.texpath.g = m_dbstate.ti.a; + m_dbstate.texpath.b = m_dbstate.ti.a; + break; + } + } + + if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTRJUST) + { + m_dbstate.texpath.r >>= 3; + m_dbstate.texpath.g >>= 3; + m_dbstate.texpath.b >>= 3; + } +} + +void m2_te_device::select_src_pixel() +{ + if ((m_db.usergen_ctrl & DBUSERGENCTL_SRCINEN) + && (m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) + && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) + { + int32_t x_offs = (m_db.src_offset & DBSRCOFFS_XOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT; + int32_t y_offs = (m_db.src_offset & DBSRCOFFS_YOFFS_MASK) >> DBSRCOFFS_YOFFS_SHIFT; + + // Sign extend + x_offs = (x_offs << 20) >> 20; + y_offs = (y_offs << 20) >> 20; + + x_offs += m_dbstate.x; + y_offs += m_dbstate.y; + + uint32_t addr = y_offs * m_db.src_xstride + x_offs; + + if (m_db.src_ctrl & DBSRCCNTL_32BPP) + { + uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint32_t); + uint32_t srcval = m_bda->read_bus32(srcaddr); + + m_dbstate.src.a = ((srcval >> 24) & 0x7f) << 1; + m_dbstate.src.r = (srcval >> 16) & 0xff; + m_dbstate.src.g = (srcval >> 8) & 0xff; + m_dbstate.src.b = (srcval >> 0) & 0xff; + + if (m_db.src_ctrl & DBSRCCNTL_MSBREP) + m_dbstate.src.a |= (m_dbstate.src.a >> 6) & 1; + + m_dbstate.dsb = (srcval >> 31) & 1; + } + else + { + uint32_t srcaddr = m_db.src_baseaddr + addr * sizeof(uint16_t); + uint32_t srcval = m_bda->read_bus16(srcaddr); + + m_dbstate.src.r = (srcval >> 10) & 0x1f; + m_dbstate.src.g = (srcval >> 5) & 0x1f; + m_dbstate.src.b = srcval & 0x1f; + m_dbstate.src.a = 0; + + m_dbstate.dsb = srcval & 0x8000; + m_dbstate.src.r <<= 3; + m_dbstate.src.g <<= 3; + m_dbstate.src.b <<= 3; + + if (m_db.src_ctrl & DBSRCCNTL_MSBREP) + { + m_dbstate.src.r |= (m_dbstate.src.r >> 5); + m_dbstate.src.g |= (m_dbstate.src.g >> 5); + m_dbstate.src.b |= (m_dbstate.src.b >> 5); + } + } +#if TEST_TIMING + g_statistics[STAT_PIXEL_LOADS]++; +#endif + } + else + { + // Source input disabled + m_dbstate.dsb = 0; + m_dbstate.src.r = 0; + m_dbstate.src.g = 0; + m_dbstate.src.b = 0; + m_dbstate.src.a = 0; + } + + // Now + switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_INSEL_MASK) >> DBSRCMULTCNTL_INSEL_SHIFT) + { + case DBSRCMULTCNTL_INSEL_SRC: + { + m_dbstate.srcpath.r = m_dbstate.src.r; + m_dbstate.srcpath.g = m_dbstate.src.g; + m_dbstate.srcpath.b = m_dbstate.src.b; + break; + } + case DBSRCMULTCNTL_INSEL_CONSTANT: + { + uint32_t cnst = m_db.const_in; + m_dbstate.srcpath.r = (cnst >> 16) & 0xff; + m_dbstate.srcpath.g = (cnst >> 8) & 0xff; + m_dbstate.srcpath.b = (cnst >> 0) & 0xff; + break; + } + case DBSRCMULTCNTL_INSEL_COMPCTI: + { + m_dbstate.srcpath.r = ~m_dbstate.ti.r; + m_dbstate.srcpath.g = ~m_dbstate.ti.g; + m_dbstate.srcpath.b = ~m_dbstate.ti.b; + break; + } + case DBSRCMULTCNTL_INSEL_TEXALPHA: + { + m_dbstate.srcpath.r = m_dbstate.src.a; + m_dbstate.srcpath.g = m_dbstate.src.a; + m_dbstate.srcpath.b = m_dbstate.src.a; + break; + } + } + + if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCRJUST) + { + m_dbstate.srcpath.r >>= 3; + m_dbstate.srcpath.g >>= 3; + m_dbstate.srcpath.b >>= 3; + } + + m_dbstate.srcpath.a = m_dbstate.src.a; +} + +uint8_t m2_te_device::dither(uint8_t in, uint8_t dithval) +{ + int32_t res; + int32_t sgn_val; + + if (dithval & 8) + sgn_val = -8 + (dithval & 7); + else + sgn_val = dithval; + + res = (int32_t)in + sgn_val; + + if (res > 255) + res = 255; + else if (res < 0) + res = 0; + + return (uint8_t)res; +} + +uint8_t m2_te_device::get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1) +{ + uint32_t sel=0; + uint8_t cnst, coef=0; + + switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCONSTCNTL_MASK) >> DBSRCMULTCNTL_SRCCONSTCNTL_SHIFT) + { + case DBSRCMULTCNTL_SRCCONSTCNTL_TEXSSB: sel = m_dbstate.ssb; break; + case DBSRCMULTCNTL_SRCCONSTCNTL_SRCDSB: sel = m_dbstate.dsb; break; + } + + cnst = sel ? dm2const1 : dm2const0; + + switch ((m_db.src_mult_cntl & DBSRCMULTCNTL_COEFSEL_MASK) >> DBSRCMULTCNTL_COEFSEL_SHIFT) + { + case DBSRCMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break; + case DBSRCMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break; + case DBSRCMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break; + case DBSRCMULTCNTL_COEFSEL_CTI: coef = cti; break; + } + + if (m_db.src_mult_cntl & DBSRCMULTCNTL_SRCCOEFCMP) + return ~coef; + else + return coef; +} + +uint8_t m2_te_device::get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1) +{ + uint32_t sel=0; + uint8_t cnst, coef=0; + + // TODO: Make like src coefficient + uint32_t cntl = ((m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCONSTCNTL_MASK) >> DBTXTMULTCNTL_TXTCONSTCNTL_SHIFT); + + if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_TEXSSB) + sel = m_dbstate.ssb; + else if (cntl == DBTXTMULTCNTL_TXTCONSTCNTL_SRCDSB) + sel = m_dbstate.dsb; + + cnst = sel ? dm1const1 : dm1const0; + + switch ((m_db.txt_mult_cntl & DBTXTMULTCNTL_COEFSEL_MASK) >> DBTXTMULTCNTL_COEFSEL_SHIFT) + { + case DBTXTMULTCNTL_COEFSEL_ATI: coef = m_dbstate.texpath.a; break; + case DBTXTMULTCNTL_COEFSEL_ASRC: coef = m_dbstate.srcpath.a; break; + case DBTXTMULTCNTL_COEFSEL_CONSTANT: coef = cnst; break; + case DBTXTMULTCNTL_COEFSEL_CSRC: coef = cs; break; + } + + if (m_db.txt_mult_cntl & DBTXTMULTCNTL_TXTCOEFCMP) + return ~coef; + else + return coef; +} + +void m2_te_device::select_alpha_dsb() +{ + if ((m_db.usergen_ctrl & DBUSERGENCTL_BLENDEN) && !(m_gc.te_master_mode & TEMASTER_MODE_DBLEND)) + { + uint32_t sel = 0; + uint8_t aconst; + + switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTCONSTCNTL_MASK) >> DBDSTACNTL_ADESTCONSTCNTL_SHIFT) + { + case 0: sel = m_dbstate.ssb; break; + case 1: sel = m_dbstate.dsb; break; + } + + if (sel) + aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST1_MASK) >> DBDSTALPHACONST_CONST1_SHIFT; + else + aconst = (m_db.dst_alpha_const & DBDSTALPHACONST_CONST0_MASK) >> DBDSTALPHACONST_CONST0_SHIFT; + + switch ((m_db.dst_alpha_ctrl & DBDSTACNTL_ADESTSEL_MASK) >> DBDSTACNTL_ADESTSEL_SHIFT) + { + case 0: m_dbstate.dst.a = m_dbstate.texpath.a; break; + case 1: m_dbstate.dst.a = aconst; break; + case 2: m_dbstate.dst.a = m_dbstate.srcpath.a; break; + case 3: m_dbstate.dst.a = m_dbstate.blend.r; break; + } + + switch ((m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBSEL_MASK) >> DBSSBDSBCNTL_DSBSEL_SHIFT) + { + case 0: m_dbstate.dsb = m_dbstate.ssb; break; + case 1: m_dbstate.dsb = (m_db.ssbdsb_ctrl & DBSSBDSBCNTL_DSBCONST_MASK) >> DBSSBDSBCNTL_DSBCONST_SHIFT; break; + case 2: m_dbstate.dsb = m_dbstate.dsb; break; + } + } + else + { + m_dbstate.dst.a = m_dbstate.texpath.a; + m_dbstate.dsb = m_dbstate.ssb; + } +} + + +uint8_t m2_te_device::color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc, + uint8_t dm10, uint8_t dm11, + uint8_t dm20, uint8_t dm21) +{ + uint8_t tcoef, scoef; + uint16_t tm, sm; + + tcoef = get_tex_coef(csrc, dm10, dm11); + scoef = get_src_coef(cti, dm20, dm21); + + tm = (tcoef == 255) ? ct : ((ct == 255) ? tcoef : ((tcoef * ct) >> 8)); + sm = (scoef == 255) ? cs : ((cs == 255) ? scoef : ((scoef * cs) >> 8)); + + return alu_calc(tm, sm); +} + +#if 1 + +uint8_t m2_te_device::alu_calc(uint16_t a, uint16_t b) +{ + uint16_t cinv; + uint16_t c = 0; + uint32_t blendout; + uint32_t result; + uint32_t carry = 0; + uint32_t borrow = 0; + uint32_t cntl = (m_db.alu_ctrl & DBALUCNTL_ALUOP_MASK) >> DBALUCNTL_ALUOP_SHIFT; + + // p271 + + /* ALU */ + if ((cntl & 8) == 0) + { + if (!(cntl & 4)) + { + result = a + b; + } + else if (cntl & 2) + { + result = b - a; + if (result < 0) + borrow = 1; + } + else + { + result = a - b; + if (result < 0) + borrow = 1; + } + } + /* Boolean */ + else + { + cinv = 0; + int i, j; + + for (i = 0; i < 8; ++i) + { + j = (a & 1) *2 + (b & 1); + + switch (j) + { + case 0: cinv |= (cntl & 1); break; + case 1: cinv |= (cntl & 2) && 1; break; + case 2: cinv |= (cntl & 4) && 1; break; + case 3: cinv |= (cntl & 8) && 1; break; + } + + cinv <<= 1; + a >>= 1; + b >>= 1; + } + cinv >>= 1; + + for (i = 0; i < 8; ++i) + { + c |= cinv & 1; + c <<= 1; + cinv >>= 1; + } + + c >>= 1; + result = (int)c; + } + + result &= 0x1ff; + + switch ((m_db.alu_ctrl & DBALUCNTL_FINALDIVIDE_MASK) >> DBALUCNTL_FINALDIVIDE_SHIFT) + { + case 1: blendout = result << 1; break; + case 2: blendout = result << 2; break; + case 3: blendout = result << 3; break; + case 7: blendout = result >> 1; break; + case 6: blendout = result >> 2; break; + case 5: blendout = result >> 3; break; + default: blendout = result; break; + } + + if (blendout > 255) + carry = 1; + +#if 0 + int alugel; + // TODO: FIX ALUGEL - Needs to be propagated to ALU status + if (borrow == 1) + alugel = 1; + else if (blendout == 0) + alugel = 2; + else + alugel = 4; +#endif + + if ((cntl & 8) == 0) + { + /* Clamp? */ + if (!(cntl & 1)) + { + blendout = carry ? 255 : blendout; + blendout = borrow ? 0 : blendout; + } + else + { + if (cntl & 2) + { + blendout = carry ? 255 : blendout; + blendout = borrow ? 0 : blendout; + } + } + } + + return blendout & 0xff; +} + + + +#endif + +//------------------------------------------------- +// walk_span - +//------------------------------------------------- + +void m2_te_device::walk_span(uint32_t wrange, bool omit_right, + uint32_t y, uint32_t xs, uint32_t xe, + int32_t r, int32_t g, int32_t b, int32_t a, + uint32_t uw, uint32_t vw, + uint32_t w) +{ + bool scan_lr = !m_es.r2l; + + // TODO: Is this correct? + xe = scan_lr ? xe + 1 : xe - 1; + + /* + Edge to Span walker + X/Y 11.0 + RGBA 8.11 + U/W, V/W 10.13 + 1/W 0.23 + RGBA DDX s8.11 + UV DDX s10.13 + 1/W DDX s0.23 + + To destination blender: + X/Y 11.0 + W 0.16 + + To texture mapper: + RGBA 8.0 + UV 10.4 + */ + + if (omit_right) + { + if (scan_lr) + { + xe -= 1; + } + else + { + xs -= 1; + r -= m_es.ddx_r; + g -= m_es.ddx_g; + b -= m_es.ddx_b; + a -= m_es.ddx_a; + uw -= m_es.ddx_uw; + vw -= m_es.ddx_vw; + w -= m_es.ddx_w; + } + } + + if (g_debug) + { + g_debug = true; + } + + while (xs != xe) + { + uint32_t sx = xs; + uint32_t sy = y; + +#if 1 // DEBUG + if (sx == 320/2 && sy == 200) + { + ; + } +#endif + + // Fetch RGB and A + uint32_t rt, gt, bt, at, ssbt; + + uint32_t w16 = 0; + + // W + { + // Undo shifting that took place during setup and reduce 0.23 to 0.16 + uint32_t normalized_w = w >> -depth_bits[wrange]; + w16 = (normalized_w >> 7) & 0xffff; + } + + if (!(m_gc.te_master_mode & TEMASTER_MODE_DTEXT) && (m_tm.tex_addr_cntl & TXTADDRCNTL_LOOKUP_EN)) + { + uint32_t u, v; + + // UV and W + texcoord_gen(wrange, uw, vw, w, u, v, w16); + + // TODO: FIXME + uint32_t lod = lod_calc(u, v, u, v); + + get_texture_color(u, v, lod, rt, gt, bt, at, ssbt); + } + else + { + rt = gt = bt = at = ssbt = 0; + } + + uint32_t ri, gi, bi, ai; + + if (!(m_gc.te_master_mode & TEMASTER_MODE_DSHADE)) + { + // Remove the fractional parts of iterated ARGB + ri = r >> 11; + gi = g >> 11; + bi = b >> 11; + ai = a >> 11; + } + else + { + ri = 0xff; + gi = 0xff; + bi = 0xff; + ai = 0xff; + } + + uint32_t ro, go, bo, ao; + + // Note: SSB may be overriden + uint32_t ssbo = ssbt; + + // Blend iterated RGB with texel + texture_blend(ri, gi, bi, ai, + rt, gt, bt, at, ssbt, + ro, go, bo, ao, ssbo); + + // Destination blend and write-out + // Interface: + // Span length + // Left 2 Right + // W0, W1 + + rgba texout; + texout.r = ro; + texout.g = go; + texout.b = bo; + texout.a = ao; + + destination_blend(sx, sy, w16, texout, ssbo); + + // Update interpolated paramters + if (scan_lr) + { + xs += 1; + r += m_es.ddx_r; + g += m_es.ddx_g; + b += m_es.ddx_b; + a += m_es.ddx_a; + uw += m_es.ddx_uw; + vw += m_es.ddx_vw; + w += m_es.ddx_w; + } + else + { + xs -= 1; + r -= m_es.ddx_r; + g -= m_es.ddx_g; + b -= m_es.ddx_b; + a -= m_es.ddx_a; + uw -= m_es.ddx_uw; + vw -= m_es.ddx_vw; + w -= m_es.ddx_w; + } + + // Clamp to 11.8 + r = clamp(r, 0, 0x0007ffff); + g = clamp(g, 0, 0x0007ffff); + b = clamp(b, 0, 0x0007ffff); + a = clamp(a, 0, 0x0007ffff); + + // Clamp to 10.13 + uw = clamp(uw, 0, 0x007fffff); + vw = clamp(vw, 0, 0x007fffff); + + // Clamp to 0.23 + w = clamp(w, 0, 0x007fffff); + +#if TEST_TIMING + g_statistics[STAT_PIXELS_PROCESSED]++; +#endif + } +} + + + +/*************************************************************************** + INSTRUCTION PROCESSING +***************************************************************************/ + +//------------------------------------------------- +// irp_fetch - +//------------------------------------------------- + +uint32_t m2_te_device::irp_fetch() +{ + uint32_t data = m_bda->read_bus32(m_gc.irp); + m_gc.irp += 4; + + return data; +} + + +//------------------------------------------------- +// irp_fetch_float - +//------------------------------------------------- + +float m2_te_device::irp_fetch_float() +{ + uint32_t data = m_bda->read_bus32(m_gc.irp); + m_gc.irp += 4; + + return *reinterpret_cast(&data); +} + + +//------------------------------------------------- +// illegal_inst - +//------------------------------------------------- + +void m2_te_device::illegal_inst() +{ + set_interrupt(INTSTAT_UNIMPLEMENTED_INSTR); + m_state = TE_STOPPED; +} + + +//------------------------------------------------- +// execute - +//------------------------------------------------- + +void m2_te_device::execute() +{ + address_space &space = machine().driver_data()->generic_space(); + +#if TEST_TIMING + memset(g_statistics, 0, sizeof(g_statistics)); +#endif + + while (m_state == TE_RUNNING) + { + uint32_t inst = irp_fetch(); + + switch (inst & INST_MASK) + { + case INST_WRITE_REG: + { + uint32_t offs = inst & 0xffff; + int32_t cnt = (inst >> 16) & 0xff; + + while (cnt-- >= 0) + { + write(space, offs >> 2, irp_fetch(), 0xffffffff); + offs += 4; + + if (m_state != TE_RUNNING) + break; + } + break; + } + + case INST_VTX_SHORT: + { + int32_t cnt = inst & 0xffff; + uint32_t flags = inst & 0x001f0000; + uint32_t ver = (inst >> 24) & 0xf; + + if (ver != 0) + { + illegal_inst(); + break; + } + + while (cnt-- >= 0) + { + se_vtx vtx = { 0 }; + + vtx.x = irp_fetch_float(); + vtx.y = irp_fetch_float(); + + if (flags & VTX_FLAG_SHAD) + { + vtx.r = irp_fetch_float(); + vtx.g = irp_fetch_float(); + vtx.b = irp_fetch_float(); + vtx.a = irp_fetch_float(); + } + if (flags & VTX_FLAG_PRSP) + { + vtx.w = irp_fetch_float(); + } + if (flags & VTX_FLAG_TEXT) + { + vtx.uw = irp_fetch_float(); + vtx.vw = irp_fetch_float(); + } + + // Send this vertex for processing + add_vertex(vtx, flags); + + // Clear the new triangle flag if set + flags &= ~VTX_FLAG_NEW; + } + + break; + } + case INST_VTX_LONG: + { + const uint32_t ver = (inst >> 24) & 0xf; + + if (ver != 0) + { + illegal_inst(); + break; + } + + fatalerror("Long format unimplemented"); + + break; + } + case INST_VTX_POINT: + { + const uint32_t ver = (inst >> 24) & 0xf; + + if (ver != 0) + { + illegal_inst(); + break; + } + + fatalerror("Point format unimplemented"); + + break; + } + default: + { + illegal_inst(); + break; + } + } + + // Stop or pause execution? + if (m_gc.irp == m_gc.iwp) + { + m_state = m_gc.te_master_mode & TEICNTL_STPL ? TE_STOPPED : TE_PAUSED; + set_interrupt(INTSTAT_LIST_END); + } + else if (m_gc.te_master_mode & (TEICNTL_STPI | TEICNTL_STEP)) + { + m_state = TE_STOPPED; + } + }; + +#if TEST_TIMING +/* + TESetup Engine: 600-700 triangles/sec (?) + + Pixel Rates: + Point - 132Mpix/s + Linear - 66Mpix/s + Bilin - 33Mpix + QTril - 22M + + No blend, no Z - 120MPix + Zbuffer - 66-120M pix + Bend - 66 M pix +*/ + + uint32_t total_cycles = (g_statistics[STAT_TRIANGLES_PROCESSED] * 100) + + (g_statistics[STAT_TEXEL_READS]) + +// (g_statistics[STAT_PIXELS_PROCESSED]) + + (g_statistics[STAT_PIXEL_LOADS]) + + (g_statistics[STAT_PIXEL_STORES]) + + (g_statistics[STAT_TEXEL_BYTES]/4) + + (g_statistics[STAT_ZBUFFER_LOADS]) + + (g_statistics[STAT_ZBUFFER_STORES]); +#if 0 + logerror(">>> END OF LIST <<<\n"); + logerror("Triangles: %u\n", g_statistics[STAT_TRIANGLES_PROCESSED]); + logerror("Texture samples: %u\n", g_statistics[STAT_TEXEL_READS]); + logerror("Texture bytes loaded: %u\n", g_statistics[STAT_TEXEL_BYTES]); + logerror("Pixels rasterized: %u\n", g_statistics[STAT_PIXELS_PROCESSED]); + logerror("Pixel reads: %u\n", g_statistics[STAT_PIXEL_LOADS]); + logerror("Pixel writes: %u\n", g_statistics[STAT_PIXEL_STORES]); + logerror("Z reads: %u\n", g_statistics[STAT_ZBUFFER_LOADS]); + logerror("Z writes: %u\n", g_statistics[STAT_ZBUFFER_STORES]); + logerror("Total: %u cycles (%fusec)\n", total_cycles, clocks_to_attotime(total_cycles).as_double()*1.0e6); +#endif + timer_set(clocks_to_attotime(total_cycles), 0); +#else + // Interrupt after stopping? + if (m_gc.te_master_mode & TEICNTL_INT) + { + set_interrupt(INTSTAT_IMMEDIATE_INSTR); + } +#endif +} + + + +/*************************************************************************** + TEXTURE RAM ACCESSORS +***************************************************************************/ + +uint8_t m2_te_device::read_tram8(offs_t address) const +{ + address &= TEXTURE_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + BYTE4_XOR_BE(address); + return *ptr; +} + +uint16_t m2_te_device::read_tram16(offs_t address) const +{ + address &= TEXTURE_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//WORD_XOR_BE(address); + return *reinterpret_cast(ptr); +} + +uint32_t m2_te_device::read_tram32(offs_t address) const +{ + address &= TEXTURE_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//DWORD_XOR_BE(address); + return *reinterpret_cast(ptr); +} + +void m2_te_device::write_tram8(offs_t address, uint8_t data) +{ + assert(address <= TEXTURE_RAM_WORDS * 4); + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//BYTE8_XOR_BE(address); + *ptr = data; +} + +void m2_te_device::write_tram16(offs_t address, uint16_t data) +{ + assert(address < TEXTURE_RAM_WORDS * 4); + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + WORD2_XOR_BE(address); + *reinterpret_cast(ptr) = data; +} + +void m2_te_device::write_tram32(offs_t address, uint32_t data) +{ + address &= TEXTURE_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_tram[0]) + address;//DWORD_XOR_BE(address); + *reinterpret_cast(ptr) = data; +} + + + +/*************************************************************************** + PIP RAM ACCESSORS +***************************************************************************/ + +uint8_t m2_te_device::read_pipram8(offs_t address) const +{ + address &= PIP_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//BYTE4_XOR_BE(address); + return *ptr; +} + +uint16_t m2_te_device::read_pipram16(offs_t address) const +{ + address &= PIP_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//WORD_XOR_BE(address); + return *reinterpret_cast(ptr); +} + +uint32_t m2_te_device::read_pipram32(offs_t address) const +{ + address &= PIP_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//DWORD_XOR_BE(address); + return *reinterpret_cast(ptr); +} + +void m2_te_device::write_pipram32(offs_t address, uint32_t data) +{ + address &= PIP_RAM_BYTEMASK; + + uint8_t *ptr = reinterpret_cast(&m_pipram[0]) + address;//DWORD_XOR_BE(address); + *reinterpret_cast(ptr) = data; +} + + +// For extracting bit fields from RAM +uint32_t m2_te_device::readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits) +{ + uint32_t src_val = m_bda->read_bus32(src_addr); + + if (((bit_offs & 31) + bits) > 32) + { + uint32_t src_val2 = m_bda->read_bus32(src_addr + 4); + + uint32_t r_bits = ((bit_offs & 31) + bits) - 32; + uint32_t l_bits = bits - r_bits; + + src_val &= (1 << l_bits) - 1; + src_val <<= r_bits; + + // Position the right hand side + src_val2 >>= (32 - r_bits); + src_val2 &= (1 << r_bits) - 1; + + src_val |= src_val2; + } + else + { + src_val = src_val >> (32 - (bits + (bit_offs & 31))); + } + + return src_val &= (1 << bits) - 1; +} + +void m2_te_device::load_texture() +{ + switch (m_tm.texld_cntl & TXTLDCNTL_LDMODE_MASK) + { + case TXTLDCNTL_LDMODE_TEXLOAD: + { + if (m_tm.texld_cntl & TXTLDCNTL_COMPRESSED) + { + // Source address is byte aligned + uint32_t src_addr = m_tm.texld_srcbase; + uint32_t bit_offs = m_tm.texld_cntl & TXTLDCNTL_SRCBITOFFS; + + // Destination address is dword-aligned + uint32_t dst_addr = m_tm.texld_dstbase << 3; + int32_t texels = m_tm.tex_bytecnt; + + uint32_t dst_type = m_tm.tex_exptype; + uint32_t dst_cdepth = (dst_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; + uint32_t dst_adepth = (dst_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; + uint32_t dst_bits = 0; + + if (dst_type & TXTEXPFORM_COLORON) + { + if (dst_type & TXTEXPFORM_LITERAL) + dst_bits += dst_cdepth * 3; + else + dst_bits += dst_cdepth; + } + + if (dst_type & TXTEXPFORM_SSBON) + ++dst_bits; + + if (dst_bits & TXTEXPFORM_ALPHAON) + dst_bits += dst_adepth; + + while (texels > 0) + { + uint8_t cntl = readbits_from_ram(src_addr, bit_offs, 8); + + uint32_t type = (cntl >> 6) & 3; + uint32_t cnst; + + // Select constant register + if (type == 0) + cnst = m_tm.tex_srcconst0; + else if (type == 1) + cnst = m_tm.tex_srcconst1; + else if (type == 2) + cnst = m_tm.tex_srcconst2; + else + cnst = m_tm.tex_srcconst3; + + // Select pixel type register + uint32_t src_type = type & 2 ? m_tm.tex_srctype23 : m_tm.tex_srctype01; + + if (type & 1) + src_type = src_type >> 16; + + const bool has_color = src_type & TXTEXPFORM_COLORON; + const bool has_alpha = src_type & TXTEXPFORM_ALPHAON; + const bool has_ssb = src_type & TXTEXPFORM_SSBON; + const bool is_transparent = src_type & TXTEXPFORM_TRANSPARENT; + const bool is_literal = src_type & TXTEXPFORM_LITERAL; + + uint32_t cnt = (cntl & (is_transparent ? 0x3f : 0x1f)) + 1; + + uint32_t src_cdepth = (src_type & TXTEXPFORM_CDEPTH_MASK) >> TXTEXPFORM_CDEPTH_SHIFT; + uint32_t src_adepth = (src_type & TXTEXPFORM_ADEPTH_MASK) >> TXTEXPFORM_ADEPTH_SHIFT; + uint32_t src_bits = 0; + + if (is_literal) + src_cdepth *= 3; + + uint32_t src_val = 0; + + if (is_transparent) + { + src_val = cnst; + } + else + { + src_bits += src_cdepth; + + if (has_ssb) + ++src_bits; + + if (has_alpha) + src_bits += src_adepth; + } + + // String + if (!is_transparent && (cntl & 0x20)) + { + for (uint32_t i = 0; i < cnt; ++i) + { + uint32_t dst_val = 0; + uint32_t src_ssb = 0; + uint32_t src_color = 0; + uint32_t src_alpha = 0; + uint32_t src_val = readbits_from_ram(src_addr, bit_offs, src_bits); + +#if TEST_TIMING // FIXME + g_statistics[STAT_TEXEL_BYTES] += 4; +#endif + + if (has_color) + { + src_color = src_val & ((1 << src_cdepth) - 1); + src_val >>= src_cdepth; + + // Indexed format - add an offset + if (!(src_type & TXTEXPFORM_INDEXON)) + src_color += cnst & 0xff; + } + + if (has_alpha) + { + if (is_transparent) + { + src_alpha = (cnst >> 24) & ((1 << src_adepth) - 1); + } + else + { + src_alpha = src_val & ((1 << src_adepth) - 1); + src_val >>= src_adepth; + } + } + + if (has_ssb) + { + if (is_transparent) + src_ssb = (cnst >> 31) & 1; + else + src_ssb = src_val & 1; + } + + // Now create the destination value + dst_val = src_color + | (src_alpha << src_cdepth) + | (src_ssb << (src_cdepth + src_adepth)); + + uint32_t oldval = m_tram[(dst_addr >> 3) >> 2]; + + // Clear out the old value + uint32_t shift = (32 - (dst_bits + (dst_addr & 31))); + oldval &= ~(((1 << dst_bits) - 1) << shift); + oldval |= dst_val << shift; + + m_tram[(dst_addr >> 3) >> 2] = oldval; + + //src_addr += src_bits; + dst_addr += dst_bits; + } + } + else + { + uint32_t dst_val; + + if (!is_transparent) + { + // Read one texel + src_val = readbits_from_ram(src_addr, bit_offs, src_bits); + +#if TEST_TIMING // FIXME + g_statistics[STAT_TEXEL_BYTES] += 4; +#endif + + // Indexed format - add an offset + if (!is_literal) + src_val += cnst & 0xff; + } + + // HACK: Bits don't match? + dst_val = src_val; + + for (uint32_t i = 0; i < cnt; ++i) + { + uint32_t oldval = m_tram[(dst_addr >> 3) & ~3]; + + // Clear out the old value + uint32_t shift = (32 - (dst_bits + (dst_addr & 31))); + oldval &= ~(((1 << dst_bits) - 1) << shift); + oldval |= dst_val << shift; + + m_tram[(dst_addr >> 3) >> 2] = oldval; + + dst_addr += dst_bits; + } + + // Copy + //src_addr += src_bits; + } + + texels -= cnt; + // assert if negative? + } + } + else + { + // Regular + fatalerror("REGULAR TEXTURE NOT SUPPORTED\n"); + } + + break; + } + + case TXTLDCNTL_LDMODE_MMDMA: + { + uint32_t srcaddr = m_tm.tex_mm_srcbase; + uint32_t dstaddr = m_tm.tex_mm_dstbase; + uint32_t bytes = m_tm.tex_bytecnt; + + // TODO: Do TRAM and PIPRAM only allow 32-bit accesses? + assert((bytes & 3) == 0); + + if (m_tm.tex_cntl & TXTCNTL_MMDMA_TRAM_ON) + { + // TRAM destination must be 32-bit aligned + assert((dstaddr & 3) == 0); + + while (bytes > 0) + { +#if 0 + uint32_t data = m_bda->read_bus32(srcaddr); + write_tram32(dstaddr, data); + dstaddr += 4; + srcaddr += 4; + bytes -= 4; +#else + uint32_t data = m_bda->read_bus8(srcaddr); + write_tram8(dstaddr, data); + dstaddr ++; + srcaddr ++; + bytes--; + +#if TEST_TIMING + g_statistics[STAT_TEXEL_BYTES]++; +#endif + +#endif + } + } + else if (m_tm.tex_cntl & TXTCNTL_MMDMA_PIP_ON) + { + // TODO: Should PIP destination be 32-bit aligned? + assert((dstaddr & 3) == 0); + + while (bytes > 0) + { + uint32_t data = m_bda->read_bus32(srcaddr); + write_pipram32(dstaddr, data); + dstaddr += 4; + srcaddr += 4; + bytes -= 4; + +#if TEST_TIMING + g_statistics[STAT_TEXEL_BYTES] += 4; +#endif + } + } + + break; + } + + case TXTLDCNTL_LDMODE_PIPLOAD: + { + // TODO: What is the difference between this and the MMDMA? + uint32_t srcaddr = m_tm.texld_srcbase; + uint32_t dstaddr = m_tm.texld_dstbase; + uint32_t bytes = m_tm.tex_bytecnt; + + // Assuming byte count must be aligned? + assert((m_tm.tex_bytecnt & 3) == 0); + + while (bytes > 0) + { + uint32_t data = m_bda->read_bus32(srcaddr); + write_pipram32(dstaddr, data); + dstaddr += 4; + srcaddr += 4; + bytes -= 4; +#if TEST_TIMING + g_statistics[STAT_TEXEL_BYTES] += 4; +#endif + } + + break; + } + + default: + { + logerror("UNHANDLED TEXTURE LOAD!\n"); + break; + } + } +} + + + +/*************************************************************************** + TIMERS +***************************************************************************/ + +void m2_te_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case 0: + if (m_gc.te_master_mode & TEICNTL_INT) + set_interrupt(INTSTAT_IMMEDIATE_INSTR); + break; + } + +} diff --git a/src/mame/video/3dom2_te.h b/src/mame/video/3dom2_te.h new file mode 100644 index 00000000000..79320cea99d --- /dev/null +++ b/src/mame/video/3dom2_te.h @@ -0,0 +1,421 @@ +// license:BSD-3-Clause +// copyright-holders:Philip Bennett +/*************************************************************************** + + 3DO M2 BDA Triangle Engine + +***************************************************************************/ + +#pragma once + +#ifndef MAME_VIDEO_3DOM2_TE_H +#define MAME_VIDEO_3DOM2_TE_H + +#include "emu.h" + +/*************************************************************************** + FORWARD DECLARATIONS +***************************************************************************/ + +class m2_bda_device; + +/*************************************************************************** + TRIANGLE ENGINE DEVICE +***************************************************************************/ + +class m2_te_device : public device_t +{ +public: + m2_te_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // Static configuration helpers + auto general_int_handler() { return m_general_int_handler.bind(); } + auto dfinstr_int_handler() { return m_dfinstr_int_handler.bind(); } + auto iminstr_int_handler() { return m_iminstr_int_handler.bind(); } + auto listend_int_handler() { return m_listend_int_handler.bind(); } + auto winclip_int_handler() { return m_winclip_int_handler.bind(); } + + DECLARE_READ32_MEMBER(read); + DECLARE_WRITE32_MEMBER(write); + + uint32_t *tram_ptr() const { return m_tram; } + + enum te_reg_wmode + { + REG_WRITE, + REG_INVALID, + REG_SET, + REG_CLEAR, + }; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_post_load() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + +private: + + enum te_state + { + TE_STOPPED, + TE_PAUSED, + TE_RUNNING, + }; + + enum misc + { + PIP_RAM_WORDS = 256, + TEXTURE_RAM_WORDS = 4096, + PIP_RAM_BYTEMASK = PIP_RAM_WORDS * 4 - 1, + TEXTURE_RAM_BYTEMASK = TEXTURE_RAM_WORDS * 4 - 1, + }; + + enum inst_type + { + INST_WRITE_REG = 0x10000000, + INST_VTX_SHORT = 0x20000000, + INST_VTX_LONG = 0x30000000, + INST_VTX_POINT = 0x40000000, + INST_MASK = 0xf0000000, + }; + + enum vtx_flag + { + VTX_FLAG_SHAD = 0x00010000, + VTX_FLAG_TEXT = 0x00020000, + VTX_FLAG_PRSP = 0x00040000, + VTX_FLAG_NEW = 0x00080000, + VTX_FLAG_RM = 0x00100000, + }; + + struct se_vtx + { + float x, y; + float r, g, b, a; + float w; + float uw, vw; + float iv[8]; + }; + + struct slope_params + { + float y23; + float y31; + float y12; + float x23; + float x31; + float x12; + float xstep_long; + float iAria; + }; + + struct rgba { uint8_t r, g, b, a; }; + + void set_interrupt(uint32_t mask); + void update_interrupts(); + + void teicntl_w(uint32_t data, te_reg_wmode wmode); + void tedcntl_w(uint32_t data, te_reg_wmode wmode); + void master_mode_w(uint32_t data, te_reg_wmode wmode); + + void execute(); + void illegal_inst(); + uint32_t irp_fetch(); + float irp_fetch_float(); + + void add_vertex(const se_vtx &vtx, uint32_t flags); + void log_triangle(uint32_t flags); + void setup_triangle(uint32_t flags); + void calculate_slope(const slope_params &sp, float q1, float q2, float q3, float &slope_out, float &ddx_out); + void walk_edges(uint32_t wrange); + void walk_span(uint32_t wrange, bool omit_right, uint32_t y, uint32_t xs, uint32_t xe, int32_t r, int32_t g, int32_t b, int32_t a, uint32_t uw, uint32_t vw, uint32_t w); + + void texcoord_gen(uint32_t wrange, uint32_t uw, uint32_t vw, uint32_t w, + uint32_t & uo, uint32_t & vo, uint32_t & wo); + + uint32_t lod_calc(uint32_t u0, uint32_t v0, uint32_t u1, uint32_t v1); + + uint32_t get_tram_bitdepth(); + + void addr_calc(uint32_t u, uint32_t v, uint32_t lod, + uint32_t & texaddr, uint32_t & texbit, uint32_t & tdepth); + + void get_texture_color(uint32_t u, uint32_t v, uint32_t lod, + uint32_t & r, uint32_t & g, uint32_t & b, uint32_t & a, uint32_t & s); + + void get_texel(uint32_t u, uint32_t v, uint32_t lod, + uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti); + + void texture_fetch(uint32_t texaddr, uint32_t texbit, uint32_t tdepth, + uint32_t &r_ti, uint32_t &g_ti, uint32_t &b_ti, uint32_t &a_ti, uint32_t &ssb_ti); + + void select_lerp(uint32_t sel, + uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, + uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, + uint32_t & ar, uint32_t & ag, uint32_t & ab ); + + void select_mul(uint32_t sel, uint32_t ai, uint32_t at, uint32_t ssbt, + uint32_t & a ); + + void texture_blend(uint32_t ri, uint32_t gi, uint32_t bi, uint32_t ai, + uint32_t rt, uint32_t gt, uint32_t bt, uint32_t at, uint32_t ssbt, + uint32_t &ro, uint32_t &go, uint32_t &bo, uint32_t &ao, uint32_t &ssbo); + + void destination_blend(uint32_t x, uint32_t y, uint32_t w, const rgba & ti_color, uint8_t ssb); + + uint8_t color_blend(uint8_t ct, uint8_t cti, uint8_t cs, uint8_t csrc, + uint8_t dm10, uint8_t dm11, + uint8_t dm20, uint8_t dm21); + + void select_alpha_dsb(); + uint8_t get_tex_coef(uint8_t cs, uint8_t dm1const0, uint8_t dm1const1); + uint8_t get_src_coef(uint8_t cti, uint8_t dm2const0, uint8_t dm2const1); + uint8_t dither(uint8_t in, uint8_t dithval); + uint8_t alu_calc(uint16_t a, uint16_t b); + void select_src_pixel(); + void select_tex_pixel(); + void write_dst_pixel(); + + uint8_t read_tram8(offs_t address) const; + uint16_t read_tram16(offs_t address) const; + uint32_t read_tram32(offs_t address) const; + void write_tram8(offs_t address, uint8_t data); + void write_tram16(offs_t address, uint16_t data); + void write_tram32(offs_t address, uint32_t data); + + uint8_t read_pipram8(offs_t address) const; + uint16_t read_pipram16(offs_t address) const; + uint32_t read_pipram32(offs_t address) const; + void write_pipram32(offs_t address, uint32_t data); + + uint32_t readbits_from_ram(uint32_t & src_addr, uint32_t & bit_offs, uint32_t bits); + void load_texture(); + + m2_bda_device *m_bda; + const address_space_config m_space_config; // TODO: Why is this still here? + + devcb_write_line m_general_int_handler; + devcb_write_line m_dfinstr_int_handler; + devcb_write_line m_iminstr_int_handler; + devcb_write_line m_listend_int_handler; + devcb_write_line m_winclip_int_handler; + + // Registers + union + { + struct + { + uint32_t te_master_mode; + uint32_t reserved; + uint32_t teicntl_data; + uint32_t teicntl; + uint32_t tedcntl_data; + uint32_t tedcntl; + uint32_t iwp; + uint32_t irp; + uint32_t int_enable; + uint32_t int_status; + uint32_t vertex_ctrl; + }; + uint32_t m_regs[11]; + } m_gc; + + union + { + struct + { + se_vtx vertices[3]; + uint32_t reserved[16]; + uint32_t vertex_state; + }; + uint32_t m_regs[65]; + } m_se; + + struct + { + union + { + struct + { + uint32_t es_cntl; + uint32_t es_capaddr; + uint32_t es_capdata; + }; + uint32_t m_regs[3]; + }; + union + { + struct + { + uint32_t x1; + uint32_t y1; + uint32_t r1; + uint32_t g1; + uint32_t b1; + uint32_t a1; + uint32_t w1; + uint32_t uw1; + uint32_t vw1; + uint32_t x2; + uint32_t y2; + uint32_t y3; + uint32_t xstep_0; + uint32_t xstep_1; + uint32_t xstep_long; + uint32_t xystep_0; + uint32_t xystep_1; + uint32_t xystep_long; + uint32_t dy_0; + uint32_t dy_1; + uint32_t dy_long; + uint32_t ddx_r; + uint32_t ddx_g; + uint32_t ddx_b; + uint32_t ddx_a; + uint32_t ddx_w; + uint32_t ddx_uw; + uint32_t ddx_vw; + uint32_t slope_r; + uint32_t slope_g; + uint32_t slope_b; + uint32_t slope_a; + uint32_t slope_uw; + uint32_t slope_vw; + uint32_t slope_w; + uint32_t r2l; + }; + uint32_t m_buffer_regs[36]; + }; + } m_es; + + union + { + struct + { + uint32_t tex_cntl; + uint32_t texld_cntl; + uint32_t tex_addr_cntl; + uint32_t tex_pip_cntl; + uint32_t tex_tab_cntl; + union + { + uint32_t tex_lod_base0; + uint32_t texld_dstbase; + uint32_t tex_mm_dstbase; + }; + uint32_t tex_lod_base1; + uint32_t tex_lod_base2; + uint32_t tex_lod_base3; + union + { + uint32_t texld_srcbase; + uint32_t tex_mm_srcbase; + }; + union + { + uint32_t tex_bytecnt; + uint32_t tex_rowcnt; + uint32_t tex_texcnt; + }; + uint32_t uv_max; + uint32_t uv_mask; + uint32_t tex_srctype01; + uint32_t tex_srctype23; + uint32_t tex_exptype; + union + { + uint32_t tex_srcconst0; + uint32_t tex_clrconst; + uint32_t tex_catconst0; + }; + union + { + uint32_t tex_srcconst1; + uint32_t tex_pipconst1; + }; + union + { + uint32_t tex_srcconst2; + uint32_t tex_catiConst0; + }; + union + { + uint32_t tex_srcconst3; + uint32_t tex_caticonst1; + }; + uint32_t tex_srcexp; + }; + uint32_t m_regs[21]; + } m_tm; + + union + { + struct + { + uint32_t snoop; + uint32_t supergen_ctrl; + uint32_t usergen_ctrl; + uint32_t discard_ctrl; + uint32_t status; + uint32_t int_ctrl; + uint32_t fbclip; + uint32_t x_winclip; + uint32_t y_winclip; + uint32_t dst_ctrl; + uint32_t dst_baseaddr; + uint32_t dst_xstride; + uint32_t src_ctrl; + uint32_t src_baseaddr; + uint32_t src_xstride; + uint32_t src_offset; + uint32_t z_ctrl; + uint32_t z_baseaddr; + uint32_t z_offset; + uint32_t z_clip; + uint32_t ssbdsb_ctrl; + uint32_t const_in; + uint32_t txt_mult_cntl; + uint32_t txt_coef_const0; + uint32_t txt_coef_const1; + uint32_t src_mult_cntl; + uint32_t src_coef_const0; + uint32_t src_coef_const1; + uint32_t alu_ctrl; + uint32_t src_alpha_ctrl; + uint32_t dst_alpha_ctrl; + uint32_t dst_alpha_const; + uint32_t dither_mat_a; + uint32_t dither_mat_b; + }; + uint32_t m_regs[34]; + } m_db; + + // Destination blender state + struct + { + uint32_t x; + uint32_t y; + uint32_t w; + + rgba ti; + uint8_t ssb; + + rgba src; + uint8_t dsb; + + rgba srcpath; + rgba texpath; + rgba blend; + rgba dst; + } m_dbstate; + + te_state m_state; + + uint32_t *m_pipram; + uint32_t *m_tram; +}; + +DECLARE_DEVICE_TYPE(M2_TE, m2_te_device) + +#endif // MAME_VIDEO_3DOM2_TE_H \ No newline at end of file -- cgit v1.2.3