summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/zeus2.h
blob: 14fc716286fccf1724816a0fcacf41ed389aec63 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/*************************************************************************

    Midway Zeus2 Video

**************************************************************************/
#ifndef __ZEUS2_H__
#define __ZEUS2_H__

#include "video/poly.h"
#include "video/rgbutil.h"
#include "cpu/tms32031/tms32031.h"

#pragma once

/*************************************
*  Constants
*************************************/
#define ZEUS2_VIDEO_CLOCK     XTAL_66_6667MHz

#define DUMP_WAVE_RAM       0
#define TRACK_REG_USAGE     0
#define PRINT_TEX_INFO      0

#define WAVERAM0_WIDTH      1024
#define WAVERAM0_HEIGHT     2048

#define WAVERAM1_WIDTH      512
#define WAVERAM1_HEIGHT     1024

/*************************************
*  Type definitions
*************************************/

struct zeus2_poly_extra_data
{
	const void *    palbase;
	const void *    texbase;
	uint16_t          solidcolor;
	uint16_t          transcolor;
	uint16_t          texwidth;
	uint16_t          color;
	uint32_t          srcAlpha;
	uint32_t		  dstAlpha;
	uint32_t          ctrl_word;
	uint32_t		  ucode_src;
	uint32_t		  tex_src;
	bool			texture_alpha;
	bool			texture_rgb555;
	bool            blend_enable;
	int32_t			zbuf_min;
	bool            depth_min_enable;
	bool            depth_test_enable;
	bool            depth_write_enable;
	bool			depth_clear_enable;

	uint8_t(*get_texel)(const void *, int, int, int);
	uint8_t(*get_alpha)(const void *, int, int, int);
};

/*************************************
*  Macros
*************************************/

#define WAVERAM_BLOCK0(blocknum)                ((void *)((uint8_t *)waveram + 8 * (blocknum)))
#define WAVERAM_BLOCK0_EXT(blocknum)                ((void *)((uint8_t *)m_state->waveram + 8 * (blocknum)))

#define WAVERAM_PTR8(base, bytenum)             ((uint8_t *)(base) + BYTE4_XOR_LE(bytenum))
#define WAVERAM_READ8(base, bytenum)            (*WAVERAM_PTR8(base, bytenum))
#define WAVERAM_WRITE8(base, bytenum, data)     do { *WAVERAM_PTR8(base, bytenum) = (data); } while (0)

#define WAVERAM_PTR16(base, wordnum)            ((uint16_t *)(base) + BYTE_XOR_LE(wordnum))
#define WAVERAM_READ16(base, wordnum)           (*WAVERAM_PTR16(base, wordnum))
#define WAVERAM_WRITE16(base, wordnum, data)    do { *WAVERAM_PTR16(base, wordnum) = (data); } while (0)

#define WAVERAM_PTR32(base, dwordnum)           ((uint32_t *)(base) + (dwordnum))
#define WAVERAM_READ32(base, dwordnum)          (*WAVERAM_PTR32(base, dwordnum))
#define WAVERAM_WRITE32(base, dwordnum, data)   do { *WAVERAM_PTR32(base, dwordnum) = (data); } while (0)

/*************************************
*  Polygon renderer
*************************************/
class zeus2_device;

class zeus2_renderer : public poly_manager<float, zeus2_poly_extra_data, 4, 10000>
{
public:
	zeus2_renderer(zeus2_device *state);

	void render_poly_8bit(int32_t scanline, const extent_t& extent, const zeus2_poly_extra_data& object, int threadid);

	void zeus2_draw_quad(const uint32_t *databuffer, uint32_t texdata, int logit);

private:
	zeus2_device* m_state;
};
typedef zeus2_renderer::vertex_t z2_poly_vertex;
typedef zeus2_renderer::extent_t z2_poly_extent;

