mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-08 10:51:11 +00:00
3531 lines
73 KiB
C++
3531 lines
73 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "glk/magnetic/magnetic_defs.h"
|
|
#include "glk/magnetic/magnetic.h"
|
|
#include "common/file.h"
|
|
#include "common/textconsole.h"
|
|
|
|
namespace Glk {
|
|
namespace Magnetic {
|
|
|
|
const char *const no_hints = "[Hints are not available.]\n";
|
|
const char *const not_supported = "[This function is not supported.]\n";
|
|
const char *const undo_ok = "\n[Previous turn undone.]";
|
|
const char *const undo_fail = "\n[You can't \"undo\" what hasn't been done!]";
|
|
|
|
#define ms_fatal error
|
|
|
|
#if defined(LOGEMU) || defined(LOGGFX) || defined(LOGHNT)
|
|
FILE *dbg_log;
|
|
#ifndef LOG_FILE
|
|
#error LOG_FILE must be defined to be the name of the log file.
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef LOGEMU
|
|
void out(char *format, ...) {
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
vfprintf(dbg_log, format, a);
|
|
va_end(a);
|
|
}
|
|
#endif
|
|
#if defined(LOGGFX) || defined(LOGHNT)
|
|
void out2(char *format, ...) {
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
vfprintf(dbg_log, format, a);
|
|
va_end(a);
|
|
fflush(dbg_log);
|
|
}
|
|
#endif
|
|
|
|
/* Convert virtual pointer to effective pointer */
|
|
type8 *Magnetic::effective(type32 ptr) {
|
|
if ((version < 4) && (mem_size == 0x10000))
|
|
return &(code[ptr & 0xffff]);
|
|
if (ptr >= mem_size) {
|
|
ms_fatal("Outside memory experience");
|
|
return code;
|
|
}
|
|
|
|
return &(code[ptr]);
|
|
}
|
|
|
|
void Magnetic::write_l(type8 *ptr, type32 val) {
|
|
ptr[3] = (type8) val;
|
|
val >>= 8;
|
|
ptr[2] = (type8) val;
|
|
val >>= 8;
|
|
ptr[1] = (type8) val;
|
|
val >>= 8;
|
|
ptr[0] = (type8) val;
|
|
}
|
|
|
|
void Magnetic::write_w(type8 *ptr, type16 val) {
|
|
ptr[1] = (type8) val;
|
|
val >>= 8;
|
|
ptr[0] = (type8) val;
|
|
}
|
|
|
|
type32 Magnetic::rand_emu() {
|
|
rseed = 1103515245L * rseed + 12345L;
|
|
return rseed & 0x7fffffffL;
|
|
}
|
|
|
|
void Magnetic::ms_freemem() {
|
|
if (code)
|
|
free(code);
|
|
if (string)
|
|
free(string);
|
|
if (string2)
|
|
free(string2);
|
|
if (string3)
|
|
free(string3);
|
|
if (dict)
|
|
free(dict);
|
|
if (undo[0])
|
|
free(undo[0]);
|
|
if (undo[1])
|
|
free(undo[1]);
|
|
if (restart)
|
|
free(restart);
|
|
code = string = string2 = string3 = dict = undo[0] = undo[1] = restart = nullptr;
|
|
if (gfx_data)
|
|
free(gfx_data);
|
|
if (gfx_buf)
|
|
free(gfx_buf);
|
|
if (gfx2_hdr)
|
|
free(gfx2_hdr);
|
|
if (gfx2_buf)
|
|
free(gfx2_buf);
|
|
delete gfx_fp;
|
|
|
|
gfx_data = gfx_buf = gfx2_hdr = gfx2_buf = nullptr;
|
|
gfx2_name = nullptr;
|
|
gfx_fp = nullptr;
|
|
gfx_ver = 0;
|
|
gfxtable = table_dist = 0;
|
|
#ifndef NO_ANIMATION
|
|
pos_table_size = 0;
|
|
command_index = 0;
|
|
anim_repeat = 0;
|
|
pos_table_index = -1;
|
|
pos_table_max = -1;
|
|
#endif
|
|
lastchar = 0;
|
|
if (hints)
|
|
free(hints);
|
|
if (hint_contents)
|
|
free(hint_contents);
|
|
hints = nullptr;
|
|
hint_contents = nullptr;
|
|
if (snd_hdr)
|
|
free(snd_hdr);
|
|
if (snd_buf)
|
|
free(snd_buf);
|
|
snd_hdr = nullptr;
|
|
snd_hsize = 0;
|
|
snd_buf = nullptr;
|
|
}
|
|
|
|
type8 Magnetic::init_gfx1(type8 *header) {
|
|
#ifdef SAVEMEM
|
|
type32 i;
|
|
#endif
|
|
|
|
if (!(gfx_buf = (type8 *)malloc(MAX_PICTURE_SIZE))) {
|
|
delete gfx_fp;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
#ifdef SAVEMEM
|
|
if (!(gfx_data = (type8 *)malloc(128))) {
|
|
#else
|
|
size_t dataSize = read_l(header + 4) - 8;
|
|
if (!(gfx_data = (type8 *)malloc(dataSize))) {
|
|
#endif
|
|
free(gfx_buf);
|
|
delete gfx_fp;
|
|
gfx_buf = nullptr;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
#ifdef SAVEMEM
|
|
if (!fp.read(gfx_data, 128, 1, gfx_fp)) {
|
|
#else
|
|
if (gfx_fp->read(gfx_data, dataSize) != dataSize) {
|
|
#endif
|
|
free(gfx_data);
|
|
free(gfx_buf);
|
|
delete gfx_fp;
|
|
gfx_data = gfx_buf = nullptr;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
#ifdef SAVEMEM
|
|
for (i = 0; i < 128; i += 4)
|
|
if (!read_l(gfx_data + i))
|
|
write_l(gfx_data + i, read_l(header + 4));
|
|
#else
|
|
delete gfx_fp;
|
|
gfx_fp = nullptr;
|
|
#endif
|
|
|
|
gfx_ver = 1;
|
|
return 2;
|
|
}
|
|
|
|
type8 Magnetic::init_gfx2(type8 *header) {
|
|
if (!(gfx_buf = (type8 *)malloc(MAX_PICTURE_SIZE))) {
|
|
delete gfx_fp;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
gfx2_hsize = read_w(header + 4);
|
|
if (!(gfx2_hdr = (type8 *)malloc(gfx2_hsize))) {
|
|
free(gfx_buf);
|
|
delete gfx_fp;
|
|
gfx_buf = nullptr;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
gfx_fp->seek(6);
|
|
if (gfx_fp->read(gfx2_hdr, gfx2_hsize) != gfx2_hsize) {
|
|
free(gfx_buf);
|
|
free(gfx2_hdr);
|
|
delete gfx_fp;
|
|
gfx_buf = nullptr;
|
|
gfx2_hdr = nullptr;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
gfx_ver = 2;
|
|
return 2;
|
|
}
|
|
|
|
type8 Magnetic::init_snd(type8 *header) {
|
|
if (!(snd_buf = (type8 *)malloc(MAX_MUSIC_SIZE))) {
|
|
delete snd_fp;
|
|
snd_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
snd_hsize = read_w(header + 4);
|
|
if (!(snd_hdr = (type8 *)malloc(snd_hsize))) {
|
|
free(snd_buf);
|
|
delete snd_fp;
|
|
snd_buf = nullptr;
|
|
snd_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
snd_fp->seek(6);
|
|
if (snd_fp->read(snd_hdr, snd_hsize) != snd_hsize) {
|
|
free(snd_buf);
|
|
free(snd_hdr);
|
|
delete snd_fp;
|
|
snd_buf = nullptr;
|
|
snd_hdr = nullptr;
|
|
snd_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
type8 Magnetic::ms_init(const char *name, const char *gfxname, const char *hntname, const char *sndname) {
|
|
Common::File fp;
|
|
type8 header[42], header2[8], header3[4];
|
|
type32 i, dict_size, string2_size, code_size, dec;
|
|
|
|
#if defined(LOGEMU) || defined(LOGGFX) || defined(LOGHNT)
|
|
dbg_log = fopen(LOG_FILE, "wt");
|
|
#endif
|
|
ms_stop();
|
|
if (!name) {
|
|
if (!restart)
|
|
return 0;
|
|
else {
|
|
memcpy(code, restart, undo_size);
|
|
undo_stat[0] = undo_stat[1] = 0;
|
|
ms_showpic(0, 0);
|
|
}
|
|
} else {
|
|
undo_stat[0] = undo_stat[1] = 0;
|
|
|
|
if (!fp.open(name))
|
|
return 0;
|
|
if ((fp.read(header, 42) != 42) || (read_l(header) != 0x4d615363))
|
|
return 0;
|
|
if (read_l(header + 8) != 42)
|
|
return 0;
|
|
|
|
ms_freemem();
|
|
version = header[13];
|
|
code_size = read_l(header + 14);
|
|
string_size = read_l(header + 18);
|
|
string2_size = read_l(header + 22);
|
|
dict_size = read_l(header + 26);
|
|
undo_size = read_l(header + 34);
|
|
undo_pc = read_l(header + 38);
|
|
|
|
if ((version < 4) && (code_size < 65536))
|
|
mem_size = 65536;
|
|
else
|
|
mem_size = code_size;
|
|
|
|
/* Some C libraries don't like malloc(0), so make
|
|
sure that undo_size is always positive. */
|
|
if (undo_size == 0)
|
|
undo_size = 8;
|
|
|
|
sd = (type8)((dict_size != 0L) ? 1 : 0); /* if (sd) => separate dict */
|
|
|
|
if (!(code = (type8 *)malloc(mem_size)) || !(string2 = (type8 *)malloc(string2_size)) ||
|
|
!(restart = (type8 *)malloc(undo_size)) || (sd &&
|
|
!(dict = (type8 *)malloc(dict_size)))) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
if (string_size > MAX_STRING_SIZE) {
|
|
if (!(string = (type8 *)malloc(MAX_STRING_SIZE)) ||
|
|
!(string3 = (type8 *)malloc(string_size - MAX_STRING_SIZE))) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (!(string = (type8 *)malloc(string_size))) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
}
|
|
if (!(undo[0] = (type8 *)malloc(undo_size)) || !(undo[1] = (type8 *)malloc(undo_size))) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
if (fp.read(code, code_size) != code_size) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
memcpy(restart, code, undo_size); /* fast restarts */
|
|
if (string_size > MAX_STRING_SIZE) {
|
|
if (fp.read(string, MAX_STRING_SIZE) != MAX_STRING_SIZE) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
if (fp.read(string3, string_size - MAX_STRING_SIZE) != string_size - MAX_STRING_SIZE) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (fp.read(string, string_size) != string_size) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
}
|
|
if (fp.read(string2, string2_size) != string2_size) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
if (sd && fp.read(dict, dict_size) != dict_size) {
|
|
ms_freemem();
|
|
fp.close();
|
|
return 0;
|
|
}
|
|
dec = read_l(header + 30);
|
|
if (dec >= string_size)
|
|
decode_table = string2 + dec - string_size;
|
|
else {
|
|
if (dec >= MAX_STRING_SIZE)
|
|
decode_table = string3 + dec - MAX_STRING_SIZE;
|
|
else
|
|
decode_table = string + dec;
|
|
}
|
|
fp.close();
|
|
}
|
|
|
|
for (i = 0; i < 8; i++)
|
|
dreg[i] = areg[i] = 0;
|
|
write_reg(8 + 7, 2, 0xfffe); /* Stack-pointer, -2 due to MS-DOS segments */
|
|
pc = 0;
|
|
zflag = nflag = cflag = vflag = 0;
|
|
i_count = 0;
|
|
running = 1;
|
|
|
|
if (!name)
|
|
return (type8)(gfx_buf ? 2 : 1); /* Restarted */
|
|
|
|
if (version == 4) {
|
|
/* Try loading a hint file */
|
|
Common::File hnt_fp;
|
|
if (hntname && hnt_fp.open(hntname)) {
|
|
if ((hnt_fp.read(&header3, 4) == 4) && (read_l(header3) == 0x4D614874)) {
|
|
type8 buf[8];
|
|
type16 j, blkcnt, elcnt, ntype, elsize, conidx;
|
|
|
|
/* Allocate memory for hints */
|
|
hints = (ms_hint *)malloc(MAX_HINTS * sizeof(struct ms_hint));
|
|
hint_contents = (type8 *)malloc(MAX_HCONTENTS);
|
|
if ((hints != nullptr) && (hint_contents != nullptr)) {
|
|
/* Read number of blocks */
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos())
|
|
return 0;
|
|
blkcnt = read_w2(buf);
|
|
#ifdef LOGHNT
|
|
out2("Blocks: %d\n", blkcnt);
|
|
#endif
|
|
conidx = 0;
|
|
for (i = 0; i < blkcnt; i++) {
|
|
#ifdef LOGHNT
|
|
out2("\nBlock No. %d\n", i);
|
|
#endif
|
|
/* Read number of elements */
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
|
|
elcnt = read_w2(buf);
|
|
#ifdef LOGHNT
|
|
out2("Elements: %d\n", elcnt);
|
|
#endif
|
|
hints[i].elcount = elcnt;
|
|
|
|
/* Read node type */
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
|
|
ntype = read_w2(buf);
|
|
#ifdef LOGHNT
|
|
if (ntype == 1)
|
|
out2("Type: Node\n");
|
|
else
|
|
out2("Type: Leaf\n");
|
|
#endif
|
|
hints[i].nodetype = ntype;
|
|
hints[i].content = (const char *)hint_contents + conidx;
|
|
#ifdef LOGHNT
|
|
out2("Elements:\n");
|
|
#endif
|
|
for (j = 0; j < elcnt; j++) {
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
|
|
elsize = read_w2(buf);
|
|
if (hnt_fp.read(hint_contents + conidx, elsize) != elsize && !hnt_fp.eos()) return 0;
|
|
hint_contents[conidx + elsize - 1] = '\0';
|
|
#ifdef LOGHNT
|
|
out2("%s\n", hint_contents + conidx);
|
|
#endif
|
|
conidx += elsize;
|
|
}
|
|
|
|
/* Do we need a jump table? */
|
|
if (ntype == 1) {
|
|
#ifdef LOGHNT
|
|
out2("Jump to block:\n");
|
|
#endif
|
|
for (j = 0; j < elcnt; j++) {
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
|
|
hints[i].links[j] = read_w2(buf);
|
|
#ifdef LOGHNT
|
|
out2("%d\n", hints[i].links[j]);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Read the parent block */
|
|
if (hnt_fp.read(&buf, 2) != 2 && !hnt_fp.eos()) return 0;
|
|
hints[i].parent = read_w2(buf);
|
|
#ifdef LOGHNT
|
|
out2("Parent: %d\n", hints[i].parent);
|
|
#endif
|
|
}
|
|
} else {
|
|
if (hints)
|
|
free(hints);
|
|
if (hint_contents)
|
|
free(hint_contents);
|
|
hints = nullptr;
|
|
hint_contents = nullptr;
|
|
}
|
|
}
|
|
hnt_fp.close();
|
|
}
|
|
|
|
/* Try loading a music file */
|
|
snd_fp = new Common::File();
|
|
if (sndname && snd_fp->open(sndname)) {
|
|
if (snd_fp->read(&header2, 8) != 8) {
|
|
delete snd_fp;
|
|
snd_fp = nullptr;
|
|
} else {
|
|
if (read_l(header2) == 0x4D615364) { /* MaSd */
|
|
init_snd(header2);
|
|
#ifdef LOGSND
|
|
out2("Sound file loaded.\n");
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
delete snd_fp;
|
|
snd_fp = nullptr;
|
|
}
|
|
}
|
|
|
|
if (!gfxname)
|
|
return 1;
|
|
|
|
gfx_fp = new Common::File();
|
|
if (!gfx_fp->open(gfxname) || gfx_fp->read(&header2, 8) != 8) {
|
|
delete gfx_fp;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
if (version < 4 && read_l(header2) == 0x4D615069) /* MaPi */
|
|
return init_gfx1(header2);
|
|
else if (version == 4 && read_l(header2) == 0x4D615032) /* MaP2 */
|
|
return init_gfx2(header2);
|
|
delete gfx_fp;
|
|
gfx_fp = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
type8 Magnetic::is_blank(type16 line, type16 width) {
|
|
type32s i;
|
|
|
|
for (i = line * width; i < (line + 1) * width; i++)
|
|
if (gfx_buf[i])
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
type8 *Magnetic::ms_extract1(type8 pic, type16 *w, type16 *h, type16 *pal) {
|
|
type8 *decodeTable, *data, bit, val, *buf;
|
|
type16 tablesize, count;
|
|
type32 i, j, upsize, offset;
|
|
|
|
offset = read_l(gfx_data + 4 * pic);
|
|
#ifdef SAVEMEM
|
|
type32 datasize;
|
|
|
|
if (fseek(gfx_fp, offset, SEEK_SET) < 0)
|
|
return 0;
|
|
datasize = read_l(gfx_data + 4 * (pic + 1)) - offset;
|
|
if (!(buf = (type8 *)malloc(datasize)))
|
|
return 0;
|
|
if (fp.read(buf, 1, datasize, gfx_fp) != datasize)
|
|
return 0;
|
|
#else
|
|
buf = gfx_data + offset - 8;
|
|
#endif
|
|
|
|
for (i = 0; i < 16; i++)
|
|
pal[i] = read_w(buf + 0x1c + 2 * i);
|
|
w[0] = (type16)(read_w(buf + 4) - read_w(buf + 2));
|
|
h[0] = read_w(buf + 6);
|
|
|
|
tablesize = read_w(buf + 0x3c);
|
|
//datasize = read_l(buf + 0x3e);
|
|
decodeTable = buf + 0x42;
|
|
data = decodeTable + tablesize * 2 + 2;
|
|
upsize = h[0] * w[0];
|
|
|
|
for (i = 0, j = 0, count = 0, val = 0, bit = 7; i < upsize; i++, count--) {
|
|
if (!count) {
|
|
count = tablesize;
|
|
while (count < 0x80) {
|
|
if (data[j] & (1 << bit))
|
|
count = decodeTable[2 * count];
|
|
else
|
|
count = decodeTable[2 * count + 1];
|
|
if (!bit)
|
|
j++;
|
|
bit = (type8)(bit ? bit - 1 : 7);
|
|
}
|
|
count &= 0x7f;
|
|
if (count >= 0x10)
|
|
count -= 0x10;
|
|
else {
|
|
val = (type8)count;
|
|
count = 1;
|
|
}
|
|
}
|
|
gfx_buf[i] = val;
|
|
}
|
|
for (j = w[0]; j < upsize; j++)
|
|
gfx_buf[j] ^= gfx_buf[j - w[0]];
|
|
|
|
#ifdef SAVEMEM
|
|
free(buf);
|
|
#endif
|
|
for (; h[0] > 0 && is_blank((type16)(h[0] - 1), w[0]); h[0]--);
|
|
for (i = 0; h[0] > 0 && is_blank((type16)i, w[0]); h[0]--, i++);
|
|
return gfx_buf + i * w[0];
|
|
}
|
|
|
|
type16s Magnetic::find_name_in_header(const char *name, type8 upper) {
|
|
type16s header_pos = 0;
|
|
char pic_name[8];
|
|
type8 i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
pic_name[i] = 0;
|
|
strncpy(pic_name, name, 6);
|
|
if (upper) {
|
|
for (i = 0; i < 8; i++)
|
|
pic_name[i] = (char)toupper(pic_name[i]);
|
|
}
|
|
|
|
while (header_pos < gfx2_hsize) {
|
|
const char *hname = (const char *)(gfx2_hdr + header_pos);
|
|
if (strncmp(hname, pic_name, 6) == 0)
|
|
return header_pos;
|
|
header_pos += 16;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Magnetic::extract_frame(struct picture *pic) {
|
|
type32 i, x, y, bit_x, mask, ywb, yw, value, values[4];
|
|
|
|
if (pic->width * pic->height > MAX_PICTURE_SIZE) {
|
|
ms_fatal("picture too large");
|
|
return;
|
|
}
|
|
|
|
for (y = 0; y < pic->height; y++) {
|
|
ywb = y * pic->wbytes;
|
|
yw = y * pic->width;
|
|
|
|
for (x = 0; x < pic->width; x++) {
|
|
if ((x % 8) == 0) {
|
|
for (i = 0; i < 4; i++)
|
|
values[i] = pic->data[ywb + (x / 8) + (pic->plane_step * i)];
|
|
}
|
|
|
|
bit_x = 7 - (x & 7);
|
|
mask = 1 << bit_x;
|
|
value = ((values[0] & mask) >> bit_x) << 0 |
|
|
((values[1] & mask) >> bit_x) << 1 |
|
|
((values[2] & mask) >> bit_x) << 2 |
|
|
((values[3] & mask) >> bit_x) << 3;
|
|
value &= 15;
|
|
|
|
gfx_buf[yw + x] = (type8)value;
|
|
}
|
|
}
|
|
}
|
|
|
|
type8 *Magnetic::ms_extract2(const char *name, type16 *w, type16 *h, type16 *pal, type8 *is_anim) {
|
|
struct picture main_pic;
|
|
type32 offset = 0, length = 0, i;
|
|
type16s header_pos = -1;
|
|
#ifndef NO_ANIMATION
|
|
type8 *anim_data;
|
|
type32 j;
|
|
#endif
|
|
|
|
if (is_anim != nullptr)
|
|
*is_anim = 0;
|
|
gfx2_name = name;
|
|
|
|
#ifndef NO_ANIMATION
|
|
pos_table_size = 0;
|
|
#endif
|
|
|
|
#ifdef NO_ANIMATION
|
|
/* Find the uppercase (no animation) version of the picture first. */
|
|
header_pos = find_name_in_header(name, 1);
|
|
#endif
|
|
if (header_pos < 0)
|
|
header_pos = find_name_in_header(name, 0);
|
|
if (header_pos < 0)
|
|
return nullptr;
|
|
|
|
offset = read_l(gfx2_hdr + header_pos + 8);
|
|
length = read_l(gfx2_hdr + header_pos + 12);
|
|
|
|
if (offset != 0) {
|
|
if (gfx2_buf) {
|
|
free(gfx2_buf);
|
|
gfx2_buf = nullptr;
|
|
}
|
|
|
|
gfx2_buf = (type8 *)malloc(length);
|
|
if (!gfx2_buf)
|
|
return nullptr;
|
|
|
|
if (!gfx_fp->seek(offset)) {
|
|
free(gfx2_buf);
|
|
gfx2_buf = nullptr;
|
|
return nullptr;
|
|
}
|
|
|
|
if (gfx_fp->read(gfx2_buf, length) != length) {
|
|
free(gfx2_buf);
|
|
gfx2_buf = nullptr;
|
|
return nullptr;
|
|
}
|
|
|
|
for (i = 0; i < 16; i++)
|
|
pal[i] = read_w2(gfx2_buf + 4 + (2 * i));
|
|
|
|
main_pic.data = gfx2_buf + 48;
|
|
main_pic.data_size = read_l2(gfx2_buf + 38);
|
|
main_pic.width = read_w2(gfx2_buf + 42);
|
|
main_pic.height = read_w2(gfx2_buf + 44);
|
|
main_pic.wbytes = (type16)(main_pic.data_size / main_pic.height);
|
|
main_pic.plane_step = (type16)(main_pic.wbytes / 4);
|
|
main_pic.mask = (type8 *)nullptr;
|
|
extract_frame(&main_pic);
|
|
|
|
*w = main_pic.width;
|
|
*h = main_pic.height;
|
|
|
|
#ifndef NO_ANIMATION
|
|
/* Check for an animation */
|
|
anim_data = gfx2_buf + 48 + main_pic.data_size;
|
|
if ((anim_data[0] != 0xD0) || (anim_data[1] != 0x5E)) {
|
|
type8 *current;
|
|
type16 frame_count;
|
|
type16 value1, value2;
|
|
|
|
if (is_anim != nullptr)
|
|
*is_anim = 1;
|
|
|
|
current = anim_data + 6;
|
|
frame_count = read_w2(anim_data + 2);
|
|
if (frame_count > MAX_ANIMS) {
|
|
ms_fatal("animation frame array too short");
|
|
return nullptr;
|
|
}
|
|
|
|
/* Loop through each animation frame */
|
|
for (i = 0; i < frame_count; i++) {
|
|
anim_frame_table[i].data = current + 10;
|
|
anim_frame_table[i].data_size = read_l2(current);
|
|
anim_frame_table[i].width = read_w2(current + 4);
|
|
anim_frame_table[i].height = read_w2(current + 6);
|
|
anim_frame_table[i].wbytes = (type16)(anim_frame_table[i].data_size / anim_frame_table[i].height);
|
|
anim_frame_table[i].plane_step = (type16)(anim_frame_table[i].wbytes / 4);
|
|
anim_frame_table[i].mask = (type8 *)nullptr;
|
|
|
|
current += anim_frame_table[i].data_size + 12;
|
|
value1 = read_w2(current - 2);
|
|
value2 = read_w2(current);
|
|
|
|
/* Get the mask */
|
|
if ((value1 == anim_frame_table[i].width) && (value2 == anim_frame_table[i].height)) {
|
|
type16 skip;
|
|
|
|
anim_frame_table[i].mask = (type8 *)(current + 4);
|
|
skip = read_w2(current + 2);
|
|
current += skip + 6;
|
|
}
|
|
}
|
|
|
|
/* Get the positioning tables */
|
|
pos_table_size = read_w2(current - 2);
|
|
if (pos_table_size > MAX_POSITIONS) {
|
|
ms_fatal("animation position array too short");
|
|
return nullptr;
|
|
}
|
|
|
|
#ifdef LOGGFX_EXT
|
|
out2("POSITION TABLE DUMP\n");
|
|
#endif
|
|
for (i = 0; i < pos_table_size; i++) {
|
|
pos_table_count[i] = read_w2(current + 2);
|
|
current += 4;
|
|
|
|
if (pos_table_count[i] > MAX_ANIMS) {
|
|
ms_fatal("animation position array too short");
|
|
return nullptr;
|
|
}
|
|
|
|
for (j = 0; j < pos_table_count[i]; j++) {
|
|
pos_table[i][j].x = read_w2(current);
|
|
pos_table[i][j].y = read_w2(current + 2);
|
|
pos_table[i][j].number = read_w2(current + 4) - 1;
|
|
current += 8;
|
|
#ifdef LOGGFX_EXT
|
|
out2("Position entry: Table: %d Entry: %d X: %d Y: %d Frame: %d\n",
|
|
i, j, pos_table[i][j].x, pos_table[i][j].y, pos_table[i][j].number);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Get the command sequence table */
|
|
//command_count = read_w2(current);
|
|
command_table = current + 2;
|
|
|
|
for (i = 0; i < MAX_POSITIONS; i++) {
|
|
anim_table[i].flag = -1;
|
|
anim_table[i].count = -1;
|
|
}
|
|
command_index = 0;
|
|
anim_repeat = 0;
|
|
pos_table_index = -1;
|
|
pos_table_max = -1;
|
|
}
|
|
#endif
|
|
return gfx_buf;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
type8 *Magnetic::ms_extract(type32 pic, type16 *w, type16 *h, type16 *pal, type8 *is_anim) {
|
|
if (is_anim)
|
|
*is_anim = 0;
|
|
|
|
if (gfx_buf) {
|
|
switch (gfx_ver) {
|
|
case 1:
|
|
return ms_extract1((type8)pic, w, h, pal);
|
|
case 2:
|
|
return ms_extract2((const char *)(code + pic), w, h, pal, is_anim);
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
type8 Magnetic::ms_animate(struct ms_position **positions, type16 *count) {
|
|
#ifndef NO_ANIMATION
|
|
type8 got_anim = 0;
|
|
type16 i, j, ttable;
|
|
|
|
if ((gfx_buf == nullptr) || (gfx2_buf == nullptr) || (gfx_ver != 2))
|
|
return 0;
|
|
if ((pos_table_size == 0) || (command_index < 0))
|
|
return 0;
|
|
|
|
*count = 0;
|
|
*positions = (struct ms_position *)nullptr;
|
|
|
|
while (got_anim == 0) {
|
|
if (pos_table_max >= 0) {
|
|
if (pos_table_index < pos_table_max) {
|
|
for (i = 0; i < pos_table_size; i++) {
|
|
if (anim_table[i].flag > -1) {
|
|
if (*count >= MAX_FRAMES) {
|
|
ms_fatal("returned animation array too short");
|
|
return 0;
|
|
}
|
|
|
|
pos_array[*count] = pos_table[i][anim_table[i].flag];
|
|
#ifdef LOGGFX_EXT
|
|
out2("Adding frame %d to buffer\n", pos_array[*count].number);
|
|
#endif
|
|
(*count)++;
|
|
|
|
if (anim_table[i].flag < (pos_table_count[i] - 1))
|
|
anim_table[i].flag++;
|
|
if (anim_table[i].count > 0)
|
|
anim_table[i].count--;
|
|
else
|
|
anim_table[i].flag = -1;
|
|
}
|
|
}
|
|
if (*count > 0) {
|
|
*positions = pos_array;
|
|
got_anim = 1;
|
|
}
|
|
pos_table_index++;
|
|
}
|
|
}
|
|
|
|
if (got_anim == 0) {
|
|
type8 command = command_table[command_index];
|
|
command_index++;
|
|
|
|
pos_table_max = -1;
|
|
pos_table_index = -1;
|
|
|
|
switch (command) {
|
|
case 0x00:
|
|
command_index = -1;
|
|
return 0;
|
|
case 0x01:
|
|
#ifdef LOGGFX_EXT
|
|
out2("Load Frame Table: %d Start at: %d Count: %d\n",
|
|
command_table[command_index], command_table[command_index + 1],
|
|
command_table[command_index + 2]);
|
|
#endif
|
|
ttable = command_table[command_index];
|
|
command_index++;
|
|
|
|
if (ttable - 1 >= MAX_POSITIONS) {
|
|
ms_fatal("animation table too short");
|
|
return 0;
|
|
}
|
|
|
|
anim_table[ttable - 1].flag = (type16s)(command_table[command_index] - 1);
|
|
command_index++;
|
|
anim_table[ttable - 1].count = (type16s)(command_table[command_index] - 1);
|
|
command_index++;
|
|
|
|
/* Workaround for Wonderland "catter" animation */
|
|
if (v4_id == 0) {
|
|
if (strcmp(gfx2_name, "catter") == 0) {
|
|
if (command_index == 96)
|
|
anim_table[ttable - 1].count = 9;
|
|
if (command_index == 108)
|
|
anim_table[ttable - 1].flag = -1;
|
|
if (command_index == 156)
|
|
anim_table[ttable - 1].flag = -1;
|
|
}
|
|
}
|
|
break;
|
|
case 0x02:
|
|
#ifdef LOGGFX_EXT
|
|
out2("Animate: %d\n", command_table[command_index]);
|
|
#endif
|
|
pos_table_max = command_table[command_index];
|
|
pos_table_index = 0;
|
|
command_index++;
|
|
break;
|
|
case 0x03:
|
|
#ifdef LOGGFX_EXT
|
|
out2("Stop/Repeat Param: %d\n", command_table[command_index]);
|
|
command_index = -1;
|
|
return 0;
|
|
#else
|
|
if (v4_id == 0) {
|
|
command_index = -1;
|
|
return 0;
|
|
} else {
|
|
command_index = 0;
|
|
anim_repeat = 1;
|
|
pos_table_index = -1;
|
|
pos_table_max = -1;
|
|
for (j = 0; j < MAX_POSITIONS; j++) {
|
|
anim_table[j].flag = -1;
|
|
anim_table[j].count = -1;
|
|
}
|
|
}
|
|
break;
|
|
#endif
|
|
case 0x04:
|
|
#ifdef LOGGFX_EXT
|
|
out2("Unknown Command: %d Prop1: %d Prop2: %d WARNING:not parsed\n", command,
|
|
command_table[command_index], command_table[command_index + 1]);
|
|
#endif
|
|
command_index += 3;
|
|
return 0;
|
|
case 0x05:
|
|
ttable = next_table;
|
|
command_index++;
|
|
|
|
anim_table[ttable - 1].flag = 0;
|
|
anim_table[ttable - 1].count = command_table[command_index];
|
|
|
|
pos_table_max = command_table[command_index];
|
|
pos_table_index = 0;
|
|
command_index++;
|
|
command_index++;
|
|
next_table++;
|
|
break;
|
|
default:
|
|
ms_fatal("unknown animation command");
|
|
command_index = -1;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
#ifdef LOGGFX_EXT
|
|
out2("ms_animate() returning %d frames\n", *count);
|
|
#endif
|
|
return got_anim;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
type8 *Magnetic::ms_get_anim_frame(type16s number, type16 *width, type16 *height, type8 **mask) {
|
|
#ifndef NO_ANIMATION
|
|
if (number >= 0) {
|
|
extract_frame(anim_frame_table + number);
|
|
*width = anim_frame_table[number].width;
|
|
*height = anim_frame_table[number].height;
|
|
*mask = anim_frame_table[number].mask;
|
|
return gfx_buf;
|
|
}
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
type8 Magnetic::ms_anim_is_repeating() const {
|
|
#ifndef NO_ANIMATION
|
|
return anim_repeat;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
type16s Magnetic::find_name_in_sndheader(const char *name) {
|
|
type16s header_pos = 0;
|
|
|
|
while (header_pos < snd_hsize) {
|
|
const char *hname = (const char *)(snd_hdr + header_pos);
|
|
if (strcmp(hname, name) == 0)
|
|
return header_pos;
|
|
header_pos += 18;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
type8 *Magnetic::sound_extract(const char *name, type32 *length, type16 *tempo) {
|
|
type32 offset = 0;
|
|
type16s header_pos = -1;
|
|
|
|
if (header_pos < 0)
|
|
header_pos = find_name_in_sndheader(name);
|
|
if (header_pos < 0)
|
|
return nullptr;
|
|
|
|
*tempo = read_w(snd_hdr + header_pos + 8);
|
|
offset = read_l(snd_hdr + header_pos + 10);
|
|
*length = read_l(snd_hdr + header_pos + 14);
|
|
|
|
if (offset != 0) {
|
|
if (!snd_buf)
|
|
return nullptr;
|
|
if (!snd_fp->seek(offset) || snd_fp->read(snd_buf, *length) != *length)
|
|
return nullptr;
|
|
|
|
return snd_buf;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void Magnetic::save_undo() {
|
|
type8 *tmp, i;
|
|
type32 tmp32;
|
|
|
|
tmp = undo[0]; /* swap buffers */
|
|
undo[0] = undo[1];
|
|
undo[1] = tmp;
|
|
|
|
for (i = 0; i < 18; i++) {
|
|
tmp32 = undo_regs[0][i];
|
|
undo_regs[0][i] = undo_regs[1][i];
|
|
undo_regs[1][i] = tmp32;
|
|
}
|
|
|
|
memcpy(undo[1], code, undo_size);
|
|
for (i = 0; i < 8; i++) {
|
|
undo_regs[1][i] = dreg[i];
|
|
undo_regs[1][8 + i] = areg[i];
|
|
}
|
|
undo_regs[1][16] = i_count;
|
|
undo_regs[1][17] = pc; /* status flags intentionally omitted */
|
|
|
|
undo_stat[0] = undo_stat[1];
|
|
undo_stat[1] = 1;
|
|
}
|
|
|
|
type8 Magnetic::ms_undo() {
|
|
type8 i;
|
|
|
|
ms_flush();
|
|
if (!undo_stat[0])
|
|
return 0;
|
|
|
|
undo_stat[0] = undo_stat[1] = 0;
|
|
memcpy(code, undo[0], undo_size);
|
|
for (i = 0; i < 8; i++) {
|
|
dreg[i] = undo_regs[0][i];
|
|
areg[i] = undo_regs[0][8 + i];
|
|
}
|
|
i_count = undo_regs[0][16];
|
|
pc = undo_regs[0][17]; /* status flags intentionally omitted */
|
|
return 1;
|
|
}
|
|
|
|
#ifdef LOGEMU
|
|
void Magnetic::log_status() {
|
|
int j;
|
|
|
|
fprintf(dbg_log, "\nD0:");
|
|
for (j = 0; j < 8; j++)
|
|
fprintf(dbg_log, " %8.8x", read_reg(j, 3));
|
|
fprintf(dbg_log, "\nA0:");
|
|
for (j = 0; j < 8; j++)
|
|
fprintf(dbg_log, " %8.8x", read_reg(8 + j, 3));
|
|
fprintf(dbg_log, "\nPC=%5.5x (%8.8x) ZCNV=%d%d%d%d - %d instructions\n\n",
|
|
pc, code, zflag & 1, cflag & 1, nflag & 1, vflag & 1, i_count);
|
|
}
|
|
#endif
|
|
|
|
void Magnetic::ms_status() {
|
|
int j;
|
|
|
|
Common::String s = "D0:";
|
|
for (j = 0; j < 8; j++)
|
|
s += Common::String::format(" %8.8lx", (long) read_reg(j, 3));
|
|
s += "\nA0:";
|
|
|
|
for (j = 0; j < 8; j++)
|
|
s += Common::String::format(" %8.8lx", (long) read_reg(8 + j, 3));
|
|
s += Common::String::format("\nPC=%5.5lx ZCNV=%d%d%d%d - %ld instructions\n",
|
|
(long) pc, zflag & 1, cflag & 1, nflag & 1, vflag & 1, (long) i_count);
|
|
warning("%s", s.c_str());
|
|
}
|
|
|
|
type8 *Magnetic::reg_align(type8 *ptr, type8 size) {
|
|
if (size == 1)
|
|
ptr += 2;
|
|
if (size == 0)
|
|
ptr += 3;
|
|
return ptr;
|
|
}
|
|
|
|
type32 Magnetic::read_reg(int i, int s) {
|
|
type8 *ptr;
|
|
|
|
if (i > 15) {
|
|
ms_fatal("invalid register in read_reg");
|
|
return 0;
|
|
}
|
|
if (i < 8)
|
|
ptr = (type8 *) & dreg[i];
|
|
else
|
|
ptr = (type8 *) & areg[i - 8];
|
|
|
|
switch (s) {
|
|
case 0:
|
|
return reg_align(ptr, 0)[0];
|
|
case 1:
|
|
return read_w(reg_align(ptr, 1));
|
|
default:
|
|
return read_l(ptr);
|
|
}
|
|
}
|
|
|
|
void Magnetic::write_reg(int i, int s, type32 val) {
|
|
type8 *ptr;
|
|
|
|
if (i > 15) {
|
|
ms_fatal("invalid register in write_reg");
|
|
return;
|
|
}
|
|
if (i < 8)
|
|
ptr = (type8 *) & dreg[i];
|
|
else
|
|
ptr = (type8 *) & areg[i - 8];
|
|
|
|
switch (s) {
|
|
case 0:
|
|
reg_align(ptr, 0)[0] = (type8)val;
|
|
break;
|
|
case 1:
|
|
write_w(reg_align(ptr, 1), (type16)val);
|
|
break;
|
|
default:
|
|
write_l(ptr, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Magnetic::char_out(type8 c) {
|
|
static type8 big = 0, period = 0, pipe = 0;
|
|
|
|
if (c == 0xff) {
|
|
big = 1;
|
|
return;
|
|
}
|
|
c &= 0x7f;
|
|
if (read_reg(3, 0)) {
|
|
if (c == 0x5f || c == 0x40)
|
|
c = 0x20;
|
|
if ((c >= 'a') && (c <= 'z'))
|
|
c &= 0xdf;
|
|
if (version < 4)
|
|
ms_statuschar(c);
|
|
return;
|
|
}
|
|
if (c == 0x5e)
|
|
c = 0x0a;
|
|
if (c == 0x40) {
|
|
if (read_reg(2, 0))
|
|
return;
|
|
else
|
|
c = 0x73;
|
|
}
|
|
if (version < 3 && c == 0x7e) {
|
|
lastchar = 0x7e;
|
|
c = 0x0a;
|
|
}
|
|
if (((c > 0x40) && (c < 0x5b)) || ((c > 0x60) && (c < 0x7b))) {
|
|
if (big) {
|
|
c &= 0xdf;
|
|
big = 0;
|
|
}
|
|
if (period)
|
|
char_out(0x20);
|
|
}
|
|
period = 0;
|
|
if (version < 4) {
|
|
if ((c == 0x2e) || (c == 0x3f) || (c == 0x21) || (c == 0x0a))
|
|
big = 1;
|
|
else if (c == 0x22)
|
|
big = 0;
|
|
} else {
|
|
if ((c == 0x20) && (lastchar == 0x0a))
|
|
return;
|
|
if ((c == 0x2e) || (c == 0x3f) || (c == 0x21) || (c == 0x0a))
|
|
big = 1;
|
|
else if (c == 0x22)
|
|
big = 0;
|
|
}
|
|
if (((c == 0x20) || (c == 0x0a)) && (c == lastchar))
|
|
return;
|
|
if (version < 3) {
|
|
if (pipe) {
|
|
pipe = 0;
|
|
return;
|
|
}
|
|
if (c == 0x7c) {
|
|
pipe = 1;
|
|
return;
|
|
}
|
|
} else {
|
|
if (c == 0x7e) {
|
|
c = 0x0a;
|
|
if (lastchar != 0x0a)
|
|
char_out(0x0a);
|
|
}
|
|
}
|
|
lastchar = c;
|
|
if (c == 0x5f)
|
|
c = 0x20;
|
|
if ((c == 0x2e) || (c == 0x2c) || (c == 0x3b) || (c == 0x3a) || (c == 0x21) || (c == 0x3f))
|
|
period = 1;
|
|
ms_putchar(c);
|
|
}
|
|
|
|
void Magnetic::set_info(type8 b) {
|
|
regnr = (type8)(b & 0x07);
|
|
admode = (type8)((b >> 3) & 0x07);
|
|
opsize = (type8)(b >> 6);
|
|
}
|
|
|
|
void Magnetic::read_word() {
|
|
type8 *epc;
|
|
|
|
epc = effective(pc);
|
|
byte1 = epc[0];
|
|
byte2 = epc[1];
|
|
pc += 2;
|
|
}
|
|
|
|
void Magnetic::set_arg1() {
|
|
type8 tmp[2], l1c;
|
|
|
|
is_reversible = 1;
|
|
switch (admode) {
|
|
case 0:
|
|
arg1 = reg_align((type8 *) & dreg[regnr], opsize); /* Dx */
|
|
is_reversible = 0;
|
|
#ifdef LOGEMU
|
|
out(" d%.1d", regnr);
|
|
#endif
|
|
break;
|
|
case 1:
|
|
arg1 = reg_align((type8 *) & areg[regnr], opsize); /* Ax */
|
|
is_reversible = 0;
|
|
#ifdef LOGEMU
|
|
out(" a%.1d", regnr);
|
|
#endif
|
|
break;
|
|
case 2:
|
|
arg1i = read_reg(8 + regnr, 2); /* (Ax) */
|
|
#ifdef LOGEMU
|
|
out(" (a%.1d)", regnr);
|
|
#endif
|
|
break;
|
|
case 3:
|
|
arg1i = read_reg(8 + regnr, 2); /* (Ax)+ */
|
|
write_reg(8 + regnr, 2, read_reg(8 + regnr, 2) + (1 << opsize));
|
|
#ifdef LOGEMU
|
|
out(" (a%.1d)+", regnr);
|
|
#endif
|
|
break;
|
|
case 4:
|
|
write_reg(8 + regnr, 2, read_reg(8 + regnr, 2) - (1 << opsize));
|
|
arg1i = read_reg(8 + regnr, 2); /* -(Ax) */
|
|
#ifdef LOGEMU
|
|
out(" -(a%.1d)", regnr);
|
|
#endif
|
|
break;
|
|
case 5: {
|
|
type16s i = (type16s) read_w(effective(pc));
|
|
arg1i = read_reg(8 + regnr, 2) + i;
|
|
pc += 2; /* offset.w(Ax) */
|
|
#ifdef LOGEMU
|
|
out(" %X(a%.1d)", i, regnr);
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
case 6:
|
|
tmp[0] = byte1;
|
|
tmp[1] = byte2;
|
|
read_word(); /* offset.b(Ax, Dx/Ax) [1d1c] */
|
|
#ifdef LOGEMU
|
|
out(" %.2X(a%.1d,", (int) byte2, regnr);
|
|
#endif
|
|
arg1i = read_reg(regnr + 8, 2) + (type8s) byte2;
|
|
#ifdef LOGEMU
|
|
if ((byte1 >> 4) > 8)
|
|
out("a%.1d", (byte1 >> 4) - 8);
|
|
else
|
|
out("d%.1d", byte1 >> 4);
|
|
#endif
|
|
if (byte1 & 0x08) {
|
|
#ifdef LOGEMU
|
|
out(".l)");
|
|
#endif
|
|
arg1i += (type32s) read_reg((byte1 >> 4), 2);
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out(".w)");
|
|
#endif
|
|
arg1i += (type16s) read_reg((byte1 >> 4), 1);
|
|
}
|
|
byte1 = tmp[0];
|
|
byte2 = tmp[1];
|
|
break;
|
|
case 7: /* specials */
|
|
switch (regnr) {
|
|
case 0:
|
|
arg1i = read_w(effective(pc)); /* $xxxx.W */
|
|
pc += 2;
|
|
#ifdef LOGEMU
|
|
out(" %.4X.w", arg1i);
|
|
#endif
|
|
break;
|
|
case 1:
|
|
arg1i = read_l(effective(pc)); /* $xxxx */
|
|
pc += 4;
|
|
#ifdef LOGEMU
|
|
out(" %.4X", arg1i);
|
|
#endif
|
|
break;
|
|
case 2:
|
|
arg1i = (type16s) read_w(effective(pc)) + pc; /* $xxxx(PC) */
|
|
pc += 2;
|
|
#ifdef LOGEMU
|
|
out(" %.4X(pc)", arg1i);
|
|
#endif
|
|
break;
|
|
case 3:
|
|
l1c = effective(pc)[0]; /* $xx(PC,A/Dx) */
|
|
#ifdef LOGEMU
|
|
out(" ???2", arg1i);
|
|
#endif
|
|
if (l1c & 0x08)
|
|
arg1i = pc + (type32s) read_reg((l1c >> 4), 2);
|
|
else
|
|
arg1i = pc + (type16s) read_reg((l1c >> 4), 1);
|
|
l1c = effective(pc)[1];
|
|
pc += 2;
|
|
arg1i += (type8s) l1c;
|
|
break;
|
|
case 4:
|
|
arg1i = pc; /* #$xxxx */
|
|
if (opsize == 0)
|
|
arg1i += 1;
|
|
pc += 2;
|
|
if (opsize == 2)
|
|
pc += 2;
|
|
#ifdef LOGEMU
|
|
out(" #%.4X", arg1i);
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
if (is_reversible)
|
|
arg1 = effective(arg1i);
|
|
}
|
|
|
|
void Magnetic::set_arg2_nosize(int use_dx, type8 b) {
|
|
if (use_dx)
|
|
arg2 = (type8 *) dreg;
|
|
else
|
|
arg2 = (type8 *) areg;
|
|
arg2 += (b & 0x0e) << 1;
|
|
}
|
|
|
|
void Magnetic::set_arg2(int use_dx, type8 b) {
|
|
set_arg2_nosize(use_dx, b);
|
|
arg2 = reg_align(arg2, opsize);
|
|
}
|
|
|
|
void Magnetic::swap_args() {
|
|
type8 *tmp;
|
|
|
|
tmp = arg1;
|
|
arg1 = arg2;
|
|
arg2 = tmp;
|
|
}
|
|
|
|
void Magnetic::push(type32 c) {
|
|
write_reg(15, 2, read_reg(15, 2) - 4);
|
|
write_l(effective(read_reg(15, 2)), c);
|
|
}
|
|
|
|
type32 Magnetic::pop() {
|
|
type32 c;
|
|
|
|
c = read_l(effective(read_reg(15, 2)));
|
|
write_reg(15, 2, read_reg(15, 2) + 4);
|
|
return c;
|
|
}
|
|
|
|
void Magnetic::get_arg() {
|
|
#ifdef LOGEMU
|
|
out(" %.4X", pc);
|
|
#endif
|
|
set_info(byte2);
|
|
arg2 = effective(pc);
|
|
pc += 2;
|
|
if (opsize == 2)
|
|
pc += 2;
|
|
if (opsize == 0)
|
|
arg2 += 1;
|
|
set_arg1();
|
|
}
|
|
|
|
void Magnetic::set_flags() {
|
|
type16 i;
|
|
type32 j;
|
|
|
|
zflag = nflag = 0;
|
|
switch (opsize) {
|
|
case 0:
|
|
if (arg1[0] > 127)
|
|
nflag = 0xff;
|
|
if (arg1[0] == 0)
|
|
zflag = 0xff;
|
|
break;
|
|
case 1:
|
|
i = read_w(arg1);
|
|
if (i == 0)
|
|
zflag = 0xff;
|
|
if ((i >> 15) > 0)
|
|
nflag = 0xff;
|
|
break;
|
|
case 2:
|
|
j = read_l(arg1);
|
|
if (j == 0)
|
|
zflag = 0xff;
|
|
if ((j >> 31) > 0)
|
|
nflag = 0xff;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int Magnetic::condition(type8 b) {
|
|
switch (b & 0x0f) {
|
|
case 0:
|
|
return 0xff;
|
|
case 1:
|
|
return 0x00;
|
|
case 2:
|
|
return (zflag | cflag) ^ 0xff;
|
|
case 3:
|
|
return (zflag | cflag);
|
|
case 4:
|
|
return cflag ^ 0xff;
|
|
case 5:
|
|
return cflag;
|
|
case 6:
|
|
return zflag ^ 0xff;
|
|
case 7:
|
|
return zflag;
|
|
case 8:
|
|
return vflag ^ 0xff;
|
|
case 9:
|
|
return vflag;
|
|
case 10:
|
|
case 12:
|
|
return nflag ^ 0xff;
|
|
case 11:
|
|
case 13:
|
|
return nflag;
|
|
case 14:
|
|
return (zflag | nflag) ^ 0xff;
|
|
case 15:
|
|
return (zflag | nflag);
|
|
default:
|
|
break;
|
|
}
|
|
return 0x00;
|
|
}
|
|
|
|
void Magnetic::branch(type8 b) {
|
|
if (b == 0)
|
|
pc += (type16s) read_w(effective(pc));
|
|
else
|
|
pc += (type8s) b;
|
|
#ifdef LOGEMU
|
|
out(" %.4X", pc);
|
|
#endif
|
|
}
|
|
|
|
void Magnetic::do_add(type8 adda) {
|
|
if (adda) {
|
|
if (opsize == 0)
|
|
write_l(arg1, read_l(arg1) + (type8s) arg2[0]);
|
|
if (opsize == 1)
|
|
write_l(arg1, read_l(arg1) + (type16s) read_w(arg2));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg1) + (type32s) read_l(arg2));
|
|
} else {
|
|
cflag = 0;
|
|
if (opsize == 0) {
|
|
arg1[0] += arg2[0];
|
|
if (arg2[0] > arg1[0])
|
|
cflag = 0xff;
|
|
}
|
|
if (opsize == 1) {
|
|
write_w(arg1, (type16)(read_w(arg1) + read_w(arg2)));
|
|
if (read_w(arg2) > read_w(arg1))
|
|
cflag = 0xff;
|
|
}
|
|
if (opsize == 2) {
|
|
write_l(arg1, read_l(arg1) + read_l(arg2));
|
|
if (read_l(arg2) > read_l(arg1))
|
|
cflag = 0xff;
|
|
}
|
|
if (version < 3 || !quick_flag) {
|
|
/* Corruption onwards */
|
|
vflag = 0;
|
|
set_flags();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Magnetic::do_sub(type8 suba) {
|
|
if (suba) {
|
|
if (opsize == 0)
|
|
write_l(arg1, read_l(arg1) - (type8s) arg2[0]);
|
|
if (opsize == 1)
|
|
write_l(arg1, read_l(arg1) - (type16s) read_w(arg2));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg1) - (type32s) read_l(arg2));
|
|
} else {
|
|
cflag = 0;
|
|
if (opsize == 0) {
|
|
if (arg2[0] > arg1[0])
|
|
cflag = 0xff;
|
|
arg1[0] -= arg2[0];
|
|
}
|
|
if (opsize == 1) {
|
|
if (read_w(arg2) > read_w(arg1))
|
|
cflag = 0xff;
|
|
write_w(arg1, (type16)(read_w(arg1) - read_w(arg2)));
|
|
}
|
|
if (opsize == 2) {
|
|
if (read_l(arg2) > read_l(arg1))
|
|
cflag = 0xff;
|
|
write_l(arg1, read_l(arg1) - read_l(arg2));
|
|
}
|
|
if (version < 3 || !quick_flag) {
|
|
/* Corruption onwards */
|
|
vflag = 0;
|
|
set_flags();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Magnetic::do_eor() {
|
|
if (opsize == 0)
|
|
arg1[0] ^= arg2[0];
|
|
if (opsize == 1)
|
|
write_w(arg1, (type16)(read_w(arg1) ^ read_w(arg2)));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg1) ^ read_l(arg2));
|
|
cflag = vflag = 0;
|
|
set_flags();
|
|
}
|
|
|
|
void Magnetic::do_and() {
|
|
if (opsize == 0)
|
|
arg1[0] &= arg2[0];
|
|
if (opsize == 1)
|
|
write_w(arg1, (type16)(read_w(arg1) & read_w(arg2)));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg1) & read_l(arg2));
|
|
cflag = vflag = 0;
|
|
set_flags();
|
|
}
|
|
|
|
void Magnetic::do_or() {
|
|
if (opsize == 0)
|
|
arg1[0] |= arg2[0];
|
|
if (opsize == 1)
|
|
write_w(arg1, (type16)(read_w(arg1) | read_w(arg2)));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg1) | read_l(arg2));
|
|
cflag = vflag = 0;
|
|
set_flags(); /* [1c2b] */
|
|
}
|
|
|
|
void Magnetic::do_cmp() {
|
|
type8 *tmp;
|
|
|
|
tmp = arg1;
|
|
tmparg[0] = arg1[0];
|
|
tmparg[1] = arg1[1];
|
|
tmparg[2] = arg1[2];
|
|
tmparg[3] = arg1[3];
|
|
arg1 = tmparg;
|
|
quick_flag = 0;
|
|
do_sub(0);
|
|
arg1 = tmp;
|
|
}
|
|
|
|
void Magnetic::do_move() {
|
|
|
|
if (opsize == 0)
|
|
arg1[0] = arg2[0];
|
|
if (opsize == 1)
|
|
write_w(arg1, read_w(arg2));
|
|
if (opsize == 2)
|
|
write_l(arg1, read_l(arg2));
|
|
if (version < 2 || admode != 1) {
|
|
/* Jinxter: no flags if destination Ax */
|
|
cflag = vflag = 0;
|
|
set_flags();
|
|
}
|
|
}
|
|
|
|
type8 Magnetic::do_btst(type8 a) {
|
|
a &= admode ? 0x7 : 0x1f;
|
|
while (admode == 0 && a >= 8) {
|
|
a -= 8;
|
|
arg1 -= 1;
|
|
}
|
|
zflag = 0;
|
|
if ((arg1[0] & (1 << a)) == 0)
|
|
zflag = 0xff;
|
|
return a;
|
|
}
|
|
|
|
void Magnetic::do_bop(type8 b, type8 a) {
|
|
#ifdef LOGEMU
|
|
out("bop (%.2x,%.2x) ", (int) b, (int) a);
|
|
#endif
|
|
b = b & 0xc0;
|
|
a = do_btst(a);
|
|
#ifdef LOGEMU
|
|
if (b == 0x00)
|
|
out("no bop???");
|
|
#endif
|
|
if (b == 0x40) {
|
|
arg1[0] ^= (1 << a); /* bchg */
|
|
#ifdef LOGEMU
|
|
out("bchg");
|
|
#endif
|
|
}
|
|
if (b == 0x80) {
|
|
arg1[0] &= ((1 << a) ^ 0xff); /* bclr */
|
|
#ifdef LOGEMU
|
|
out("bclr");
|
|
#endif
|
|
}
|
|
if (b == 0xc0) {
|
|
arg1[0] |= (1 << a); /* bset */
|
|
#ifdef LOGEMU
|
|
out("bset");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Magnetic::check_btst() {
|
|
#ifdef LOGEMU
|
|
out("btst");
|
|
#endif
|
|
set_info((type8)(byte2 & 0x3f));
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
do_bop(byte2, arg2[0]);
|
|
}
|
|
|
|
void Magnetic::check_lea() {
|
|
#ifdef LOGEMU
|
|
out("lea");
|
|
#endif
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
set_info(byte2);
|
|
opsize = 2;
|
|
set_arg1();
|
|
set_arg2(0, byte1);
|
|
write_w(arg2, 0);
|
|
if (is_reversible)
|
|
write_l(arg2, arg1i);
|
|
else
|
|
ms_fatal("illegal addressing mode for LEA");
|
|
} else {
|
|
ms_fatal("unimplemented instruction CHK");
|
|
}
|
|
}
|
|
|
|
void Magnetic::check_movem() {
|
|
type8 l1c;
|
|
|
|
#ifdef LOGEMU
|
|
out("movem");
|
|
#endif
|
|
set_info((type8)(byte2 - 0x40));
|
|
read_word();
|
|
for (l1c = 0; l1c < 8; l1c++) {
|
|
if (byte2 & 1 << l1c) {
|
|
set_arg1();
|
|
if (opsize == 2)
|
|
write_l(arg1, read_reg(15 - l1c, 2));
|
|
if (opsize == 1)
|
|
write_w(arg1, (type16)read_reg(15 - l1c, 1));
|
|
}
|
|
}
|
|
for (l1c = 0; l1c < 8; l1c++) {
|
|
if (byte1 & 1 << l1c) {
|
|
set_arg1();
|
|
if (opsize == 2)
|
|
write_l(arg1, read_reg(7 - l1c, 2));
|
|
if (opsize == 1)
|
|
write_w(arg1, (type16)read_reg(7 - l1c, 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Magnetic::check_movem2() {
|
|
type8 l1c;
|
|
|
|
#ifdef LOGEMU
|
|
out("movem (2)");
|
|
#endif
|
|
set_info((type8)(byte2 - 0x40));
|
|
read_word();
|
|
for (l1c = 0; l1c < 8; l1c++) {
|
|
if (byte2 & 1 << l1c) {
|
|
set_arg1();
|
|
if (opsize == 2)
|
|
write_reg(l1c, 2, read_l(arg1));
|
|
if (opsize == 1)
|
|
write_reg(l1c, 1, read_w(arg1));
|
|
}
|
|
}
|
|
for (l1c = 0; l1c < 8; l1c++) {
|
|
if (byte1 & 1 << l1c) {
|
|
set_arg1();
|
|
if (opsize == 2)
|
|
write_reg(8 + l1c, 2, read_l(arg1));
|
|
if (opsize == 1)
|
|
write_reg(8 + l1c, 1, read_w(arg1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Magnetic::dict_lookup() {
|
|
type16 dtab, doff, output, output_bak, bank, word, output2;
|
|
type16 tmp16, i, obj_adj, adjlist, adjlist_bak;
|
|
type8 c, c2, c3, flag, matchlen, longest, flag2;
|
|
type8 restartFlag = 0, accept = 0;
|
|
|
|
/*
|
|
dtab=A5.W ;dict_table offset <L22>
|
|
output=output_bak=A2.W ;output <L24>
|
|
A5.W=A6.W ;input word
|
|
doff=A3.W ;lookup offset (doff) <L1C>
|
|
adjlist=A0.W ;adjlist <L1E>
|
|
*/
|
|
|
|
dtab = (type16)read_reg(8 + 5, 1); /* used by version>0 */
|
|
output = (type16)read_reg(8 + 2, 1);
|
|
write_reg(8 + 5, 1, read_reg(8 + 6, 1));
|
|
doff = (type16)read_reg(8 + 3, 1);
|
|
adjlist = (type16)read_reg(8 + 0, 1);
|
|
|
|
bank = (type16)read_reg(6, 0); /* l2d */
|
|
flag = 0; /* l2c */
|
|
word = 0; /* l26 */
|
|
matchlen = 0; /* l2e */
|
|
longest = 0; /* 30e2 */
|
|
write_reg(0, 1, 0); /* apostroph */
|
|
|
|
while ((c = sd ? dict[doff] : effective(doff)[0]) != 0x81) {
|
|
if (c >= 0x80) {
|
|
if (c == 0x82) {
|
|
flag = matchlen = 0;
|
|
word = 0;
|
|
write_reg(8 + 6, 1, read_reg(8 + 5, 1));
|
|
bank++;
|
|
doff++;
|
|
continue;
|
|
}
|
|
c3 = c;
|
|
c &= 0x5f;
|
|
c2 = effective(read_reg(8 + 6, 1))[0] & 0x5f;
|
|
if (c2 == c) {
|
|
write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
|
|
c = effective(read_reg(8 + 6, 1))[0];
|
|
if ((!c) || (c == 0x20) || (c == 0x27) || (!version && (matchlen > 6))) {
|
|
if (c == 0x27) {
|
|
write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
|
|
write_reg(0, 1, 0x200 + effective(read_reg(8 + 6, 1))[0]);
|
|
}
|
|
if ((version < 4) || (c3 != 0xa0))
|
|
accept = 1;
|
|
} else
|
|
restartFlag = 1;
|
|
} else if (!version && matchlen > 6 && !c2)
|
|
accept = 1;
|
|
else
|
|
restartFlag = 1;
|
|
} else {
|
|
c &= 0x5f;
|
|
c2 = effective(read_reg(8 + 6, 1))[0] & 0x5f;
|
|
if ((c2 == c && c) || (version && !c2 && (c == 0x5f))) {
|
|
if (version && !c2 && (c == 0x5f))
|
|
flag = 0x80;
|
|
matchlen++;
|
|
write_reg(8 + 6, 1, read_reg(8 + 6, 1) + 1);
|
|
doff++;
|
|
} else if (!version && matchlen > 6 && !c2)
|
|
accept = 1;
|
|
else
|
|
restartFlag = 1;
|
|
}
|
|
if (accept) {
|
|
effective(read_reg(8 + 2, 1))[0] = (version) ? flag : 0;
|
|
effective(read_reg(8 + 2, 1))[1] = (type8)bank;
|
|
write_w(effective(read_reg(8 + 2, 1) + 2), word);
|
|
write_reg(8 + 2, 1, read_reg(8 + 2, 1) + 4);
|
|
if (matchlen >= longest)
|
|
longest = matchlen;
|
|
restartFlag = 1;
|
|
accept = 0;
|
|
}
|
|
if (restartFlag) {
|
|
write_reg(8 + 6, 1, read_reg(8 + 5, 1));
|
|
flag = matchlen = 0;
|
|
word++;
|
|
if (sd)
|
|
while (dict[doff++] < 0x80);
|
|
else
|
|
while (effective(doff++)[0] < 0x80);
|
|
restartFlag = 0;
|
|
}
|
|
}
|
|
write_w(effective(read_reg(8 + 2, 1)), 0xffff);
|
|
|
|
if (version) {
|
|
/* version > 0 */
|
|
output_bak = output; /* check synonyms */
|
|
while ((c = effective(output)[1]) != 0xff) {
|
|
if (c == 0x0b) {
|
|
if (sd)
|
|
tmp16 = read_w(&dict[dtab + read_w(effective(output + 2)) * 2]);
|
|
else
|
|
tmp16 = read_w(effective(dtab + read_w(effective(output + 2)) * 2));
|
|
effective(output)[1] = tmp16 & 0x1f;
|
|
write_w(effective(output + 2), (type16)(tmp16 >> 5));
|
|
}
|
|
output += 4;
|
|
}
|
|
output = output_bak;
|
|
}
|
|
|
|
/* l22 = output2, l1e = adjlist, l20 = obj_adj, l26 = word, l2f = c2 */
|
|
/* l1c = adjlist_bak, 333C = i, l2d = bank, l2c = flag, l30e3 = flag2 */
|
|
|
|
write_reg(1, 1, 0); /* D1.W=0 [32B5] */
|
|
flag2 = 0;
|
|
output_bak = output;
|
|
output2 = output;
|
|
while ((bank = effective(output2)[1]) != 0xff) {
|
|
obj_adj = (type16)read_reg(8 + 1, 1); /* A1.W - obj_adj, ie. adjs for this word */
|
|
write_reg(1, 0, 0); /* D1.B=0 */
|
|
flag = effective(output2)[0]; /* flag */
|
|
word = read_w(effective(output2 + 2)); /* wordnumber */
|
|
output2 += 4; /* next match */
|
|
if ((read_w(effective(obj_adj))) && (bank == 6)) {
|
|
/* Any adjectives? */
|
|
if ((i = word) != 0) {
|
|
/* Find list of valid adjs */
|
|
do {
|
|
while (effective(adjlist++)[0]);
|
|
} while (--i > 0);
|
|
}
|
|
adjlist_bak = adjlist;
|
|
do {
|
|
adjlist = adjlist_bak;
|
|
c2 = effective(obj_adj)[1]; /* given adjective */
|
|
if ((tmp16 = read_w(effective(obj_adj))) != 0) {
|
|
obj_adj += 2;
|
|
while ((c = effective(adjlist++)[0]) && (c - 3 != c2));
|
|
if (c - 3 != c2)
|
|
write_reg(1, 0, 1); /* invalid adjective */
|
|
}
|
|
} while (tmp16 && !read_reg(1, 0));
|
|
adjlist = (type16)read_reg(8 + 0, 1);
|
|
}
|
|
if (!read_reg(1, 0)) {
|
|
/* invalid_flag */
|
|
flag2 |= flag;
|
|
effective(output)[0] = flag2;
|
|
effective(output)[1] = (type8)bank;
|
|
write_w(effective(output + 2), word);
|
|
output += 4;
|
|
}
|
|
}
|
|
write_reg(8 + 2, 1, output);
|
|
output = output_bak;
|
|
|
|
if (flag2 & 0x80) {
|
|
tmp16 = output;
|
|
output -= 4;
|
|
do {
|
|
output += 4;
|
|
c = effective(output)[0];
|
|
} while (!(c & 0x80));
|
|
write_l(effective(tmp16), read_l(effective(output)) & 0x7fffffff);
|
|
write_reg(8 + 2, 2, tmp16 + 4);
|
|
if (longest > 1) {
|
|
write_reg(8 + 5, 1, read_reg(8 + 5, 1) + longest - 2);
|
|
}
|
|
}
|
|
write_reg(8 + 6, 1, read_reg(8 + 5, 1) + 1);
|
|
}
|
|
|
|
void Magnetic::do_findprop() {
|
|
type16 tmp;
|
|
|
|
if ((version > 2) && ((read_reg(0, 1) & 0x3fff) > fp_size)) {
|
|
tmp = (type16)(((fp_size - (read_reg(0, 1) & 0x3fff)) ^ 0xffff) << 1);
|
|
tmp += fp_tab;
|
|
tmp = read_w(effective(tmp));
|
|
} else {
|
|
if (version < 2)
|
|
write_reg(0, 2, read_reg(0, 2) & 0x7fff);
|
|
else
|
|
write_reg(0, 1, read_reg(0, 1) & 0x7fff);
|
|
tmp = (type16)read_reg(0, 1);
|
|
}
|
|
tmp &= 0x3fff;
|
|
write_reg(8 + 0, 2, tmp * 14 + properties);
|
|
}
|
|
|
|
void Magnetic::write_string() {
|
|
static type32 offset_bak;
|
|
static type8 mask_bak;
|
|
type8 c, b, mask;
|
|
type16 ptr;
|
|
type32 offset;
|
|
|
|
if (!cflag) {
|
|
/* new string */
|
|
ptr = (type16)read_reg(0, 1);
|
|
if (!ptr)
|
|
offset = 0;
|
|
else {
|
|
offset = read_w(&decode_table[0x100 + 2 * ptr]);
|
|
if (read_w(&decode_table[0x100])) {
|
|
if (ptr >= read_w(&decode_table[0x100]))
|
|
offset += string_size;
|
|
}
|
|
}
|
|
mask = 1;
|
|
} else {
|
|
offset = offset_bak;
|
|
mask = mask_bak;
|
|
}
|
|
do {
|
|
c = 0;
|
|
while (c < 0x80) {
|
|
if (offset >= string_size)
|
|
b = string2[offset - string_size];
|
|
else {
|
|
if (offset >= MAX_STRING_SIZE)
|
|
b = string3[offset - MAX_STRING_SIZE];
|
|
else
|
|
b = string[offset];
|
|
}
|
|
if (b & mask)
|
|
c = decode_table[0x80 + c];
|
|
else
|
|
c = decode_table[c];
|
|
mask <<= 1;
|
|
if (!mask) {
|
|
mask = 1;
|
|
offset++;
|
|
}
|
|
}
|
|
c &= 0x7f;
|
|
if (c && ((c != 0x40) || (lastchar != 0x20)))
|
|
char_out(c);
|
|
} while (c && ((c != 0x40) || (lastchar != 0x20)));
|
|
cflag = c ? 0xff : 0;
|
|
if (c) {
|
|
offset_bak = offset;
|
|
mask_bak = mask;
|
|
}
|
|
}
|
|
|
|
void Magnetic::output_number(type16 number) {
|
|
type16 tens = number / 10;
|
|
|
|
if (tens > 0)
|
|
ms_putchar('0' + tens);
|
|
number -= (tens * 10);
|
|
ms_putchar('0' + number);
|
|
}
|
|
|
|
type16 Magnetic::output_text(const char *text) {
|
|
type16 i;
|
|
|
|
for (i = 0; text[i] != 0; i++)
|
|
ms_putchar(text[i]);
|
|
return i;
|
|
}
|
|
|
|
type16s Magnetic::hint_input() {
|
|
type8 c1, c2, c3;
|
|
|
|
output_text(">>");
|
|
ms_flush();
|
|
|
|
do {
|
|
c1 = ms_getchar(0);
|
|
} while (c1 == '\n');
|
|
if (c1 == 1)
|
|
return -1; /* New game loaded, abort hints */
|
|
|
|
c2 = ms_getchar(0);
|
|
if (c2 == 1)
|
|
return -1;
|
|
|
|
/* Get and discard any remaining characters */
|
|
c3 = c2;
|
|
while (c3 != '\n') {
|
|
c3 = ms_getchar(0);
|
|
if (c3 == 1)
|
|
return -1;
|
|
}
|
|
ms_putchar('\n');
|
|
|
|
if ((c1 >= '0') && (c1 <= '9')) {
|
|
type16 number = c1 - '0';
|
|
if ((c2 >= '0') && (c2 <= '9')) {
|
|
number *= 10;
|
|
number += c2 - '0';
|
|
}
|
|
return number;
|
|
}
|
|
|
|
if ((c1 >= 'A') && (c1 <= 'Z'))
|
|
c1 = 'a' + (c1 - 'A');
|
|
if ((c1 >= 'a') && (c1 <= 'z')) {
|
|
switch (c1) {
|
|
case 'e':
|
|
return -2; /* End hints */
|
|
case 'n':
|
|
return -3; /* Next hint */
|
|
case 'p':
|
|
return -4; /* Show parent hint list */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
type16 Magnetic::show_hints_text(ms_hint *hintsData, type16 index) {
|
|
type16 i = 0, j = 0;
|
|
type16s input;
|
|
ms_hint *hint = hintsData + index;
|
|
|
|
while (1) {
|
|
switch (hint->nodetype) {
|
|
|
|
case 1: /* folders */
|
|
output_text("Hint categories:\n");
|
|
for (i = 0, j = 0; i < hint->elcount; i++) {
|
|
output_number(i + 1);
|
|
output_text(". ");
|
|
j += output_text(hint->content + j) + 1;
|
|
ms_putchar('\n');
|
|
}
|
|
output_text("Enter hint category number, ");
|
|
if (hint->parent != 0xffff)
|
|
output_text("P for the parent hint menu, ");
|
|
output_text("or E to end hintsData.\n");
|
|
|
|
input = hint_input();
|
|
switch (input) {
|
|
case -1: /* A new game is being loaded */
|
|
return 1;
|
|
case -2: /* End hintsData */
|
|
return 1;
|
|
case -4: /* Show parent hint list */
|
|
if (hint->parent != 0xffff)
|
|
return 0;
|
|
// fallthrough
|
|
default:
|
|
if ((input > 0) && (input <= hint->elcount)) {
|
|
if (show_hints_text(hintsData, hint->links[input - 1]) == 1)
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 2: /* hintsData */
|
|
if (i < hint->elcount) {
|
|
output_number(i + 1);
|
|
output_text(". ");
|
|
j += output_text(hint->content + j) + 1;
|
|
|
|
if (i == hint->elcount - 1) {
|
|
output_text("\nNo more hintsData.\n");
|
|
return 0; /* Last hint */
|
|
} else {
|
|
output_text("\nEnter N for the next hint, ");
|
|
output_text("P for the parent hint menu, ");
|
|
output_text("or E to end hintsData.\n");
|
|
}
|
|
|
|
input = hint_input();
|
|
switch (input) {
|
|
case -1: /* A new game is being loaded */
|
|
return 1;
|
|
case -2: /* End hintsData */
|
|
return 1;
|
|
case -3:
|
|
i++;
|
|
break;
|
|
case -4: /* Show parent hint list */
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
return 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Magnetic::do_line_a() {
|
|
type8 l1c;
|
|
char *str;
|
|
type16 ptr, ptr2, tmp16, dtype;
|
|
type32 a1reg, tmp32;
|
|
|
|
#ifdef LOGGFX
|
|
/*
|
|
if (((byte2-0xdd) == 4) || ((byte2-0xdd) == 13))
|
|
out2("--> %d\n",byte2-0xdd);
|
|
else
|
|
out2("LINE A %d\n",byte2-0xdd);
|
|
*/
|
|
#endif
|
|
if ((byte2 < 0xdd) || (version < 4 && byte2 < 0xe4) || (version < 2 && byte2 < 0xed)) {
|
|
ms_flush(); /* flush output-buffer */
|
|
rand_emu(); /* Increase game randomness */
|
|
l1c = ms_getchar(1); /* 0 means UNDO */
|
|
if (l1c == 1)
|
|
return;
|
|
if (l1c)
|
|
write_reg(1, 2, l1c); /* d1=getkey() */
|
|
else {
|
|
if ((l1c = ms_undo()) != 0)
|
|
output_text(undo_ok);
|
|
else
|
|
output_text(undo_fail);
|
|
if (!l1c)
|
|
write_reg(1, 2, '\n');
|
|
}
|
|
} else
|
|
switch (byte2 - 0xdd) {
|
|
|
|
case 0: /* A0DD - Won't probably be needed at all */
|
|
break;
|
|
|
|
case 1: /* A0DE */
|
|
write_reg(1, 0, 1); /* Should remove the manual check */
|
|
break;
|
|
|
|
case 2: /* A0DF */
|
|
a1reg = (type32)read_reg(9, 2);
|
|
dtype = (code + a1reg + 2)[0];
|
|
|
|
switch (dtype) {
|
|
case 7: /* Picture */
|
|
#ifdef LOGGFX
|
|
out2("PICTURE IS %s\n", code + a1reg + 3);
|
|
#endif
|
|
/* gfx mode = normal, df is not called if graphics are off */
|
|
ms_showpic(a1reg + 3, 2);
|
|
break;
|
|
|
|
case 10: /* Open window commands */
|
|
switch ((code + a1reg + 3)[0]) {
|
|
case 4: /* Help/Hints */
|
|
if (hints != nullptr) {
|
|
if (ms_showhints(hints) == 0)
|
|
show_hints_text(hints, 0);
|
|
} else
|
|
output_text(no_hints);
|
|
break;
|
|
case 0: /* Carried items */
|
|
case 1: /* Room items */
|
|
case 2: /* Map */
|
|
case 3: /* Compass */
|
|
output_text(not_supported);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 13: /* Music */
|
|
switch ((code + a1reg + 3)[0]) {
|
|
case 0: /* stop music */
|
|
ms_playmusic(nullptr, 0, 0);
|
|
break;
|
|
default: /* play music */
|
|
#ifdef LOGSND
|
|
out2("MUSIC IS %s\n", code + a1reg + 3);
|
|
#endif
|
|
{
|
|
type32 length = 0;
|
|
type16 tempo = 0;
|
|
type8 *midi = sound_extract((const char *)(code + a1reg + 3), &length, &tempo);
|
|
if (midi != nullptr)
|
|
ms_playmusic(midi, length, tempo);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 3: /* A0E0 */
|
|
/* printf("A0E0 stubbed\n"); */
|
|
break;
|
|
|
|
case 4: /* A0E1 Read from keyboard to (A1), status in D1 (0 for ok) */
|
|
ms_flush();
|
|
rand_emu();
|
|
tmp32 = read_reg(8 + 1, 2);
|
|
str = (char *)effective(tmp32);
|
|
tmp16 = 0;
|
|
do {
|
|
if (!(l1c = ms_getchar(1))) {
|
|
if (g_vm->shouldQuit())
|
|
return;
|
|
if ((l1c = ms_undo()) != 0)
|
|
output_text(undo_ok);
|
|
else
|
|
output_text(undo_fail);
|
|
if (!l1c) {
|
|
tmp16 = 0;
|
|
str[tmp16++] = '\n';
|
|
l1c = '\n';
|
|
output_text("\n>");
|
|
} else {
|
|
ms_putchar('\n');
|
|
return;
|
|
}
|
|
} else {
|
|
if (l1c == 1)
|
|
return;
|
|
str[tmp16++] = l1c;
|
|
#ifdef LOGGFX
|
|
out2("%c", l1c);
|
|
#endif
|
|
}
|
|
} while (l1c != '\n' && tmp16 < 256);
|
|
write_reg(8 + 1, 2, tmp32 + tmp16 - 1);
|
|
if (tmp16 != 256 && tmp16 != 1)
|
|
write_reg(1, 1, 0);
|
|
else
|
|
write_reg(1, 1, 1);
|
|
break;
|
|
|
|
case 5: /* A0E2 */
|
|
/* printf("A0E2 stubbed\n"); */
|
|
break;
|
|
|
|
case 6: /* A0E3 */
|
|
if (read_reg(1, 2) == 0) {
|
|
if ((version < 4) || (read_reg(6, 2) == 0))
|
|
ms_showpic(0, 0);
|
|
}
|
|
/* printf("\nMoves: %u\n",read_reg(0,1)); */
|
|
break;
|
|
|
|
case 7: /* A0E4 sp+=4, RTS */
|
|
write_reg(8 + 7, 1, read_reg(8 + 7, 1) + 4);
|
|
pc = pop();
|
|
break;
|
|
|
|
case 8: /* A0E5 set z, RTS */
|
|
case 9: /* A0E6 clear z, RTS */
|
|
pc = pop();
|
|
zflag = (byte2 == 0xe5) ? 0xff : 0;
|
|
break;
|
|
|
|
case 10: /* A0E7 set z */
|
|
zflag = 0xff;
|
|
break;
|
|
|
|
case 11: /* A0E8 clear z */
|
|
zflag = 0;
|
|
break;
|
|
|
|
case 12: /* A0E9 [3083 - j] */
|
|
ptr = (type16)read_reg(8 + 0, 1);
|
|
ptr2 = (type16)read_reg(8 + 1, 1);
|
|
do {
|
|
l1c = dict[ptr2++];
|
|
effective(ptr++)[0] = l1c;
|
|
} while ((l1c & 0x80) == 0);
|
|
write_reg(8 + 0, 1, ptr);
|
|
write_reg(8 + 1, 1, ptr2);
|
|
break;
|
|
|
|
case 13: /* A0EA A1=write_dictword(A1,D1=output_mode) */
|
|
ptr = (type16)read_reg(8 + 1, 1);
|
|
tmp32 = read_reg(3, 0);
|
|
write_reg(3, 0, read_reg(1, 0));
|
|
do {
|
|
l1c = dict[ptr++];
|
|
char_out(l1c);
|
|
} while (l1c < 0x80);
|
|
write_reg(8 + 1, 1, ptr);
|
|
write_reg(3, 0, tmp32);
|
|
break;
|
|
|
|
case 14: /* A0EB [3037 - j] */
|
|
dict[read_reg(8 + 1, 1)] = (type8)read_reg(1, 0);
|
|
break;
|
|
|
|
case 15: /* A0EC */
|
|
write_reg(1, 0, dict[read_reg(8 + 1, 1)]);
|
|
break;
|
|
|
|
case 16:
|
|
ms_stop(); /* infinite loop A0ED */
|
|
break;
|
|
case 17:
|
|
if (!ms_init(nullptr, nullptr, nullptr, nullptr))
|
|
ms_stop(); /* restart game ie. pc, sp etc. A0EE */
|
|
break;
|
|
case 18: /* printer A0EF */
|
|
break;
|
|
case 19:
|
|
ms_showpic(read_reg(0, 0), (type8)read_reg(1, 0)); /* Do_picture(D0) A0F0 */
|
|
break;
|
|
case 20:
|
|
ptr = (type16)read_reg(8 + 1, 1); /* A1=nth_string(A1,D0) A0F1 */
|
|
tmp32 = read_reg(0, 1);
|
|
while (tmp32-- > 0) {
|
|
while (effective(ptr++)[0]);
|
|
}
|
|
write_reg(8 + 1, 1, ptr);
|
|
break;
|
|
|
|
case 21: /* [2a43] A0F2 */
|
|
cflag = 0;
|
|
write_reg(0, 1, read_reg(2, 1));
|
|
do_findprop();
|
|
ptr = (type16)read_reg(8 + 0, 1);
|
|
while (read_reg(2, 1) > 0) {
|
|
if (read_w(effective(ptr + 12)) & 0x3fff) {
|
|
cflag = 0xff;
|
|
break;
|
|
}
|
|
if (read_reg(2, 1) == (read_reg(4, 1) & 0x7fff)) {
|
|
cflag = 0xff;
|
|
break;
|
|
}
|
|
ptr -= 0x0e;
|
|
write_reg(2, 1, read_reg(2, 1) - 1);
|
|
}
|
|
break;
|
|
|
|
case 22:
|
|
char_out((type8)read_reg(1, 0)); /* A0F3 */
|
|
break;
|
|
|
|
case 23: /* D7=Save_(filename A0) D1 bytes starting from A1 A0F4 */
|
|
str = (version < 4) ? (char *)effective(read_reg(8 + 0, 1)) : nullptr;
|
|
write_reg(7, 0, ms_save_file(str, effective(read_reg(8 + 1, 1)),
|
|
(type16)read_reg(1, 1)));
|
|
break;
|
|
|
|
case 24: /* D7=Load_(filename A0) D1 bytes starting from A1 A0F5 */
|
|
str = (version < 4) ? (char *)effective(read_reg(8 + 0, 1)) : nullptr;
|
|
write_reg(7, 0, ms_load_file(str, effective(read_reg(8 + 1, 1)),
|
|
(type16)read_reg(1, 1)));
|
|
break;
|
|
|
|
case 25: /* D1=Random(0..D1-1) [3748] A0F6 */
|
|
l1c = (type8)read_reg(1, 0);
|
|
write_reg(1, 1, rand_emu() % (l1c ? l1c : 1));
|
|
break;
|
|
|
|
case 26: /* D0=Random(0..255) [3742] A0F7 */
|
|
tmp16 = (type16)rand_emu();
|
|
write_reg(0, 0, tmp16 + (tmp16 >> 8));
|
|
break;
|
|
|
|
case 27: /* write string [D0] [2999] A0F8 */
|
|
write_string();
|
|
break;
|
|
|
|
case 28: /* Z,D0=Get_inventory_item(D0) [2a9e] A0F9 */
|
|
zflag = 0;
|
|
ptr = (type16)read_reg(0, 1);
|
|
do {
|
|
write_reg(0, 1, ptr);
|
|
do {
|
|
do_findprop();
|
|
ptr2 = (type16)read_reg(8 + 0, 1); /* object properties */
|
|
if ((effective(ptr2)[5]) & 1)
|
|
break; /* is_described or so */
|
|
l1c = effective(ptr2)[6]; /* some_flags */
|
|
tmp16 = read_w(effective(ptr2 + 8)); /* parent_object */
|
|
if (!l1c) {
|
|
/* ordinary object? */
|
|
if (!tmp16)
|
|
zflag = 0xff; /* return if parent()=player */
|
|
break; /* otherwise try next */
|
|
}
|
|
if (l1c & 0xcc)
|
|
break; /* skip worn, bodypart, room, hidden */
|
|
if (tmp16 == 0) {
|
|
/* return if parent()=player? */
|
|
zflag = 0xff;
|
|
break;
|
|
}
|
|
write_reg(0, 1, tmp16); /* else look at parent() */
|
|
} while (1);
|
|
ptr--;
|
|
} while ((!zflag) && ptr);
|
|
write_reg(0, 1, ptr + 1);
|
|
break;
|
|
|
|
case 29: /* [2b18] A0FA */
|
|
ptr = (type16)read_reg(8, 1);
|
|
do {
|
|
if (read_reg(5, 0)) {
|
|
l1c = ((type32)((read_w(effective(ptr)) & 0x3fff)) == read_reg(2, 1));
|
|
} else {
|
|
l1c = (effective(ptr)[0] == read_reg(2, 0));
|
|
}
|
|
if (read_reg(3, 1) == read_reg(4, 1)) {
|
|
cflag = 0;
|
|
write_reg(8, 1, ptr);
|
|
} else {
|
|
write_reg(3, 1, read_reg(3, 1) + 1);
|
|
ptr += 0x0e;
|
|
if (l1c) {
|
|
cflag = 0xff;
|
|
write_reg(8, 1, ptr);
|
|
}
|
|
}
|
|
} while ((!l1c) && (read_reg(3, 1) != read_reg(4, 1)));
|
|
break;
|
|
|
|
case 30: /* [2bd1] A0FB */
|
|
ptr = (type16)read_reg(8 + 1, 1);
|
|
do {
|
|
if (dict)
|
|
while (dict[ptr++] < 0x80);
|
|
else
|
|
while (effective(ptr++)[0] < 0x80);
|
|
write_reg(2, 1, read_reg(2, 1) - 1);
|
|
} while (read_reg(2, 1));
|
|
write_reg(8 + 1, 1, ptr);
|
|
break;
|
|
|
|
case 31: /* [2c3b] A0FC */
|
|
ptr = (type16)read_reg(8 + 0, 1);
|
|
ptr2 = (type16)read_reg(8 + 1, 1);
|
|
do {
|
|
if (dict)
|
|
while (dict[ptr++] < 0x80);
|
|
else
|
|
while (effective(ptr++)[0] < 0x80);
|
|
while (effective(ptr2++)[0]);
|
|
write_reg(0, 1, read_reg(0, 1) - 1);
|
|
} while (read_reg(0, 1));
|
|
write_reg(8 + 0, 1, ptr);
|
|
write_reg(8 + 1, 1, ptr2);
|
|
break;
|
|
|
|
case 32: /* Set properties pointer from A0 [2b7b] A0FD */
|
|
properties = (type16)read_reg(8 + 0, 1);
|
|
if (version > 0)
|
|
fl_sub = (type16)read_reg(8 + 3, 1);
|
|
if (version > 1) {
|
|
fl_tab = (type16)read_reg(8 + 5, 1);
|
|
fl_size = (type16)read_reg(7, 1) + 1;
|
|
/* A3 [routine], A5 [table] and D7 [table-size] */
|
|
}
|
|
if (version > 2) {
|
|
fp_tab = (type16)read_reg(8 + 6, 1);
|
|
fp_size = (type16)read_reg(6, 1);
|
|
}
|
|
break;
|
|
|
|
case 33: /* A0FE */
|
|
do_findprop();
|
|
break;
|
|
|
|
case 34: /* Dictionary_lookup A0FF */
|
|
dict_lookup();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
type8 Magnetic::ms_rungame() {
|
|
type8 l1c;
|
|
type16 ptr;
|
|
type32 tmp32;
|
|
#ifdef LOGEMU
|
|
static int stat = 0;
|
|
#endif
|
|
|
|
if (!running)
|
|
return running;
|
|
if (pc == undo_pc)
|
|
save_undo();
|
|
|
|
#ifdef LOGEMU
|
|
if (pc == 0x0000)
|
|
stat = 0;
|
|
if (stat) {
|
|
log_status();
|
|
fflush(dbg_log);
|
|
}
|
|
|
|
fprintf(dbg_log, "%.8X: ", pc);
|
|
#endif
|
|
i_count++;
|
|
read_word();
|
|
switch (byte1 >> 1) {
|
|
|
|
/* 00-0F */
|
|
case 0x00:
|
|
if (byte1 == 0x00) {
|
|
if (byte2 == 0x3c || byte2 == 0x7c) {
|
|
/* OR immediate to CCR (30D9) */
|
|
read_word();
|
|
#ifdef LOGEMU
|
|
out("or_ccr #%.2x", byte2);
|
|
#endif
|
|
if (byte2 & 0x01)
|
|
cflag = 0xff;
|
|
if (byte2 & 0x02)
|
|
vflag = 0xff;
|
|
if (byte2 & 0x04)
|
|
zflag = 0xff;
|
|
if (byte2 & 0x08)
|
|
nflag = 0xff;
|
|
} else {
|
|
/* OR [27df] */
|
|
#ifdef LOGEMU
|
|
out("or");
|
|
#endif
|
|
get_arg();
|
|
do_or();
|
|
}
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x01:
|
|
if (byte1 == 0x02) {
|
|
if (byte2 == 0x3c || byte2 == 0x7c) {
|
|
/* AND immediate to CCR */
|
|
read_word();
|
|
#ifdef LOGEMU
|
|
out("and_ccr #%.2x", byte2);
|
|
#endif
|
|
if (!(byte2 & 0x01))
|
|
cflag = 0;
|
|
if (!(byte2 & 0x02))
|
|
vflag = 0;
|
|
if (!(byte2 & 0x04))
|
|
zflag = 0;
|
|
if (!(byte2 & 0x08))
|
|
nflag = 0;
|
|
} else {
|
|
/* AND */
|
|
#ifdef LOGEMU
|
|
out("and");
|
|
#endif
|
|
get_arg();
|
|
do_and();
|
|
}
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x02:
|
|
if (byte1 == 0x04) {
|
|
/* SUB */
|
|
#ifdef LOGEMU
|
|
out("sub");
|
|
#endif
|
|
get_arg();
|
|
do_sub(0);
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x03:
|
|
if (byte1 == 0x06) {
|
|
/* ADD */
|
|
#ifdef LOGEMU
|
|
out("addi");
|
|
#endif
|
|
get_arg();
|
|
do_add(0);
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x04:
|
|
if (byte1 == 0x08) {
|
|
/* bit operations (immediate) */
|
|
set_info((type8)(byte2 & 0x3f));
|
|
l1c = (effective(pc))[1];
|
|
pc += 2;
|
|
set_arg1();
|
|
do_bop(byte2, l1c);
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x05:
|
|
if (byte1 == 0x0a) {
|
|
if (byte2 == 0x3c || byte2 == 0x7c) {
|
|
/* EOR immediate to CCR */
|
|
read_word();
|
|
#ifdef LOGEMU
|
|
out("eor_ccr #%.2X", byte2);
|
|
#endif
|
|
if (byte2 & 0x01)
|
|
cflag ^= 0xff;
|
|
if (byte2 & 0x02)
|
|
vflag ^= 0xff;
|
|
if (byte2 & 0x04)
|
|
zflag ^= 0xff;
|
|
if (byte2 & 0x08)
|
|
nflag ^= 0xff;
|
|
} else {
|
|
/* EOR */
|
|
#ifdef LOGEMU
|
|
out("eor");
|
|
#endif
|
|
get_arg();
|
|
do_eor();
|
|
}
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x06:
|
|
if (byte1 == 0x0c) {
|
|
/* CMP */
|
|
#ifdef LOGEMU
|
|
out("cmp");
|
|
#endif
|
|
get_arg();
|
|
do_cmp();
|
|
} else
|
|
check_btst();
|
|
break;
|
|
|
|
case 0x07:
|
|
check_btst();
|
|
break;
|
|
|
|
/* 10-1F [3327] MOVE.B */
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
|
|
#ifdef LOGEMU
|
|
out("move.b");
|
|
#endif
|
|
set_info((type8)(byte2 & 0x3f));
|
|
set_arg1();
|
|
swap_args();
|
|
l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
|
|
set_info(l1c);
|
|
set_arg1();
|
|
do_move();
|
|
break;
|
|
|
|
/* 20-2F [32d1] MOVE.L */
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
|
|
#ifdef LOGEMU
|
|
out("move.l");
|
|
#endif
|
|
set_info((type8)((byte2 & 0x3f) | 0x80));
|
|
set_arg1();
|
|
swap_args();
|
|
l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
|
|
set_info((type8)(l1c | 0x80));
|
|
set_arg1();
|
|
do_move();
|
|
break;
|
|
|
|
/* 30-3F [3327] MOVE.W */
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
|
|
#ifdef LOGEMU
|
|
out("move.w");
|
|
#endif
|
|
set_info((type8)((byte2 & 0x3f) | 0x40));
|
|
set_arg1();
|
|
swap_args();
|
|
l1c = (byte1 >> 1 & 0x07) | (byte2 >> 3 & 0x18) | (byte1 << 5 & 0x20);
|
|
set_info((type8)(l1c | 0x40));
|
|
set_arg1();
|
|
do_move();
|
|
break;
|
|
|
|
/* 40-4F various commands */
|
|
|
|
case 0x20:
|
|
if (byte1 == 0x40) {
|
|
/* [31d5] */
|
|
ms_fatal("unimplemented instructions NEGX and MOVE SR,xx");
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x21:
|
|
if (byte1 == 0x42) {
|
|
/* [3188] */
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instruction MOVE CCR,xx");
|
|
} else {
|
|
/* CLR */
|
|
#ifdef LOGEMU
|
|
out("clr");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
if (opsize == 0)
|
|
arg1[0] = 0;
|
|
if (opsize == 1)
|
|
write_w(arg1, 0);
|
|
if (opsize == 2)
|
|
write_l(arg1, 0);
|
|
nflag = cflag = 0;
|
|
zflag = 0xff;
|
|
}
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x22:
|
|
if (byte1 == 0x44) {
|
|
/* [31a0] */
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
/* MOVE to CCR */
|
|
#ifdef LOGEMU
|
|
out("move_ccr");
|
|
#endif
|
|
zflag = nflag = cflag = vflag = 0;
|
|
set_info((type8)(byte2 & 0x7f));
|
|
set_arg1();
|
|
byte2 = arg1[1];
|
|
if (byte2 & 0x01)
|
|
cflag = 0xff;
|
|
if (byte2 & 0x02)
|
|
vflag = 0xff;
|
|
if (byte2 & 0x04)
|
|
zflag = 0xff;
|
|
if (byte2 & 0x08)
|
|
nflag = 0xff;
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("neg");
|
|
#endif
|
|
set_info(byte2); /* NEG */
|
|
set_arg1();
|
|
cflag = 0xff;
|
|
if (opsize == 0) {
|
|
arg1[0] = (-arg1[0]);
|
|
cflag = arg1[0] ? 0xff : 0;
|
|
}
|
|
if (opsize == 1) {
|
|
write_w(arg1, (type16)(-1 * read_w(arg1)));
|
|
cflag = read_w(arg1) ? 0xff : 0;
|
|
}
|
|
if (opsize == 2) {
|
|
write_l(arg1, -1 * read_l(arg1));
|
|
cflag = read_l(arg1) ? 0xff : 0;
|
|
}
|
|
vflag = 0;
|
|
set_flags();
|
|
}
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x23:
|
|
if (byte1 == 0x46) {
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instruction MOVE xx,SR");
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("not");
|
|
#endif
|
|
set_info(byte2); /* NOT */
|
|
set_arg1();
|
|
tmparg[0] = tmparg[1] = tmparg[2] = tmparg[3] = 0xff;
|
|
arg2 = tmparg;
|
|
do_eor();
|
|
}
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x24:
|
|
if (byte1 == 0x48) {
|
|
if ((byte2 & 0xf8) == 0x40) {
|
|
#ifdef LOGEMU
|
|
out("swap");
|
|
#endif
|
|
opsize = 2; /* SWAP */
|
|
admode = 0;
|
|
regnr = byte2 & 0x07;
|
|
set_arg1();
|
|
tmp32 = read_w(arg1);
|
|
write_w(arg1, read_w(arg1 + 2));
|
|
write_w(arg1 + 2, (type16)tmp32);
|
|
set_flags();
|
|
} else if ((byte2 & 0xf8) == 0x80) {
|
|
#ifdef LOGEMU
|
|
out("ext.w");
|
|
#endif
|
|
opsize = 1; /* EXT.W */
|
|
admode = 0;
|
|
regnr = byte2 & 0x07;
|
|
set_arg1();
|
|
if (arg1[1] > 0x7f)
|
|
arg1[0] = 0xff;
|
|
else
|
|
arg1[0] = 0;
|
|
set_flags();
|
|
} else if ((byte2 & 0xf8) == 0xc0) {
|
|
#ifdef LOGEMU
|
|
out("ext.l");
|
|
#endif
|
|
opsize = 2; /* EXT.L */
|
|
admode = 0;
|
|
regnr = byte2 & 0x07;
|
|
set_arg1();
|
|
if (read_w(arg1 + 2) > 0x7fff)
|
|
write_w(arg1, 0xffff);
|
|
else
|
|
write_w(arg1, 0);
|
|
set_flags();
|
|
} else if ((byte2 & 0xc0) == 0x40) {
|
|
#ifdef LOGEMU
|
|
out("pea");
|
|
#endif
|
|
set_info((type8)((byte2 & 0x3f) | 0x80)); /* PEA */
|
|
set_arg1();
|
|
if (is_reversible)
|
|
push(arg1i);
|
|
else
|
|
ms_fatal("illegal addressing mode for PEA");
|
|
} else {
|
|
check_movem(); /* MOVEM */
|
|
}
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x25:
|
|
if (byte1 == 0x4a) {
|
|
/* [3219] TST */
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instruction TAS");
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("tst");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
cflag = vflag = 0;
|
|
set_flags();
|
|
}
|
|
} else
|
|
check_lea();
|
|
break;
|
|
|
|
case 0x26:
|
|
if (byte1 == 0x4c)
|
|
check_movem2(); /* [3350] MOVEM.L (Ax)+,A/Dx */
|
|
else
|
|
check_lea(); /* LEA */
|
|
break;
|
|
|
|
case 0x27:
|
|
if (byte1 == 0x4e) {
|
|
/* [3290] */
|
|
if (byte2 == 0x75) {
|
|
/* RTS */
|
|
#ifdef LOGEMU
|
|
out("rts\n");
|
|
#endif
|
|
pc = pop();
|
|
} else if (byte2 == 0x71) {
|
|
/* NOP */
|
|
#ifdef LOGEMU
|
|
out("nop");
|
|
#endif
|
|
} else if ((byte2 & 0xc0) == 0xc0) {
|
|
/* indir JMP */
|
|
#ifdef LOGEMU
|
|
out("jmp");
|
|
#endif
|
|
set_info((type8)(byte2 | 0xc0));
|
|
set_arg1();
|
|
if (is_reversible)
|
|
pc = arg1i;
|
|
else
|
|
ms_fatal("illegal addressing mode for JMP");
|
|
} else if ((byte2 & 0xc0) == 0x80) {
|
|
#ifdef LOGEMU
|
|
out("jsr");
|
|
#endif
|
|
set_info((type8)(byte2 | 0xc0)); /* indir JSR */
|
|
set_arg1();
|
|
push(pc);
|
|
if (is_reversible)
|
|
pc = arg1i;
|
|
else
|
|
ms_fatal("illegal addressing mode for JSR");
|
|
} else {
|
|
ms_fatal("unimplemented instructions 0x4EXX");
|
|
}
|
|
} else
|
|
check_lea(); /* LEA */
|
|
break;
|
|
|
|
/* 50-5F [2ed5] ADDQ/SUBQ/Scc/DBcc */
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
case 0x2c:
|
|
case 0x2d:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
set_info((type8)(byte2 & 0x3f));
|
|
set_arg1();
|
|
if (admode == 1) {
|
|
/* DBcc */
|
|
#ifdef LOGEMU
|
|
out("dbcc");
|
|
#endif
|
|
if (condition(byte1) == 0) {
|
|
arg1 = (arg1 - (type8 *) areg) + (type8 *) dreg - 1;
|
|
write_w(arg1, (type16)(read_w(arg1) - 1));
|
|
if (read_w(arg1) != 0xffff)
|
|
branch(0);
|
|
else
|
|
pc += 2;
|
|
} else
|
|
pc += 2;
|
|
} else {
|
|
/* Scc */
|
|
#ifdef LOGEMU
|
|
out("scc");
|
|
#endif
|
|
arg1[0] = condition(byte1) ? 0xff : 0;
|
|
}
|
|
} else {
|
|
set_info(byte2);
|
|
set_arg1();
|
|
quick_flag = (admode == 1) ? 0xff : 0;
|
|
l1c = byte1 >> 1 & 0x07;
|
|
tmparg[0] = tmparg[1] = tmparg[2] = 0;
|
|
tmparg[3] = l1c ? l1c : 8;
|
|
arg2 = reg_align(tmparg, opsize);
|
|
{
|
|
#ifdef LOGEMU
|
|
type32s outnum = 0;
|
|
switch (opsize) {
|
|
case 0:
|
|
outnum = (type8s) arg2[0];
|
|
break;
|
|
case 1:
|
|
outnum = (type16s) read_w(arg2);
|
|
break;
|
|
case 2:
|
|
outnum = (type32s) read_l(arg2);
|
|
break;
|
|
}
|
|
#endif
|
|
if ((byte1 & 0x01) == 1) {
|
|
#ifdef LOGEMU
|
|
out("subq #%.8X", outnum);
|
|
#endif
|
|
do_sub(0); /* SUBQ */
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("addq #%.8X", outnum);
|
|
#endif
|
|
do_add(0); /* ADDQ */
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* 60-6F [26ba] Bcc */
|
|
|
|
case 0x30:
|
|
if (byte1 == 0x61) {
|
|
/* BRA, BSR */
|
|
#ifdef LOGEMU
|
|
out("bsr");
|
|
#endif
|
|
if (byte2 == 0)
|
|
push(pc + 2);
|
|
else
|
|
push(pc);
|
|
}
|
|
#ifdef LOGEMU
|
|
else
|
|
out("bra");
|
|
#endif
|
|
if ((byte1 == 0x60) && (byte2 == 0xfe)) {
|
|
ms_flush(); /* flush stdout */
|
|
ms_stop(); /* infinite loop - just exit */
|
|
}
|
|
branch(byte2);
|
|
break;
|
|
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
|
|
if (condition(byte1) == 0) {
|
|
#ifdef LOGEMU
|
|
out("beq.s");
|
|
#endif
|
|
if (byte2 == 0)
|
|
pc += 2;
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("bra");
|
|
#endif
|
|
branch(byte2);
|
|
}
|
|
break;
|
|
|
|
/* 70-7F [260a] MOVEQ */
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3a:
|
|
case 0x3b:
|
|
case 0x3c:
|
|
case 0x3d:
|
|
case 0x3e:
|
|
case 0x3f:
|
|
|
|
#ifdef LOGEMU
|
|
out("moveq");
|
|
#endif
|
|
arg1 = (type8 *) & dreg[byte1 >> 1 & 0x07];
|
|
if (byte2 > 127)
|
|
nflag = arg1[0] = arg1[1] = arg1[2] = 0xff;
|
|
else
|
|
nflag = arg1[0] = arg1[1] = arg1[2] = 0;
|
|
arg1[3] = byte2;
|
|
zflag = byte2 ? 0 : 0xff;
|
|
break;
|
|
|
|
/* 80-8F [2f36] */
|
|
case 0x40:
|
|
case 0x41:
|
|
case 0x42:
|
|
case 0x43:
|
|
case 0x44:
|
|
case 0x45:
|
|
case 0x46:
|
|
case 0x47:
|
|
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instructions DIVS and DIVU");
|
|
} else if (((byte2 & 0xf0) == 0) && ((byte1 & 0x01) != 0)) {
|
|
ms_fatal("unimplemented instruction SBCD");
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("or?");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
if ((byte1 & 0x01) == 0)
|
|
swap_args();
|
|
do_or();
|
|
}
|
|
break;
|
|
|
|
/* 90-9F [3005] SUB */
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4a:
|
|
case 0x4b:
|
|
case 0x4c:
|
|
case 0x4d:
|
|
case 0x4e:
|
|
case 0x4f:
|
|
|
|
#ifdef LOGEMU
|
|
out("sub");
|
|
#endif
|
|
quick_flag = 0;
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
if ((byte1 & 0x01) == 1)
|
|
set_info((type8)(byte2 & 0xbf));
|
|
else
|
|
set_info((type8)(byte2 & 0x7f));
|
|
set_arg1();
|
|
set_arg2_nosize(0, byte1);
|
|
swap_args();
|
|
do_sub(1);
|
|
} else {
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
if ((byte1 & 0x01) == 0)
|
|
swap_args();
|
|
do_sub(0);
|
|
}
|
|
break;
|
|
|
|
/* A0-AF various special commands [LINE_A] */
|
|
|
|
case 0x50:
|
|
case 0x56:
|
|
case 0x57: /* [2521] */
|
|
do_line_a();
|
|
#ifdef LOGEMU
|
|
out("LINE_A A0%.2X", byte2);
|
|
#endif
|
|
break;
|
|
|
|
case 0x51:
|
|
#ifdef LOGEMU
|
|
out("rts\n");
|
|
#endif
|
|
pc = pop(); /* RTS */
|
|
break;
|
|
|
|
case 0x52:
|
|
#ifdef LOGEMU
|
|
out("bsr");
|
|
#endif
|
|
if (byte2 == 0)
|
|
push(pc + 2); /* BSR */
|
|
else
|
|
push(pc);
|
|
branch(byte2);
|
|
break;
|
|
|
|
case 0x53:
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
/* TST [321d] */
|
|
ms_fatal("unimplemented instructions LINE_A #$6C0-#$6FF");
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("tst");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
cflag = vflag = 0;
|
|
set_flags();
|
|
}
|
|
break;
|
|
|
|
case 0x54:
|
|
check_movem();
|
|
break;
|
|
|
|
case 0x55:
|
|
check_movem2();
|
|
break;
|
|
|
|
/* B0-BF [2fe4] */
|
|
case 0x58:
|
|
case 0x59:
|
|
case 0x5a:
|
|
case 0x5b:
|
|
case 0x5c:
|
|
case 0x5d:
|
|
case 0x5e:
|
|
case 0x5f:
|
|
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
#ifdef LOGEMU
|
|
out("cmp");
|
|
#endif
|
|
if ((byte1 & 0x01) == 1)
|
|
set_info((type8)(byte2 & 0xbf));
|
|
else
|
|
set_info((type8)(byte2 & 0x7f));
|
|
set_arg1();
|
|
set_arg2(0, byte1);
|
|
swap_args();
|
|
do_cmp(); /* CMP */
|
|
} else {
|
|
if ((byte1 & 0x01) == 0) {
|
|
#ifdef LOGEMU
|
|
out("cmp");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
swap_args();
|
|
do_cmp(); /* CMP */
|
|
} else {
|
|
#ifdef LOGEMU
|
|
out("eor");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
do_eor(); /* EOR */
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* C0-CF [2f52] EXG, AND */
|
|
case 0x60:
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63:
|
|
case 0x64:
|
|
case 0x65:
|
|
case 0x66:
|
|
case 0x67:
|
|
|
|
if ((byte1 & 0x01) == 0) {
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instruction MULU");
|
|
} else {
|
|
/* AND */
|
|
#ifdef LOGEMU
|
|
out("and");
|
|
#endif
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
if ((byte1 & 0x01) == 0)
|
|
swap_args();
|
|
do_and();
|
|
}
|
|
} else {
|
|
if ((byte2 & 0xf8) == 0x40) {
|
|
#ifdef LOGEMU
|
|
out("exg (dx)");
|
|
#endif
|
|
opsize = 2; /* EXG Dx,Dx */
|
|
set_arg2(1, (type8)(byte2 << 1));
|
|
swap_args();
|
|
set_arg2(1, byte1);
|
|
tmp32 = read_l(arg1);
|
|
write_l(arg1, read_l(arg2));
|
|
write_l(arg2, tmp32);
|
|
} else if ((byte2 & 0xf8) == 0x48) {
|
|
opsize = 2; /* EXG Ax,Ax */
|
|
#ifdef LOGEMU
|
|
out("exg (ax)");
|
|
#endif
|
|
set_arg2(0, (type8)(byte2 << 1));
|
|
swap_args();
|
|
set_arg2(0, byte1);
|
|
tmp32 = read_l(arg1);
|
|
write_l(arg1, read_l(arg2));
|
|
write_l(arg2, tmp32);
|
|
} else if ((byte2 & 0xf8) == 0x88) {
|
|
opsize = 2; /* EXG Dx,Ax */
|
|
#ifdef LOGEMU
|
|
out("exg (dx,ax)");
|
|
#endif
|
|
set_arg2(0, (type8)(byte2 << 1));
|
|
swap_args();
|
|
set_arg2(1, byte1);
|
|
tmp32 = read_l(arg1);
|
|
write_l(arg1, read_l(arg2));
|
|
write_l(arg2, tmp32);
|
|
} else {
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
ms_fatal("unimplemented instruction MULS");
|
|
} else {
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
if ((byte1 & 0x01) == 0)
|
|
swap_args();
|
|
do_and();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* D0-DF [2fc8] ADD */
|
|
case 0x68:
|
|
case 0x69:
|
|
case 0x6a:
|
|
case 0x6b:
|
|
case 0x6c:
|
|
case 0x6d:
|
|
case 0x6e:
|
|
case 0x6f:
|
|
|
|
#ifdef LOGEMU
|
|
out("add");
|
|
#endif
|
|
quick_flag = 0;
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
if ((byte1 & 0x01) == 1)
|
|
set_info((type8)(byte2 & 0xbf));
|
|
else
|
|
set_info((type8)(byte2 & 0x7f));
|
|
set_arg1();
|
|
set_arg2_nosize(0, byte1);
|
|
swap_args();
|
|
do_add(1);
|
|
} else {
|
|
set_info(byte2);
|
|
set_arg1();
|
|
set_arg2(1, byte1);
|
|
if ((byte1 & 0x01) == 0)
|
|
swap_args();
|
|
do_add(0);
|
|
}
|
|
break;
|
|
|
|
/* E0-EF [3479] LSR ASL ROR ROL */
|
|
case 0x70:
|
|
case 0x71:
|
|
case 0x72:
|
|
case 0x73:
|
|
case 0x74:
|
|
case 0x75:
|
|
case 0x76:
|
|
case 0x77:
|
|
|
|
#ifdef LOGEMU
|
|
out("lsr,asl,ror,rol");
|
|
#endif
|
|
if ((byte2 & 0xc0) == 0xc0) {
|
|
set_info((type8)(byte2 & 0xbf)); /* OP Dx */
|
|
set_arg1();
|
|
l1c = 1; /* steps=1 */
|
|
byte2 = (byte1 >> 1) & 0x03;
|
|
} else {
|
|
set_info((type8)(byte2 & 0xc7));
|
|
set_arg1();
|
|
if ((byte2 & 0x20) == 0) {
|
|
/* immediate */
|
|
l1c = (byte1 >> 1) & 0x07;
|
|
if (l1c == 0)
|
|
l1c = 8;
|
|
} else {
|
|
l1c = (type8)read_reg(byte1 >> 1 & 0x07, 0);
|
|
}
|
|
byte2 = (byte2 >> 3) & 0x03;
|
|
}
|
|
if ((byte1 & 0x01) == 0) {
|
|
/* right */
|
|
while (l1c-- > 0) {
|
|
if (opsize == 0) {
|
|
cflag = arg1[0] & 0x01 ? 0xff : 0;
|
|
arg1[0] >>= 1;
|
|
if (cflag && (byte2 == 3))
|
|
arg1[0] |= 0x80;
|
|
}
|
|
if (opsize == 1) {
|
|
cflag = read_w(arg1) & 0x01 ? 0xff : 0;
|
|
write_w(arg1, (type16)(read_w(arg1) >> 1));
|
|
if (cflag && (byte2 == 3))
|
|
write_w(arg1, (type16)(read_w(arg1) | ((type16) 1 << 15)));
|
|
}
|
|
if (opsize == 2) {
|
|
cflag = read_l(arg1) & 0x01 ? 0xff : 0;
|
|
write_l(arg1, read_l(arg1) >> 1);
|
|
if (cflag && (byte2 == 3))
|
|
write_l(arg1, read_l(arg1) | ((type32) 1 << 31));
|
|
}
|
|
}
|
|
} else {
|
|
/* left */
|
|
while (l1c-- > 0) {
|
|
if (opsize == 0) {
|
|
cflag = arg1[0] & 0x80 ? 0xff : 0; /* [3527] */
|
|
arg1[0] <<= 1;
|
|
if (cflag && (byte2 == 3))
|
|
arg1[0] |= 0x01;
|
|
}
|
|
if (opsize == 1) {
|
|
cflag = read_w(arg1) & ((type16) 1 << 15) ? 0xff : 0;
|
|
write_w(arg1, (type16)(read_w(arg1) << 1));
|
|
if (cflag && (byte2 == 3))
|
|
write_w(arg1, (type16)(read_w(arg1) | 0x01));
|
|
}
|
|
if (opsize == 2) {
|
|
cflag = read_l(arg1) & ((type32) 1 << 31) ? 0xff : 0;
|
|
write_l(arg1, read_l(arg1) << 1);
|
|
if (cflag && (byte2 == 3))
|
|
write_l(arg1, read_l(arg1) | 0x01);
|
|
}
|
|
}
|
|
}
|
|
set_flags();
|
|
break;
|
|
|
|
/* F0-FF [24f3] LINE_F */
|
|
case 0x78:
|
|
case 0x79:
|
|
case 0x7a:
|
|
case 0x7b:
|
|
case 0x7c:
|
|
case 0x7d:
|
|
case 0x7e:
|
|
case 0x7f:
|
|
|
|
if (version == 0) {
|
|
/* hardcoded jump */
|
|
char_out(l1c = (type8)read_reg(1, 0));
|
|
} else if (version == 1) {
|
|
/* single programmable shortcut */
|
|
push(pc);
|
|
pc = fl_sub;
|
|
} else {
|
|
/* programmable shortcuts from table */
|
|
#ifdef LOGEMU
|
|
out("LINK: %.2X,%.2X", byte1, byte2);
|
|
#endif
|
|
ptr = (byte1 & 7) << 8 | byte2;
|
|
if (ptr >= fl_size) {
|
|
if ((byte1 & 8) == 0)
|
|
push(pc);
|
|
ptr = byte1 << 8 | byte2 | 0x0800;
|
|
ptr = fl_tab + 2 * (ptr ^ 0xffff);
|
|
pc = (type32) ptr + (type16s) read_w(effective(ptr));
|
|
} else {
|
|
push(pc);
|
|
pc = fl_sub;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ms_fatal("Constants aren't and variables don't");
|
|
break;
|
|
}
|
|
#ifdef LOGEMU
|
|
fprintf(dbg_log, "\n");
|
|
#endif
|
|
return running;
|
|
}
|
|
|
|
} // End of namespace Magnetic
|
|
} // End of namespace Glk
|