summaryrefslogtreecommitdiffstats
path: root/src/mame/includes/lynx.h
blob: ffce5bdb741bd4c9f4b9f974baa12e05966db540 (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
// license:GPL-2.0+
// copyright-holders:Peter Trauner
/*****************************************************************************

 Atari Lynx

******************************************************************************/
#ifndef MAME_INCLUDES_LYNX_H
#define MAME_INCLUDES_LYNX_H

#pragma once

#include "emupal.h"
#include "screen.h"
#include "sound/lynx.h"
#include "imagedev/snapquik.h"
#include "bus/generic/slot.h"
#include "bus/generic/carts.h"

#define LYNX_CART       0
#define LYNX_QUICKLOAD  1


#define NR_LYNX_TIMERS  8

class lynx_state : public driver_device
{
public:
	lynx_state(const machine_config &mconfig, device_type type, const char *tag) :
		driver_device(mconfig, type, tag),
		m_dram(*this, "dram"),
		m_maincpu(*this, "maincpu"),
		m_sound(*this, "custom"),
		m_cart(*this, "cartslot"),
		m_palette(*this, "palette"),
		m_screen(*this, "screen"),
		m_suzy_view(*this, "suzy_view"),
		m_mikey_view(*this, "mikey_view"),
		m_rom_view(*this, "rom_view"),
		m_vector_view(*this, "vector_view"),
		m_joy_io(*this, "JOY"),
		m_pause_io(*this, "PAUSE")
	{ }

	void lynx(machine_config &config);

protected:
	virtual void machine_start() override;
	virtual void machine_reset() override;
	virtual void video_start() override;

	virtual void device_post_load() override;

private:
	struct BLITTER
	{
		// 0xfc80 SPRCTL0 Sprite control bits 0
		u8     BPP()            const { return BIT(spr_ctl0, 6, 2); } // Bit per pixel - 1
		bool   HFLIP()          const { return BIT(spr_ctl0, 5); }    // Horizontal flip
		bool   VFLIP()          const { return BIT(spr_ctl0, 4); }    // Vertical flip
		u8     SPRITE_TYPE()    const { return BIT(spr_ctl0, 0, 3); } // Sprite type

		// 0xfc81 SPRCTL1 Sprite control bits 1
		bool   RLE()            const { return BIT(spr_ctl1, 7); }    // Normal(1) or RLE(0) sprite
		//bool ALGO3()          const { return BIT(spr_ctl1, 6); }    // Size algorithm, Adder(0, Algo4), Shifter(1, algo3) (not implemented)
		u8     RELOAD_SCALE()   const { return BIT(spr_ctl1, 4, 2); } // Reload scale factors
		bool   REUSE_PALETTE()  const { return BIT(spr_ctl1, 3); }    // Reload(0) or Reuse(1) palette
		bool   SKIP_SPRITE()    const { return BIT(spr_ctl1, 2); }    // Skip this sprite
		u8     DRAW_ORIGIN()    const { return BIT(spr_ctl1, 0, 2); } // Start draw origin
		//bool DRAW_UP()        const { return BIT(spr_ctl1, 1); }    // Start drawing up(1) or down(0)
		//bool DRAW_LEFT()      const { return BIT(spr_ctl1, 0); }    // Start drawing left(1) or right(0)

		// 0xfc82 SPRCOLL Sprite collision number
		bool   SPRITE_COLLEN()  const { return BIT(spr_coll, 5); }    // Sprite collide(0) or Don't collide(1) flag
		u8     SPRITE_COLNUM()  const { return BIT(spr_coll, 0, 4); } // Sprite collision number

		bool   SPRITE_COLLIDE() const { return sprite_collide && (!(no_collide)); } // collision enabled?

		// global
		u16 screen = 0;
		u16 colbuf = 0;
		u16 colpos = 0; // byte where value of collision is written
		s16 xoff = 0;
		s16 yoff = 0;
		// in command
		u8 mode = 0;
		u8 spr_coll = 0;
		u8 spritenr = 0;
		s16 x_pos = 0;
		s16 y_pos = 0;
		u16 width = 0;
		u16 height = 0; // uint16 important for blue lightning
		s16 tilt_accumulator = 0;
		u16 height_accumulator = 0;
		u16 width_accumulator = 0;
		u16 width_offset = 0;
		u16 height_offset = 0;
		s16 stretch = 0;
		s16 tilt = 0;
		u8 color[16] = {0}; // or stored
		u16 bitmap = 0;
		bool use_rle = false;
		u8 line_color = 0;

		u8 spr_ctl0 = 0;
		u8 spr_ctl1 = 0;
		u16 scb = 0;
		u16 scb_next = 0;
		bool sprite_collide = false;

		bool everon = false;
		u8 fred = 0;
		u32 memory_accesses = 0;
		//attotime time;

		bool no_collide = false;
		bool vstretch = false;
		bool lefthanded = false;
		bool busy = false;
	};

	struct UART
	{
		// 0xfd8c SERCTL Serial control register (Write)
		bool   TXINTEN()  const { return BIT(serctl, 7); } // Transmit interrupt enable
		bool   RXINTEN()  const { return BIT(serctl, 6); } // Receive interrupt enable
		//bool PAREN()    const { return BIT(serctl, 4); } // Xmit parity bit enable (not implemented)
		//bool RESETERR() const { return BIT(serctl, 3); } // Reset all errors (not implemented)
		//bool TXOPEN()   const { return BIT(serctl, 2); } // Open collector driver(1) or TTL driver(0) (not implemented)
		//bool TXBRK()    const { return BIT(serctl, 1); } // Send a break (not implemented)
		//bool PAREVEN()  const { return BIT(serctl, 0); } // Send/Recevie even parity (not implemented)

		u8 serctl = 0;
		u8 data_received = 0;
		u8 data_to_send = 0;
		u8 buffer = 0;
		bool received = false;
		bool sending = false;
		bool buffer_loaded = false;
	};

	struct SUZY
	{
		// 0xfc91 SPRGO Sprite process start bit
		bool EVER_ON()   const { return BIT(data[0x91], 2); } // Everon detector enable
		bool SPRITE_GO() const { return BIT(data[0x91], 0); } // Sprite process enable

		u8 data[0x100] = {0};
		bool signed_math = false;
		bool accumulate = false;
		bool accumulate_overflow = false;
	};

	struct MIKEY
	{
		// 0xfd8a IODIR
		u8 IODIR() const { return data[0x8a]; } // Parallel I/O direction

		// 0xfd8b IODAT
		u8 IODAT() const { return data[0x8b]; } // Parallel I/O data

		// 0xfd92 DISPCTL Video bus request enable
		//bool COLOR()       const { return BIT(data[0x92], 3); } // Color(1) or Monochrome(0) display (not implemented)
		//bool FOURBIT()     const { return BIT(data[0x92], 2); } // 4bpp(1) or 2bpp(0) color (not implemented)
		bool   FLIP_SCREEN() const { return BIT(data[0x92], 1); } // Flipped screen
		//bool VIDEO_DMA()   const { return BIT(data[0x92], 0); } // Video DMA enabled (not implemented)

		u8 data[0x100] = {0};
		u16 disp_addr = 0;
		bool vb_rest = false;
		u8 interrupt = 0;
	};

	struct LYNX_TIMER
	{
		bool   int_en()      const { return BIT(cntrl1, 7); }         // Interrupt enable
		//bool reset_done()  const { return BIT(cntrl1, 6); }         // Reset timer done flag
		bool   reload_en()   const { return BIT(cntrl1, 4); }         // Reload enable
		bool   count_en()    const { return BIT(cntrl1, 3); }         // Count enable
		u8     timer_clock() const { return BIT(cntrl1, 0, 3); }      // Timer clock
		bool   linked()      const { return timer_clock() == 0b111; } // Linked timer?

		bool   timer_done()  const { return BIT(cntrl2, 3); }         // Timer done flag
		//bool last_clock()  const { return BIT(cntrl2, 2); }         // Last clock (not implemented)
		//bool borrow_in()   const { return BIT(cntrl2, 1); }         // Borrow in (not implemented)
		bool   borrow_out()  const { return BIT(cntrl2, 0); }         // Borrow out

		// set timer done flag
		void set_timer_done(bool set)
		{
			if (set) // set
				cntrl2 |= 8;
			else // clear
				cntrl2 &= ~8;
		}

		// set borrow out flag
		void set_borrow_out(bool set)
		{
			if (set) // set
				cntrl2 |= 1;
			else // clear
				cntrl2 &= ~1;
		}

		u8   bakup = 0;
		u8   cntrl1 = 0;
		u8   cntrl2 = 0;
		u8   counter = 0;
		emu_timer *timer = nullptr;
		bool      timer_active = false;
	};

	enum
	{
		TIMER_BLITTER,
		TIMER_SHOT,
		TIMER_UART_LOOPBACK,
		TIMER_UART
	};

	// devices
	required_shared_ptr<u8> m_dram; // 2 64Kx4 bit DRAMs connected to CPU
	required_device<cpu_device> m_maincpu;
	required_device<lynx_sound_device> m_sound;
	required_device<generic_slot_device> m_cart;
	required_device<palette_device> m_palette;
	required_device<screen_device> m_screen;

	// memory views
	memory_view m_suzy_view;
	memory_view m_mikey_view;
	memory_view m_rom_view;
	memory_view m_vector_view;

	// io ports
	required_ioport m_joy_io;
	required_ioport m_pause_io;

	// timers
	emu_timer *m_blitter_timer = nullptr;
	emu_timer *m_loopback_timer = nullptr;
	emu_timer *m_uart_timer = nullptr;

	// connected to cartridge slot
	inline u32 get_cart_addr() { return (BIT(m_mikey.IODAT(), 4) * m_audin_offset) + (m_cart_addr_block * m_granularity) + m_cart_addr_counter; }
	u8 m_cart_addr_block = 0; // Address block (74HC164 at schematics, connected to cartridge slot A12...A19)
	u16 m_cart_addr_counter = 0; // Address counter (4040 at schematics, connected to cartridge slot A0...A10)
	u16 m_granularity = 0; // Address counter granularity
	u32 m_audin_offset = 0; // Some cartridge uses AUDIN pin for bankswitch
	// AUDIN pin, can be input or output

	// internal states
	int m_sign_AB = 1;
	int m_sign_CD = 1;
	int m_rotate = 0;
	u8 m_memory_config;
	u32 m_pixclock = ~0;
	u8 m_hcount = ~0;
	u8 m_vcount = ~0;

	BLITTER m_blitter;
	SUZY m_suzy;
	MIKEY m_mikey;
	UART m_uart;
	LYNX_TIMER m_timer[NR_LYNX_TIMERS];

	bitmap_rgb32 m_bitmap;
	bitmap_rgb32 m_bitmap_temp;

	void cpu_map(address_map &map);

	u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);

	u8 suzy_read(offs_t offset);
	void suzy_write(offs_t offset, u8 data);
	void uart_w(offs_t offset, u8 data);
	u8 uart_r(offs_t offset);
	u8 mikey_read(offs_t offset);
	void mikey_write(offs_t offset, u8 data);
	u8 memory_config_r();
	void memory_config_w(u8 data);
	void suzy_divide();
	void suzy_multiply();
	u8 timer_read(int which, int offset);
	void timer_write(int which, int offset, u8 data);
	void update_screen_timing();
	void sound_cb();
	TIMER_CALLBACK_MEMBER(blitter_timer);
	TIMER_CALLBACK_MEMBER(timer_shot);
	TIMER_CALLBACK_MEMBER(uart_loopback_timer);
	TIMER_CALLBACK_MEMBER(uart_timer);
	DECLARE_DEVICE_IMAGE_LOAD_MEMBER(cart_load);

	// DRAM accessor, 0xfff8-0xfff9 Reserved?
	inline u8 dram_byte_r(u16 addr) { return ((addr & 0xfffe) != 0xfff8) ? m_dram[addr] : 0; }
	inline void dram_byte_w(u16 addr, u8 data, u8 mem_mask = ~0) { if ((addr & 0xfffe) != 0xfff8) { COMBINE_DATA(&m_dram[addr]); } }
	inline u16 dram_word_r(u16 addr) { return dram_byte_r(addr) | (u16(dram_byte_r((addr + 1) & 0xffff)) << 8); }

	inline void plot_pixel(const s16 x, const s16 y, const u8 color);
	void blit_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask);
	void blit_rle_do_work(const s16 y, const int xdir, const int bits_per_pixel, const u8 mask);
	void blit_lines();
	void blitter();
	void draw_line();
	void timer_init(int which);
	void timer_signal_irq(int which);
	void timer_count_down(int which);
	u32 time_factor(int val);
	void uart_reset();
	void interrupt_set(u8 line);
	void interrupt_update();
	image_verify_result verify_cart(char *header, int kind);
	DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb);
};


