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