1 // license:BSD-3-Clause 2 // copyright-holders:Anthony Kruize, Fabio Priuli 3 /*************************************************************************** 4 5 SNES PPU 6 7 ***************************************************************************/ 8 9 #ifndef MAME_VIDEO_SNES_PPU_H 10 #define MAME_VIDEO_SNES_PPU_H 11 12 #pragma once 13 14 #include "screen.h" 15 16 17 #define MCLK_NTSC (21477272) /* verified */ 18 #define MCLK_PAL (21218370) /* verified */ 19 20 #define DOTCLK_NTSC (MCLK_NTSC/4) 21 #define DOTCLK_PAL (MCLK_PAL/4) 22 23 #define SNES_SCR_WIDTH 256 /* 32 characters 8 pixels wide */ 24 #define SNES_SCR_HEIGHT_NTSC 225 /* Can be 224 or 240 height */ 25 #define SNES_SCR_HEIGHT_PAL 240 /* ??? */ 26 #define SNES_VTOTAL_NTSC 262 /* Maximum number of lines for NTSC systems */ 27 #define SNES_VTOTAL_PAL 312 /* Maximum number of lines for PAL systems */ 28 #define SNES_HTOTAL 341 /* Maximum number pixels per line (incl. hblank) */ 29 30 #define SNES_NTSC 0x00 31 #define SNES_PAL 0x10 32 33 34 #define SNES_LAYER_DEBUG 0 35 36 37 // ======================> snes_ppu_device 38 39 class snes_ppu_device : public device_t, 40 public device_video_interface 41 { 42 public: 43 // construction/destruction 44 snes_ppu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 45 46 // inline configuration helpers open_bus_callback()47 auto open_bus_callback() { return m_openbus_cb.bind(); } 48 49 void refresh_scanline(bitmap_rgb32 &bitmap, uint16_t curline); 50 current_x()51 int16_t current_x() const { return screen().hpos(); } current_y()52 int16_t current_y() const { return screen().vpos(); } 53 void set_latch_hv(int16_t x, int16_t y); 54 55 uint8_t read(uint32_t offset, uint8_t wrio_bit7); 56 void write(uint32_t offset, uint8_t data); 57 vtotal()58 int vtotal() const { return ((m_stat78 & 0x10) == SNES_NTSC) ? SNES_VTOTAL_NTSC : SNES_VTOTAL_PAL; } htmult()59 uint16_t htmult() const { return m_htmult; } interlace()60 uint8_t interlace() const { return m_interlace; } screen_disabled()61 bool screen_disabled() const { return bool(m_screen_disabled); } last_visible_line()62 uint8_t last_visible_line() const { return m_beam.last_visible_line; } current_vert()63 uint16_t current_vert() const { return m_beam.current_vert; } 64 65 void oam_address_reset(); 66 void oam_set_first_object(); 67 clear_time_range_over()68 void clear_time_range_over() { m_stat77 &= 0x3f; } toggle_field()69 void toggle_field() { m_stat78 ^= 0x80; } reset_interlace()70 void reset_interlace() 71 { 72 m_htmult = 1; 73 m_interlace = 1; 74 m_oam.interlace = 0; 75 } 76 void set_current_vert(uint16_t value); 77 78 protected: 79 /* offset-per-tile modes */ 80 enum 81 { 82 SNES_OPT_NONE = 0, 83 SNES_OPT_MODE2, 84 SNES_OPT_MODE4, 85 SNES_OPT_MODE6 86 }; 87 88 /* layers */ 89 enum 90 { 91 SNES_BG1 = 0, 92 SNES_BG2, 93 SNES_BG3, 94 SNES_BG4, 95 SNES_OAM, 96 SNES_COLOR 97 }; 98 99 100 struct SNES_SCANLINE 101 { 102 int enable, clip; 103 104 uint16_t buffer[SNES_SCR_WIDTH]; 105 uint8_t priority[SNES_SCR_WIDTH]; 106 uint8_t layer[SNES_SCR_WIDTH]; 107 uint8_t blend_exception[SNES_SCR_WIDTH]; 108 }; 109 110 uint8_t m_regs[0x40]; 111 112 SNES_SCANLINE m_scanlines[2]; 113 114 struct layer_t 115 { 116 /* clipmasks */ 117 uint8_t window1_enabled, window1_invert; 118 uint8_t window2_enabled, window2_invert; 119 uint8_t wlog_mask; 120 /* color math enabled */ 121 uint8_t color_math; 122 123 uint16_t charmap; 124 uint16_t tilemap; 125 uint8_t tilemap_size; 126 127 uint8_t tile_size; 128 uint8_t tile_mode; 129 uint8_t mosaic_enabled; // actually used only for layers 0->3! 130 131 uint8_t main_window_enabled; 132 uint8_t sub_window_enabled; 133 uint8_t main_bg_enabled; 134 uint8_t sub_bg_enabled; 135 136 uint16_t hoffs; 137 uint16_t voffs; 138 139 uint8_t priority[2]; 140 141 uint16_t mosaic_counter; 142 uint16_t mosaic_offset; 143 }; 144 145 layer_t m_layer[6]; // this is for the BG1 - BG2 - BG3 - BG4 - OBJ - color layers 146 147 struct 148 { 149 uint16_t address; 150 uint16_t base_address; 151 uint8_t priority_rotation; 152 uint16_t tile_data_address; 153 uint8_t name_select; 154 uint8_t base_size; 155 uint8_t first; 156 uint16_t write_latch; 157 uint8_t data_latch; 158 uint8_t interlace; 159 uint8_t priority[4]; 160 } m_oam; 161 162 struct 163 { 164 uint16_t latch_horz; 165 uint16_t latch_vert; 166 uint16_t current_vert; 167 uint8_t last_visible_line; 168 uint8_t interlace_count; 169 } m_beam; 170 171 struct 172 { 173 uint8_t repeat; 174 uint8_t hflip; 175 uint8_t vflip; 176 int16_t matrix_a; 177 int16_t matrix_b; 178 int16_t matrix_c; 179 int16_t matrix_d; 180 int16_t origin_x; 181 int16_t origin_y; 182 int16_t hor_offset; 183 int16_t ver_offset; 184 uint8_t extbg; 185 } m_mode7; 186 187 #if SNES_LAYER_DEBUG 188 struct DEBUGOPTS 189 { 190 uint8_t bg_disabled[5]; 191 uint8_t mode_disabled[8]; 192 uint8_t draw_subscreen; 193 uint8_t windows_disabled; 194 uint8_t mosaic_disabled; 195 uint8_t colormath_disabled; 196 uint8_t select_pri[5]; 197 }; 198 struct DEBUGOPTS m_debug_options; 199 uint8_t dbg_video( uint16_t curline ); 200 #endif 201 202 uint8_t m_mosaic_size; 203 uint8_t m_clip_to_black; 204 uint8_t m_prevent_color_math; 205 uint8_t m_sub_add_mode; 206 uint8_t m_bg_priority; 207 uint8_t m_direct_color; 208 uint8_t m_ppu_last_scroll; /* as per Anomie's doc and Theme Park, all scroll regs shares (but mode 7 ones) the same 209 'previous' scroll value */ 210 uint8_t m_mode7_last_scroll; /* as per Anomie's doc mode 7 scroll regs use a different value, shared with mode 7 matrix! */ 211 212 uint8_t m_ppu1_open_bus, m_ppu2_open_bus; 213 uint8_t m_ppu1_version, m_ppu2_version; 214 uint8_t m_window1_left, m_window1_right, m_window2_left, m_window2_right; 215 216 uint16_t m_mosaic_table[16][4096]; 217 uint8_t m_clipmasks[6][SNES_SCR_WIDTH]; 218 uint8_t m_mode; 219 uint8_t m_interlace; //doubles the visible resolution 220 uint8_t m_screen_brightness; 221 uint8_t m_screen_disabled; 222 uint8_t m_pseudo_hires; 223 uint8_t m_color_modes; 224 uint8_t m_stat77; 225 uint8_t m_stat78; 226 227 uint16_t m_htmult; /* in 512 wide, we run HTOTAL double and halve it on latching */ 228 uint16_t m_cgram_address; /* CGRAM address */ 229 uint8_t m_read_ophct; 230 uint8_t m_read_opvct; 231 uint16_t m_vram_fgr_high; 232 uint16_t m_vram_fgr_increment; 233 uint16_t m_vram_fgr_count; 234 uint16_t m_vram_fgr_mask; 235 uint16_t m_vram_fgr_shift; 236 uint16_t m_vram_read_buffer; 237 uint16_t m_vmadd; 238 239 struct object_item 240 { 241 bool valid; 242 uint8_t index; 243 uint8_t width; 244 uint8_t height; 245 }; 246 247 struct object_tile 248 { 249 bool valid; 250 uint16_t x; 251 uint8_t y; 252 uint8_t pri; 253 uint8_t pal; 254 uint8_t hflip; 255 uint32_t data; 256 }; 257 258 struct object 259 { 260 uint16_t x; 261 uint8_t y; 262 uint8_t character; 263 uint8_t name_select; 264 uint8_t vflip; 265 uint8_t hflip; 266 uint8_t pri; 267 uint8_t pal; 268 uint8_t size; 269 }; 270 271 inline uint32_t get_tile(uint8_t layer_idx, uint32_t hoffset, uint32_t voffset); 272 void update_line(uint16_t curline, uint8_t layer, uint8_t direct_colors); 273 void update_line_mode7(uint16_t curline, uint8_t layer_idx); 274 void update_objects(uint16_t curline); 275 void update_mode_0(uint16_t curline); 276 void update_mode_1(uint16_t curline); 277 void update_mode_2(uint16_t curline); 278 void update_mode_3(uint16_t curline); 279 void update_mode_4(uint16_t curline); 280 void update_mode_5(uint16_t curline); 281 void update_mode_6(uint16_t curline); 282 void update_mode_7(uint16_t curline); 283 void draw_screens(uint16_t curline); 284 void render_window(uint16_t layer_idx, uint8_t enable, uint8_t *output); 285 inline void plot_above(uint16_t x, uint8_t source, uint8_t priority, uint16_t color, int blend_exception = 0); 286 inline void plot_below(uint16_t x, uint8_t source, uint8_t priority, uint16_t color, int blend_exception = 0); 287 void update_color_windowmasks(uint8_t mask, uint8_t *output); 288 void update_video_mode(void); 289 void cache_background(); 290 uint16_t pixel(uint16_t x, SNES_SCANLINE *above, SNES_SCANLINE *below, uint8_t *window_above, uint8_t *window_below); 291 uint16_t direct_color(uint16_t palette, uint16_t group); 292 inline uint16_t blend(uint16_t x, uint16_t y, bool halve); 293 294 void dynamic_res_change(); 295 inline uint32_t get_vram_address(); 296 297 uint8_t read_oam(uint16_t address); 298 void write_oam(uint16_t address, uint8_t data); 299 uint8_t read_object(uint16_t address); 300 void write_object(uint16_t address, uint8_t data); 301 302 uint8_t cgram_read(offs_t offset); 303 void cgram_write(offs_t offset, uint8_t data); 304 uint8_t vram_read(offs_t offset); 305 void vram_write(offs_t offset, uint8_t data); 306 object m_objects[128]; /* Object Attribute Memory (OAM) */ 307 std::unique_ptr<uint16_t[]> m_cgram; /* Palette RAM */ 308 std::unique_ptr<uint8_t[]> m_vram; /* Video RAM (TODO: Should be 16-bit, but it's easier this way) */ 309 std::unique_ptr<std::unique_ptr<uint16_t[]>[]> m_light_table; /* Luma ramp */ 310 311 // device-level overrides 312 virtual void device_start() override; 313 virtual void device_reset() override; 314 315 private: 316 devcb_read16 m_openbus_cb; 317 optional_ioport m_options; 318 optional_ioport m_debug1; 319 optional_ioport m_debug2; 320 optional_ioport m_debug3; 321 optional_ioport m_debug4; 322 }; 323 324 325 // device type definition 326 DECLARE_DEVICE_TYPE(SNES_PPU, snes_ppu_device) 327 328 329 #endif // MAME_VIDEO_SNES_PPU_H 330