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