/*************************************
*  Zeus2 Video Device
*************************************/
#define MCFG_ZEUS2_VBLANK_CB(_devcb) \
	devcb = &zeus2_device::set_vblank_callback(*device, DEVCB_##_devcb);

#define MCFG_ZEUS2_IRQ_CB(_devcb) \
	devcb = &zeus2_device::set_irq_callback(*device, DEVCB_##_devcb);

#define MCFG_ZEUS2_FLOAT_MODE(_mode) \
	downcast<zeus2_device *>(device)->set_float_mode(_mode);

class zeus2_device : public device_t
{
public:
	zeus2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	screen_device *m_screen;              /* the screen we are acting on */

	uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
	DECLARE_READ32_MEMBER( zeus2_r );
	DECLARE_WRITE32_MEMBER( zeus2_w );
	TIMER_CALLBACK_MEMBER(display_irq_off);
	TIMER_CALLBACK_MEMBER(display_irq);

	template<class _Object> static devcb_base &set_vblank_callback(device_t &device, _Object object) { return downcast<zeus2_device &>(device).m_vblank.set_callback(object); }
	template<class _Object> static devcb_base &set_irq_callback(device_t &device, _Object object) { return downcast<zeus2_device &>(device).m_irq.set_callback(object); }
	devcb_write_line   m_vblank;
	devcb_write_line   m_irq;

	void set_float_mode(int mode) { m_atlantis = mode; }
	int m_atlantis; // Used to switch to using IEEE754 floating point format for atlantis

	uint32_t m_zeusbase[0x80];
	uint32_t m_renderRegs[0x50];

	zeus2_renderer* poly;

	rectangle zeus_cliprect;

	int m_palSize;
	float zeus_matrix[3][3];
	float zeus_trans[4];
	float zeus_light[3];
	uint32_t zeus_texbase;
	int zeus_quad_size;
	bool m_useZOffset;

	uint32_t *waveram;
	std::unique_ptr<uint32_t[]> m_frameColor;
	std::unique_ptr<int32_t[]> m_frameDepth;
	uint32_t m_pal_table[0x100];
	uint32_t m_ucode[0x200];
	uint32_t m_curUCodeSrc;
	uint32_t m_curPalTableSrc;
	uint32_t m_texmodeReg;

	emu_timer *int_timer;
	emu_timer *vblank_timer;
	int yoffs;
	int texel_width;
	float zbase;

	enum { THEGRID, CRUSNEXO, MWSKINS };
	int m_system;
#if PRINT_TEX_INFO
	void check_tex(uint32_t &texmode, float &zObj, float &zMat, float &zOff);
	std::string tex_info(void);
#endif

protected:
	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_stop() override;

private:
	TIMER_CALLBACK_MEMBER(int_timer_callback);
	void zeus2_register32_w(offs_t offset, uint32_t data, int logit);
	void zeus2_register_update(offs_t offset, uint32_t oldval, int logit);
	bool zeus2_fifo_process(const uint32_t *data, int numwords);
	void zeus2_pointer_write(uint8_t which, uint32_t value, int logit);
	void load_pal_table(void *wavePtr, uint32_t ctrl, int type, int logit);
	void load_ucode(void *wavePtr, uint32_t ctrl, int logit);
	void zeus2_draw_model(uint32_t baseaddr, uint16_t count, int logit);
	void log_fifo_command(const uint32_t *data, int numwords, const char *suffix);
	void print_fifo_command(const uint32_t *data, int numwords, const char *suffix);
	void log_render_info(uint32_t texdata);

	/*************************************
	*  Member variables
	*************************************/
	uint8_t log_fifo;

	uint32_t zeus_fifo[20];
	uint8_t zeus_fifo_words;

	uint32_t m_fill_color;
	int32_t m_fill_depth;

	int m_yScale;

#if PRINT_TEX_INFO
	std::map<uint32_t, std::string> tex_map;
#endif

#if TRACK_REG_USAGE
	struct reg_info
	{
		struct reg_info *next;
		uint32_t value;
	};

	reg_info *regdata[0x80];
	int regdata_count[0x80];
	int regread_count[0x80];
	int regwrite_count[0x80];
	reg_info *subregdata[0x100];
	int subregdata_count[0x80];
	int subregwrite_count[0x100];
#endif
public:
	/*************************************
	*  Inlines for block addressing
	*************************************/
	inline float convert_float(uint32_t val)
	{
		if (m_atlantis) {
			return reinterpret_cast<float&>(val);
		}
		else
			return tms3203x_device::fp_to_float(val);
	}

	inline uint32_t frame_addr_from_xy(uint32_t x, uint32_t y, bool render)
	{
		uint32_t addr;
		if (render) {
			// Rendering is y location
			addr = m_renderRegs[0x4] << (9 + m_yScale);
		}
		else {
			// y.16:x.16 row/col
			// Ignore col for now
			addr = m_zeusbase[0x38] >> (16 - 9 - 2 * m_yScale);
		}
		//uint32_t addr = render ? frame_addr_from_phys_addr(m_renderRegs[0x4] << (15 + m_yScale))
		//	: frame_addr_from_phys_addr((m_zeusbase[0x38] >> 1) << (m_yScale << 1));
		addr += (y << (9 + m_yScale)) + x;
		return addr;
	}

	// Convert 0xRRRRCCCC to frame buffer address
	//inline uint32_t frame_addr_from_expanded_addr(uint32_t addr)
	//{
	//  return (((addr & 0x3ff0000) >> (16 - 9 + 1)) | (addr & 0x1ff)) << 1;
	//}

	// Convert Physical 0xRRRRCCCC to frame buffer address
	// Based on address reg 51 (no scaling)
	inline uint32_t frame_addr_from_phys_addr(uint32_t physAddr)
	{
		uint32_t addr = (((physAddr & 0x3ff0000) >> (16 - 9)) | (physAddr & 0x1ff)) << 1;
		return addr;
	}

	// Read from frame buffer
	inline void frame_read()
	{
		uint32_t addr = frame_addr_from_phys_addr(m_zeusbase[0x51]);
		m_zeusbase[0x58] = m_frameColor[addr];
		m_zeusbase[0x59] = m_frameColor[addr + 1];
		m_zeusbase[0x5a] = *(uint32_t*)&m_frameDepth[addr];
		if (m_zeusbase[0x5e] & 0x40)
		{
			m_zeusbase[0x51]++;
			m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7;
			m_zeusbase[0x51] &= ~0xfe00;
		}
	}

	// Write to frame buffer
	inline void frame_write()
	{
		uint32_t addr = frame_addr_from_phys_addr(m_zeusbase[0x51]);
		if (m_zeusbase[0x57] & 0x1)
			m_frameColor[addr] = m_zeusbase[0x58];
		if (m_zeusbase[0x5e] & 0x20) {
			if (m_zeusbase[0x57] & 0x4)
				m_frameColor[addr + 1] = m_zeusbase[0x5a];
		} else
		{
			if (m_zeusbase[0x57] & 0x4)
					m_frameColor[addr + 1] = m_zeusbase[0x59];
			if (m_zeusbase[0x57] & 0x10)
				*(uint32_t*)&m_frameDepth[addr] = m_zeusbase[0x5a];
		}

		if (m_zeusbase[0x5e] & 0x40)
		{
			m_zeusbase[0x51]++;
			m_zeusbase[0x51] += (m_zeusbase[0x51] & 0x200) << 7;
			m_zeusbase[0x51] &= ~0xfe00;
		}
	}

	inline void *waveram0_ptr_from_expanded_addr(uint32_t addr)
	{
		uint32_t blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
		return WAVERAM_BLOCK0(blocknum);
	}

#ifdef UNUSED_FUNCTION
	inline void *waveram0_ptr_from_texture_addr(uint32_t addr, int width)
	{
		uint32_t blocknum = ((addr & ~1) * width) / 8;
		return WAVERAM_BLOCK0(blocknum);
	}
#endif

	/*************************************
	*  Inlines for rendering
	*************************************/
	inline uint32_t conv_rgb555_to_rgb32(uint16_t color)
	{
		return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x1f) << 3);
	}

	inline uint32_t conv_rgb565_to_rgb32(uint16_t color)
	{
		return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x8000) >> 5) | ((color & 0x1f) << 3);
	}
	inline uint32_t conv_rgb332_to_rgb32(uint8_t color)
	{
		uint32_t result;
		result =  ((((color) >> 0) & 0xe0) | (((color) >> 3) & 0x1c) | (((color) >> 6) & 0x03)) << 16;
		result |= ((((color) << 3) & 0xe0) | (((color) >> 0) & 0x1c) | (((color) >> 3) & 0x03)) << 8;
		result |= ((((color) << 6) & 0xc0) | (((color) << 4) & 0x30) | (((color) << 2) & 0x0c) | (((color) << 0) & 0x03)) << 0;
		return result;
	}
