554 lines
11 KiB
C
Raw Normal View History

2011-06-07 00:00:48 +04:00
#ifndef ENGINES_DREAMGEN_RUNTIME_H__
#define ENGINES_DREAMGEN_RUNTIME_H__
2011-06-05 13:38:05 +04:00
#include <assert.h>
2011-06-07 00:00:48 +04:00
#include "common/scummsys.h"
2011-06-07 00:10:51 +04:00
#include "common/array.h"
2011-06-08 01:03:53 +04:00
#include "common/debug.h"
#include "common/hashmap.h"
2011-06-10 01:48:46 +04:00
#include "common/list.h"
#include "common/ptr.h"
2011-06-05 13:38:05 +04:00
2011-06-12 18:15:06 +04:00
namespace DreamWeb {
class DreamWebEngine;
}
2011-06-16 16:31:17 +04:00
namespace DreamGen {
2011-06-07 00:00:48 +04:00
//fixme: name clash
#undef random
2011-06-05 13:38:05 +04:00
struct Register {
union {
uint16 _value;
uint8 _part[2];
};
2011-06-05 13:38:05 +04:00
inline Register(): _value() {}
2011-06-07 00:10:51 +04:00
inline Register& operator=(uint16 v) { _value = v; return *this; }
2011-06-05 13:38:05 +04:00
inline operator uint16&() { return _value; }
inline void cbw() {
if (_value & 0x80)
_value |= 0xff00;
else
_value &= 0x7f;
2011-06-05 13:38:05 +04:00
}
};
template<int kIndex> //from low to high
2011-06-05 13:38:05 +04:00
struct RegisterPart {
uint8 &_value;
2011-06-05 13:38:05 +04:00
explicit inline RegisterPart(Register &reg) : _value(reg._part[kIndex]) {}
2011-06-05 13:38:05 +04:00
inline operator uint8&() {
return _value;
2011-06-05 13:38:05 +04:00
}
2011-06-05 13:38:05 +04:00
inline RegisterPart& operator=(const RegisterPart& o) {
_value = o._value;
2011-06-05 13:38:05 +04:00
return *this;
}
2011-06-07 00:10:51 +04:00
inline RegisterPart& operator=(uint8 v) {
_value = v;
2011-06-05 13:38:05 +04:00
return *this;
}
};
2011-06-07 22:56:13 +04:00
#ifdef SCUMM_LITTLE_ENDIAN
typedef RegisterPart<0> LowPartOfRegister;
typedef RegisterPart<1> HighPartOfRegister;
#else
typedef RegisterPart<1> LowPartOfRegister;
typedef RegisterPart<0> HighPartOfRegister;
#endif
2011-06-05 13:38:05 +04:00
class WordRef {
2011-06-08 01:03:53 +04:00
uint8 *_data;
unsigned _index;
uint16 _value;
2011-06-05 13:38:05 +04:00
public:
2011-06-08 01:03:53 +04:00
inline WordRef(Common::Array<uint8> &data, unsigned index) : _data(data.begin() + index), _index(index) {
2011-06-05 13:38:05 +04:00
assert(index + 1 < data.size());
2011-06-08 01:03:53 +04:00
_value = _data[0] | (_data[1] << 8);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline WordRef& operator=(const WordRef &ref) {
_value = ref._value;
2011-06-05 13:38:05 +04:00
return *this;
}
2011-06-08 01:03:53 +04:00
2011-06-07 00:10:51 +04:00
inline WordRef& operator=(uint16 v) {
_value = v;
2011-06-05 13:38:05 +04:00
return *this;
}
2011-06-08 01:03:53 +04:00
2011-06-07 00:10:51 +04:00
inline operator uint16&() {
return _value;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline ~WordRef() {
2011-06-08 01:03:53 +04:00
_data[0] = _value & 0xff;
_data[1] = _value >> 8;
_value = _data[0] | (_data[1] << 8);
2011-06-05 13:38:05 +04:00
}
};
struct Segment {
2011-06-07 00:10:51 +04:00
Common::Array<uint8> data;
inline void assign(const uint8 *b, const uint8 *e) {
data.assign(b, e);
}
2011-06-07 00:10:51 +04:00
inline uint8 &byte(unsigned index) {
2011-06-05 13:38:05 +04:00
assert(index < data.size());
return data[index];
}
2011-06-05 13:38:05 +04:00
inline WordRef word(unsigned index) {
return WordRef(data, index);
}
2011-06-08 01:38:12 +04:00
inline uint8* ptr(unsigned index, unsigned size) {
assert(index + size <= data.size());
return data.begin() + index;
}
2011-06-05 13:38:05 +04:00
};
2011-06-10 01:48:46 +04:00
typedef Common::SharedPtr<Segment> SegmentPtr;
class Context;
2011-06-05 13:38:05 +04:00
class SegmentRef {
2011-06-10 01:48:46 +04:00
Context *_context;
uint16 _value;
SegmentPtr _segment;
public:
2011-06-10 01:48:46 +04:00
SegmentRef(Context *ctx, uint16 value = 0, SegmentPtr segment = SegmentPtr()): _context(ctx), _value(value), _segment(segment) {
2011-06-05 13:38:05 +04:00
}
inline void reset(uint16 value);
2011-06-07 00:10:51 +04:00
inline SegmentRef& operator=(const uint16 id) {
2011-06-07 02:34:27 +04:00
reset(id);
2011-06-05 13:38:05 +04:00
return *this;
}
inline SegmentRef& operator=(const SegmentRef &ref) {
_context = ref._context;
_value = ref._value;
_segment = ref._segment;
return *this;
}
2011-06-07 00:10:51 +04:00
inline uint8 &byte(unsigned index) {
assert(_segment != 0);
return _segment->byte(index);
2011-06-05 13:38:05 +04:00
}
2011-06-07 00:10:51 +04:00
inline operator uint16() const {
return _value;
2011-06-05 13:38:05 +04:00
}
inline WordRef word(unsigned index) {
//debug(1, "getting word ref for %04x:%d", _value, index);
assert(_segment != 0);
return _segment->word(index);
2011-06-05 13:38:05 +04:00
}
inline void assign(const uint8 *b, const uint8 *e) {
assert(_segment != 0);
_segment->assign(b, e);
}
2011-06-08 01:38:12 +04:00
inline uint8* ptr(unsigned index, unsigned size) {
assert(_segment != 0);
return _segment->ptr(index, size);
}
2011-06-05 13:38:05 +04:00
};
struct Flags {
bool _z, _c, _s, _o;
inline Flags(): _z(true), _c(false), _s(false), _o(false) {}
2011-06-09 01:23:37 +04:00
inline bool z() const { return _z; }
inline bool c() const { return _c; }
inline bool s() const { return _s; }
2011-06-12 23:08:19 +04:00
inline bool l() const { return _o != _s; }
inline bool le() const { return _o != _s|| _z; }
2011-06-05 13:38:05 +04:00
2011-06-12 19:53:48 +04:00
inline void update_zs(uint8 v) {
2011-06-09 01:35:40 +04:00
_s = v & 0x80;
2011-06-05 13:38:05 +04:00
_z = v == 0;
}
2011-06-12 19:53:48 +04:00
inline void update_zs(uint16 v) {
2011-06-09 01:35:40 +04:00
_s = v & 0x8000;
2011-06-05 13:38:05 +04:00
_z = v == 0;
}
2011-06-09 01:35:40 +04:00
2011-06-12 23:08:19 +04:00
inline void update_o(uint8 v, uint8 a, uint8 b) {
uint8 s1 = a & 0x80, s2 = b & 0x80;
_o = (s1 == s2) && (v & 0x80) != s1;
}
2011-06-12 23:08:19 +04:00
inline void update_o(uint16 v, uint16 a, uint16 b) {
uint16 s1 = a & 0x8000, s2 = b & 0x8000;
_o = (s1 == s2) && (v & 0x8000) != s1;
2011-06-09 01:35:40 +04:00
}
2011-06-05 13:38:05 +04:00
};
class Context {
2011-06-10 01:48:46 +04:00
typedef Common::HashMap<uint16, SegmentPtr> SegmentMap;
SegmentMap _segments;
2011-06-10 01:48:46 +04:00
typedef Common::List<uint16> FreeSegmentList;
FreeSegmentList _freeSegments;
2011-06-12 18:15:06 +04:00
public:
2011-06-12 18:15:06 +04:00
DreamWeb::DreamWebEngine *engine;
enum { kDefaultDataSegment = 0x1000 };
2011-06-12 18:15:06 +04:00
2011-06-05 13:38:05 +04:00
Register ax, dx, bx, cx, si, di;
LowPartOfRegister al;
HighPartOfRegister ah;
LowPartOfRegister bl;
HighPartOfRegister bh;
LowPartOfRegister cl;
HighPartOfRegister ch;
LowPartOfRegister dl;
HighPartOfRegister dh;
2011-06-12 18:15:06 +04:00
SegmentRef cs, ds, es, data;
//data == fake segment register always pointing to data segment
2011-06-05 13:38:05 +04:00
Flags flags;
2011-06-12 18:15:06 +04:00
inline Context(): engine(0), al(ax), ah(ax), bl(bx), bh(bx), cl(cx), ch(cx), dl(dx), dh(dx),
cs(this), ds(this), es(this), data(this) {
2011-06-10 01:48:46 +04:00
_segments[kDefaultDataSegment] = SegmentPtr(new Segment());
2011-06-07 00:56:23 +04:00
cs.reset(kDefaultDataSegment);
ds.reset(kDefaultDataSegment);
es.reset(kDefaultDataSegment);
data.reset(kDefaultDataSegment);
}
2011-06-08 01:03:53 +04:00
SegmentRef getSegment(uint16 value) {
SegmentMap::iterator i = _segments.find(value);
assert(i != _segments.end());
2011-06-10 01:48:46 +04:00
return SegmentRef(this, value, i->_value);
}
2011-06-08 01:03:53 +04:00
SegmentRef allocateSegment(uint size) {
2011-06-10 01:48:46 +04:00
unsigned id;
if (_freeSegments.empty())
id = kDefaultDataSegment + _segments.size();
else {
id = _freeSegments.front();
_freeSegments.pop_front();
}
assert(!_segments.contains(id));
2011-06-10 01:48:46 +04:00
SegmentPtr seg(new Segment());
seg->data.resize(size);
_segments[id] = seg;
return SegmentRef(this, id, seg);
}
void deallocateSegment(uint16 id) {
SegmentMap::iterator i = _segments.find(id);
assert(i != _segments.end());
_segments.erase(i);
_freeSegments.push_back(id);
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _cmp(uint8 a, uint8 b) {
_sub(a, b);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _cmp(uint16 a, uint16 b) {
_sub(a, b);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _test(uint8 a, uint8 b) {
_and(a, b);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _test(uint16 a, uint16 b) {
_and(a, b);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _add(uint8 &dst, uint8 src) {
2011-06-08 03:12:14 +04:00
unsigned r = (unsigned)dst + src;
2011-06-12 23:08:19 +04:00
flags.update_o((uint8)r, dst, src);
2011-06-08 03:12:14 +04:00
flags._c = r >= 0x100;
dst = r;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _add(uint16 &dst, uint16 src) {
2011-06-08 03:12:14 +04:00
unsigned r = (unsigned)dst + src;
2011-06-12 23:08:19 +04:00
flags.update_o((uint16)r, dst, src);
2011-06-08 03:12:14 +04:00
flags._c = r >= 0x10000;
dst = r;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _sub(uint8 &dst, uint8 src) {
2011-06-12 23:08:19 +04:00
flags.update_o(uint8(dst - src), dst, (uint8)-src);
2011-06-05 13:38:05 +04:00
flags._c = dst < src;
dst -= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _sub(uint16 &dst, uint16 src) {
2011-06-12 23:08:19 +04:00
flags.update_o(uint16(dst - src), dst, (uint16)-src);
2011-06-05 13:38:05 +04:00
flags._c = dst < src;
dst -= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-12 20:10:17 +04:00
}
inline void _inc(uint8 &dst) {
2011-06-12 23:08:19 +04:00
flags.update_o((uint8)(dst + 1), dst, 1);
2011-06-12 20:10:17 +04:00
++dst;
flags.update_zs(dst);
}
inline void _inc(uint16 &dst) {
2011-06-12 23:08:19 +04:00
flags.update_o((uint16)(dst + 1), dst, 1);
2011-06-12 20:10:17 +04:00
++dst;
flags.update_zs(dst);
}
inline void _dec(uint8 &dst) {
2011-06-12 23:08:19 +04:00
flags.update_o(uint8(dst - 1), dst, 1);
2011-06-12 20:10:17 +04:00
--dst;
flags.update_zs(dst);
}
inline void _dec(uint16 &dst) {
2011-06-12 23:08:19 +04:00
flags.update_o(uint16(dst - 1), dst, 1);
2011-06-12 20:10:17 +04:00
--dst;
flags.update_zs(dst);
2011-06-05 13:38:05 +04:00
}
inline void _and(uint8 &dst, uint8 src) {
dst &= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _and(uint16 &dst, uint16 src) {
dst &= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _or(uint8 &dst, uint8 src) {
dst |= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _or(uint16 &dst, uint16 src) {
dst |= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
inline void _xor(uint8 &dst, uint8 src) {
dst ^= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _xor(uint16 &dst, uint16 src) {
dst ^= src;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
flags._c = flags._o = false;
2011-06-05 13:38:05 +04:00
}
2011-06-08 03:12:14 +04:00
inline void _shr(uint8 &dst, uint8 src) {
src &= 0x1f;
if (src > 0) {
2011-06-08 03:12:14 +04:00
dst >>= (src - 1);
flags._c = dst & 1;
dst >>= 1;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-08 03:12:14 +04:00
}
if (src == 1)
flags._o = dst & 0x80;
2011-06-08 03:12:14 +04:00
}
2011-06-08 03:12:14 +04:00
inline void _shr(uint16 &dst, uint8 src) {
src &= 0x1f;
if (src > 0) {
2011-06-08 03:12:14 +04:00
dst >>= (src - 1);
flags._c = dst & 1;
dst >>= 1;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-08 03:12:14 +04:00
}
if (src == 1)
flags._o = dst & 0x8000;
2011-06-08 03:12:14 +04:00
}
2011-06-08 03:12:14 +04:00
inline void _shl(uint8 &dst, uint8 src) {
src &= 0x1f;
if (src > 0) {
2011-06-08 03:12:14 +04:00
dst <<= (src - 1);
flags._c = dst & 0x80;
dst <<= 1;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-08 03:12:14 +04:00
}
if (src == 1)
flags._o = ((dst & 0x80) != 0) == flags._c;
2011-06-08 03:12:14 +04:00
}
inline void _shl(uint16 &dst, uint8 src) {
src &= 0x1f;
if (src > 0) {
2011-06-08 03:12:14 +04:00
dst <<= (src - 1);
flags._c = dst & 0x8000;
dst <<= 1;
2011-06-12 19:53:48 +04:00
flags.update_zs(dst);
2011-06-08 03:12:14 +04:00
}
if (src == 1)
flags._o = ((dst & 0x8000) != 0) == flags._c;
2011-06-08 03:12:14 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _mul(uint8 src) {
unsigned r = unsigned(al) * src;
ax = (uint16)r;
flags._c = r >= 0x10000;
flags._z = r == 0;
2011-06-09 01:35:40 +04:00
flags._s = r & 0x8000;
flags._o = ah != 0;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _mul(uint16 src) {
unsigned r = unsigned(ax) * src; //assuming here that we have at least 32 bits
dx = (r >> 16) & 0xffff;
ax = r & 0xffff;
flags._c = false;
2011-06-05 13:38:05 +04:00
flags._z = r == 0;
2011-06-09 01:35:40 +04:00
flags._s = r & 0x80000000;
flags._o = dx != 0;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _neg(uint8 &src) {
2011-06-12 21:45:29 +04:00
uint8 r = 0;
_sub(r, src);
src = r;
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _neg(uint16 &src) {
2011-06-12 21:45:29 +04:00
uint16 r = 0;
_sub(r, src);
src = r;
2011-06-05 13:38:05 +04:00
}
inline void _lodsb() {
al = ds.byte(si++);
}
inline void _lodsw() {
ax = ds.word(si);
si += 2;
}
2011-06-05 13:38:05 +04:00
inline void _movsb() {
es.byte(di++) = ds.byte(si++);
}
2011-06-08 01:03:53 +04:00
inline void _movsb(uint size) {
uint8 *dst = es.ptr(di, size);
uint8 *src = ds.ptr(si, size);
memcpy(dst, src, size);
di += size;
si += size;
}
2011-06-05 13:38:05 +04:00
inline void _movsw() {
2011-06-10 02:29:05 +04:00
_movsb();
_movsb();
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
inline void _movsw(uint size) {
_movsb(size * 2);
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _stosb() {
es.byte(di++) = al;
}
2011-06-08 01:03:53 +04:00
inline void _stosb(uint size) {
uint8 *dst = es.ptr(di, size);
memset(dst, al, size);
di += size;
}
2011-06-05 13:38:05 +04:00
inline void _stosw() {
es.byte(di++) = al;
es.byte(di++) = ah;
}
inline void _stosw(uint size) {
uint8 *dst = es.ptr(di, size);
di += 2 * size;
while(size--) {
*dst++ = al;
*dst++ = ah;
}
2011-06-05 13:38:05 +04:00
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline void _xchg(uint16 &a, uint16 &b) {
uint16 x = a;
a = b;
b = x;
}
inline void _xchg(uint8 &a, uint8 &b) {
uint8 t = a;
a = b;
b = t;
}
2011-06-07 00:10:51 +04:00
Common::Array<uint16> stack;
2011-06-05 13:38:05 +04:00
inline void push(uint16 v) {
stack.push_back(v);
}
2011-06-08 01:03:53 +04:00
2011-06-05 13:38:05 +04:00
inline uint16 pop() {
2011-06-10 00:53:20 +04:00
assert(!stack.empty());
2011-06-05 13:38:05 +04:00
uint16 v = stack.back();
stack.pop_back();
return v;
}
};
inline void SegmentRef::reset(uint16 value) {
*this = _context->getSegment(value);
}
class StackChecker {
const Context &_context;
const uint _stackDepth;
public:
StackChecker(const Context &context): _context(context), _stackDepth(context.stack.size()) {}
~StackChecker() { assert(_context.stack.size() == _stackDepth); }
};
#ifndef NDEBUG
# define STACK_CHECK(context) StackChecker checker(context)
#else
# define STACK_CHECK(context) do {} while (0)
#endif
}
2011-06-05 13:38:05 +04:00
#endif