1 // license:GPL-2.0+
2 // copyright-holders:Juergen Buchmueller
3 /******************************************************************************
4  *  Microtan 65
5  *
6  *  machine driver
7  *
8  *  Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000
9  *
10  *  Thanks go to Geoff Macdonald <mail@geoff.org.uk>
11  *  for his site http://www.geoff.org.uk/microtan/index.htm
12  *  and to Fabrice Frances <frances@ensica.fr>
13  *  for his site http://oric.free.fr/microtan.html
14  *
15  *****************************************************************************/
16 
17 #include "emu.h"
18 #include "includes/microtan.h"
19 
20 //#define VERBOSE 1
21 #include "logmacro.h"
22 
23 
24 static const char keyboard[8][9][8] = {
25 	{ /* normal */
26 		{ 27,'1','2','3','4','5','6','7'},
27 		{'8','9','0',':','-', 12,127,'^'},
28 		{'q','w','e','r','t','y','u','i'},
29 		{'o','p','[',']', 13,  3,  0,  0},
30 		{'a','s','d','f','g','h','j','k'},
31 		{'l',';','@', 92,  0,'z','x','c'},
32 		{'v','b','n','m',',','.','/',  0},
33 		{ 10,' ','-',',', 13,'.','0','1'},
34 		{'2','3','4','5','6','7','8','9'},
35 	},
36 	{ /* Shift */
37 		{ 27,'!','"','#','$','%','&', 39},
38 		{'(',')','~','*','=', 12,127,'_'},
39 		{'Q','W','E','R','T','Y','U','I'},
40 		{'O','P','{','}', 13,  3,  0,  0},
41 		{'A','S','D','F','G','H','J','K'},
42 		{'L','+','`','|',  0,'Z','X','C'},
43 		{'V','B','N','M','<','>','?',  0},
44 		{ 10,' ','-',',', 13,'.','0','1'},
45 		{'2','3','4','5','6','7','8','9'},
46 	},
47 	{ /* Control */
48 		{ 27,'1','2','3','4','5','6','7'},
49 		{'8','9','0',':','-','`',127, 30},
50 		{ 17, 23,  5, 18, 20, 25, 21,  9},
51 		{ 15, 16, 27, 29, 13,  3,  0,  0},
52 		{  1, 19,  4,  6,  7,  8, 10, 11},
53 		{ 12,';','@', 28,  0, 26, 24,  3},
54 		{ 22,  2, 14, 13,',','.','/',  0},
55 		{ 10,' ','-',',', 13,'.','0','1'},
56 		{'2','3','4','5','6','7','8','9'},
57 	},
58 	{ /* Shift+Control */
59 		{ 27,'!','"','#','$','%','&', 39},
60 		{'(',')','~','*','=', 12,127, 31},
61 		{ 17, 23,  5, 18, 20, 25, 21,  9},
62 		{ 15, 16, 27, 29, 13,127,  0,  0},
63 		{  1, 19,  4,  6,  7,  8, 10, 11},
64 		{ 12,'+','`', 28,  0, 26, 24,  3},
65 		{ 22,  2, 14, 13,',','.','/',  0},
66 		{ 10,' ','-',',', 13,'.','0','1'},
67 		{'2','3','4','5','6','7','8','9'},
68 	},
69 	{ /* CapsLock */
70 		{ 27,'1','2','3','4','5','6','7'},
71 		{'8','9','0',':','-', 12,127,'^'},
72 		{'Q','W','E','R','T','Y','U','I'},
73 		{'O','P','[',']', 13,  3,  0,  0},
74 		{'A','S','D','F','G','H','J','K'},
75 		{'L',';','@', 92,  0,'Z','X','C'},
76 		{'V','B','N','M',',','.','/',  0},
77 		{ 10,' ','-',',', 13,'.','0','1'},
78 		{'2','3','4','5','6','7','8','9'},
79 	},
80 	{ /* Shift+CapsLock */
81 		{ 27,'!','"','#','$','%','&', 39},
82 		{'(',')','~','*','=', 12,127,'_'},
83 		{'q','w','e','r','t','y','u','i'},
84 		{'o','p','{','}', 13,  3,  0,  0},
85 		{'a','s','d','f','g','h','j','k'},
86 		{'l','+','`','|',  0,'z','x','c'},
87 		{'v','b','n','m','<','>','?',  0},
88 		{ 10,' ','-',',', 13,'.','0','1'},
89 		{'2','3','4','5','6','7','8','9'},
90 	},
91 	{ /* Control+CapsLock */
92 		{ 27,'1','2','3','4','5','6','7'},
93 		{'8','9','0',':','-', 12,127,  9},
94 		{ 17, 23,  5, 18, 20, 25, 21,  9},
95 		{ 15, 16, 27, 29, 13,127,  0,  0},
96 		{  1, 19,  4,  6,  7,  8, 10, 11},
97 		{ 12,';', 39, 28,  0, 26, 24,  3},
98 		{ 22,  2, 14, 13,',','.','/',  0},
99 		{ 10,' ','-',',', 13,'.','0','1'},
100 		{'2','3','4','5','6','7','8','9'},
101 	},
102 	{ /* Shift+Control+CapsLock */
103 		{ 27,'!','"','#','$','%','&', 39},
104 		{'(',')','~','*','=', 12,127,  9},
105 		{ 17, 23,  5, 18, 20, 25, 21,  9},
106 		{ 15, 16, 27, 29, 13,127,  0,  0},
107 		{  1, 19,  4,  6,  7,  8, 10, 11},
108 		{ 12,':','"', 28,  0, 26, 24,  3},
109 		{ 22,  2, 14, 13,',','.','/',  0},
110 		{ 10,' ','-',',', 13,'.','0','1'},
111 		{'2','3','4','5','6','7','8','9'},
112 	},
113 };
114 
115 
sound_r()116 uint8_t microtan_state::sound_r()
117 {
118 	int data = 0xff;
119 	LOG("sound_r: -> %02x\n", data);
120 	return data;
121 }
122 
sound_w(uint8_t data)123 void microtan_state::sound_w(uint8_t data)
124 {
125 	LOG("sound_w: <- %02x\n", data);
126 }
127 
128 
bffx_r(offs_t offset)129 uint8_t microtan_state::bffx_r(offs_t offset)
130 {
131 	int data = 0xff;
132 	switch( offset & 3 )
133 	{
134 	case  0: /* BFF0: read enables chunky graphics */
135 		m_chunky_graphics = 1;
136 		LOG("bff0_r: -> %02x (chunky graphics on)\n", data);
137 		break;
138 	case  1: /* BFF1: read undefined (?) */
139 		LOG("bff1_r: -> %02x\n", data);
140 		break;
141 	case  2: /* BFF2: read undefined (?) */
142 		LOG("bff2_r: -> %02x\n", data);
143 		break;
144 	case 3: /* BFF3: read keyboard/keypad */
145 		switch (m_config->read() & 3)
146 		{
147 		case 0: /* ASCII Keyboard */
148 			data = m_keyboard_ascii;
149 			break;
150 		case 1: /* Hex Keypad */
151 			data = 0x00;
152 			for (u8 i = 0; i < 4; i++)
153 				if (BIT(m_keypad_column, i))
154 					data |= m_io_keypad[i]->read();
155 
156 			break;
157 		case 2: /* ETI Keypad */
158 			data = (m_keypad->read() & 0x1f) | (m_config->read() & 0x60);
159 			break;
160 		}
161 		LOG("bff3_r: -> %02x (keyboard ASCII)\n", data);
162 		break;
163 	}
164 	return data;
165 }
166 
167 
168 /* This callback is called one clock cycle after BFF2 is written (delayed nmi) */
TIMER_CALLBACK_MEMBER(microtan_state::pulse_nmi)169 TIMER_CALLBACK_MEMBER(microtan_state::pulse_nmi)
170 {
171 	m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
172 }
173 
bffx_w(offs_t offset,uint8_t data)174 void microtan_state::bffx_w(offs_t offset, uint8_t data)
175 {
176 	switch( offset & 3 )
177 	{
178 	case 0: /* BFF0: write reset keyboard interrupt flag */
179 		/* This removes bit 7 from the ASCII value of the last key pressed. */
180 		LOG("bff0_w: %d <- %02x (keyboard IRQ clear )\n", offset, data);
181 		m_keyboard_ascii &= ~0x80;
182 		m_irq_line->in_w<IRQ_KBD>(0);
183 		break;
184 	case 1: /* BFF1: write delayed NMI */
185 		LOG("bff1_w: %d <- %02x (delayed NMI)\n", offset, data);
186 		m_pulse_nmi_timer->adjust(m_maincpu->cycles_to_attotime(8));
187 		break;
188 	case 2: /* BFF2: write keypad */
189 		LOG("bff2_w: %d <- %02x (keypad column)\n", offset, data); // 1, 2, 4, 7, f
190 		m_keypad_column = data & 0x0f;
191 		break;
192 	case 3: /* BFF3: write disable chunky graphics */
193 		LOG("bff3_w: %d <- %02x (chunky graphics off)\n", offset, data);
194 		m_chunky_graphics = 0;
195 		break;
196 	}
197 }
198 
keyboard_r()199 uint8_t mt6809_state::keyboard_r()
200 {
201 	uint8_t data = m_keyboard_ascii;
202 
203 	m_keyboard_ascii = 0x00;
204 
205 	return data;
206 }
207 
store_key(int key)208 void mt6809_state::store_key(int key)
209 {
210 	m_keyboard_ascii = key | 0x80;
211 }
212 
store_key(int key)213 void microtan_state::store_key(int key)
214 {
215 	m_keyboard_ascii = key | 0x80;
216 	m_irq_line->in_w<IRQ_KBD>(1);
217 }
218 
TIMER_DEVICE_CALLBACK_MEMBER(microtan_state::kbd_scan)219 TIMER_DEVICE_CALLBACK_MEMBER(microtan_state::kbd_scan)
220 {
221 	/* ASCII Keyboard only */
222 	if (m_config->read() & 3)
223 		return;
224 
225 	int mod, row, col, chg, newvar;
226 
227 	if( m_repeat )
228 	{
229 		if( !--m_repeat )
230 			m_repeater = 4;
231 	}
232 	else if( m_repeater )
233 		m_repeat = m_repeater;
234 
235 	row = 9;
236 	newvar = m_io_keyboard[8]->read();
237 	chg = m_keyrows[--row] ^ newvar;
238 
239 	while ( !chg && row > 0)
240 	{
241 		newvar = m_io_keyboard[row - 1]->read();
242 		chg = m_keyrows[--row] ^ newvar;
243 	}
244 	if (!chg)
245 		--row;
246 
247 	if (row >= 0)
248 	{
249 		m_repeater = 0x00;
250 		m_mask = 0x00;
251 		m_key = 0x00;
252 		m_lastrow = row;
253 		/* CapsLock LED */
254 		if( row == 3 && chg == 0x80 )
255 			m_led = BIT(~m_keyrows[3], 7);
256 
257 		if (newvar & chg)  /* key(s) pressed ? */
258 		{
259 			mod = 0;
260 
261 			/* Shift modifier */
262 			if ( (m_keyrows[5] & 0x10) || (m_keyrows[6] & 0x80) )
263 				mod |= 1;
264 
265 			/* Control modifier */
266 			if (m_keyrows[3] & 0x40)
267 				mod |= 2;
268 
269 			/* CapsLock modifier */
270 			if (m_keyrows[3] & 0x80)
271 				mod |= 4;
272 
273 			/* find newvar key */
274 			m_mask = 0x01;
275 			for (col = 0; col < 8; col ++)
276 			{
277 				if (chg & m_mask)
278 				{
279 					newvar &= m_mask;
280 					m_key = keyboard[mod][row][col];
281 					break;
282 				}
283 				m_mask <<= 1;
284 			}
285 			if( m_key )   /* normal key */
286 			{
287 				m_repeater = 30;
288 				store_key(m_key);
289 			}
290 			else
291 			if( (row == 0) && (chg == 0x04) ) /* Ctrl-@ (NUL) */
292 				store_key(0);
293 			m_keyrows[row] |= newvar;
294 		}
295 		else
296 			m_keyrows[row] = newvar;
297 
298 		m_repeat = m_repeater;
299 	}
300 	else
301 	if ( m_key && (m_keyrows[m_lastrow] & m_mask) && m_repeat == 0 )
302 		store_key(m_key);
303 }
304 
305 
pgm_chargen_w(offs_t offset,uint8_t data)306 void microtan_state::pgm_chargen_w(offs_t offset, uint8_t data)
307 {
308 	switch (offset & 0x200)
309 	{
310 	case 0x000:
311 		/* update char &80-&1F */
312 		m_gfx1->base()[offset | 0x800] = data;
313 		m_gfxdecode->gfx(0)->mark_dirty(0x80 | (offset >> 4));
314 		break;
315 	case 0x200:
316 		/* update char &E0-&FF */
317 		m_gfx1->base()[offset | 0xc00] = data;
318 		m_gfxdecode->gfx(0)->mark_dirty(0xc0 | (offset >> 4));
319 		break;
320 	}
321 }
322 
init_gfx2()323 void microtan_state::init_gfx2()
324 {
325 	uint8_t *dst = memregion("gfx2")->base();
326 
327 	for (int i = 0; i < 256; i++)
328 	{
329 		switch (i & 3)
330 		{
331 		case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
332 		case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
333 		case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
334 		case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
335 		}
336 		dst += 4;
337 		switch (BIT(i, 2, 2))
338 		{
339 		case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
340 		case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
341 		case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
342 		case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
343 		}
344 		dst += 4;
345 		switch (BIT(i, 4, 2))
346 		{
347 		case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
348 		case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
349 		case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
350 		case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
351 		}
352 		dst += 4;
353 		switch (BIT(i, 6, 2))
354 		{
355 		case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
356 		case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
357 		case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
358 		case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
359 		}
360 		dst += 4;
361 	}
362 }
363 
init_microtan()364 void microtan_state::init_microtan()
365 {
366 	init_gfx2();
367 
368 	m_pulse_nmi_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(microtan_state::pulse_nmi), this));
369 }
370 
machine_start()371 void microtan_state::machine_start()
372 {
373 	m_led.resolve();
374 
375 	save_item(NAME(m_keypad_column));
376 	save_item(NAME(m_keyboard_ascii));
377 	save_item(NAME(m_keyrows));
378 	save_item(NAME(m_lastrow));
379 	save_item(NAME(m_mask));
380 	save_item(NAME(m_key));
381 	save_item(NAME(m_repeat));
382 	save_item(NAME(m_repeater));
383 }
384 
machine_reset()385 void microtan_state::machine_reset()
386 {
387 	for (int i = 1; i < 10;  i++)
388 		m_keyrows[i] = m_io_keyboard[i-1].read_safe(0);
389 
390 	m_led = BIT(~m_keyrows[3], 7);
391 }
392 
verify_snapshot(uint8_t * data,int size)393 image_verify_result microtan_state::verify_snapshot(uint8_t *data, int size)
394 {
395 	if (size == 8263)
396 	{
397 		logerror("snapshot_id: magic size %d found\n", size);
398 		return image_verify_result::PASS;
399 	}
400 	else
401 	{
402 		if (4 + data[2] + 256 * data[3] + 1 + 16 + 16 + 16 + 1 + 1 + 16 + 16 + 64 + 7 == size)
403 		{
404 			logerror("snapshot_id: header RAM size + structures matches filesize %d\n", size);
405 			return image_verify_result::PASS;
406 		}
407 	}
408 
409 	return image_verify_result::FAIL;
410 }
411 
parse_intel_hex(uint8_t * snapshot_buff,char * src)412 image_init_result microtan_state::parse_intel_hex(uint8_t *snapshot_buff, char *src)
413 {
414 	char line[128];
415 	int /*row = 0,*/ column = 0, last_addr = 0, last_size = 0;
416 
417 	while (*src)
418 	{
419 		if (*src == '\r' || *src == '\n')
420 		{
421 			if (column)
422 			{
423 				unsigned int size, addr, null, b[32], cs, n;
424 
425 				line[column] = '\0';
426 				/*row++;*/
427 				n = sscanf(line, ":%02x%04x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
428 					&size, &addr, &null,
429 					&b[ 0], &b[ 1], &b[ 2], &b[ 3], &b[ 4], &b[ 5], &b[ 6], &b[ 7],
430 					&b[ 8], &b[ 9], &b[10], &b[11], &b[12], &b[13], &b[14], &b[15],
431 					&b[16], &b[17], &b[18], &b[19], &b[20], &b[21], &b[22], &b[23],
432 					&b[24], &b[25], &b[26], &b[27], &b[28], &b[29], &b[30], &b[31],
433 					&cs);
434 				if (n == 0)
435 					logerror("parse_intel_hex: malformed line [%s]\n", line);
436 				else
437 				if (n == 1)
438 					logerror("parse_intel_hex: only size found [%s]\n", line);
439 				else
440 				if (n == 2)
441 					logerror("parse_intel_hex: only size and addr found [%s]\n", line);
442 				else
443 				if (n == 3)
444 					logerror("parse_intel_hex: only size, addr and null found [%s]\n", line);
445 				else
446 				if (null != 0)
447 					logerror("parse_intel_hex: warning null byte is != 0 [%s]\n", line);
448 				else
449 				{
450 					int i, sum;
451 
452 					n -= 3;
453 
454 					sum = size + (addr & 0xff) + ((addr >> 8) & 0xff);
455 					if (n != 32 + 1)
456 						cs = b[n-1];
457 
458 					last_addr = addr;
459 					last_size = n-1;
460 					logerror("parse_intel_hex: %04X", addr);
461 					for (i = 0; i < n-1; i++)
462 					{
463 						sum += b[i];
464 						snapshot_buff[addr++] = b[i];
465 					}
466 					logerror("-%04X checksum %02X+%02X = %02X\n", addr-1, cs, sum & 0xff, (cs + sum) & 0xff);
467 				}
468 			}
469 			column = 0;
470 		}
471 		else
472 			line[column++] = *src;
473 
474 		src++;
475 	}
476 	/* register preset? */
477 	if (last_size == 7)
478 	{
479 		logerror("parse_intel_hex: registers (?) at %04X\n", last_addr);
480 		memcpy(&snapshot_buff[8192+64], &snapshot_buff[last_addr], last_size);
481 	}
482 	return image_init_result::PASS;
483 }
484 
parse_zillion_hex(uint8_t * snapshot_buff,char * src)485 image_init_result microtan_state::parse_zillion_hex(uint8_t *snapshot_buff, char *src)
486 {
487 	char line[128];
488 	int parsing = 0, /*row = 0,*/ column = 0;
489 
490 	while (*src)
491 	{
492 		if (parsing)
493 		{
494 			if (*src == '}')
495 				parsing = 0;
496 			else
497 			{
498 				if (*src == '\r' || *src == '\n')
499 				{
500 					if (column)
501 					{
502 						unsigned int addr, b[8], n;
503 
504 						line[column] = '\0';
505 						/*row++;*/
506 						n = sscanf(line, "%x %x %x %x %x %x %x %x %x", &addr, &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6], &b[7]);
507 						if (n == 0)
508 							logerror("parse_zillion_hex: malformed line [%s]\n", line);
509 						else
510 						if (n == 1)
511 							logerror("parse_zillion_hex: only addr found [%s]\n", line);
512 						else
513 						{
514 							logerror("parse_zillion_hex: %04X", addr);
515 							for (int i = 0; i < n-1; i++)
516 								snapshot_buff[addr++] = b[i];
517 							logerror("-%04X\n", addr-1);
518 						}
519 					}
520 					column = 0;
521 				}
522 				else
523 					line[column++] = *src;
524 			}
525 		}
526 		else
527 		{
528 			if (*src == '\r' || *src == '\n')
529 			{
530 				if (column)
531 				{
532 					int addr;
533 
534 					/*row++;*/
535 					line[column] = '\0';
536 					int n = sscanf(line, "G%x", (unsigned int *) &addr);
537 					if (n == 1 && !snapshot_buff[8192+64+0] && !snapshot_buff[8192+64+1])
538 					{
539 						logerror("microtan_hexfile_init: go addr %04X\n", addr);
540 						snapshot_buff[8192+64+0] = addr & 0xff;
541 						snapshot_buff[8192+64+1] = (addr >> 8) & 0xff;
542 					}
543 				}
544 				column = 0;
545 			}
546 			else
547 				line[column++] = *src;
548 
549 			if (*src == '{')
550 			{
551 				parsing = 1;
552 				column = 0;
553 			}
554 		}
555 		src++;
556 	}
557 	return image_init_result::PASS;
558 }
559 
set_cpu_regs(const uint8_t * snapshot_buff,int base)560 void microtan_state::set_cpu_regs(const uint8_t *snapshot_buff, int base)
561 {
562 	logerror("snapshot_copy: PC:%02X%02X P:%02X A:%02X X:%02X Y:%02X SP:1%02X\n",
563 		snapshot_buff[base+1], snapshot_buff[base+0], snapshot_buff[base+2], snapshot_buff[base+3],
564 		snapshot_buff[base+4], snapshot_buff[base+5], snapshot_buff[base+6]);
565 	m_maincpu->set_state_int(M6502_PC, snapshot_buff[base+0] + (snapshot_buff[base+1] << 8));
566 	m_maincpu->set_state_int(M6502_P, snapshot_buff[base+2]);
567 	m_maincpu->set_state_int(M6502_A, snapshot_buff[base+3]);
568 	m_maincpu->set_state_int(M6502_X, snapshot_buff[base+4]);
569 	m_maincpu->set_state_int(M6502_Y, snapshot_buff[base+5]);
570 	m_maincpu->set_state_int(M6502_S, snapshot_buff[base+6] + 0x100);
571 }
572 
snapshot_copy(uint8_t * snapshot_buff,int snapshot_size)573 void microtan_state::snapshot_copy(uint8_t *snapshot_buff, int snapshot_size)
574 {
575 	address_space &space = m_maincpu->space(AS_PROGRAM);
576 
577 	/* check for .DMP file format */
578 	if (snapshot_size == 8263)
579 	{
580 		/********** DMP format
581 		 * Lower 8k of RAM (0000 to 1fff)
582 		 * 64 bytes of chunky graphics bits (first byte bit is for character at 0200, bit 1=0201, etc)
583 		 * 7 bytes of CPU registers (PCL, PCH, PSW, A, IX, IY, SP)
584 		 */
585 
586 		int base = 0;
587 		/* 8K of RAM from 0000 to 1fff */
588 		for (int i = 0; i < 0x2000; i++)
589 			space.write_byte(i, snapshot_buff[base + i]);
590 
591 		base += 8192;
592 		/* 64 bytes of chunky graphics info */
593 		for (int i = 0; i < 32*16; i++)
594 			m_chunky_buffer[i] = (snapshot_buff[base+i/8] >> (i&7)) & 1;
595 
596 		base += 64;
597 		set_cpu_regs(snapshot_buff, base);
598 	}
599 	else
600 	{
601 		/********** M65 format ************************************
602 		 *  2 bytes: File version
603 		 *  2 bytes: RAM size
604 		 *  n bytes: RAM (0000 to RAM Size)
605 		 * 16 bytes: 1st 6522 (0xbfc0 to 0xbfcf)
606 		 * 16 bytes: 2nd 6522 (0xbfe0 to 0xbfef)
607 		 * 16 bytes: Microtan IO (0xbff0 to 0xbfff)
608 		 *  1 byte : Space Invasion sound (0xbc04)
609 		 *  1 byte : Chunky graphics state (0=off, 1=on)
610 		 * 16 bytes: 1st AY8910 registers
611 		 * 16 bytes: 2nd AY8910 registers
612 		 * 64 bytes: Chunky graphics bits (first byte bit 0 is for character at 0200, bit 1=0201, etc)
613 		 *  7 bytes: CPU registers (PCL, PCH, PSW, A, IX, IY, SP)
614 		 */
615 		int ramend = snapshot_buff[2] + 256 * snapshot_buff[3];
616 		if (2 + 2 + ramend + 1 + 16 + 16 + 16 + 1 + 1 + 16 + 16 + 64 + 7 != snapshot_size)
617 		{
618 			logerror("snapshot_copy: size %d doesn't match RAM size %d + structure size\n", snapshot_size, ramend+1);
619 			return;
620 		}
621 
622 		int base = 4;
623 		for (int i = 0; i < snapshot_buff[2] + 256 * snapshot_buff[3] + 1; i++)
624 			space.write_byte(i, snapshot_buff[base + i]);
625 		base += ramend + 1;
626 
627 		/* first set of VIA6522 registers */
628 		for (int i = 0; i < 16; i++ )
629 			space.write_byte(0xbfc0 + i, snapshot_buff[base++]);
630 
631 		/* second set of VIA6522 registers */
632 		for (int i = 0; i < 16; i++ )
633 			space.write_byte(0xbfe0 + i, snapshot_buff[base++]);
634 
635 		/* microtan IO bff0-bfff */
636 		for (int i = 0; i < 16; i++ )
637 		{
638 			if (i < 4)
639 				bffx_w(i, snapshot_buff[base++]);
640 		}
641 
642 		sound_w(snapshot_buff[base++]);
643 		m_chunky_graphics = snapshot_buff[base++];
644 
645 		/* first set of AY8910 registers */
646 		for (int i = 0; i < 16; i++ )
647 		{
648 			space.write_byte(0xbc00, i);
649 			space.write_byte(0xbc01, snapshot_buff[base++]);
650 		}
651 
652 		/* second set of AY8910 registers */
653 		for (int i = 0; i < 16; i++ )
654 		{
655 			space.write_byte(0xbc02, i);
656 			space.write_byte(0xbc03, snapshot_buff[base++]);
657 		}
658 
659 		for (int i = 0; i < 32*16; i++)
660 			m_chunky_buffer[i] = (snapshot_buff[base+i/8] >> (i&7)) & 1;
661 
662 		base += 64;
663 
664 		set_cpu_regs(snapshot_buff, base);
665 	}
666 }
667 
SNAPSHOT_LOAD_MEMBER(microtan_state::snapshot_cb)668 SNAPSHOT_LOAD_MEMBER(microtan_state::snapshot_cb)
669 {
670 	uint8_t *snapshot_buff = (uint8_t*)image.ptr();
671 	if (!snapshot_buff)
672 		return image_init_result::FAIL;
673 
674 	if (verify_snapshot(snapshot_buff, snapshot_size) != image_verify_result::PASS)
675 		return image_init_result::FAIL;
676 
677 	snapshot_copy(snapshot_buff, snapshot_size);
678 	return image_init_result::PASS;
679 }
680 
QUICKLOAD_LOAD_MEMBER(microtan_state::quickload_cb)681 QUICKLOAD_LOAD_MEMBER(microtan_state::quickload_cb)
682 {
683 	int snapshot_size = 8263;   /* magic size */
684 	std::vector<uint8_t> snapshot_buff(snapshot_size, 0);
685 	std::vector<char> buff(quickload_size + 1);
686 	image_init_result rc;
687 
688 	image.fread(&buff[0], quickload_size);
689 
690 	buff[quickload_size] = '\0';
691 
692 	if (buff[0] == ':')
693 		rc = parse_intel_hex(&snapshot_buff[0], &buff[0]);
694 	else
695 		rc = parse_zillion_hex(&snapshot_buff[0], &buff[0]);
696 	if (rc == image_init_result::PASS)
697 		snapshot_copy(&snapshot_buff[0], snapshot_size);
698 	return rc;
699 }
700