#ifdef UNUSED_FUNCTION
	inline void WAVERAM_plot(int y, int x, uint32_t color)
	{
		if (zeus_cliprect.contains(x, y))
			WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
	}
#endif

#ifdef UNUSED_FUNCTION
	inline void waveram_plot_depth(int y, int x, uint32_t color, uint16_t depth)
	{
		if (zeus_cliprect.contains(x, y))
		{
			WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
			WAVERAM_WRITEDEPTH(zeus_renderbase, y, x, depth);
		}
	}
#endif

#ifdef UNUSED_FUNCTION
	inline void waveram_plot_check_depth(int y, int x, uint32_t color, uint16_t depth)
	{
		if (zeus_cliprect.contains(x, y))
		{
			uint16_t *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x);
			if (depth <= *depthptr)
			{
				WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
				*depthptr = depth;
			}
		}
	}
#endif

#ifdef UNUSED_FUNCTION
	inline void waveram_plot_check_depth_nowrite(int y, int x, uint32_t color, uint16_t depth)
	{
		if (zeus_cliprect.contains(x, y))
		{
			uint16_t *depthptr = WAVERAM_PTRDEPTH(zeus_renderbase, y, x);
			if (depth <= *depthptr)
				WAVERAM_WRITEPIX(zeus_renderbase, y, x, color);
		}
	}
