1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/magnetic/magnetic_defs.h"
24 #include "glk/magnetic/magnetic.h"
25 #include "common/file.h"
26 #include "common/textconsole.h"
27
28 namespace Glk {
29 namespace Magnetic {
30
31 const char *const no_hints = "[Hints are not available.]\n";
32 const char *const not_supported = "[This function is not supported.]\n";
33 const char *const undo_ok = "\n[Previous turn undone.]";
34 const char *const undo_fail = "\n[You can't \"undo\" what hasn't been done!]";
35
36 #define ms_fatal error
37
38 #if defined(LOGEMU) || defined(LOGGFX) || defined(LOGHNT)
39 FILE *dbg_log;
40 #ifndef LOG_FILE
41 #error LOG_FILE must be defined to be the name of the log file.
42 #endif
43 #endif
44
45 #ifdef LOGEMU
out(char * format,...)46 void out(char *format, ...) {
47 va_list a;
48
49 va_start(a, format);
50 vfprintf(dbg_log, format, a);
51 va_end(a);
52 }
53 #endif
54 #if defined(LOGGFX) || defined(LOGHNT)
out2(char * format,...)55 void out2(char *format, ...) {
56 va_list a;
57
58 va_start(a, format);
59 vfprintf(dbg_log, format, a);
60 va_end(a);
61 fflush(dbg_log);
62 }
63 #endif
64
65 /* Convert virtual pointer to effective pointer */
effective(type32 ptr)66 type8 *Magnetic::effective(type32 ptr) {
67 if ((version < 4) && (mem_size == 0x10000))
68 return &(code[ptr & 0xffff]);
69 if (ptr >= mem_size) {
70 ms_fatal("Outside memory experience");
71 return code;
72 }
73
74 return &(code[ptr]);
75 }
76
write_l(type8 * ptr,type32 val)77 void Magnetic::write_l(type8 *ptr, type32 val) {
78 ptr[3] = (type8) val;
79 val >>= 8;
80 ptr[2] = (type8) val;
81 val >>= 8;
82 ptr[1] = (type8) val;
83 val >>= 8;
84 ptr[0] = (type8) val;
85 }
86
write_w(type8 * ptr,type16 val)87 void Magnetic::write_w(type8 *ptr, type16 val) {
88 ptr[1] = (type8) val;
89 val >>= 8;
90 ptr[0] = (type8) val;
91 }
92
rand_emu()93 type32 Magnetic::rand_emu() {
94 rseed = 1103515245L * rseed + 12345L;
95 return rseed & 0x7fffffffL;
96 }
97
ms_freemem()98 void Magnetic::ms_freemem() {
99 if (code)
100 free(code);
101 if (string)
102 free(string);
103 if (string2)
104 free(string2);
105 if (string3)
106 free(string3);
107 if (dict)
108 free(dict);
109 if (undo[0])
110 free(undo[0]);
111 if (undo[1])
112 free(undo[1]);
113 if (restart)
114 free(restart);
115 code = string = string2 = string3 = dict = undo[0] = undo[1] = restart = 0;
116 if (gfx_data)
117 free(gfx_data);
118 if (gfx_buf)
119 free(gfx_buf);
120 if (gfx2_hdr)
121 free(gfx2_hdr);
122 if (gfx2_buf)
123 free(gfx2_buf);
124 delete gfx_fp;
125
126 gfx_data = gfx_buf = gfx2_hdr = gfx2_buf = nullptr;
127 gfx2_name = 0;
128 gfx_fp = nullptr;
129 gfx_ver = 0;
130 gfxtable = table_dist = 0;
131 #ifndef NO_ANIMATION
132 pos_table_size = 0;
133 command_index = 0;
134 anim_repeat = 0;
135 pos_table_index = -1;
136 pos_table_max = -1;
137 #endif
138 lastchar = 0;
139 if (hints)
140 free(hints);
141 if (hint_contents)
142 free(hint_contents);
143 hints = 0;
144 hint_contents = 0;
145 if (snd_hdr)
146 free(snd_hdr);
147 if (snd_buf)
148 free(snd_buf);
149 snd_hdr = nullptr;
150 snd_hsize = 0;
151 snd_buf = nullptr;
152 }
153
init_gfx1(type8 * header)154 type8 Magnetic::init_gfx1(type8 *header) {
155 #ifdef SAVEMEM
156 type32 i;
157 #endif
158
159 if (!(gfx_buf = (type8 *)malloc(MAX_PICTURE_SIZE))) {
160 delete gfx_fp;
161 gfx_fp = nullptr;
162 return 1;
163 }
164 #ifdef SAVEMEM
165 if (!(gfx_data = (type8 *)malloc(128))) {
166 #else
167 size_t dataSize = read_l(header + 4) - 8;
168 if (!(gfx_data = (type8 *)malloc(dataSize))) {
169 #endif
170 free(gfx_buf);
171 delete gfx_fp;
172 gfx_buf = nullptr;
173 gfx_fp = nullptr;
174 return 1;
175 }
176 #ifdef SAVEMEM
177 if (!fp.read(gfx_data, 128, 1, gfx_fp)) {
178 #else
179 if (gfx_fp->read(gfx_data, dataSize) != dataSize) {
180 #endif
181 free(gfx_data);
182 free(gfx_buf);
183 delete gfx_fp;
184 gfx_data = gfx_buf = nullptr;
185 gfx_fp = nullptr;
186 return 1;
187 }
188
189 #ifdef SAVEMEM
190 for (i = 0; i < 128; i += 4)
191 if (!read_l(gfx_data + i))
192 write_l(gfx_data + i, read_l(header + 4));
193 #else
194 delete gfx_fp;
195 gfx_fp = nullptr;
196 #endif
197
198 gfx_ver = 1;
199 return 2;
200 }
201
202 type8 Magnetic::init_gfx2(type8 *header) {
203 if (!(gfx_buf = (type8 *)malloc(MAX_PICTURE_SIZE))) {
204 delete gfx_fp;
205 gfx_fp = nullptr;
206 return 1;
207 }
208
209 gfx2_hsize = read_w(header + 4);
210 if (!(gfx2_hdr = (type8 *)malloc(gfx2_hsize))) {
211 free(gfx_buf);
212 delete gfx_fp;
213 gfx_buf = nullptr;
214 gfx_fp = nullptr;
215 return 1;
216 }
217
218 gfx_fp->seek(6);
219 if (gfx_fp->read(gfx2_hdr, gfx2_hsize) != gfx2_hsize) {
220 free(gfx_buf);
221 free(gfx2_hdr);
222 delete gfx_fp;
223 gfx_buf = nullptr;
224 gfx2_hdr = 0;
225 gfx_fp = nullptr;
226 return 1;
227 }
228
229 gfx_ver = 2;
230 return 2;
231 }
232
233 type8 Magnetic::init_snd(type8 *header) {
234 if (!(snd_buf = (type8 *)malloc(MAX_MUSIC_SIZE))) {
235 delete snd_fp;
236 snd_fp = nullptr;
237 return 1;
238 }
239
240 snd_hsize = read_w(header + 4);
241 if (!(snd_hdr = (type8 *)malloc(snd_hsize))) {
242 free(snd_buf);
243 delete snd_fp;
244 snd_buf = nullptr;
245 snd_fp = nullptr;
246 return 1;
247 }
248
249 snd_fp->seek(6);
250 if (snd_fp->read(snd_hdr, snd_hsize) != snd_hsize) {
251 free(snd_buf);
252 free(snd_hdr);
253 delete snd_fp;
254 snd_buf = nullptr;
255 snd_hdr = nullptr;
256 snd_fp = nullptr;
257 return 1;
258 }
259
260 return 2;
261 }
262
263 type8 Magnetic::ms_init(const char *name, const char *gfxname, const char *hntname, const char *sndname) {
264 Common::File fp;
265 type8 header[42], header2[8], header3[4];
266 type32 i, dict_size, string2_size, code_size, dec;
267
268 #if defined(LOGEMU) || defined(LOGGFX) || defined(LOGHNT)
269 dbg_log = fopen(LOG_FILE, "wt");
270 #endif
271 ms_stop();
272 if (!name) {
273 if (!restart)
274 return 0;
275 else {
276 memcpy(code, restart, undo_size);
277 undo_stat[0] = undo_stat[1] = 0;
278 ms_showpic(0, 0);
279 }
280 } else {
281 undo_stat[0] = undo_stat[1] = 0;
282
283 if (!fp.open(name))
284 return 0;
285 if ((fp.read(header, 42) != 42) || (read_l(header) != 0x4d615363))
286 return 0;
287 if (read_l(header + 8) != 42)
288 return 0;
289
290 ms_freemem();
291 version = header[13];
292 code_size = read_l(header + 14);
293 string_size = read_l(header + 18);
294 string2_size = read_l(header + 22);
295 dict_size = read_l(header + 26);
296 undo_size = read_l(header + 34);
297 undo_pc = read_l(header + 38);
298
299 if ((version < 4) && (code_size < 65536))
300 mem_size = 65536;
301 else
302 mem_size = code_size;
303
304 /* Some C libraries don't like malloc(0), so make
305 sure that undo_size is always positive. */
306 if (undo_size == 0)
307 undo_size = 8;
308
309 sd = (type8)((dict_size != 0L) ? 1 : 0); /* if (sd) => separate dict */
310
311 if (!(code = (type8 *)malloc(mem_size)) || !(string2 = (type8 *)malloc(string2_size)) ||
312 !(restart = (type8 *)malloc(undo_size)) || (sd &&
313 !(dict = (type8 *)malloc(dict_size)))) {
314 ms_freemem();
315 fp.close();
316 return 0;
317 }
318 if (string_size > MAX_STRING_SIZE) {
319 if (!(string = (type8 *)malloc(MAX_STRING_SIZE)) ||
320 !(string3 = (type8 *)malloc(string_size - MAX_STRING_SIZE))) {
321 ms_freemem();
322 fp.close();
323 return 0;
324 }
325 } else {
326 if (!(string = (type8 *)malloc(string_size))) {
327 ms_freemem();
328 fp.close();
329 return 0;
330 }
331 }
332 if (!(undo[0] = (type8 *)malloc(undo_size)) || !(undo[1] = (type8 *)malloc(undo_size))) {
333 ms_freemem();
334 fp.close();
335 return 0;
336 }
337 if (fp.read(code, code_size) != code_size) {
338 ms_freemem();
339 fp.close();
340 return 0;
341 }
342 memcpy(restart, code, undo_size); /* fast restarts */
343 if (string_size > MAX_STRING_SIZE) {
344 if (fp.read(string, MAX_STRING_SIZE) != MAX_STRING_SIZE) {
345 ms_freemem();
346 fp.close();
347 return 0;
348 }
349 if (fp.read(string3, string_size - MAX_STRING_SIZE) != string_size - MAX_STRING_SIZE) {
350 ms_freemem();
351 fp.close();
352 return 0;
353 }
354 } else {
355 if (fp.read(string, string_size) != string_size) {
356 ms_freemem();
357 fp.close();
358 return 0;
359 }
360 }
361 if (fp.read(string2, string2_size) != string2_size) {
362 ms_freemem();
363 fp.close();
364 return 0;
365 }
366 if (sd && fp.read(dict, dict_size) != dict_size) {
367 ms_freemem();
368 fp.close();
369 return 0;
370 }
371 dec = read_l(header + 30);
372 if (dec >= string_size)
373 decode_table = string2 + dec - string_size;
374 else {
375 if (dec >= MAX_STRING_SIZE)
376 decode_table = string3 + dec - MAX_STRING_SIZE;
377 else
378 decode_table = string + dec;
379 }
380 fp.close();
381 }
382
383 for (i = 0; i < 8; i++)
384 dreg[i] = areg[i] = 0;
385 write_reg(8 + 7, 2, 0xfffe); /* Stack-pointer, -2 due to MS-DOS segments */
386 pc = 0;
387 zflag = nflag = cflag = vflag = 0;
388 i_count = 0;
389 running = 1;
390
391 if (!name)
392 return (type8)(gfx_buf ? 2 : 1); /* Restarted */
393
394 if (version == 4) {
395 /* Try loading a hint file */
396 Common::File hnt_fp;
397 if (hntname && hnt_fp.open(hntname)) {
398 if ((hnt_fp.read(&header3, 4) == 4) && (read_l(header3) == 0x4D614874)) {
399 type8 buf[8];
400 type16 j, blkcnt, elcnt, ntype, elsize, conidx;
401
402 /* Allocate memory for hints */
403 hints = (ms_hint *)malloc(MAX_HINTS * sizeof(struct ms_hint));
404 hint_contents = (type8 *)malloc(MAX_HCONTENTS);
405 if ((hints != 0) && (hint_contents != 0)) {
406 /* Read number of blocks */
407 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos())
408 return 0;
409 blkcnt = read_w2(buf);
410 #ifdef LOGHNT
411 out2("Blocks: %d\n", blkcnt);
412 #endif
413 conidx = 0;
414 for (i = 0; i < blkcnt; i++) {
415 #ifdef LOGHNT
416 out2("\nBlock No. %d\n", i);
417 #endif
418 /* Read number of elements */
419 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
420 elcnt = read_w2(buf);
421 #ifdef LOGHNT
422 out2("Elements: %d\n", elcnt);
423 #endif
424 hints[i].elcount = elcnt;
425
426 /* Read node type */
427 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
428 ntype = read_w2(buf);
429 #ifdef LOGHNT
430 if (ntype == 1)
431 out2("Type: Node\n");
432 else
433 out2("Type: Leaf\n");
434 #endif
435 hints[i].nodetype = ntype;
436 hints[i].content = (const char *)hint_contents + conidx;
437 #ifdef LOGHNT
438 out2("Elements:\n");
439 #endif
440 for (j = 0; j < elcnt; j++) {
441 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
442 elsize = read_w2(buf);
443 if (hnt_fp.read(hint_contents + conidx, elsize) != elsize && !hnt_fp.eos()) return 0;
444 hint_contents[conidx + elsize - 1] = '\0';
445 #ifdef LOGHNT
446 out2("%s\n", hint_contents + conidx);
447 #endif
448 conidx += elsize;
449 }
450
451 /* Do we need a jump table? */
452 if (ntype == 1) {
453 #ifdef LOGHNT
454 out2("Jump to block:\n");
455 #endif
456 for (j = 0; j < elcnt; j++) {
457 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
458 hints[i].links[j] = read_w2(buf);
459 #ifdef LOGHNT
460 out2("%d\n", hints[i].links[j]);
461 #endif
462 }
463 }
464
465 /* Read the parent block */
466 if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
467 hints[i].parent = read_w2(buf);
468 #ifdef LOGHNT
469 out2("Parent: %d\n", hints[i].parent);
470 #endif
471 }
472 } else {
473 if (hints)
474 free(hints);
475 if (hint_contents)
476 free(hint_contents);
477 hints = 0;
478 hint_contents = 0;
479 }
480 }
481 hnt_fp.close();
482 }
483
484 /* Try loading a music file */
485 snd_fp = new Common::File();
486 if (sndname && snd_fp->open(sndname)) {
487 if (snd_fp->read(&header2, 8) != 8) {
488 delete snd_fp;
489 snd_fp = nullptr;
490 } else {
491 if (read_l(header2) == 0x4D615364) { /* MaSd */
492 init_snd(header2);
493 #ifdef LOGSND
494 out2("Sound file loaded.\n");
495 #endif
496 }
497 }
498 } else {
499 delete snd_fp;
500 snd_fp = nullptr;
501 }
502 }
503
504 if (!gfxname)
505 return 1;
506
507 gfx_fp = new Common::File();
508 if (!gfx_fp->open(gfxname) || gfx_fp->read(&header2, 8) != 8) {
509 delete gfx_fp;
510 gfx_fp = nullptr;
511 return 1;
512 }
513
514 if (version < 4 && read_l(header2) == 0x4D615069) /* MaPi */
515 return init_gfx1(header2);
516 else if (version == 4 && read_l(header2) == 0x4D615032) /* MaP2 */
517 return init_gfx2(header2);
518 delete gfx_fp;
519 gfx_fp = nullptr;
520 return 1;
521 }
522
523 type8 Magnetic::is_blank(type16 line, type16 width) {
524 type32s i;
525
526 for (i = line * width; i < (line + 1) * width; i++)
527 if (gfx_buf[i])
528 return 0;
529 return 1;
530 }
531
532 type8 *Magnetic::ms_extract1(type8 pic, type16 *w, type16 *h, type16 *pal) {
533 type8 *decodeTable, *data, bit, val, *buf;
534 type16 tablesize, count;
535 type32 i, j, upsize, offset;
536
537 offset = read_l(gfx_data + 4 * pic);
538 #ifdef SAVEMEM
539 type32 datasize;
540
541 if (fseek(gfx_fp, offset, SEEK_SET) < 0)
542 return 0;
543 datasize = read_l(gfx_data + 4 * (pic + 1)) - offset;
544 if (!(buf = (type8 *)malloc(datasize)))
545 return 0;
546 if (fp.read(buf, 1, datasize, gfx_fp) != datasize)
547 return 0;
548 #else
549 buf = gfx_data + offset - 8;
550 #endif
551
552 for (i = 0; i < 16; i++)
553 pal[i] = read_w(buf + 0x1c + 2 * i);
554 w[0] = (type16)(read_w(buf + 4) - read_w(buf + 2));
555 h[0] = read_w(buf + 6);
556
557 tablesize = read_w(buf + 0x3c);
558 //datasize = read_l(buf + 0x3e);
559 decodeTable = buf + 0x42;
560 data = decodeTable + tablesize * 2 + 2;
561 upsize = h[0] * w[0];
562
563 for (i = 0, j = 0, count = 0, val = 0, bit = 7; i < upsize; i++, count--) {
564 if (!count) {
565 count = tablesize;
566 while (count < 0x80) {
567 if (data[j] & (1 << bit))
568 count = decodeTable[2 * count];
569 else
570 count = decodeTable[2 * count + 1];
571 if (!bit)
572 j++;
573 bit = (type8)(bit ? bit - 1 : 7);
574 }
575 count &= 0x7f;
576 if (count >= 0x10)
577 count -= 0x10;
578 else {
579 val = (type8)count;
580 count = 1;
581 }
582 }
583 gfx_buf[i] = val;
584 }
585 for (j = w[0]; j < upsize; j++)
586 gfx_buf[j] ^= gfx_buf[j - w[0]];
587
588 #ifdef SAVEMEM
589 free(buf);
590 #endif
591 for (; h[0] > 0 && is_blank((type16)(h[0] - 1), w[0]); h[0]--);
592 for (i = 0; h[0] > 0 && is_blank((type16)i, w[0]); h[0]--, i++);
593 return gfx_buf + i * w[0];
594 }
595
596 type16s Magnetic::find_name_in_header(const char *name, type8 upper) {
597 type16s header_pos = 0;
598 char pic_name[8];
599 type8 i;
600
601 for (i = 0; i < 8; i++)
602 pic_name[i] = 0;
603 strncpy(pic_name, name, 6);
604 if (upper) {
605 for (i = 0; i < 8; i++)
606 pic_name[i] = (char)toupper(pic_name[i]);
607 }
608
609 while (header_pos < gfx2_hsize) {
610 const char *hname = (const char *)(gfx2_hdr + header_pos);
611 if (strncmp(hname, pic_name, 6) == 0)
612 return header_pos;
613 header_pos += 16;
614 }
615 return -1;
616 }
617
618 void Magnetic::extract_frame(struct picture *pic) {
619 type32 i, x, y, bit_x, mask, ywb, yw, value, values[4];
620
621 if (pic->width * pic->height > MAX_PICTURE_SIZE) {
622 ms_fatal("picture too large");
623 return;
624 }
625
626 for (y = 0; y < pic->height; y++) {
627 ywb = y * pic->wbytes;
628 yw = y * pic->width;
629
630 for (x = 0; x < pic->width; x++) {
631 if ((x % 8) == 0) {
632 for (i = 0; i < 4; i++)
633 values[i] = pic->data[ywb + (x / 8) + (pic->plane_step * i)];
634 }
635
636 bit_x = 7 - (x & 7);
637 mask = 1 << bit_x;
638 value = ((values[0] & mask) >> bit_x) << 0 |
639 ((values[1] & mask) >> bit_x) << 1 |
640 ((values[2] & mask) >> bit_x) << 2 |
641 ((values[3] & mask) >> bit_x) << 3;
642 value &= 15;
643
644 gfx_buf[yw + x] = (type8)value;
645 }
646 }
647 }
648
649 type8 *Magnetic::ms_extract2(const char *name, type16 *w, type16 *h, type16 *pal, type8 *is_anim) {
650 struct picture main_pic;
651 type32 offset = 0, length = 0, i;
652 type16s header_pos = -1;
653 #ifndef NO_ANIMATION
654 type8 *anim_data;
655 type32 j;
656 #endif
657
658 if (is_anim != 0)
659 *is_anim = 0;
660 gfx2_name = name;
661
662 #ifndef NO_ANIMATION
663 pos_table_size = 0;
664 #endif
665
666 #ifdef NO_ANIMATION
667 /* Find the uppercase (no animation) version of the picture first. */
668 header_pos = find_name_in_header(name, 1);
669 #endif
670 if (header_pos < 0)
671 header_pos = find_name_in_header(name, 0);
672 if (header_pos < 0)
673 return 0;
674
675 offset = read_l(gfx2_hdr + header_pos + 8);
676 length = read_l(gfx2_hdr + header_pos + 12);
677
678 if (offset != 0) {
679 if (gfx2_buf) {
680 free(gfx2_buf);
681 gfx2_buf = nullptr;
682 }
683
684 gfx2_buf = (type8 *)malloc(length);
685 if (!gfx2_buf)
686 return 0;
687
688 if (!gfx_fp->seek(offset)) {
689 free(gfx2_buf);
690 gfx2_buf = nullptr;
691 return 0;
692 }
693
694 if (gfx_fp->read(gfx2_buf, length) != length) {
695 free(gfx2_buf);
696 gfx2_buf = nullptr;
697 return 0;
698 }
699
700 for (i = 0; i < 16; i++)
701 pal[i] = read_w2(gfx2_buf + 4 + (2 * i));
702
703 main_pic.data = gfx2_buf + 48;
704 main_pic.data_size = read_l2(gfx2_buf + 38);
705 main_pic.width = read_w2(gfx2_buf + 42);
706 main_pic.height = read_w2(gfx2_buf + 44);
707 main_pic.wbytes = (type16)(main_pic.data_size / main_pic.height);
708 main_pic.plane_step = (type16)(main_pic.wbytes / 4);
709 main_pic.mask = (type8 *)0;
710 extract_frame(&main_pic);
711
712 *w = main_pic.width;
713 *h = main_pic.height;
714
715 #ifndef NO_ANIMATION
716 /* Check for an animation */
717 anim_data = gfx2_buf + 48 + main_pic.data_size;
718 if ((anim_data[0] != 0xD0) || (anim_data[1] != 0x5E)) {
719 type8 *current;
720 type16 frame_count;
721 type16 value1, value2;
722
723 if (is_anim != 0)
724 *is_anim = 1;
725
726 current = anim_data + 6;
727 frame_count = read_w2(anim_data + 2);
728 if (frame_count > MAX_ANIMS) {
729 ms_fatal("animation frame array too short");
730 return 0;
731 }
732
733 /* Loop through each animation frame */
734 for (i = 0; i < frame_count; i++) {
735 anim_frame_table[i].data = current + 10;
736 anim_frame_table[i].data_size = read_l2(current);
737 anim_frame_table[i].width = read_w2(current + 4);
738 anim_frame_table[i].height = read_w2(current + 6);
739 anim_frame_table[i].wbytes = (type16)(anim_frame_table[i].data_size / anim_frame_table[i].height);
740 anim_frame_table[i].plane_step = (type16)(anim_frame_table[i].wbytes / 4);
741 anim_frame_table[i].mask = (type8 *)0;
742
743 current += anim_frame_table[i].data_size + 12;
744 value1 = read_w2(current - 2);
745 value2 = read_w2(current);
746
747 /* Get the mask */
748 if ((value1 == anim_frame_table[i].width) && (value2 == anim_frame_table[i].height)) {
749 type16 skip;
750
751 anim_frame_table[i].mask = (type8 *)(current + 4);
752 skip = read_w2(current + 2);
753 current += skip + 6;
754 }
755 }
756
757 /* Get the positioning tables */
758 pos_table_size = read_w2(current - 2);
759 if (pos_table_size > MAX_POSITIONS) {
760 ms_fatal("animation position array too short");
761 return 0;
762 }
763
764 #ifdef LOGGFX_EXT
765 out2("POSITION TABLE DUMP\n");
766 #endif
767 for (i = 0; i < pos_table_size; i++) {
768 pos_table_count[i] = read_w2(current + 2);
769 current += 4;
770
771 if (pos_table_count[i] > MAX_ANIMS) {
772 ms_fatal("animation position array too short");
773 return 0;
774 }
775
776 for (j = 0; j < pos_table_count[i]; j++) {
777 pos_table[i][j].x = read_w2(current);
778 pos_table[i][j].y = read_w2(current + 2);
779 pos_table[i][j].number = read_w2(current + 4) - 1;
780 current += 8;
781 #ifdef LOGGFX_EXT
782 out2("Position entry: Table: %d Entry: %d X: %d Y: %d Frame: %d\n",
783 i, j, pos_table[i][j].x, pos_table[i][j].y, pos_table[i][j].number);
784 #endif
785 }
786 }
787
788 /* Get the command sequence table */
789 //command_count = read_w2(current);
790 command_table = current + 2;
791
792 for (i = 0; i < MAX_POSITIONS; i++) {
793 anim_table[i].flag = -1;
794 anim_table[i].count = -1;
795 }
796 command_index = 0;
797 anim_repeat = 0;
798 pos_table_index = -1;
799 pos_table_max = -1;
800 }
801 #endif
802 return gfx_buf;
803 }
804 return 0;
805 }
806
807 type8 *Magnetic::ms_extract(type32 pic, type16 *w, type16 *h, type16 *pal, type8 *is_anim) {
808 if (is_anim)
809 *is_anim = 0;
810
811 if (gfx_buf) {
812 switch (gfx_ver) {
813 case 1:
814 return ms_extract1((type8)pic, w, h, pal);
815 case 2:
816 return ms_extract2((const char *)(code + pic), w, h, pal, is_anim);
817 default:
818 break;
819 }
820 }
821 return 0;
822 }
823
824 type8 Magnetic::ms_animate(struct ms_position **positions, type16 *count) {
825 #ifndef NO_ANIMATION
826 type8 got_anim = 0;
827 type16 i, j, ttable;
828
829 if ((gfx_buf == 0) || (gfx2_buf == 0) || (gfx_ver != 2))
830 return 0;
831 if ((pos_table_size == 0) || (command_index < 0))
832 return 0;
833
834 *count = 0;
835 *positions = (struct ms_position *)0;
836
837 while (got_anim == 0) {
838 if (pos_table_max >= 0) {
839 if (pos_table_index < pos_table_max) {
840 for (i = 0; i < pos_table_size; i++) {
841 if (anim_table[i].flag > -1) {
842 if (*count >= MAX_FRAMES) {
843 ms_fatal("returned animation array too short");
844 return 0;
845 }
846
847 pos_array[*count] = pos_table[i][anim_table[i].flag];
848 #ifdef LOGGFX_EXT
849 out2("Adding frame %d to buffer\n", pos_array[*count].number);
850 #endif
851 (*count)++;
852
853 if (anim_table[i].flag < (pos_table_count[i] - 1))
854 anim_table[i].flag++;
855 if (anim_table[i].count > 0)
856 anim_table[i].count--;
857 else
858 anim_table[i].flag = -1;
859 }
860 }
861 if (*count > 0) {
862 *positions = pos_array;
863 got_anim = 1;
864 }
865 pos_table_index++;
866 }
867 }
868
869 if (got_anim == 0) {
870 type8 command = command_table[command_index];
871 command_index++;
872
873 pos_table_max = -1;
874 pos_table_index = -1;
875
876 switch (command) {
877 case 0x00:
878 command_index = -1;
879 return 0;
880 case 0x01:
881 #ifdef LOGGFX_EXT
882 out2("Load Frame Table: %d Start at: %d Count: %d\n",
883 command_table[command_index], command_table[command_index + 1],
884 command_table[command_index + 2]);
885 #endif
886 ttable = command_table[command_index];
887 command_index++;
888
889 if (ttable - 1 >= MAX_POSITIONS) {
890 ms_fatal("animation table too short");
891 return 0;
892 }
893
894 anim_table[ttable - 1].flag = (type16s)(command_table[command_index] - 1);
895 command_index++;
896 anim_table[ttable - 1].count = (type16s)(command_table[command_index] - 1);
897 command_index++;
898
899 /* Workaround for Wonderland "catter" animation */
900 if (v4_id == 0) {
901 if (strcmp(gfx2_name, "catter") == 0) {
902 if (command_index == 96)
903 anim_table[ttable - 1].count = 9;
904 if (command_index == 108)
905 anim_table[ttable - 1].flag = -1;
906 if (command_index == 156)
907 anim_table[ttable - 1].flag = -1;
908 }
909 }
910 break;
911 case 0x02:
912 #ifdef LOGGFX_EXT
913 out2("Animate: %d\n", command_table[command_index]);
914 #endif
915 pos_table_max = command_table[command_index];
916 pos_table_index = 0;
917 command_index++;
918 break;
919 case 0x03:
920 #ifdef LOGGFX_EXT
921 out2("Stop/Repeat Param: %d\n", command_table[command_index]);
922 command_index = -1;
923 return 0;
924 #else
925 if (v4_id == 0) {
926 command_index = -1;
927 return 0;
928 } else {
929 command_index = 0;
930 anim_repeat = 1;
931 pos_table_index = -1;
932 pos_table_max = -1;
933 for (j = 0; j < MAX_POSITIONS; j++) {
934 anim_table[j].flag = -1;
935 anim_table[j].count = -1;
936 }
937 }
938 break;
939 #endif
940 case 0x04:
941 #ifdef LOGGFX_EXT
942 out2("Unknown Command: %d Prop1: %d Prop2: %d WARNING:not parsed\n", command,
943 command_table[command_index], command_table[command_index + 1]);
944 #endif
945 command_index += 3;
946 return 0;
947 case 0x05:
948 ttable = next_table;
949 command_index++;
950
951 anim_table[ttable - 1].flag = 0;
952 anim_table[ttable - 1].count = command_table[command_index];
953
954 pos_table_max = command_table[command_index];
955 pos_table_index = 0;
956 command_index++;
957 command_index++;
958 next_table++;
959 break;
960 default:
961 ms_fatal("unknown animation command");
962 command_index = -1;
963 return 0;
964 }
965 }
966 }
967 #ifdef LOGGFX_EXT
968 out2("ms_animate() returning %d frames\n", *count);
969 #endif
970 return got_anim;
971 #else
972 return 0;
973 #endif
974 }
975
976 type8 *Magnetic::ms_get_anim_frame(type16s number, type16 *width, type16 *height, type8 **mask) {
977 #ifndef NO_ANIMATION
978 if (number >= 0) {
979 extract_frame(anim_frame_table + number);
980 *width = anim_frame_table[number].width;
981 *height = anim_frame_table[number].height;
982 *mask = anim_frame_table[number].mask;
983 return gfx_buf;
984 }
985 #endif
986 return 0;
987 }
988
989 type8 Magnetic::ms_anim_is_repeating() const {
990 #ifndef NO_ANIMATION
991 return anim_repeat;
992 #else
993 return 0;
994 #endif
995 }
996
997 type16s Magnetic::find_name_in_sndheader(const char *name) {
998 type16s header_pos = 0;
999
1000 while (header_pos < snd_hsize) {
1001 const char *hname = (const char *)(snd_hdr + header_pos);
1002 if (strcmp(hname, name) == 0)
1003 return header_pos;
1004 header_pos += 18;
1005 }
1006
1007 return -1;
1008 }
1009
1010 type8 *Magnetic::sound_extract(const char *name, type32 *length, type16 *tempo) {
1011 type32 offset = 0;
1012 type16s header_pos = -1;
1013
1014 if (header_pos < 0)
1015 header_pos = find_name_in_sndheader(name);
1016 if (header_pos < 0)
1017 return 0;
1018
1019 *tempo = read_w(snd_hdr + header_pos + 8);
1020 offset = read_l(snd_hdr + header_pos + 10);
1021 *length = read_l(snd_hdr + header_pos + 14);
1022
1023 if (offset != 0) {
1024 if (!snd_buf)
1025 return 0;
1026 if (!snd_fp->seek(offset) || snd_fp->read(snd_buf, *length) != *length)
1027 return 0;
1028
1029 return snd_buf;
1030 }
1031
1032 return nullptr;
1033 }
1034
1035 void Magnetic::save_undo() {
1036 type8 *tmp, i;
1037 type32 tmp32;
1038
1039 tmp = undo[0]; /* swap buffers */
1040 undo[0] = undo[1];
1041 undo[1] = tmp;
1042
1043 for (i = 0; i < 18; i++) {
1044 tmp32 = undo_regs[0][i];
1045 undo_regs[0][i] = undo_regs[1][i];
1046 undo_regs[1][i] = tmp32;
1047 }
1048
1049 memcpy(undo[1], code, undo_size);
1050 for (i = 0; i < 8; i++) {
1051 undo_regs[1][i] = dreg[i];
1052 undo_regs[1][8 + i] = areg[i];
1053 }
1054 undo_regs[1][16] = i_count;
1055 undo_regs[1][17] = pc; /* status flags intentionally omitted */
1056
1057 undo_stat[0] = undo_stat[1];
1058 undo_stat[1] = 1;
1059 }
1060
1061 type8 Magnetic::ms_undo() {
1062 type8 i;
1063
1064 ms_flush();
1065 if (!undo_stat[0])
1066 return 0;
1067
1068 undo_stat[0] = undo_stat[1] = 0;
1069 memcpy(code, undo[0], undo_size);
1070 for (i = 0; i < 8; i++) {
1071 dreg[i] = undo_regs[0][i];
1072 areg[i] = undo_regs[0][8 + i];
1073 }
1074 i_count = undo_regs[0][16];
1075 pc = undo_regs[0][17]; /* status flags intentionally omitted */
1076 return 1;
1077 }
1078
1079 #ifdef LOGEMU
1080 void Magnetic::log_status() {
1081 int j;
1082
1083 fprintf(dbg_log, "\nD0:");
1084 for (j = 0; j < 8; j++)
1085 fprintf(dbg_log, " %8.8x", read_reg(j, 3));
1086 fprintf(dbg_log, "\nA0:");
1087 for (j = 0; j < 8; j++)
1088 fprintf(dbg_log, " %8.8x", read_reg(8 + j, 3));
1089 fprintf(dbg_log, "\nPC=%5.5x (%8.8x) ZCNV=%d%d%d%d - %d instructions\n\n",
1090 pc, code, zflag & 1, cflag & 1, nflag & 1, vflag & 1, i_count);
1091 }
1092 #endif
1093
1094 void Magnetic::ms_status() {
1095 int j;
1096
1097 Common::String s = "D0:";
1098 for (j = 0; j < 8; j++)
1099 s += Common::String::format(" %8.8lx", (long) read_reg(j, 3));
1100 s += "\nA0:";
1101
1102 for (j = 0; j < 8; j++)
1103 s += Common::String::format(" %8.8lx", (long) read_reg(8 + j, 3));
1104 s += Common::String::format("\nPC=%5.5lx ZCNV=%d%d%d%d - %ld instructions\n",
1105 (long) pc, zflag & 1, cflag & 1, nflag & 1, vflag & 1, (long) i_count);
1106 warning("%s", s.c_str());
1107 }
1108
1109 type8 *Magnetic::reg_align(type8 *ptr, type8 size) {
1110 if (size == 1)
1111 ptr += 2;
1112 if (size == 0)
1113 ptr += 3;
1114 return ptr;
1115 }
1116
1117 type32 Magnetic::read_reg(int i, int s) {
1118 type8 *ptr;
1119
1120 if (i > 15) {
1121 ms_fatal("invalid register in read_reg");
1122 return 0;
1123 }
1124 if (i < 8)
1125 ptr = (type8 *) & dreg[i];
1126 else
1127 ptr = (type8 *) & areg[i - 8];
1128
1129 switch (s) {
1130 case 0:
1131 return reg_align(ptr, 0)[0];
1132 case 1:
1133 return read_w(reg_align(ptr, 1));
1134 default:
1135 return read_l(ptr);
1136 }
1137 }
1138
1139 void Magnetic::write_reg(int i, int s, type32 val) {
1140 type8 *ptr;
1141
1142 if (i > 15) {
1143 ms_fatal("invalid register in write_reg");
1144 return;
1145 }
1146 if (i < 8)
1147 ptr = (type8 *) & dreg[i];
1148 else
1149 ptr = (type8 *) & areg[i - 8];
1150
1151 switch (s) {
1152 case 0:
1153 reg_align(ptr, 0)[0] = (type8)val;
1154 break;
1155 case 1:
1156 write_w(reg_align(ptr, 1), (type16)val);
1157 break;
1158 default:
1159 write_l(ptr, val);
1160 break;
1161 }
1162 }
1163
1164 void Magnetic::char_out(type8 c) {
1165 static type8 big = 0, period = 0, pipe = 0;
1166
1167 if (c == 0xff) {
1168 big = 1;
1169 return;
1170 }
1171 c &= 0x7f;
1172 if (read_reg(3, 0)) {
1173 if (c == 0x5f || c == 0x40)
1174 c = 0x20;
1175 if ((c >= 'a') && (c <= 'z'))
1176 c &= 0xdf;
1177 if (version < 4)
1178 ms_statuschar(c);
1179 return;
1180 }
1181 if (c == 0x5e)
1182 c = 0x0a;
1183 if (c == 0x40) {
1184 if (read_reg(2, 0))
1185 return;
1186 else
1187 c = 0x73;
1188 }
1189 if (version < 3 && c == 0x7e) {
1190 lastchar = 0x7e;
1191 c = 0x0a;
1192 }
1193 if (((c > 0x40) && (c < 0x5b)) || ((c > 0x60) && (c < 0x7b))) {
1194 if (big) {
1195 c &= 0xdf;
1196 big = 0;
1197 }
1198 if (period)
1199 char_out(0x20);
1200 }
1201 period = 0;
1202 if (version < 4) {
1203 if ((c == 0x2e) || (c == 0x3f) || (c == 0x21) || (c == 0x0a))
1204 big = 1;
1205 else if (c == 0x22)
1206 big = 0;
1207 } else {
1208 if ((c == 0x20) && (lastchar == 0x0a))
1209 return;
1210 if ((c == 0x2e) || (c == 0x3f) || (c == 0x21) || (c == 0x0a))
1211 big = 1;
1212 else if (c == 0x22)
1213 big = 0;
1214 }
1215 if (((c == 0x20) || (c == 0x0a)) && (c == lastchar))
1216 return;
1217 if (version < 3) {
1218 if (pipe) {
1219 pipe = 0;
1220 return;
1221 }
1222 if (c == 0x7c) {
1223 pipe = 1;
1224 return;
1225 }
1226 } else {
1227 if (c == 0x7e) {
1228 c = 0x0a;
1229 if (lastchar != 0x0a)
1230 char_out(0x0a);
1231 }
1232 }
1233 lastchar = c;
1234 if (c == 0x5f)
1235 c = 0x20;
1236 if ((c == 0x2e) || (c == 0x2c) || (c == 0x3b) || (c == 0x3a) || (c == 0x21) || (c == 0x3f))
1237 period = 1;
1238 ms_putchar(c);
1239 }
1240
1241 void Magnetic::set_info(type8 b) {
1242 regnr = (type8)(b & 0x07);
1243 admode = (type8)((b >> 3) & 0x07);
1244 opsize = (type8)(b >> 6);
1245 }
1246
1247 void Magnetic::read_word() {
1248 type8 *epc;
1249
1250 epc = effective(pc);
1251 byte1 = epc[0];
1252 byte2 = epc[1];
1253 pc += 2;
1254 }
1255
1256 void Magnetic::set_arg1() {
1257 type8 tmp[2], l1c;
1258
1259 is_reversible = 1;
1260 switch (admode) {
1261 case 0:
1262 arg1 = reg_align((type8 *) & dreg[regnr], opsize); /* Dx */
1263 is_reversible = 0;
1264 #ifdef LOGEMU
1265 out(" d%.1d", regnr);
1266 #endif
1267 break;
1268 case 1:
1269 arg1 = reg_align((type8 *) & areg[regnr], opsize); /* Ax */
1270 is_reversible = 0;
1271 #ifdef LOGEMU
1272 out(" a%.1d", regnr);
1273 #endif
1274 break;
1275 case 2:
1276 arg1i = read_reg(8 + regnr, 2); /* (Ax) */
1277 #ifdef LOGEMU
1278 out(" (a%.1d)", regnr);
1279 #endif
1280 break;
1281 case 3:
1282 arg1i = read_reg(8 + regnr, 2); /* (Ax)+ */
1283 write_reg(8 + regnr, 2, read_reg(8 + regnr, 2) + (1 << opsize));
1284 #ifdef LOGEMU
1285 out(" (a%.1d)+", regnr);
1286 #endif
1287 break;
1288 case 4:
1289 write_reg(8 + regnr, 2, read_reg(8 + regnr, 2) - (1 << opsize));
1290 arg1i = read_reg(8 + regnr, 2); /* -(Ax) */
1291 #ifdef LOGEMU
1292 out(" -(a%.1d)", regnr);
1293 #endif
1294 break;
1295 case 5: {
1296 type16s i = (type16s) read_w(effective(pc));
1297 arg1i = read_reg(8 + regnr, 2) + i;
1298 pc += 2; /* offset.w(Ax) */
1299 #ifdef LOGEMU
1300 out(" %X(a%.1d)", i, regnr);
1301 #endif
1302 }
1303 break;
1304 default:
1305 break;
1306 case 6:
1307 tmp[0] = byte1;
1308 tmp[1] = byte2;
1309 read_word(); /* offset.b(Ax, Dx/Ax) [1d1c] */
1310 #ifdef LOGEMU
1311 out(" %.2X(a%.1d,", (int) byte2, regnr);
1312 #endif
1313 arg1i = read_reg(regnr + 8, 2) + (type8s) byte2;
1314 #ifdef LOGEMU
1315 if ((byte1 >> 4) > 8)
1316 out("a%.1d", (byte1 >> 4) - 8);
1317 else
1318 out("d%.1d", byte1 >> 4);
1319 #endif
1320 if (byte1 & 0x08) {
1321 #ifdef LOGEMU
1322 out(".l)");
1323 #endif
1324 arg1i += (type32s) read_reg((byte1 >> 4), 2);
1325 } else {
1326 #ifdef LOGEMU
1327 out(".w)");
1328 #endif
1329 arg1i += (type16s) read_reg((byte1 >> 4), 1);
1330 }
1331 byte1 = tmp[0];
1332 byte2 = tmp[1];
1333 break;
1334 case 7: /* specials */
1335 switch (regnr) {
1336 case 0:
1337 arg1i = read_w(effective(pc)); /* $xxxx.W */
1338 pc += 2;
1339 #ifdef LOGEMU
1340 out(" %.4X.w", arg1i);
1341 #endif
1342 break;
1343 case 1:
1344 arg1i = read_l(effective(pc)); /* $xxxx */
1345 pc += 4;
1346 #ifdef LOGEMU
1347 out(" %.4X", arg1i);
1348 #endif
1349 break;
1350 case 2:
1351 arg1i = (type16s) read_w(effective(pc)) + pc; /* $xxxx(PC) */
1352 pc += 2;
1353 #ifdef LOGEMU
1354 out(" %.4X(pc)", arg1i);
1355 #endif
1356 break;
1357 case 3:
1358 l1c = effective(pc)[0]; /* $xx(PC,A/Dx) */
1359 #ifdef LOGEMU
1360 out(" ???2", arg1i);
1361 #endif
1362 if (l1c & 0x08)
1363 arg1i = pc + (type32s) read_reg((l1c >> 4), 2);
1364 else
1365 arg1i = pc + (type16s) read_reg((l1c >> 4), 1);
1366 l1c = effective(pc)[1];
1367 pc += 2;
1368 arg1i += (type8s) l1c;
1369 break;
1370 case 4:
1371 arg1i = pc; /* #$xxxx */
1372 if (opsize == 0)
1373 arg1i += 1;
1374 pc += 2;
1375 if (opsize == 2)
1376 pc += 2;
1377 #ifdef LOGEMU
1378 out(" #%.4X", arg1i);
1379 #endif
1380 break;
1381 default:
1382 break;
1383 }
1384 break;
1385 }
1386 if (is_reversible)
1387 arg1 = effective(arg1i);
1388 }
1389
1390 void Magnetic::set_arg2_nosize(int use_dx, type8 b) {
1391 if (use_dx)
1392 arg2 = (type8 *) dreg;
1393 else
1394 arg2 = (type8 *) areg;
1395 arg2 += (b & 0x0e) << 1;
1396 }
1397
1398 void Magnetic::set_arg2(int use_dx, type8 b) {
1399 set_arg2_nosize(use_dx, b);
1400 arg2 = reg_align(arg2, opsize);
1401 }
1402
1403 void Magnetic::swap_args() {
1404 type8 *tmp;
1405
1406 tmp = arg1;
1407 arg1 = arg2;
1408 arg2 = tmp;
1409 }
1410
1411 void Magnetic::push(type32 c) {
1412 write_reg(15, 2, read_reg(15, 2) - 4);
1413 write_l(effective(read_reg(15, 2)), c);
1414 }
1415
1416 type32 Magnetic::pop() {
1417 type32 c;
1418
1419 c = read_l(effective(read_reg(15, 2)));
1420 write_reg(15, 2, read_reg(15, 2) + 4);
1421 return c;
1422 }
1423
1424 void Magnetic::get_arg() {
1425 #ifdef LOGEMU
1426 out(" %.4X", pc);
1427 #endif
1428 set_info(byte2);
1429 arg2 = effective(pc);
1430 pc += 2;
1431 if (opsize == 2)
1432 pc += 2;
1433 if (opsize == 0)
1434 arg2 += 1;
1435 set_arg1();
1436 }
1437
1438 void Magnetic::set_flags() {
1439 type16 i;
1440 type32 j;
1441
1442 zflag = nflag = 0;
1443 switch (opsize) {
1444 case 0:
1445 if (arg1[0] > 127)
1446 nflag = 0xff;
1447 if (arg1[0] == 0)
1448 zflag = 0xff;
1449 break;
1450 case 1:
1451 i = read_w(arg1);
1452 if (i == 0)
1453 zflag = 0xff;
1454 if ((i >> 15) > 0)
1455 nflag = 0xff;
1456 break;
1457 case 2:
1458 j = read_l(arg1);
1459 if (j == 0)
1460 zflag = 0xff;
1461 if ((j >> 31) > 0)
1462 nflag = 0xff;
1463 break;
1464 default:
1465 break;
1466 }
1467 }
1468
1469 int Magnetic::condition(type8 b) {
1470 switch (b & 0x0f) {
1471 case 0:
1472 return 0xff;
1473 case 1:
1474 return 0x00;
1475 case 2:
1476 return (zflag | cflag) ^ 0xff;
1477 case 3:
1478 return (zflag | cflag);
1479 case 4:
1480 return cflag ^ 0xff;
1481 case 5:
1482 return cflag;
1483 case 6:
1484 return zflag ^ 0xff;
1485 case 7:
1486 return zflag;
1487 case 8:
1488 return vflag ^ 0xff;
1489 case 9:
1490 return vflag;
1491 case 10:
1492 case 12:
1493 return nflag ^ 0xff;
1494 case 11:
1495 case 13:
1496 return nflag;
1497 case 14:
1498 return (zflag | nflag) ^ 0xff;
1499 case 15:
1500 return (zflag | nflag);
1501 default:
1502 break;
1503 }
1504 return 0x00;
1505 }
1506
1507 void Magnetic::branch(type8 b) {
1508 if (b == 0)
1509 pc += (type16s) read_w(effective(pc));
1510 else
1511 pc += (type8s) b;
1512 #ifdef LOGEMU
1513 out(" %.4X", pc);
1514 #endif
1515 }
1516
1517 void Magnetic::do_add(type8 adda) {
1518 if (adda) {
1519 if (opsize == 0)
1520 write_l(arg1, read_l(arg1) + (type8s) arg2[0]);
1521 if (opsize == 1)
1522 write_l(arg1, read_l(arg1) + (type16s) read_w(arg2));
1523 if (opsize == 2)
1524 write_l(arg1, read_l(arg1) + (type32s) read_l(arg2));
1525 } else {
1526 cflag = 0;
1527 if (opsize == 0) {
1528 arg1[0] += arg2[0];
1529 if (arg2[0] > arg1[0])
1530 cflag = 0xff;
1531 }
1532 if (opsize == 1) {
1533 write_w(arg1, (type16)(read_w(arg1) + read_w(arg2)));
1534 if (read_w(arg2) > read_w(arg1))
1535 cflag = 0xff;
1536 }
1537 if (opsize == 2) {
1538 write_l(arg1, read_l(arg1) + read_l(arg2));
1539 if (read_l(arg2) > read_l(arg1))
1540 cflag = 0xff;
1541 }
1542 if (version < 3 || !quick_flag) {
1543 /* Corruption onwards */
1544 vflag = 0;
1545 set_flags();
1546 }
1547 }
1548 }
1549
1550 void Magnetic::do_sub(type8 suba) {
1551 if (suba) {
1552 if (opsize == 0)
1553 write_l(arg1, read_l(arg1) - (type8s) arg2[0]);
1554 if (opsize == 1)
1555 write_l(arg1, read_l(arg1) - (type16s) read_w(arg2));
1556 if (opsize == 2)
1557 write_l(arg1, read_l(arg1) - (type32s) read_l(arg2));
1558 } else {
1559 cflag = 0;
1560 if (opsize == 0) {
1561 if (arg2[0] > arg1[0])
1562 cflag = 0xff;
1563 arg1[0] -= arg2[0];
1564 }
1565 if (opsize == 1) {
1566 if (read_w(arg2) > read_w(arg1))
1567 cflag = 0xff;
1568 write_w(arg1, (type16)(read_w(arg1) - read_w(arg2)));
1569 }
1570 if (opsize == 2) {
1571 if (read_l(arg2) > read_l(arg1))
1572 cflag = 0xff;
1573 write_l(arg1, read_l(arg1) - read_l(arg2));
1574 }
1575 if (version < 3 || !quick_flag) {
1576 /* Corruption onwards */
1577 vflag = 0;
1578 set_flags();
1579 }
1580 }
1581 }
1582
1583 void Magnetic::do_eor() {
1584 if (opsize == 0)
1585 arg1[0] ^= arg2[0];
1586 if (opsize == 1)
1587 write_w(arg1, (type16)(read_w(arg1) ^ read_w(arg2)));
1588 if (opsize == 2)
1589 write_l(arg1, read_l(arg1) ^ read_l(arg2));
1590 cflag = vflag = 0;
1591 set_flags();
1592 }
1593
1594 void Magnetic::do_and() {
1595 if (opsize == 0)
1596 arg1[0] &= arg2[0];
1597 if (opsize == 1)
1598 write_w(arg1, (type16)(read_w(arg1) & read_w(arg2)));
1599 if (opsize == 2)
1600 write_l(arg1, read_l(arg1) & read_l(arg2));
1601 cflag = vflag = 0;
1602 set_flags();
1603 }
1604
1605 void Magnetic::do_or() {
1606 if (opsize == 0)
1607 arg1[0] |= arg2[0];
1608 if (opsize == 1)
1609 write_w(arg1, (type16)(read_w(arg1) | read_w(arg2)));
1610 if (opsize == 2)
1611 write_l(arg1, read_l(arg1) | read_l(arg2));
1612 cflag = vflag = 0;
1613 set_flags(); /* [1c2b] */
1614 }
1615
1616 void Magnetic::do_cmp() {
1617 type8 *tmp;
1618
1619 tmp = arg1;
1620 tmparg[0] = arg1[0];
1621 tmparg[1] = arg1[1];
1622 tmparg[2] = arg1[2];
1623 tmparg[3] = arg1[3];
1624 arg1 = tmparg;
1625 quick_flag = 0;
1626 do_sub(0);
1627 arg1 = tmp;
1628 }
1629
1630 void Magnetic::do_move() {
1631
1632 if (opsize == 0)
1633 arg1[0] = arg2[0];
1634 if (opsize == 1)
1635 write_w(arg1, read_w(arg2));
1636 if (opsize == 2)
1637 write_l(arg1, read_l(arg2));
1638 if (version < 2 || admode != 1) {
1639 /* Jinxter: no flags if destination Ax */
1640 cflag = vflag = 0;
1641 set_flags();
1642 }
1643 }
1644
1645 type8 Magnetic::do_btst(type8 a) {
1646 a &= admode ? 0x7 : 0x1f;
1647 while (admode == 0 && a >= 8) {
1648 a -= 8;
1649 arg1 -= 1;
1650 }
1651 zflag = 0;
1652 if ((arg1[0] & (1 << a)) == 0)
1653 zflag = 0xff;
1654 return a;
1655 }
1656
1657 void Magnetic::do_bop(type8 b, type8 a) {
1658 #ifdef LOGEMU
1659 out("bop (%.2x,%.2x) ", (int) b, (int) a);
1660 #endif
1661 b = b & 0xc0;
1662 a = do_btst(a);
1663 #ifdef LOGEMU
1664 if (b == 0x00)
1665 out("no bop???");
1666 #endif
1667 if (b == 0x40) {
1668 arg1[0] ^= (1 << a); /* bchg */
1669 #ifdef LOGEMU
1670 out("bchg");
1671 #endif
1672 }
1673 if (b == 0x80) {
1674 arg1[0] &= ((1 << a) ^ 0xff); /* bclr */
1675 #ifdef LOGEMU
1676 out("bclr");
1677 #endif
1678 }
1679 if (b == 0xc0) {
1680 arg1[0] |= (1 << a); /* bset */
1681 #ifdef LOGEMU
1682 out("bset");
1683 #endif
1684 }
1685 }
1686
1687 void Magnetic::check_btst() {
1688 #ifdef LOGEMU
1689 out("btst");
1690 #endif
1691 set_info((type8)(byte2 & 0x3f));
1692 set_arg1();
1693 set_arg2(1, byte1);
1694 do_bop(byte2, arg2[0]);
1695 }
1696
1697 void Magnetic::check_lea() {
1698 #ifdef LOGEMU
1699 out("lea");
1700 #endif
1701 if ((byte2 & 0xc0) == 0xc0) {
1702 set_info(byte2);
1703 opsize = 2;
1704 set_arg1();
1705 set_arg2(0, byte1);
1706 write_w(arg2, 0);
1707 if (is_reversible)
1708 write_l(arg2, arg1i);
1709 else
1710 ms_fatal("illegal addressing mode for LEA");
1711 } else {
1712 ms_fatal("unimplemented instruction CHK");
1713 }
1714 }
1715
1716 void Magnetic::check_movem() {
1717 type8 l1c;
1718
1719 #ifdef LOGEMU
1720 out("movem");
1721 #endif
1722 set_info((type8)(byte2 - 0x40));
1723 read_word();
1724 for (l1c = 0; l1c < 8; l1c++) {
1725 if (byte2 & 1 << l1c) {
1726 set_arg1();
1727 if (opsize == 2)
1728 write_l(arg1, read_reg(15 - l1c, 2));
1729 if (opsize == 1)
1730 write_w(arg1, (type16)read_reg(15 - l1c, 1));
1731 }
1732 }
1733 for (l1c = 0; l1c < 8; l1c++) {
1734 if (byte1 & 1 << l1c) {
1735 set_arg1();
1736 if (opsize == 2)
1737 write_l(arg1, read_reg(7 - l1c, 2));
1738 if (opsize == 1)
1739 write_w(arg1, (type16)read_reg(7 - l1c, 1));
1740 }
1741 }
1742 }
1743
1744 void Magnetic::check_movem2() {
1745 type8 l1c;
1746
1747 #ifdef LOGEMU
1748 out("movem (2)");
1749 #endif
1750 set_info((type8)(byte2 - 0x40));
1751 read_word();
1752 for (l1c = 0; l1c < 8; l1c++) {
1753 if (byte2 & 1 << l1c) {
1754 set_arg1();
1755 if (opsize == 2)
1756 write_reg(l1c, 2, read_l(arg1));
1757 if (opsize == 1)
1758 write_reg(l1c, 1, read_w(arg1));
1759 }
1760 }
1761 for (l1c = 0; l1c < 8; l1c++) {
1762 if (byte1 & 1 << l1c) {
1763 set_arg1();
1764 if (opsize == 2)
1765 write_reg(8 + l1c, 2, read_l(arg1));
1766 if (opsize == 1)
1767 write_reg(8 + l1c, 1, read_w(arg1));
1768 }
1769 }
1770 }
1771
1772 void Magnetic::dict_lookup() {
1773 type16 dtab, doff, output, output_bak, bank, word, output2;
1774 type16 tmp16, i, obj_adj, adjlist, adjlist_bak;
1775 type8 c, c2, c3, flag, matchlen, longest, flag2;
1776 type8 restartFlag = 0, accept = 0;
1777
1778 /*
1779 dtab=A5.W ;dict_table offset <L22>
1780 output=output_bak=A2.W ;output <L24>
1781 A5.W=A6.W ;input word
1782 doff=A3.W ;lookup offset (doff) <L1C>
1783 adjlist=A0.W ;adjlist <L1E>
1784 */
1785
1786 dtab = (type16)read_reg(8 + 5, 1); /* used by version>0 */
1787 output = (type16)read_reg(8 + 2, 1);
1788 write_reg(8 + 5, 1, read_reg(8 + 6, 1));
1789 doff = (type16)read_reg(8 + 3, 1);
1790 adjlist = (type16)read_reg(8 + 0, 1);
1791
1792 bank = (type16)read_reg(6, 0); /* l2d */
1793 flag = 0; /* l2c */
1794 word = 0; /* l26 */
1795 matchlen = 0; /* l2e */
1796 longest = 0; /* 30e2 */
1797 write_reg(0, 1, 0); /* apostroph */
1798
1799 while ((c = sd ? dict[doff] : effective(doff)[0]) != 0x81) {
1800 if (c >= 0x80) {
1801 if (c == 0x82) {
1802 flag = matchlen = 0;
1803 word = 0;
1804 write_reg(8 + 6, 1, read_reg(8 + 5, 1));
1805 bank++;
1806 doff++;
1807 continue;
1808 }
1809 c3 = c;
1810 c &= 0x5f;
1811 c2 = effective(read_reg(8 + 6, 1))[0] & 0x5f;
1812 if (c2 == c) {
1813 write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
1814 c = effective(read_reg(8 + 6, 1))[0];
1815 if ((!c) || (c == 0x20) || (c == 0x27) || (!version && (matchlen > 6))) {
1816 if (c == 0x27) {
1817 write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
1818 write_reg(0, 1, 0x200 + effective(read_reg(8 + 6, 1))[0]);
1819 }
1820 if ((version < 4) || (c3 != 0xa0))
1821 accept = 1;
1822 } else
1823 restartFlag = 1;
1824 } else if (!version && matchlen > 6 && !c2)
1825 accept = 1;
1826 else
1827 restartFlag = 1;
1828 } else {
1829 c &= 0x5f;
1830 c2 = effective(read_reg(8 + 6, 1))[0] & 0x5f;
1831 if ((c2 == c && c) || (version && !c2 && (c == 0x5f))) {
1832 if (version && !c2 && (c == 0x5f))
1833 flag = 0x80;
1834 matchlen++;
1835 write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
1836 doff++;
1837 } else if (!version && matchlen > 6 && !c2)
1838 accept = 1;
1839 else
1840 restartFlag = 1;
1841 }
1842 if (accept) {
1843 effective(read_reg(8 + 2, 1))[0] = (version) ? flag : 0;
1844 effective(read_reg(8 + 2, 1))[1] = (type8)bank;
1845 write_w(effective(read_reg(8 + 2, 1) + 2), word);
1846 write_reg(8 + 2, 1, read_reg(8 + 2, 1) + 4);
1847 if (matchlen >= longest)
1848 longest = matchlen;
1849 restartFlag = 1;
1850 accept = 0;
1851 }
1852 if (restartFlag) {
1853 write_reg(8 + 6, 1, read_reg(8 + 5, 1));
1854 flag = matchlen = 0;
1855 word++;
1856 if (sd)
1857 while (dict[doff++] < 0x80);
1858 else
1859 while (effective(doff++)[0] < 0x80);
1860 restartFlag = 0;
1861 }
1862 }
1863 write_w(effective(read_reg(8 + 2, 1)), 0xffff);
1864
1865 if (version) {
1866 /* version > 0 */
1867 output_bak = output; /* check synonyms */
1868 while ((c = effective(output)[1]) != 0xff) {
1869 if (c == 0x0b) {
1870 if (sd)
1871 tmp16 = read_w(&dict[dtab + read_w(effective(output + 2)) * 2]);
1872 else
1873 tmp16 = read_w(effective(dtab + read_w(effective(output + 2)) * 2));
1874 effective(output)[1] = tmp16 & 0x1f;
1875 write_w(effective(output + 2), (type16)(tmp16 >> 5));
1876 }
1877 output += 4;
1878 }
1879 output = output_bak;
1880 }
1881
1882 /* l22 = output2, l1e = adjlist, l20 = obj_adj, l26 = word, l2f = c2 */
1883 /* l1c = adjlist_bak, 333C = i, l2d = bank, l2c = flag, l30e3 = flag2 */
1884
1885 write_reg(1, 1, 0); /* D1.W=0 [32B5] */
1886 flag2 = 0;
1887 output_bak = output;
1888 output2 = output;
1889 while ((bank = effective(output2)[1]) != 0xff) {
1890 obj_adj = (type16)read_reg(8 + 1, 1); /* A1.W - obj_adj, ie. adjs for this word */
1891 write_reg(1, 0, 0); /* D1.B=0 */
1892 flag = effective(output2)[0]; /* flag */
1893 word = read_w(effective(output2 + 2)); /* wordnumber */
1894 output2 += 4; /* next match */
1895 if ((read_w(effective(obj_adj))) && (bank == 6)) {
1896 /* Any adjectives? */
1897 if ((i = word) != 0) {
1898 /* Find list of valid adjs */
1899 do {
1900 while (effective(adjlist++)[0]);
1901 } while (--i > 0);
1902 }
1903 adjlist_bak = adjlist;
1904 do {
1905 adjlist = adjlist_bak;
1906 c2 = effective(obj_adj)[1]; /* given adjective */
1907 if ((tmp16 = read_w(effective(obj_adj))) != 0) {
1908 obj_adj += 2;
1909 while ((c = effective(adjlist++)[0]) && (c - 3 != c2));
1910 if (c - 3 != c2)
1911 write_reg(1, 0, 1); /* invalid adjective */
1912 }
1913 } while (tmp16 && !read_reg(1, 0));
1914 adjlist = (type16)read_reg(8 + 0, 1);
1915 }
1916 if (!read_reg(1, 0)) {
1917 /* invalid_flag */
1918 flag2 |= flag;
1919 effective(output)[0] = flag2;
1920 effective(output)[1] = (type8)bank;
1921 write_w(effective(output + 2), word);
1922 output += 4;
1923 }
1924 }
1925 write_reg(8 + 2, 1, output);
1926 output = output_bak;
1927
1928 if (flag2 & 0x80) {
1929 tmp16 = output;
1930 output -= 4;
1931 do {
1932 output += 4;
1933 c = effective(output)[0];
1934 } while (!(c & 0x80));
1935 write_l(effective(tmp16), read_l(effective(output)) & 0x7fffffff);
1936 write_reg(8 + 2, 2, tmp16 + 4);
1937 if (longest > 1) {
1938 write_reg(8 + 5, 1, read_reg(8 + 5, 1) + longest - 2);
1939 }
1940 }
1941 write_reg(8 + 6, 1, read_reg(8 + 5, 1) + 1);
1942 }
1943
1944 void Magnetic::do_findprop() {
1945 type16 tmp;
1946
1947 if ((version > 2) && ((read_reg(0, 1) & 0x3fff) > fp_size)) {
1948 tmp = (type16)(((fp_size - (read_reg(0, 1) & 0x3fff)) ^ 0xffff) << 1);
1949 tmp += fp_tab;
1950 tmp = read_w(effective(tmp));
1951 } else {
1952 if (version < 2)
1953 write_reg(0, 2, read_reg(0, 2) & 0x7fff);
1954 else
1955 write_reg(0, 1, read_reg(0, 1) & 0x7fff);
1956 tmp = (type16)read_reg(0, 1);
1957 }
1958 tmp &= 0x3fff;
1959 write_reg(8 + 0, 2, tmp * 14 + properties);
1960 }
1961
1962 void Magnetic::write_string() {
1963 static type32 offset_bak;
1964 static type8 mask_bak;
1965 type8 c, b, mask;
1966 type16 ptr;
1967 type32 offset;
1968
1969 if (!cflag) {
1970 /* new string */
1971 ptr = (type16)read_reg(0, 1);
1972 if (!ptr)
1973 offset = 0;
1974 else {
1975 offset = read_w(&decode_table[0x100 + 2 * ptr]);
1976 if (read_w(&decode_table[0x100])) {
1977 if (ptr >= read_w(&decode_table[0x100]))
1978 offset += string_size;
1979 }
1980 }
1981 mask = 1;
1982 } else {
1983 offset = offset_bak;
1984 mask = mask_bak;
1985 }
1986 do {
1987 c = 0;
1988 while (c < 0x80) {
1989 if (offset >= string_size)
1990 b = string2[offset - string_size];
1991 else {
1992 if (offset >= MAX_STRING_SIZE)
1993 b = string3[offset - MAX_STRING_SIZE];
1994 else
1995 b = string[offset];
1996 }
1997 if (b & mask)
1998 c = decode_table[0x80 + c];
1999 else
2000 c = decode_table[c];
2001 mask <<= 1;
2002 if (!mask) {
2003 mask = 1;
2004 offset++;
2005 }
2006 }
2007 c &= 0x7f;
2008 if (c && ((c != 0x40) || (lastchar != 0x20)))
2009 char_out(c);
2010 } while (c && ((c != 0x40) || (lastchar != 0x20)));
2011 cflag = c ? 0xff : 0;
2012 if (c) {
2013 offset_bak = offset;
2014 mask_bak = mask;
2015 }
2016 }
2017
2018 void Magnetic::output_number(type16 number) {
2019 type16 tens = number / 10;
2020
2021 if (tens > 0)
2022 ms_putchar('0' + tens);
2023 number -= (tens * 10);
2024 ms_putchar('0' + number);
2025 }
2026
2027 type16 Magnetic::output_text(const char *text) {
2028 type16 i;
2029
2030 for (i = 0; text[i] != 0; i++)
2031 ms_putchar(text[i]);
2032 return i;
2033 }
2034
2035 type16s Magnetic::hint_input() {
2036 type8 c1, c2, c3;
2037
2038 output_text(">>");
2039 ms_flush();
2040
2041 do {
2042 c1 = ms_getchar(0);
2043 } while (c1 == '\n');
2044 if (c1 == 1)
2045 return -1; /* New game loaded, abort hints */
2046
2047 c2 = ms_getchar(0);
2048 if (c2 == 1)
2049 return -1;
2050
2051 /* Get and discard any remaining characters */
2052 c3 = c2;
2053 while (c3 != '\n') {
2054 c3 = ms_getchar(0);
2055 if (c3 == 1)
2056 return -1;
2057 }
2058 ms_putchar('\n');
2059
2060 if ((c1 >= '0') && (c1 <= '9')) {
2061 type16 number = c1 - '0';
2062 if ((c2 >= '0') && (c2 <= '9')) {
2063 number *= 10;
2064 number += c2 - '0';
2065 }
2066 return number;
2067 }
2068
2069 if ((c1 >= 'A') && (c1 <= 'Z'))
2070 c1 = 'a' + (c1 - 'A');
2071 if ((c1 >= 'a') && (c1 <= 'z')) {
2072 switch (c1) {
2073 case 'e':
2074 return -2; /* End hints */
2075 case 'n':
2076 return -3; /* Next hint */
2077 case 'p':
2078 return -4; /* Show parent hint list */
2079 default:
2080 break;
2081 }
2082 }
2083 return 0;
2084 }
2085
2086 type16 Magnetic::show_hints_text(ms_hint *hintsData, type16 index) {
2087 type16 i = 0, j = 0;
2088 type16s input;
2089 ms_hint *hint = hintsData + index;
2090
2091 while (1) {
2092 switch (hint->nodetype) {
2093
2094 case 1: /* folders */
2095 output_text("Hint categories:\n");
2096 for (i = 0, j = 0; i < hint->elcount; i++) {
2097 output_number(i + 1);
2098 output_text(". ");
2099 j += output_text(hint->content + j) + 1;
2100 ms_putchar('\n');
2101 }
2102 output_text("Enter hint category number, ");
2103 if (hint->parent != 0xffff)
2104 output_text("P for the parent hint menu, ");
2105 output_text("or E to end hintsData.\n");
2106
2107 input = hint_input();
2108 switch (input) {
2109 case -1: /* A new game is being loaded */
2110 return 1;
2111 case -2: /* End hintsData */
2112 return 1;
2113 case -4: /* Show parent hint list */
2114 if (hint->parent != 0xffff)
2115 return 0;
2116 // fallthrough
2117 default:
2118 if ((input > 0) && (input <= hint->elcount)) {
2119 if (show_hints_text(hintsData, hint->links[input - 1]) == 1)
2120 return 1;
2121 }
2122 break;
2123 }
2124 break;
2125
2126 case 2: /* hintsData */
2127 if (i < hint->elcount) {
2128 output_number(i + 1);
2129 output_text(". ");
2130 j += output_text(hint->content + j) + 1;
2131
2132 if (i == hint->elcount - 1) {
2133 output_text("\nNo more hintsData.\n");
2134 return 0; /* Last hint */
2135 } else {
2136 output_text("\nEnter N for the next hint, ");
2137 output_text("P for the parent hint menu, ");
2138 output_text("or E to end hintsData.\n");
2139 }
2140
2141 input = hint_input();
2142 switch (input) {
2143 case -1: /* A new game is being loaded */
2144 return 1;
2145 case -2: /* End hintsData */
2146 return 1;
2147 case -3:
2148 i++;
2149 break;
2150 case -4: /* Show parent hint list */
2151 return 0;
2152 default:
2153 break;
2154 }
2155 } else
2156 return 0;
2157 break;
2158
2159 default:
2160 break;
2161 }
2162 }
2163 return 0;
2164 }
2165
2166 void Magnetic::do_line_a() {
2167 type8 l1c;
2168 char *str;
2169 type16 ptr, ptr2, tmp16, dtype;
2170 type32 a1reg, tmp32;
2171
2172 #ifdef LOGGFX
2173 /*
2174 if (((byte2-0xdd) == 4) || ((byte2-0xdd) == 13))
2175 out2("--> %d\n",byte2-0xdd);
2176 else
2177 out2("LINE A %d\n",byte2-0xdd);
2178 */
2179 #endif
2180 if ((byte2 < 0xdd) || (version < 4 && byte2 < 0xe4) || (version < 2 && byte2 < 0xed)) {
2181 ms_flush(); /* flush output-buffer */
2182 rand_emu(); /* Increase game randomness */
2183 l1c = ms_getchar(1); /* 0 means UNDO */
2184 if (l1c == 1)
2185 return;
2186 if (l1c)
2187 write_reg(1, 2, l1c); /* d1=getkey() */
2188 else {
2189 if ((l1c = ms_undo()) != 0)
2190 output_text(undo_ok);
2191 else
2192 output_text(undo_fail);
2193 if (!l1c)
2194 write_reg(1, 2, '\n');
2195 }
2196 } else
2197 switch (byte2 - 0xdd) {
2198
2199 case 0: /* A0DD - Won't probably be needed at all */
2200 break;
2201
2202 case 1: /* A0DE */
2203 write_reg(1, 0, 1); /* Should remove the manual check */
2204 break;
2205
2206 case 2: /* A0DF */
2207 a1reg = (type32)read_reg(9, 2);
2208 dtype = (code + a1reg + 2)[0];
2209
2210 switch (dtype) {
2211 case 7: /* Picture */
2212 #ifdef LOGGFX
2213 out2("PICTURE IS %s\n", code + a1reg + 3);
2214 #endif
2215 /* gfx mode = normal, df is not called if graphics are off */
2216 ms_showpic(a1reg + 3, 2);
2217 break;
2218
2219 case 10: /* Open window commands */
2220 switch ((code + a1reg + 3)[0]) {
2221 case 4: /* Help/Hints */
2222 if (hints != 0) {
2223 if (ms_showhints(hints) == 0)
2224 show_hints_text(hints, 0);
2225 } else
2226 output_text(no_hints);
2227 break;
2228 case 0: /* Carried items */
2229 case 1: /* Room items */
2230 case 2: /* Map */
2231 case 3: /* Compass */
2232 output_text(not_supported);
2233 break;
2234 default:
2235 break;
2236 }
2237 break;
2238
2239 case 13: /* Music */
2240 switch ((code + a1reg + 3)[0]) {
2241 case 0: /* stop music */
2242 ms_playmusic(0, 0, 0);
2243 break;
2244 default: /* play music */
2245 #ifdef LOGSND
2246 out2("MUSIC IS %s\n", code + a1reg + 3);
2247 #endif
2248 {
2249 type32 length = 0;
2250 type16 tempo = 0;
2251 type8 *midi = sound_extract((const char *)(code + a1reg + 3), &length, &tempo);
2252 if (midi != NULL)
2253 ms_playmusic(midi, length, tempo);
2254 }
2255 break;
2256 }
2257 break;
2258
2259 default:
2260 break;
2261 }
2262 break;
2263
2264 case 3: /* A0E0 */
2265 /* printf("A0E0 stubbed\n"); */
2266 break;
2267
2268 case 4: /* A0E1 Read from keyboard to (A1), status in D1 (0 for ok) */
2269 ms_flush();
2270 rand_emu();
2271 tmp32 = read_reg(8 + 1, 2);
2272 str = (char *)effective(tmp32);
2273 tmp16 = 0;
2274 do {
2275 if (!(l1c = ms_getchar(1))) {
2276 if (g_vm->shouldQuit())
2277 return;
2278 if ((l1c = ms_undo()) != 0)
2279 output_text(undo_ok);
2280 else
2281 output_text(undo_fail);
2282 if (!l1c) {
2283 tmp16 = 0;
2284 str[tmp16++] = '\n';
2285 l1c = '\n';
2286 output_text("\n>");
2287 } else {
2288 ms_putchar('\n');
2289 return;
2290 }
2291 } else {
2292 if (l1c == 1)
2293 return;
2294 str[tmp16++] = l1c;
2295 #ifdef LOGGFX
2296 out2("%c", l1c);
2297 #endif
2298 }
2299 } while (l1c != '\n' && tmp16 < 256);
2300 write_reg(8 + 1, 2, tmp32 + tmp16 - 1);
2301 if (tmp16 != 256 && tmp16 != 1)
2302 write_reg(1, 1, 0);
2303 else
2304 write_reg(1, 1, 1);
2305 break;
2306
2307 case 5: /* A0E2 */
2308 /* printf("A0E2 stubbed\n"); */
2309 break;
2310
2311 case 6: /* A0E3 */
2312 if (read_reg(1, 2) == 0) {
2313 if ((version < 4) || (read_reg(6, 2) == 0))
2314 ms_showpic(0, 0);
2315 }
2316 /* printf("\nMoves: %u\n",read_reg(0,1)); */
2317 break;
2318
2319 case 7: /* A0E4 sp+=4, RTS */
2320 write_reg(8 + 7, 1, read_reg(8 + 7, 1) + 4);
2321 pc = pop();
2322 break;
2323
2324 case 8: /* A0E5 set z, RTS */
2325 case 9: /* A0E6 clear z, RTS */
2326 pc = pop();
2327 zflag = (byte2 == 0xe5) ? 0xff : 0;
2328 break;
2329
2330 case 10: /* A0E7 set z */
2331 zflag = 0xff;
2332 break;
2333
2334 case 11: /* A0E8 clear z */
2335 zflag = 0;
2336 break;
2337
2338 case 12: /* A0E9 [3083 - j] */
2339 ptr = (type16)read_reg(8 + 0, 1);
2340 ptr2 = (type16)read_reg(8 + 1, 1);
2341 do {
2342 l1c = dict[ptr2++];
2343 effective(ptr++)[0] = l1c;
2344 } while ((l1c & 0x80) == 0);
2345 write_reg(8 + 0, 1, ptr);
2346 write_reg(8 + 1, 1, ptr2);
2347 break;
2348
2349 case 13: /* A0EA A1=write_dictword(A1,D1=output_mode) */
2350 ptr = (type16)read_reg(8 + 1, 1);
2351 tmp32 = read_reg(3, 0);
2352 write_reg(3, 0, read_reg(1, 0));
2353 do {
2354 l1c = dict[ptr++];
2355 char_out(l1c);
2356 } while (l1c < 0x80);
2357 write_reg(8 + 1, 1, ptr);
2358 write_reg(3, 0, tmp32);
2359 break;
2360
2361 case 14: /* A0EB [3037 - j] */
2362 dict[read_reg(8 + 1, 1)] = (type8)read_reg(1, 0);
2363 break;
2364
2365 case 15: /* A0EC */
2366 write_reg(1, 0, dict[read_reg(8 + 1, 1)]);
2367 break;
2368
2369 case 16:
2370 ms_stop(); /* infinite loop A0ED */
2371 break;
2372 case 17:
2373 if (!ms_init(nullptr, nullptr, nullptr, nullptr))
2374 ms_stop(); /* restart game ie. pc, sp etc. A0EE */
2375 break;
2376 case 18: /* printer A0EF */
2377 break;
2378 case 19:
2379 ms_showpic(read_reg(0, 0), (type8)read_reg(1, 0)); /* Do_picture(D0) A0F0 */
2380 break;
2381 case 20:
2382 ptr = (type16)read_reg(8 + 1, 1); /* A1=nth_string(A1,D0) A0F1 */
2383 tmp32 = read_reg(0, 1);
2384 while (tmp32-- > 0) {
2385 while (effective(ptr++)[0]);
2386 }
2387 write_reg(8 + 1, 1, ptr);
2388 break;
2389
2390 case 21: /* [2a43] A0F2 */
2391 cflag = 0;
2392 write_reg(0, 1, read_reg(2, 1));
2393 do_findprop();
2394 ptr = (type16)read_reg(8 + 0, 1);
2395 while (read_reg(2, 1) > 0) {
2396 if (read_w(effective(ptr + 12)) & 0x3fff) {
2397 cflag = 0xff;
2398 break;
2399 }
2400 if (read_reg(2, 1) == (read_reg(4, 1) & 0x7fff)) {
2401 cflag = 0xff;
2402 break;
2403 }
2404 ptr -= 0x0e;
2405 write_reg(2, 1, read_reg(2, 1) - 1);
2406 }
2407 break;
2408
2409 case 22:
2410 char_out((type8)read_reg(1, 0)); /* A0F3 */
2411 break;
2412
2413 case 23: /* D7=Save_(filename A0) D1 bytes starting from A1 A0F4 */
2414 str = (version < 4) ? (char *)effective(read_reg(8 + 0, 1)) : nullptr;
2415 write_reg(7, 0, ms_save_file(str, effective(read_reg(8 + 1, 1)),
2416 (type16)read_reg(1, 1)));
2417 break;
2418
2419 case 24: /* D7=Load_(filename A0) D1 bytes starting from A1 A0F5 */
2420 str = (version < 4) ? (char *)effective(read_reg(8 + 0, 1)) : nullptr;
2421 write_reg(7, 0, ms_load_file(str, effective(read_reg(8 + 1, 1)),
2422 (type16)read_reg(1, 1)));
2423 break;
2424
2425 case 25: /* D1=Random(0..D1-1) [3748] A0F6 */
2426 l1c = (type8)read_reg(1, 0);
2427 write_reg(1, 1, rand_emu() % (l1c ? l1c : 1));
2428 break;
2429
2430 case 26: /* D0=Random(0..255) [3742] A0F7 */
2431 tmp16 = (type16)rand_emu();
2432 write_reg(0, 0, tmp16 + (tmp16 >> 8));
2433 break;
2434
2435 case 27: /* write string [D0] [2999] A0F8 */
2436 write_string();
2437 break;
2438
2439 case 28: /* Z,D0=Get_inventory_item(D0) [2a9e] A0F9 */
2440 zflag = 0;
2441 ptr = (type16)read_reg(0, 1);
2442 do {
2443 write_reg(0, 1, ptr);
2444 do {
2445 do_findprop();
2446 ptr2 = (type16)read_reg(8 + 0, 1); /* object properties */
2447 if ((effective(ptr2)[5]) & 1)
2448 break; /* is_described or so */
2449 l1c = effective(ptr2)[6]; /* some_flags */
2450 tmp16 = read_w(effective(ptr2 + 8)); /* parent_object */
2451 if (!l1c) {
2452 /* ordinary object? */
2453 if (!tmp16)
2454 zflag = 0xff; /* return if parent()=player */
2455 break; /* otherwise try next */
2456 }
2457 if (l1c & 0xcc)
2458 break; /* skip worn, bodypart, room, hidden */
2459 if (tmp16 == 0) {
2460 /* return if parent()=player? */
2461 zflag = 0xff;
2462 break;
2463 }
2464 write_reg(0, 1, tmp16); /* else look at parent() */
2465 } while (1);
2466 ptr--;
2467 } while ((!zflag) && ptr);
2468 write_reg(0, 1, ptr + 1);
2469 break;
2470
2471 case 29: /* [2b18] A0FA */
2472 ptr = (type16)read_reg(8, 1);
2473 do {
2474 if (read_reg(5, 0)) {
2475 l1c = ((type32)((read_w(effective(ptr)) & 0x3fff)) == read_reg(2, 1));
2476 } else {
2477 l1c = (effective(ptr)[0] == read_reg(2, 0));
2478 }
2479 if (read_reg(3, 1) == read_reg(4, 1)) {
2480 cflag = 0;
2481 write_reg(8, 1, ptr);
2482 } else {
2483 write_reg(3, 1, read_reg(3, 1) + 1);
2484 ptr += 0x0e;
2485 if (l1c) {
2486 cflag = 0xff;
2487 write_reg(8, 1, ptr);
2488 }
2489 }
2490 } while ((!l1c) && (read_reg(3, 1) != read_reg(4, 1)));
2491 break;
2492
2493 case 30: /* [2bd1] A0FB */
2494 ptr = (type16)read_reg(8 + 1, 1);
2495 do {
2496 if (dict)
2497 while (dict[ptr++] < 0x80);
2498 else
2499 while (effective(ptr++)[0] < 0x80);
2500 write_reg(2, 1, read_reg(2, 1) - 1);
2501 } while (read_reg(2, 1));
2502 write_reg(8 + 1, 1, ptr);
2503 break;
2504
2505 case 31: /* [2c3b] A0FC */
2506 ptr = (type16)read_reg(8 + 0, 1);
2507 ptr2 = (type16)read_reg(8 + 1, 1);
2508 do {
2509 if (dict)
2510 while (dict[ptr++] < 0x80);
2511 else
2512 while (effective(ptr++)[0] < 0x80);
2513 while (effective(ptr2++)[0]);
2514 write_reg(0, 1, read_reg(0, 1) - 1);
2515 } while (read_reg(0, 1));
2516 write_reg(8 + 0, 1, ptr);
2517 write_reg(8 + 1, 1, ptr2);
2518 break;
2519
2520 case 32: /* Set properties pointer from A0 [2b7b] A0FD */
2521 properties = (type16)read_reg(8 + 0, 1);
2522 if (version > 0)
2523 fl_sub = (type16)read_reg(8 + 3, 1);
2524 if (version > 1) {
2525 fl_tab = (type16)read_reg(8 + 5, 1);
2526 fl_size = (type16)read_reg(7, 1) + 1;
2527 /* A3 [routine], A5 [table] and D7 [table-size] */
2528 }
2529 if (version > 2) {
2530 fp_tab = (type16)read_reg(8 + 6, 1);
2531 fp_size = (type16)read_reg(6, 1);
2532 }
2533 break;
2534
2535 case 33: /* A0FE */
2536 do_findprop();
2537 break;
2538
2539 case 34: /* Dictionary_lookup A0FF */
2540 dict_lookup();
2541 break;
2542
2543 default:
2544 break;
2545 }
2546 }
2547
2548 type8 Magnetic::ms_rungame() {
2549 type8 l1c;
2550 type16 ptr;
2551 type32 tmp32;
2552 #ifdef LOGEMU
2553 static int stat = 0;
2554 #endif
2555
2556 if (!running)
2557 return running;
2558 if (pc == undo_pc)
2559 save_undo();
2560
2561 #ifdef LOGEMU
2562 if (pc == 0x0000)
2563 stat = 0;
2564 if (stat) {
2565 log_status();
2566 fflush(dbg_log);
2567 }
2568
2569 fprintf(dbg_log, "%.8X: ", pc);
2570 #endif
2571 i_count++;
2572 read_word();
2573 switch (byte1 >> 1) {
2574
2575 /* 00-0F */
2576 case 0x00:
2577 if (byte1 == 0x00) {
2578 if (byte2 == 0x3c || byte2 == 0x7c) {
2579 /* OR immediate to CCR (30D9) */
2580 read_word();
2581 #ifdef LOGEMU
2582 out("or_ccr #%.2x", byte2);
2583 #endif
2584 if (byte2 & 0x01)
2585 cflag = 0xff;
2586 if (byte2 & 0x02)
2587 vflag = 0xff;
2588 if (byte2 & 0x04)
2589 zflag = 0xff;
2590 if (byte2 & 0x08)
2591 nflag = 0xff;
2592 } else {
2593 /* OR [27df] */
2594 #ifdef LOGEMU
2595 out("or");
2596 #endif
2597 get_arg();
2598 do_or();
2599 }
2600 } else
2601 check_btst();
2602 break;
2603
2604 case 0x01:
2605 if (byte1 == 0x02) {
2606 if (byte2 == 0x3c || byte2 == 0x7c) {
2607 /* AND immediate to CCR */
2608 read_word();
2609 #ifdef LOGEMU
2610 out("and_ccr #%.2x", byte2);
2611 #endif
2612 if (!(byte2 & 0x01))
2613 cflag = 0;
2614 if (!(byte2 & 0x02))
2615 vflag = 0;
2616 if (!(byte2 & 0x04))
2617 zflag = 0;
2618 if (!(byte2 & 0x08))
2619 nflag = 0;
2620 } else {
2621 /* AND */
2622 #ifdef LOGEMU
2623 out("and");
2624 #endif
2625 get_arg();
2626 do_and();
2627 }
2628 } else
2629 check_btst();
2630 break;
2631
2632 case 0x02:
2633 if (byte1 == 0x04) {
2634 /* SUB */
2635 #ifdef LOGEMU
2636 out("sub");
2637 #endif
2638 get_arg();
2639 do_sub(0);
2640 } else
2641 check_btst();
2642 break;
2643
2644 case 0x03:
2645 if (byte1 == 0x06) {
2646 /* ADD */
2647 #ifdef LOGEMU
2648 out("addi");
2649 #endif
2650 get_arg();
2651 do_add(0);
2652 } else
2653 check_btst();
2654 break;
2655
2656 case 0x04:
2657 if (byte1 == 0x08) {
2658 /* bit operations (immediate) */
2659 set_info((type8)(byte2 & 0x3f));
2660 l1c = (effective(pc))[1];
2661 pc += 2;
2662 set_arg1();
2663 do_bop(byte2, l1c);
2664 } else
2665 check_btst();
2666 break;
2667
2668 case 0x05:
2669 if (byte1 == 0x0a) {
2670 if (byte2 == 0x3c || byte2 == 0x7c) {
2671 /* EOR immediate to CCR */
2672 read_word();
2673 #ifdef LOGEMU
2674 out("eor_ccr #%.2X", byte2);
2675 #endif
2676 if (byte2 & 0x01)
2677 cflag ^= 0xff;
2678 if (byte2 & 0x02)
2679 vflag ^= 0xff;
2680 if (byte2 & 0x04)
2681 zflag ^= 0xff;
2682 if (byte2 & 0x08)
2683 nflag ^= 0xff;
2684 } else {
2685 /* EOR */
2686 #ifdef LOGEMU
2687 out("eor");
2688 #endif
2689 get_arg();
2690 do_eor();
2691 }
2692 } else
2693 check_btst();
2694 break;
2695
2696 case 0x06:
2697 if (byte1 == 0x0c) {
2698 /* CMP */
2699 #ifdef LOGEMU
2700 out("cmp");
2701 #endif
2702 get_arg();
2703 do_cmp();
2704 } else
2705 check_btst();
2706 break;
2707
2708 case 0x07:
2709 check_btst();
2710 break;
2711
2712 /* 10-1F [3327] MOVE.B */
2713 case 0x08:
2714 case 0x09:
2715 case 0x0a:
2716 case 0x0b:
2717 case 0x0c:
2718 case 0x0d:
2719 case 0x0e:
2720 case 0x0f:
2721
2722 #ifdef LOGEMU
2723 out("move.b");
2724 #endif
2725 set_info((type8)(byte2 & 0x3f));
2726 set_arg1();
2727 swap_args();
2728 l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
2729 set_info(l1c);
2730 set_arg1();
2731 do_move();
2732 break;
2733
2734 /* 20-2F [32d1] MOVE.L */
2735 case 0x10:
2736 case 0x11:
2737 case 0x12:
2738 case 0x13:
2739 case 0x14:
2740 case 0x15:
2741 case 0x16:
2742 case 0x17:
2743
2744 #ifdef LOGEMU
2745 out("move.l");
2746 #endif
2747 set_info((type8)((byte2 & 0x3f) | 0x80));
2748 set_arg1();
2749 swap_args();
2750 l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
2751 set_info((type8)(l1c | 0x80));
2752 set_arg1();
2753 do_move();
2754 break;
2755
2756 /* 30-3F [3327] MOVE.W */
2757 case 0x18:
2758 case 0x19:
2759 case 0x1a:
2760 case 0x1b:
2761 case 0x1c:
2762 case 0x1d:
2763 case 0x1e:
2764 case 0x1f:
2765
2766 #ifdef LOGEMU
2767 out("move.w");
2768 #endif
2769 set_info((type8)((byte2 & 0x3f) | 0x40));
2770 set_arg1();
2771 swap_args();
2772 l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
2773 set_info((type8)(l1c | 0x40));
2774 set_arg1();
2775 do_move();
2776 break;
2777
2778 /* 40-4F various commands */
2779
2780 case 0x20:
2781 if (byte1 == 0x40) {
2782 /* [31d5] */
2783 ms_fatal("unimplemented instructions NEGX and MOVE SR,xx");
2784 } else
2785 check_lea();
2786 break;
2787
2788 case 0x21:
2789 if (byte1 == 0x42) {
2790 /* [3188] */
2791 if ((byte2 & 0xc0) == 0xc0) {
2792 ms_fatal("unimplemented instruction MOVE CCR,xx");
2793 } else {
2794 /* CLR */
2795 #ifdef LOGEMU
2796 out("clr");
2797 #endif
2798 set_info(byte2);
2799 set_arg1();
2800 if (opsize == 0)
2801 arg1[0] = 0;
2802 if (opsize == 1)
2803 write_w(arg1, 0);
2804 if (opsize == 2)
2805 write_l(arg1, 0);
2806 nflag = cflag = 0;
2807 zflag = 0xff;
2808 }
2809 } else
2810 check_lea();
2811 break;
2812
2813 case 0x22:
2814 if (byte1 == 0x44) {
2815 /* [31a0] */
2816 if ((byte2 & 0xc0) == 0xc0) {
2817 /* MOVE to CCR */
2818 #ifdef LOGEMU
2819 out("move_ccr");
2820 #endif
2821 zflag = nflag = cflag = vflag = 0;
2822 set_info((type8)(byte2 & 0x7f));
2823 set_arg1();
2824 byte2 = arg1[1];
2825 if (byte2 & 0x01)
2826 cflag = 0xff;
2827 if (byte2 & 0x02)
2828 vflag = 0xff;
2829 if (byte2 & 0x04)
2830 zflag = 0xff;
2831 if (byte2 & 0x08)
2832 nflag = 0xff;
2833 } else {
2834 #ifdef LOGEMU
2835 out("neg");
2836 #endif
2837 set_info(byte2); /* NEG */
2838 set_arg1();
2839 cflag = 0xff;
2840 if (opsize == 0) {
2841 arg1[0] = (-arg1[0]);
2842 cflag = arg1[0] ? 0xff : 0;
2843 }
2844 if (opsize == 1) {
2845 write_w(arg1, (type16)(-1 * read_w(arg1)));
2846 cflag = read_w(arg1) ? 0xff : 0;
2847 }
2848 if (opsize == 2) {
2849 write_l(arg1, -1 * read_l(arg1));
2850 cflag = read_l(arg1) ? 0xff : 0;
2851 }
2852 vflag = 0;
2853 set_flags();
2854 }
2855 } else
2856 check_lea();
2857 break;
2858
2859 case 0x23:
2860 if (byte1 == 0x46) {
2861 if ((byte2 & 0xc0) == 0xc0) {
2862 ms_fatal("unimplemented instruction MOVE xx,SR");
2863 } else {
2864 #ifdef LOGEMU
2865 out("not");
2866 #endif
2867 set_info(byte2); /* NOT */
2868 set_arg1();
2869 tmparg[0] = tmparg[1] = tmparg[2] = tmparg[3] = 0xff;
2870 arg2 = tmparg;
2871 do_eor();
2872 }
2873 } else
2874 check_lea();
2875 break;
2876
2877 case 0x24:
2878 if (byte1 == 0x48) {
2879 if ((byte2 & 0xf8) == 0x40) {
2880 #ifdef LOGEMU
2881 out("swap");
2882 #endif
2883 opsize = 2; /* SWAP */
2884 admode = 0;
2885 regnr = byte2 & 0x07;
2886 set_arg1();
2887 tmp32 = read_w(arg1);
2888 write_w(arg1, read_w(arg1 + 2));
2889 write_w(arg1 + 2, (type16)tmp32);
2890 set_flags();
2891 } else if ((byte2 & 0xf8) == 0x80) {
2892 #ifdef LOGEMU
2893 out("ext.w");
2894 #endif
2895 opsize = 1; /* EXT.W */
2896 admode = 0;
2897 regnr = byte2 & 0x07;
2898 set_arg1();
2899 if (arg1[1] > 0x7f)
2900 arg1[0] = 0xff;
2901 else
2902 arg1[0] = 0;
2903 set_flags();
2904 } else if ((byte2 & 0xf8) == 0xc0) {
2905 #ifdef LOGEMU
2906 out("ext.l");
2907 #endif
2908 opsize = 2; /* EXT.L */
2909 admode = 0;
2910 regnr = byte2 & 0x07;
2911 set_arg1();
2912 if (read_w(arg1 + 2) > 0x7fff)
2913 write_w(arg1, 0xffff);
2914 else
2915 write_w(arg1, 0);
2916 set_flags();
2917 } else if ((byte2 & 0xc0) == 0x40) {
2918 #ifdef LOGEMU
2919 out("pea");
2920 #endif
2921 set_info((type8)((byte2 & 0x3f) | 0x80)); /* PEA */
2922 set_arg1();
2923 if (is_reversible)
2924 push(arg1i);
2925 else
2926 ms_fatal("illegal addressing mode for PEA");
2927 } else {
2928 check_movem(); /* MOVEM */
2929 }
2930 } else
2931 check_lea();
2932 break;
2933
2934 case 0x25:
2935 if (byte1 == 0x4a) {
2936 /* [3219] TST */
2937 if ((byte2 & 0xc0) == 0xc0) {
2938 ms_fatal("unimplemented instruction TAS");
2939 } else {
2940 #ifdef LOGEMU
2941 out("tst");
2942 #endif
2943 set_info(byte2);
2944 set_arg1();
2945 cflag = vflag = 0;
2946 set_flags();
2947 }
2948 } else
2949 check_lea();
2950 break;
2951
2952 case 0x26:
2953 if (byte1 == 0x4c)
2954 check_movem2(); /* [3350] MOVEM.L (Ax)+,A/Dx */
2955 else
2956 check_lea(); /* LEA */
2957 break;
2958
2959 case 0x27:
2960 if (byte1 == 0x4e) {
2961 /* [3290] */
2962 if (byte2 == 0x75) {
2963 /* RTS */
2964 #ifdef LOGEMU
2965 out("rts\n");
2966 #endif
2967 pc = pop();
2968 } else if (byte2 == 0x71) {
2969 /* NOP */
2970 #ifdef LOGEMU
2971 out("nop");
2972 #endif
2973 } else if ((byte2 & 0xc0) == 0xc0) {
2974 /* indir JMP */
2975 #ifdef LOGEMU
2976 out("jmp");
2977 #endif
2978 set_info((type8)(byte2 | 0xc0));
2979 set_arg1();
2980 if (is_reversible)
2981 pc = arg1i;
2982 else
2983 ms_fatal("illegal addressing mode for JMP");
2984 } else if ((byte2 & 0xc0) == 0x80) {
2985 #ifdef LOGEMU
2986 out("jsr");
2987 #endif
2988 set_info((type8)(byte2 | 0xc0)); /* indir JSR */
2989 set_arg1();
2990 push(pc);
2991 if (is_reversible)
2992 pc = arg1i;
2993 else
2994 ms_fatal("illegal addressing mode for JSR");
2995 } else {
2996 ms_fatal("unimplemented instructions 0x4EXX");
2997 }
2998 } else
2999 check_lea(); /* LEA */
3000 break;
3001
3002 /* 50-5F [2ed5] ADDQ/SUBQ/Scc/DBcc */
3003 case 0x28:
3004 case 0x29:
3005 case 0x2a:
3006 case 0x2b:
3007 case 0x2c:
3008 case 0x2d:
3009 case 0x2e:
3010 case 0x2f:
3011
3012 if ((byte2 & 0xc0) == 0xc0) {
3013 set_info((type8)(byte2 & 0x3f));
3014 set_arg1();
3015 if (admode == 1) {
3016 /* DBcc */
3017 #ifdef LOGEMU
3018 out("dbcc");
3019 #endif
3020 if (condition(byte1) == 0) {
3021 arg1 = (arg1 - (type8 *) areg) + (type8 *) dreg - 1;
3022 write_w(arg1, (type16)(read_w(arg1) - 1));
3023 if (read_w(arg1) != 0xffff)
3024 branch(0);
3025 else
3026 pc += 2;
3027 } else
3028 pc += 2;
3029 } else {
3030 /* Scc */
3031 #ifdef LOGEMU
3032 out("scc");
3033 #endif
3034 arg1[0] = condition(byte1) ? 0xff : 0;
3035 }
3036 } else {
3037 set_info(byte2);
3038 set_arg1();
3039 quick_flag = (admode == 1) ? 0xff : 0;
3040 l1c = byte1 >> 1 & 0x07;
3041 tmparg[0] = tmparg[1] = tmparg[2] = 0;
3042 tmparg[3] = l1c ? l1c : 8;
3043 arg2 = reg_align(tmparg, opsize);
3044 {
3045 #ifdef LOGEMU
3046 type32s outnum = 0;
3047 switch (opsize) {
3048 case 0:
3049 outnum = (type8s) arg2[0];
3050 break;
3051 case 1:
3052 outnum = (type16s) read_w(arg2);
3053 break;
3054 case 2:
3055 outnum = (type32s) read_l(arg2);
3056 break;
3057 }
3058 #endif
3059 if ((byte1 & 0x01) == 1) {
3060 #ifdef LOGEMU
3061 out("subq #%.8X", outnum);
3062 #endif
3063 do_sub(0); /* SUBQ */
3064 } else {
3065 #ifdef LOGEMU
3066 out("addq #%.8X", outnum);
3067 #endif
3068 do_add(0); /* ADDQ */
3069 }
3070 }
3071 }
3072 break;
3073
3074 /* 60-6F [26ba] Bcc */
3075
3076 case 0x30:
3077 if (byte1 == 0x61) {
3078 /* BRA, BSR */
3079 #ifdef LOGEMU
3080 out("bsr");
3081 #endif
3082 if (byte2 == 0)
3083 push(pc + 2);
3084 else
3085 push(pc);
3086 }
3087 #ifdef LOGEMU
3088 else
3089 out("bra");
3090 #endif
3091 if ((byte1 == 0x60) && (byte2 == 0xfe)) {
3092 ms_flush(); /* flush stdout */
3093 ms_stop(); /* infinite loop - just exit */
3094 }
3095 branch(byte2);
3096 break;
3097
3098 case 0x31:
3099 case 0x32:
3100 case 0x33:
3101 case 0x34:
3102 case 0x35:
3103 case 0x36:
3104 case 0x37:
3105
3106 if (condition(byte1) == 0) {
3107 #ifdef LOGEMU
3108 out("beq.s");
3109 #endif
3110 if (byte2 == 0)
3111 pc += 2;
3112 } else {
3113 #ifdef LOGEMU
3114 out("bra");
3115 #endif
3116 branch(byte2);
3117 }
3118 break;
3119
3120 /* 70-7F [260a] MOVEQ */
3121 case 0x38:
3122 case 0x39:
3123 case 0x3a:
3124 case 0x3b:
3125 case 0x3c:
3126 case 0x3d:
3127 case 0x3e:
3128 case 0x3f:
3129
3130 #ifdef LOGEMU
3131 out("moveq");
3132 #endif
3133 arg1 = (type8 *) & dreg[byte1 >> 1 & 0x07];
3134 if (byte2 > 127)
3135 nflag = arg1[0] = arg1[1] = arg1[2] = 0xff;
3136 else
3137 nflag = arg1[0] = arg1[1] = arg1[2] = 0;
3138 arg1[3] = byte2;
3139 zflag = byte2 ? 0 : 0xff;
3140 break;
3141
3142 /* 80-8F [2f36] */
3143 case 0x40:
3144 case 0x41:
3145 case 0x42:
3146 case 0x43:
3147 case 0x44:
3148 case 0x45:
3149 case 0x46:
3150 case 0x47:
3151
3152 if ((byte2 & 0xc0) == 0xc0) {
3153 ms_fatal("unimplemented instructions DIVS and DIVU");
3154 } else if (((byte2 & 0xf0) == 0) && ((byte1 & 0x01) != 0)) {
3155 ms_fatal("unimplemented instruction SBCD");
3156 } else {
3157 #ifdef LOGEMU
3158 out("or?");
3159 #endif
3160 set_info(byte2);
3161 set_arg1();
3162 set_arg2(1, byte1);
3163 if ((byte1 & 0x01) == 0)
3164 swap_args();
3165 do_or();
3166 }
3167 break;
3168
3169 /* 90-9F [3005] SUB */
3170 case 0x48:
3171 case 0x49:
3172 case 0x4a:
3173 case 0x4b:
3174 case 0x4c:
3175 case 0x4d:
3176 case 0x4e:
3177 case 0x4f:
3178
3179 #ifdef LOGEMU
3180 out("sub");
3181 #endif
3182 quick_flag = 0;
3183 if ((byte2 & 0xc0) == 0xc0) {
3184 if ((byte1 & 0x01) == 1)
3185 set_info((type8)(byte2 & 0xbf));
3186 else
3187 set_info((type8)(byte2 & 0x7f));
3188 set_arg1();
3189 set_arg2_nosize(0, byte1);
3190 swap_args();
3191 do_sub(1);
3192 } else {
3193 set_info(byte2);
3194 set_arg1();
3195 set_arg2(1, byte1);
3196 if ((byte1 & 0x01) == 0)
3197 swap_args();
3198 do_sub(0);
3199 }
3200 break;
3201
3202 /* A0-AF various special commands [LINE_A] */
3203
3204 case 0x50:
3205 case 0x56:
3206 case 0x57: /* [2521] */
3207 do_line_a();
3208 #ifdef LOGEMU
3209 out("LINE_A A0%.2X", byte2);
3210 #endif
3211 break;
3212
3213 case 0x51:
3214 #ifdef LOGEMU
3215 out("rts\n");
3216 #endif
3217 pc = pop(); /* RTS */
3218 break;
3219
3220 case 0x52:
3221 #ifdef LOGEMU
3222 out("bsr");
3223 #endif
3224 if (byte2 == 0)
3225 push(pc + 2); /* BSR */
3226 else
3227 push(pc);
3228 branch(byte2);
3229 break;
3230
3231 case 0x53:
3232 if ((byte2 & 0xc0) == 0xc0) {
3233 /* TST [321d] */
3234 ms_fatal("unimplemented instructions LINE_A #$6C0-#$6FF");
3235 } else {
3236 #ifdef LOGEMU
3237 out("tst");
3238 #endif
3239 set_info(byte2);
3240 set_arg1();
3241 cflag = vflag = 0;
3242 set_flags();
3243 }
3244 break;
3245
3246 case 0x54:
3247 check_movem();
3248 break;
3249
3250 case 0x55:
3251 check_movem2();
3252 break;
3253
3254 /* B0-BF [2fe4] */
3255 case 0x58:
3256 case 0x59:
3257 case 0x5a:
3258 case 0x5b:
3259 case 0x5c:
3260 case 0x5d:
3261 case 0x5e:
3262 case 0x5f:
3263
3264 if ((byte2 & 0xc0) == 0xc0) {
3265 #ifdef LOGEMU
3266 out("cmp");
3267 #endif
3268 if ((byte1 & 0x01) == 1)
3269 set_info((type8)(byte2 & 0xbf));
3270 else
3271 set_info((type8)(byte2 & 0x7f));
3272 set_arg1();
3273 set_arg2(0, byte1);
3274 swap_args();
3275 do_cmp(); /* CMP */
3276 } else {
3277 if ((byte1 & 0x01) == 0) {
3278 #ifdef LOGEMU
3279 out("cmp");
3280 #endif
3281 set_info(byte2);
3282 set_arg1();
3283 set_arg2(1, byte1);
3284 swap_args();
3285 do_cmp(); /* CMP */
3286 } else {
3287 #ifdef LOGEMU
3288 out("eor");
3289 #endif
3290 set_info(byte2);
3291 set_arg1();
3292 set_arg2(1, byte1);
3293 do_eor(); /* EOR */
3294 }
3295 }
3296 break;
3297
3298 /* C0-CF [2f52] EXG, AND */
3299 case 0x60:
3300 case 0x61:
3301 case 0x62:
3302 case 0x63:
3303 case 0x64:
3304 case 0x65:
3305 case 0x66:
3306 case 0x67:
3307
3308 if ((byte1 & 0x01) == 0) {
3309 if ((byte2 & 0xc0) == 0xc0) {
3310 ms_fatal("unimplemented instruction MULU");
3311 } else {
3312 /* AND */
3313 #ifdef LOGEMU
3314 out("and");
3315 #endif
3316 set_info(byte2);
3317 set_arg1();
3318 set_arg2(1, byte1);
3319 if ((byte1 & 0x01) == 0)
3320 swap_args();
3321 do_and();
3322 }
3323 } else {
3324 if ((byte2 & 0xf8) == 0x40) {
3325 #ifdef LOGEMU
3326 out("exg (dx)");
3327 #endif
3328 opsize = 2; /* EXG Dx,Dx */
3329 set_arg2(1, (type8)(byte2 << 1));
3330 swap_args();
3331 set_arg2(1, byte1);
3332 tmp32 = read_l(arg1);
3333 write_l(arg1, read_l(arg2));
3334 write_l(arg2, tmp32);
3335 } else if ((byte2 & 0xf8) == 0x48) {
3336 opsize = 2; /* EXG Ax,Ax */
3337 #ifdef LOGEMU
3338 out("exg (ax)");
3339 #endif
3340 set_arg2(0, (type8)(byte2 << 1));
3341 swap_args();
3342 set_arg2(0, byte1);
3343 tmp32 = read_l(arg1);
3344 write_l(arg1, read_l(arg2));
3345 write_l(arg2, tmp32);
3346 } else if ((byte2 & 0xf8) == 0x88) {
3347 opsize = 2; /* EXG Dx,Ax */
3348 #ifdef LOGEMU
3349 out("exg (dx,ax)");
3350 #endif
3351 set_arg2(0, (type8)(byte2 << 1));
3352 swap_args();
3353 set_arg2(1, byte1);
3354 tmp32 = read_l(arg1);
3355 write_l(arg1, read_l(arg2));
3356 write_l(arg2, tmp32);
3357 } else {
3358 if ((byte2 & 0xc0) == 0xc0) {
3359 ms_fatal("unimplemented instruction MULS");
3360 } else {
3361 set_info(byte2);
3362 set_arg1();
3363 set_arg2(1, byte1);
3364 if ((byte1 & 0x01) == 0)
3365 swap_args();
3366 do_and();
3367 }
3368 }
3369 }
3370 break;
3371
3372 /* D0-DF [2fc8] ADD */
3373 case 0x68:
3374 case 0x69:
3375 case 0x6a:
3376 case 0x6b:
3377 case 0x6c:
3378 case 0x6d:
3379 case 0x6e:
3380 case 0x6f:
3381
3382 #ifdef LOGEMU
3383 out("add");
3384 #endif
3385 quick_flag = 0;
3386 if ((byte2 & 0xc0) == 0xc0) {
3387 if ((byte1 & 0x01) == 1)
3388 set_info((type8)(byte2 & 0xbf));
3389 else
3390 set_info((type8)(byte2 & 0x7f));
3391 set_arg1();
3392 set_arg2_nosize(0, byte1);
3393 swap_args();
3394 do_add(1);
3395 } else {
3396 set_info(byte2);
3397 set_arg1();
3398 set_arg2(1, byte1);
3399 if ((byte1 & 0x01) == 0)
3400 swap_args();
3401 do_add(0);
3402 }
3403 break;
3404
3405 /* E0-EF [3479] LSR ASL ROR ROL */
3406 case 0x70:
3407 case 0x71:
3408 case 0x72:
3409 case 0x73:
3410 case 0x74:
3411 case 0x75:
3412 case 0x76:
3413 case 0x77:
3414
3415 #ifdef LOGEMU
3416 out("lsr,asl,ror,rol");
3417 #endif
3418 if ((byte2 & 0xc0) == 0xc0) {
3419 set_info((type8)(byte2 & 0xbf)); /* OP Dx */
3420 set_arg1();
3421 l1c = 1; /* steps=1 */
3422 byte2 = (byte1 >> 1) & 0x03;
3423 } else {
3424 set_info((type8)(byte2 & 0xc7));
3425 set_arg1();
3426 if ((byte2 & 0x20) == 0) {
3427 /* immediate */
3428 l1c = (byte1 >> 1) & 0x07;
3429 if (l1c == 0)
3430 l1c = 8;
3431 } else {
3432 l1c = (type8)read_reg(byte1 >> 1 & 0x07, 0);
3433 }
3434 byte2 = (byte2 >> 3) & 0x03;
3435 }
3436 if ((byte1 & 0x01) == 0) {
3437 /* right */
3438 while (l1c-- > 0) {
3439 if (opsize == 0) {
3440 cflag = arg1[0] & 0x01 ? 0xff : 0;
3441 arg1[0] >>= 1;
3442 if (cflag && (byte2 == 3))
3443 arg1[0] |= 0x80;
3444 }
3445 if (opsize == 1) {
3446 cflag = read_w(arg1) & 0x01 ? 0xff : 0;
3447 write_w(arg1, (type16)(read_w(arg1) >> 1));
3448 if (cflag && (byte2 == 3))
3449 write_w(arg1, (type16)(read_w(arg1) | ((type16) 1 << 15)));
3450 }
3451 if (opsize == 2) {
3452 cflag = read_l(arg1) & 0x01 ? 0xff : 0;
3453 write_l(arg1, read_l(arg1) >> 1);
3454 if (cflag && (byte2 == 3))
3455 write_l(arg1, read_l(arg1) | ((type32) 1 << 31));
3456 }
3457 }
3458 } else {
3459 /* left */
3460 while (l1c-- > 0) {
3461 if (opsize == 0) {
3462 cflag = arg1[0] & 0x80 ? 0xff : 0; /* [3527] */
3463 arg1[0] <<= 1;
3464 if (cflag && (byte2 == 3))
3465 arg1[0] |= 0x01;
3466 }
3467 if (opsize == 1) {
3468 cflag = read_w(arg1) & ((type16) 1 << 15) ? 0xff : 0;
3469 write_w(arg1, (type16)(read_w(arg1) << 1));
3470 if (cflag && (byte2 == 3))
3471 write_w(arg1, (type16)(read_w(arg1) | 0x01));
3472 }
3473 if (opsize == 2) {
3474 cflag = read_l(arg1) & ((type32) 1 << 31) ? 0xff : 0;
3475 write_l(arg1, read_l(arg1) << 1);
3476 if (cflag && (byte2 == 3))
3477 write_l(arg1, read_l(arg1) | 0x01);
3478 }
3479 }
3480 }
3481 set_flags();
3482 break;
3483
3484 /* F0-FF [24f3] LINE_F */
3485 case 0x78:
3486 case 0x79:
3487 case 0x7a:
3488 case 0x7b:
3489 case 0x7c:
3490 case 0x7d:
3491 case 0x7e:
3492 case 0x7f:
3493
3494 if (version == 0) {
3495 /* hardcoded jump */
3496 char_out(l1c = (type8)read_reg(1, 0));
3497 } else if (version == 1) {
3498 /* single programmable shortcut */
3499 push(pc);
3500 pc = fl_sub;
3501 } else {
3502 /* programmable shortcuts from table */
3503 #ifdef LOGEMU
3504 out("LINK: %.2X,%.2X", byte1, byte2);
3505 #endif
3506 ptr = (byte1 & 7) << 8 | byte2;
3507 if (ptr >= fl_size) {
3508 if ((byte1 & 8) == 0)
3509 push(pc);
3510 ptr = byte1 << 8 | byte2 | 0x0800;
3511 ptr = fl_tab + 2 * (ptr ^ 0xffff);
3512 pc = (type32) ptr + (type16s) read_w(effective(ptr));
3513 } else {
3514 push(pc);
3515 pc = fl_sub;
3516 }
3517 }
3518 break;
3519
3520 default:
3521 ms_fatal("Constants aren't and variables don't");
3522 break;
3523 }
3524 #ifdef LOGEMU
3525 fprintf(dbg_log, "\n");
3526 #endif
3527 return running;
3528 }
3529
3530 } // End of namespace Magnetic
3531 } // End of namespace Glk
3532