/*---------- suzy registers ------------- */
#define TMPADRL     0x00    // Temporary address (not sure what this is used for)
#define TMPADRH     0x01
#define TILTACUML   0x02    // Tilt accumulator (signed fixed-point, eight bits to the left of decimal)
#define TILTACUMH   0x03
#define HOFFL       0x04    // X offset to edge of visible window
#define HOFFH       0x05
#define VOFFL       0x06    // Y offset to edge of visible window
#define VOFFH       0x07
#define VIDBASL     0x08    // Video buffer address
#define VIDBASH     0x09
#define COLLBASL    0x0A    // Collision buffer address
#define COLLBASH    0x0B
#define VIDADRL     0x0C    // Current Video Build Address
#define VIDADRH     0x0D
#define COLLADRL    0x0E    // Current Collision Build Address
#define COLLADRH    0x0F
#define SCBNEXTL    0x10    // Address of next SCB
#define SCBNEXTH    0x11
#define SPRDLINEL   0x12    // Sprite data start address
#define SPRDLINEH   0x13
#define HPOSSTRTL   0x14    // Starting Hpos
#define HPOSSTRTH   0x15
#define VPOSSTRTL   0x16    // Starting Vpos
#define VPOSSTRTH   0x17
#define SPRHSIZL    0x18    // H Size
#define SPRHSIZH    0x19
#define SPRVSIZL    0x1A    // V Size
#define SPRVSIZH    0x1B
#define STRETCHL    0x1C    // H/V Size Adder (signed fixed-point)
#define STRETCHH    0x1D
#define TILTL       0x1E    // H Position Adder (signed fixed-point)
#define TILTH       0x1F
#define SPRDOFFL    0x20    // Offset to Next Sprite Data Line
#define SPRDOFFH    0x21
#define SPRVPOSL    0x22    // Current Vpos
#define SPRVPOSH    0x23
#define COLLOFFL    0x24    // Offset to Collision Depository
#define COLLOFFH    0x25
#define VSIZACUML   0x26    // Vertical Size Accumulator
#define VSIZACUMH   0x27
#define HSIZOFFL    0x28    // Horizontal Size Offset
#define HSIZOFFH    0x29
#define VSIZOFFL    0x2A    // Vertical Size Offset
#define VSIZOFFH    0x2B
#define SCBADRL     0x2C    // Address of Current SCB
#define SCBADRH     0x2D
#define PROCADRL    0x2E    // Current Spr Data Proc Address