#endif
	/*************************************
	*  Inlines for texel accesses
	*************************************/
	// 4x2 block size
	static inline uint8_t get_texel_4bit_4x2(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 8) << 3) + ((y & 1) << 2) + ((x / 2) & 3);
		return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
	}

	static inline uint8_t get_texel_8bit_4x2(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 4) << 3) + ((y & 1) << 2) + (x & 3);
		return WAVERAM_READ8(base, byteoffs);
	}

	// 2x2 block size within 32 bits, 2 2x2 blocks stacked in y in 64 bits
	static inline uint8_t get_texel_4bit_2x2(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 4) * (width * 4) + ((x / 4) << 3) + ((y & 3) << 1) + ((x / 2) & 1);
		return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
	}

	static inline uint8_t get_texel_8bit_2x2(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 4) * (width * 4) + ((x / 2) << 3) + ((y & 3) << 1) + (x & 1);
		return WAVERAM_READ8(base, byteoffs);
	}
	// 2x2 block size of texel, alpha in 64 bits
	// 8 Bit texel, 8 bit alpha
	static inline uint8_t get_texel_8bit_2x2_alpha(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
		// Only grab RGB value for now
		byteoffs <<= 1;
		return WAVERAM_READ8(base, byteoffs + 0);
	}
	static inline uint8_t get_alpha_8bit_2x2_alpha(const void *base, int y, int x, int width)
	{
		uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
		// Only grab Alpha value for now
		byteoffs <<= 1;
		return WAVERAM_READ8(base, byteoffs + 1);
	}
	// 2x2 block size of r5g5r5 in 64 bits
	static inline uint32_t get_rgb555(const void *base, int y, int x, int width)
	{
		uint32_t wordoffs = (y / 2) * (width * 2) + ((x / 2) << 2) + ((y & 1) << 1) + (x & 1);
		uint16_t color = WAVERAM_READ16(base, wordoffs);
		return ((color & 0x7c00) << 9) | ((color & 0x3e0) << 6) | ((color & 0x1f) << 3);
	}

};

// device type definition
extern const device_type ZEUS2;

#endif