1 /*
2 * libtilemcore - Graphing calculator emulation library
3 *
4 * Copyright (C) 2001 Solignac Julien
5 * Copyright (C) 2004-2011 Benjamin Moody
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <time.h>
28 #include <tilem.h>
29
30 #include "xn.h"
31
set_lcd_wait_timer(TilemCalc * calc)32 static void set_lcd_wait_timer(TilemCalc* calc)
33 {
34 static const int delaytime[8] = { 48, 112, 176, 240,
35 304, 368, 432, 496 };
36 int i;
37
38 switch (calc->hwregs[PORT20] & 3) {
39 case 0:
40 return;
41 case 1:
42 i = (calc->hwregs[PORT2F] & 3);
43 break;
44 case 2:
45 i = ((calc->hwregs[PORT2F] >> 2) & 7);
46 break;
47 default:
48 i = ((calc->hwregs[PORT2F] >> 5) & 7);
49 break;
50 }
51
52 tilem_z80_set_timer(calc, TIMER_LCD_WAIT, delaytime[i], 0, 0);
53 calc->hwregs[LCD_WAIT] = 1;
54 }
55
xn_z80_in(TilemCalc * calc,dword port)56 byte xn_z80_in(TilemCalc* calc, dword port)
57 {
58 /* FIXME: measure actual levels */
59 static const byte battlevel[4] = { 33, 39, 36, 43 };
60 byte v;
61 unsigned int f;
62 time_t curtime;
63
64 switch(port&0xff) {
65 case 0x00:
66 if (tilem_z80_timer_running(calc, TIMER_FREEZE_LINK_PORT))
67 return(3);
68
69 v = tilem_linkport_get_lines(calc);
70 v |= (calc->linkport.lines << 4);
71 return(v);
72
73 case 0x01:
74 return(tilem_keypad_read_keys(calc));
75
76 case 0x02:
77 v = battlevel[calc->hwregs[PORT4] >> 6];
78 return ((calc->battery >= v ? 0xe1 : 0xe0)
79 | (calc->hwregs[LCD_WAIT] ? 0 : 2)
80 | (calc->flash.unlock << 2));
81
82 case 0x03:
83 return(calc->hwregs[PORT3]);
84
85 case 0x04:
86 v = (calc->keypad.onkeydown ? 0x00 : 0x08);
87
88 if (calc->z80.interrupts & TILEM_INTERRUPT_ON_KEY)
89 v |= 0x01;
90 if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER1)
91 v |= 0x02;
92 if (calc->z80.interrupts & TILEM_INTERRUPT_TIMER2)
93 v |= 0x04;
94 if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ACTIVE)
95 v |= 0x10;
96
97 if (calc->usertimers[0].status & TILEM_USER_TIMER_FINISHED)
98 v |= 0x20;
99 if (calc->usertimers[1].status & TILEM_USER_TIMER_FINISHED)
100 v |= 0x40;
101 if (calc->usertimers[2].status & TILEM_USER_TIMER_FINISHED)
102 v |= 0x80;
103
104 return(v);
105
106 case 0x05:
107 return(calc->hwregs[PORT5] & 0x0f);
108
109 case 0x06:
110 return(calc->hwregs[PORT6]);
111
112 case 0x07:
113 return(calc->hwregs[PORT7]);
114
115 case 0x08:
116 return(calc->hwregs[PORT8]);
117
118 case 0x09:
119 f = tilem_linkport_get_assist_flags(calc);
120
121 if (f & (TILEM_LINK_ASSIST_READ_BUSY
122 | TILEM_LINK_ASSIST_WRITE_BUSY))
123 v = 0x00;
124 else
125 v = 0x20;
126
127 if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_READ)
128 v |= 0x01;
129 if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_IDLE)
130 v |= 0x02;
131 if (calc->z80.interrupts & TILEM_INTERRUPT_LINK_ERROR)
132 v |= 0x04;
133 if (f & TILEM_LINK_ASSIST_READ_BUSY)
134 v |= 0x08;
135 if (f & TILEM_LINK_ASSIST_READ_BYTE)
136 v |= 0x10;
137 if (f & (TILEM_LINK_ASSIST_READ_ERROR
138 | TILEM_LINK_ASSIST_WRITE_ERROR))
139 v |= 0x40;
140 if (f & TILEM_LINK_ASSIST_WRITE_BUSY)
141 v |= 0x80;
142
143 calc->z80.interrupts &= ~TILEM_INTERRUPT_LINK_ERROR;
144
145 return(v);
146
147 case 0x0A:
148 v = calc->linkport.assistlastbyte;
149 tilem_linkport_read_byte(calc);
150 return(v);
151
152 case 0x0E:
153 return(calc->hwregs[PORTE] & 3);
154
155 case 0x0F:
156 return(calc->hwregs[PORTF] & 3);
157
158 case 0x10:
159 case 0x12:
160 calc->z80.clock += calc->hwregs[LCD_PORT_DELAY];
161 set_lcd_wait_timer(calc);
162 return(tilem_lcd_t6a04_status(calc));
163
164 case 0x11:
165 case 0x13:
166 calc->z80.clock += calc->hwregs[LCD_PORT_DELAY];
167 set_lcd_wait_timer(calc);
168 return(tilem_lcd_t6a04_read(calc));
169
170 case 0x15:
171 return(0x45); /* ??? */
172
173 case 0x1C:
174 return(tilem_md5_assist_get_value(calc));
175
176 case 0x1D:
177 return(tilem_md5_assist_get_value(calc) >> 8);
178
179 case 0x1E:
180 return(tilem_md5_assist_get_value(calc) >> 16);
181
182 case 0x1F:
183 return(tilem_md5_assist_get_value(calc) >> 24);
184
185 case 0x20:
186 return(calc->hwregs[PORT20] & 3);
187
188 case 0x21:
189 return(calc->hwregs[PORT21] & 0x33);
190
191 case 0x22:
192 return(calc->hwregs[PORT22]);
193
194 case 0x23:
195 return(calc->hwregs[PORT23]);
196
197 case 0x25:
198 return(calc->hwregs[PORT25]);
199
200 case 0x26:
201 return(calc->hwregs[PORT26]);
202
203 case 0x27:
204 return(calc->hwregs[PORT27]);
205
206 case 0x28:
207 return(calc->hwregs[PORT28]);
208
209 case 0x29:
210 return(calc->hwregs[PORT29]);
211
212 case 0x2A:
213 return(calc->hwregs[PORT2A]);
214
215 case 0x2B:
216 return(calc->hwregs[PORT2B]);
217
218 case 0x2C:
219 return(calc->hwregs[PORT2C]);
220
221 case 0x2D:
222 return(calc->hwregs[PORT2D] & 3);
223
224 case 0x2E:
225 return(calc->hwregs[PORT2E]);
226
227 case 0x2F:
228 return(calc->hwregs[PORT2F]);
229
230 case 0x30:
231 return(calc->usertimers[0].frequency);
232 case 0x31:
233 return(calc->usertimers[0].status);
234 case 0x32:
235 return(tilem_user_timer_get_value(calc, 0));
236
237 case 0x33:
238 return(calc->usertimers[1].frequency);
239 case 0x34:
240 return(calc->usertimers[1].status);
241 case 0x35:
242 return(tilem_user_timer_get_value(calc, 1));
243
244 case 0x36:
245 return(calc->usertimers[2].frequency);
246 case 0x37:
247 return(calc->usertimers[2].status);
248 case 0x38:
249 return(tilem_user_timer_get_value(calc, 2));
250
251 case 0x39:
252 return(0xf0); /* ??? */
253
254 case 0x40:
255 return calc->hwregs[CLOCK_MODE];
256
257 case 0x41:
258 return calc->hwregs[CLOCK_INPUT]&0xff;
259
260 case 0x42:
261 return (calc->hwregs[CLOCK_INPUT]>>8)&0xff;
262
263 case 0x43:
264 return (calc->hwregs[CLOCK_INPUT]>>16)&0xff;
265
266 case 0x44:
267 return (calc->hwregs[CLOCK_INPUT]>>24)&0xff;
268
269 case 0x45:
270 case 0x46:
271 case 0x47:
272 case 0x48:
273 if (calc->hwregs[CLOCK_MODE] & 1) {
274 time(&curtime);
275 }
276 else {
277 curtime = 0;
278 }
279 curtime += calc->hwregs[CLOCK_DIFF];
280 return (curtime >> ((port - 0x45) * 8));
281
282 case 0x4C:
283 return(0x22);
284
285 case 0x4D:
286 /* USB port - not emulated, calculator should
287 recognize that the USB cable is
288 disconnected.
289
290 Thanks go to Dan Englender for these
291 values. */
292
293 return(0xA5);
294
295 case 0x55:
296 return(0x1F);
297
298 case 0x56:
299 return(0x00);
300
301 case 0x57:
302 return(0x50);
303
304 case 0x0B:
305 case 0x0C:
306 case 0x0D:
307 case 0x14:
308 case 0x16:
309 case 0x17:
310 case 0x18:
311 case 0x19:
312 case 0x1A:
313 case 0x1B:
314 return(0);
315 }
316
317 tilem_warning(calc, "Input from port %x", port);
318 return(0x00);
319 }
320
321
setup_mapping(TilemCalc * calc)322 static void setup_mapping(TilemCalc* calc)
323 {
324 unsigned int pageA, pageB, pageC;
325
326 if (calc->hwregs[PORT6] & 0x80)
327 pageA = (0x80 | (calc->hwregs[PORT6] & 7));
328 else
329 pageA = (calc->hwregs[PORT6] & 0x7f);
330
331 if (calc->hwregs[PORT7] & 0x80)
332 pageB = (0x80 | (calc->hwregs[PORT7] & 7));
333 else
334 pageB = (calc->hwregs[PORT7] & 0x7f);
335
336 pageC = (0x80 | (calc->hwregs[PORT5] & 7));
337
338 if (calc->hwregs[PORT4] & 1) {
339 calc->mempagemap[1] = (pageA & ~1);
340 calc->mempagemap[2] = (pageA | 1);
341 calc->mempagemap[3] = pageB;
342 }
343 else {
344 calc->mempagemap[1] = pageA;
345 calc->mempagemap[2] = pageB;
346 calc->mempagemap[3] = pageC;
347 }
348 }
349
setup_clockdelays(TilemCalc * calc)350 static void setup_clockdelays(TilemCalc* calc)
351 {
352 byte lcdport = calc->hwregs[PORT29 + (calc->hwregs[PORT20] & 3)];
353 byte memport = calc->hwregs[PORT2E];
354
355 if (!(lcdport & 1))
356 memport &= ~0x07;
357 if (!(lcdport & 2))
358 memport &= ~0x70;
359
360 calc->hwregs[FLASH_EXEC_DELAY] = (memport & 1);
361 calc->hwregs[FLASH_READ_DELAY] = ((memport >> 1) & 1);
362 calc->hwregs[FLASH_WRITE_DELAY] = ((memport >> 2) & 1);
363
364 calc->hwregs[RAM_EXEC_DELAY] = ((memport >> 4) & 1);
365 calc->hwregs[RAM_READ_DELAY] = ((memport >> 5) & 1);
366 calc->hwregs[RAM_WRITE_DELAY] = ((memport >> 6) & 1);
367
368 calc->hwregs[LCD_PORT_DELAY] = (lcdport >> 2);
369 }
370
xn_z80_out(TilemCalc * calc,dword port,byte value)371 void xn_z80_out(TilemCalc* calc, dword port, byte value)
372 {
373 static const int tmrvalues[4] = { 1953, 4395, 6836, 9277 };
374 int t, r;
375 unsigned int mode;
376 time_t curtime;
377
378 switch(port&0xff) {
379 case 0x00:
380 if (value == 0
381 && calc->linkport.lines != 0
382 && calc->linkport.extlines == 0) {
383 /* Kludge to work around TI's broken
384 RecAByteIO implementation on 2.46+, which
385 will fail if the sending device is too
386 fast. */
387 tilem_z80_set_timer(calc, TIMER_FREEZE_LINK_PORT,
388 100, 0, 0);
389 }
390
391 tilem_linkport_set_lines(calc, value);
392 break;
393
394 case 0x01:
395 tilem_keypad_set_group(calc, value);
396 break;
397
398 case 0x03:
399 if (value & 0x01) {
400 calc->keypad.onkeyint = 1;
401 }
402 else {
403 calc->z80.interrupts &= ~TILEM_INTERRUPT_ON_KEY;
404 calc->keypad.onkeyint = 0;
405 }
406
407 if (!(value & 0x02))
408 calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER1;
409
410 if (!(value & 0x04))
411 calc->z80.interrupts &= ~TILEM_INTERRUPT_TIMER2;
412
413 if (value & 0x06) {
414 calc->usertimers[0].status &= ~TILEM_USER_TIMER_NO_HALT_INT;
415 calc->usertimers[1].status &= ~TILEM_USER_TIMER_NO_HALT_INT;
416 calc->usertimers[2].status &= ~TILEM_USER_TIMER_NO_HALT_INT;
417 }
418 else {
419 calc->usertimers[0].status |= TILEM_USER_TIMER_NO_HALT_INT;
420 calc->usertimers[1].status |= TILEM_USER_TIMER_NO_HALT_INT;
421 calc->usertimers[2].status |= TILEM_USER_TIMER_NO_HALT_INT;
422 }
423
424 mode = calc->linkport.mode;
425 if (value & 0x10)
426 mode |= TILEM_LINK_MODE_INT_ON_ACTIVE;
427 else
428 mode &= ~TILEM_LINK_MODE_INT_ON_ACTIVE;
429
430 tilem_linkport_set_mode(calc, mode);
431
432 calc->poweronhalt = ((value & 8) >> 3);
433 calc->hwregs[PORT3] = value;
434 break;
435
436
437 case 0x04:
438 calc->hwregs[PORT4] = value;
439
440 t = tmrvalues[(value & 6) >> 1];
441 tilem_z80_set_timer_period(calc, TIMER_INT1, t);
442 tilem_z80_set_timer_period(calc, TIMER_INT2A, t);
443 tilem_z80_set_timer_period(calc, TIMER_INT2B, t);
444
445 setup_mapping(calc);
446 break;
447
448 case 0x05:
449 calc->hwregs[PORT5] = value & 0x0f;
450 setup_mapping(calc);
451 break;
452
453 case 0x06:
454 calc->hwregs[PORT6] = value;
455 setup_mapping(calc);
456 break;
457
458 case 0x07:
459 calc->hwregs[PORT7] = value;
460 setup_mapping(calc);
461 break;
462
463 case 0x08:
464 calc->hwregs[PORT8] = value;
465
466 mode = calc->linkport.mode;
467
468 if (value & 0x01)
469 mode |= TILEM_LINK_MODE_INT_ON_READ;
470 else
471 mode &= ~TILEM_LINK_MODE_INT_ON_READ;
472
473 if (value & 0x02)
474 mode |= TILEM_LINK_MODE_INT_ON_IDLE;
475 else
476 mode &= ~TILEM_LINK_MODE_INT_ON_IDLE;
477
478 if (value & 0x04)
479 mode |= TILEM_LINK_MODE_INT_ON_ERROR;
480 else
481 mode &= ~TILEM_LINK_MODE_INT_ON_ERROR;
482
483 if (value & 0x80)
484 mode &= ~TILEM_LINK_MODE_ASSIST;
485 else
486 mode |= TILEM_LINK_MODE_ASSIST;
487
488 tilem_linkport_set_mode(calc, mode);
489 break;
490
491 case 0x09:
492 calc->hwregs[PORT9] = value;
493 break;
494
495 case 0x0A:
496 calc->hwregs[PORTA] = value;
497 break;
498
499 case 0x0B:
500 calc->hwregs[PORTB] = value;
501 break;
502
503 case 0x0C:
504 calc->hwregs[PORTC] = value;
505 break;
506
507
508 case 0x0D:
509 if (!(calc->hwregs[PORT8] & 0x80))
510 tilem_linkport_write_byte(calc, value);
511 break;
512
513 case 0x0E:
514 calc->hwregs[PORTE] = value;
515 break;
516
517 case 0x0F:
518 calc->hwregs[PORTF] = value;
519 break;
520
521 case 0x10:
522 case 0x12:
523 calc->z80.clock += calc->hwregs[LCD_PORT_DELAY];
524 set_lcd_wait_timer(calc);
525 tilem_lcd_t6a04_control(calc, value);
526 break;
527
528 case 0x11:
529 case 0x13:
530 calc->z80.clock += calc->hwregs[LCD_PORT_DELAY];
531 set_lcd_wait_timer(calc);
532 tilem_lcd_t6a04_write(calc, value);
533 break;
534
535 case 0x14:
536 if (calc->hwregs[PROTECTSTATE] == 7) {
537 /*
538 if (value & 1)
539 tilem_message(calc, "Flash unlocked");
540 else
541 tilem_message(calc, "Flash locked");
542 */
543 calc->flash.unlock = value&1;
544 }
545 break;
546
547 case 0x18:
548 case 0x19:
549 case 0x1A:
550 case 0x1B:
551 case 0x1C:
552 case 0x1D:
553 r = (port & 0xff) - 0x18;
554 calc->md5assist.regs[r] >>= 8;
555 calc->md5assist.regs[r] |= (value << 24);
556 break;
557
558 case 0x1E:
559 calc->md5assist.shift = value & 0x1f;
560 break;
561
562 case 0x1F:
563 calc->md5assist.mode = value & 3;
564 break;
565
566 case 0x20:
567 calc->hwregs[PORT20] = value;
568
569 if (value & 3) {
570 tilem_z80_set_speed(calc, 15000);
571 }
572 else {
573 tilem_z80_set_speed(calc, 6000);
574 }
575
576 setup_clockdelays(calc);
577 break;
578
579 case 0x21:
580 if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) {
581 calc->hwregs[PORT21] = value;
582
583 /* FIXME: these restrictions were tested on
584 83+ SE; someone should confirm them for
585 84+ */
586 switch (value & 0x30) {
587 case 0x00:
588 /* restrict pp. 0, 2, 4, 6, 8, A, C, E */
589 calc->hwregs[NO_EXEC_RAM] = 0x5555;
590 break;
591
592 case 0x10:
593 /* restrict pp. 0, 3, 4, 7, 8, B, C, F */
594 calc->hwregs[NO_EXEC_RAM] = 0x9999;
595 break;
596
597 case 0x20:
598 /* restrict pp. 0, 3-7, 8, B-F */
599 calc->hwregs[NO_EXEC_RAM] = 0xF9F9;
600 break;
601
602 case 0x30:
603 /* restrict pp. 0, 3-F */
604 calc->hwregs[NO_EXEC_RAM] = 0xFFF9;
605 break;
606 }
607 }
608 break;
609
610 case 0x22:
611 if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) {
612 calc->hwregs[PORT22] = value;
613 }
614 break;
615
616 case 0x23:
617 if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) {
618 calc->hwregs[PORT23] = value;
619 }
620 break;
621
622 case 0x25:
623 if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) {
624 calc->hwregs[PORT25] = value;
625 }
626 break;
627
628 case 0x26:
629 if (calc->flash.unlock && calc->hwregs[PROTECTSTATE] == 7) {
630 calc->hwregs[PORT26] = value;
631 }
632 break;
633
634 case 0x27:
635 calc->hwregs[PORT27] = value;
636 break;
637
638 case 0x28:
639 calc->hwregs[PORT28] = value;
640 break;
641
642 case 0x29:
643 calc->hwregs[PORT29] = value;
644 setup_clockdelays(calc);
645 break;
646
647 case 0x2A:
648 calc->hwregs[PORT2A] = value;
649 setup_clockdelays(calc);
650 break;
651
652 case 0x2B:
653 calc->hwregs[PORT2B] = value;
654 setup_clockdelays(calc);
655 break;
656
657 case 0x2C:
658 calc->hwregs[PORT2C] = value;
659 setup_clockdelays(calc);
660 break;
661
662 case 0x2D:
663 calc->hwregs[PORT2D] = value;
664 break;
665
666 case 0x2E:
667 calc->hwregs[PORT2E] = value;
668 setup_clockdelays(calc);
669 break;
670
671 case 0x2F:
672 calc->hwregs[PORT2F] = value;
673 break;
674
675 case 0x30:
676 tilem_user_timer_set_frequency(calc, 0, value);
677 break;
678 case 0x31:
679 tilem_user_timer_set_mode(calc, 0, value);
680 break;
681 case 0x32:
682 tilem_user_timer_start(calc, 0, value);
683 break;
684
685 case 0x33:
686 tilem_user_timer_set_frequency(calc, 1, value);
687 break;
688 case 0x34:
689 tilem_user_timer_set_mode(calc, 1, value);
690 break;
691 case 0x35:
692 tilem_user_timer_start(calc, 1, value);
693 break;
694
695 case 0x36:
696 tilem_user_timer_set_frequency(calc, 2, value);
697 break;
698 case 0x37:
699 tilem_user_timer_set_mode(calc, 2, value);
700 break;
701 case 0x38:
702 tilem_user_timer_start(calc, 2, value);
703 break;
704
705 case 0x40:
706 time(&curtime);
707
708 if ((calc->hwregs[CLOCK_MODE] & 1) != (value & 1)) {
709 if (value & 1)
710 calc->hwregs[CLOCK_DIFF] -= curtime;
711 else
712 calc->hwregs[CLOCK_DIFF] += curtime;
713 }
714
715 if (!(calc->hwregs[CLOCK_MODE] & 2) && (value & 2)) {
716 calc->hwregs[CLOCK_DIFF] = calc->hwregs[CLOCK_INPUT];
717 if (value & 1)
718 calc->hwregs[CLOCK_DIFF] -= curtime;
719 }
720 calc->hwregs[CLOCK_MODE] = value & 3;
721 break;
722
723 case 0x41:
724 calc->hwregs[CLOCK_INPUT] &= 0xffffff00;
725 calc->hwregs[CLOCK_INPUT] |= value;
726 break;
727
728 case 0x42:
729 calc->hwregs[CLOCK_INPUT] &= 0xffff00ff;
730 calc->hwregs[CLOCK_INPUT] |= (value << 8);
731 break;
732
733 case 0x43:
734 calc->hwregs[CLOCK_INPUT] &= 0xff00ffff;
735 calc->hwregs[CLOCK_INPUT] |= (value << 16);
736 break;
737
738 case 0x44:
739 calc->hwregs[CLOCK_INPUT] &= 0x00ffffff;
740 calc->hwregs[CLOCK_INPUT] |= (value << 24);
741 break;
742 }
743
744 return;
745 }
746
xn_z80_instr(TilemCalc * calc,dword opcode)747 void xn_z80_instr(TilemCalc* calc, dword opcode)
748 {
749 dword pa;
750 byte l, h;
751
752 switch (opcode) {
753 case 0xeded:
754 /* emulator control instruction */
755 l = xn_z80_rdmem(calc, calc->z80.r.pc.d);
756 h = xn_z80_rdmem(calc, calc->z80.r.pc.d + 1);
757
758 calc->z80.r.pc.d += 2;
759
760 opcode = (l | (h << 8));
761 switch (opcode) {
762 case 0x1000: /* Power off */
763 case 0x1001: /* Power on */
764 case 0x1002: /* Prepare for power off */
765 break;
766
767 case 0x1003:
768 /* Disable Nspire keypad */
769 tilem_message(calc, "Keypad locked");
770 break;
771
772 case 0x1004:
773 /* Enable Nspire keypad */
774 tilem_message(calc, "Keypad unlocked");
775 break;
776
777 case 0x1005:
778 /* ??? */
779 break;
780
781 case 0x1008:
782 /* check if USB data waiting (?) */
783 calc->z80.r.af.d |= 0x40;
784 break;
785
786 case 0x100C:
787 /* ??? */
788 calc->z80.r.af.d &= ~0x40;
789 break;
790
791 case 0x100D:
792 /* check if USB link should be used (???) */
793 calc->z80.r.af.d &= ~0x40;
794 break;
795
796 case 0x100E:
797 case 0x100F:
798 /* ??? */
799 break;
800
801 case 0x101C:
802 /* disable USB device (???) */
803 break;
804
805 case 0x1020:
806 /* check for something USB-related */
807 calc->z80.r.af.d |= 0x40;
808 break;
809
810 case 0x1024:
811 /* check if USB data waiting */
812 calc->z80.r.af.d |= 0x40;
813 break;
814
815 case 0x1029:
816 /* check for something USB-related */
817 calc->z80.r.af.d |= 0x40;
818 break;
819
820 case 0x1027:
821 /* check for something USB-related */
822 calc->z80.r.af.d |= 0x40;
823 break;
824
825 case 0x102E:
826 /* ??? */
827 break;
828
829 case 0x102F:
830 /* ??? */
831 break;
832
833 default:
834 tilem_warning(calc, "Unknown control instruction %x",
835 opcode);
836 }
837 break;
838
839 case 0xedee:
840 /* erase Flash at address HL */
841 if (calc->flash.unlock) {
842 pa = xn_mem_ltop(calc, calc->z80.r.hl.w.l);
843 if (pa < 0x200000) {
844 tilem_flash_erase_address(calc, pa);
845 }
846 }
847 break;
848
849 case 0xedef:
850 /* enable Flash writing for following instruction */
851 if (calc->flash.unlock) {
852 calc->flash.state = 3;
853 }
854 break;
855
856 default:
857 tilem_warning(calc, "Invalid opcode %x", opcode);
858 tilem_z80_exception(calc, TILEM_EXC_INSTRUCTION);
859 break;
860 }
861 }
862
xn_z80_ptimer(TilemCalc * calc,int id)863 void xn_z80_ptimer(TilemCalc* calc, int id)
864 {
865 switch (id) {
866 case TIMER_INT1:
867 if (calc->hwregs[PORT3] & 0x02)
868 calc->z80.interrupts |= TILEM_INTERRUPT_TIMER1;
869 break;
870
871 case TIMER_INT2A:
872 case TIMER_INT2B:
873 if (calc->hwregs[PORT3] & 0x04)
874 calc->z80.interrupts |= TILEM_INTERRUPT_TIMER2;
875 break;
876
877 case TIMER_LCD_WAIT:
878 calc->hwregs[LCD_WAIT] = 0;
879 break;
880 }
881 }
882