#define MATH_D      0x52
#define MATH_C      0x53
#define MATH_B      0x54
#define MATH_A      0x55
#define MATH_P      0x56
#define MATH_N      0x57
#define MATH_H      0x60
#define MATH_G      0x61
#define MATH_F      0x62
#define MATH_E      0x63

#define MATH_M      0x6c
#define MATH_L      0x6d
#define MATH_K      0x6e
#define MATH_J      0x6f

#define SPRCTL0     0x80 // Sprite Control Bits 0 (W)(U)
#define SPRCTL1     0x81 // Sprite Control Bits 1 (W)(U)
#define SPRCOLL     0x82 // Sprite Collision Number (W)
#define SPRINIT     0x83 // Sprite Initialization Bits (W)(U)

#define SUZYHREV    0x88 // Suzy Hardware Revision (R) = '01'

#define SUZYBUSEN   0x90 // Suzy Bus Enable (W)
#define SPRGO       0x91 // Sprite Process Start Bit (W)
#define SPRSYS      0x92 // System Control Bits (R/W)

#define JOYSTICK    0xB0 // Read Joystick and Switches(R)
#define SWITCHES    0xB1 // Read Other Switches (R)
#define RCART       0xB2 // Read / Write Cartridge Bank 0 (R/W)
#define RCART_BANK1 0xB3 // Read / Write Cartridge Bank 1 (R/W) (Unused in existing cartridges?)

//0xC0 LEDs (W)
//0xC2 Parallel Port Status(R/W)
//0xC3 Parallel Port Data (R/W)
//0xC4 Howie (R/W)

// SCB offsets

//8-bit
#define SCB_SPRCTL0     0x00 // 8 bit
#define SCB_SPRCTL1     0x01 // 8 bit
#define SCB_SPRCOLL     0x02 // 4 bit

//16-bit
#define SCB_SCBNEXT     0x03    // L,H Address of Next SCB
#define SCB_SPRDLINE    0x05    // L,H Start of Sprite Data Line Address
#define SCB_HPOSSTRT    0x07    // L,H Starting Hpos
#define SCB_VPOSSTRT    0x09    // L,H Starting Vpos
#define SCB_SPRHSIZ     0x0B    // L,H H Size
#define SCB_SPRVSIZ     0x0D    // L,H V Size
#define SCB_STRETCH     0x0F    // L H H/V Size Adder
#define SCB_TILT        0x11    // L,H H Position Adder

#endif // MAME_INCLUDES_LYNX_H