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"
|
2011-06-07 00:20:43 +04:00
|
|
|
#include "common/hashmap.h"
|
2011-06-05 13:38:05 +04:00
|
|
|
|
2011-06-07 00:35:48 +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 {
|
2011-06-07 03:23:57 +04:00
|
|
|
uint16 _value;
|
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 &= 0xff;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-06-07 22:52:06 +04:00
|
|
|
template<int Mask, int Shift>
|
2011-06-05 13:38:05 +04:00
|
|
|
struct RegisterPart {
|
2011-06-07 03:23:57 +04:00
|
|
|
Register &_reg;
|
|
|
|
uint8 _value;
|
2011-06-05 13:38:05 +04:00
|
|
|
|
2011-06-07 22:56:13 +04:00
|
|
|
explicit inline RegisterPart(Register ®) : _reg(reg), _value(reg._value >> Shift) {}
|
2011-06-05 13:38:05 +04:00
|
|
|
|
|
|
|
inline operator uint8&() {
|
2011-06-07 03:23:57 +04:00
|
|
|
return _value;
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
|
|
|
inline RegisterPart& operator=(const RegisterPart& o) {
|
2011-06-07 03:23:57 +04:00
|
|
|
_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) {
|
2011-06-07 03:23:57 +04:00
|
|
|
_value = v;
|
2011-06-05 13:38:05 +04:00
|
|
|
return *this;
|
|
|
|
}
|
2011-06-07 03:23:57 +04:00
|
|
|
inline ~RegisterPart() {
|
2011-06-08 00:46:36 +04:00
|
|
|
_reg._value = (_reg._value & ~Mask) | (_value << Shift);
|
2011-06-07 03:23:57 +04:00
|
|
|
}
|
2011-06-05 13:38:05 +04:00
|
|
|
};
|
2011-06-07 22:56:13 +04:00
|
|
|
|
2011-06-07 22:52:06 +04:00
|
|
|
typedef RegisterPart<0xff, 0> LowPartOfRegister;
|
|
|
|
typedef RegisterPart<0xff00, 8> HighPartOfRegister;
|
2011-06-05 13:38:05 +04:00
|
|
|
|
2011-06-07 00:20:43 +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
|
|
|
|
2011-06-07 00:20:43 +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);
|
|
|
|
debug(1, "word ref %d -> 0x%04x", _index, _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& operator=(const WordRef &ref) {
|
2011-06-07 00:20:43 +04:00
|
|
|
_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) {
|
2011-06-07 00:20:43 +04:00
|
|
|
_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&() {
|
2011-06-07 00:20:43 +04:00
|
|
|
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
|
|
|
debug(1, "writing %d -> 0x%04x", _index, _value);
|
|
|
|
_data[0] = _value & 0xff;
|
|
|
|
_data[1] = _value >> 8;
|
|
|
|
_value = _data[0] | (_data[1] << 8);
|
|
|
|
debug(1, "word ref result %d -> 0x%04x", _index, _value);
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Segment {
|
2011-06-07 00:10:51 +04:00
|
|
|
Common::Array<uint8> data;
|
2011-06-07 00:35:48 +04:00
|
|
|
|
|
|
|
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-07 00:35:48 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline WordRef word(unsigned index) {
|
|
|
|
return WordRef(data, index);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-06-07 00:35:48 +04:00
|
|
|
class Context;
|
2011-06-05 13:38:05 +04:00
|
|
|
|
2011-06-07 00:20:43 +04:00
|
|
|
class SegmentRef {
|
2011-06-07 00:35:48 +04:00
|
|
|
Context *_context;
|
|
|
|
uint16 _value;
|
|
|
|
Segment *_segment;
|
2011-06-07 00:20:43 +04:00
|
|
|
|
|
|
|
public:
|
2011-06-07 00:53:47 +04:00
|
|
|
SegmentRef(Context *ctx, uint16 value = 0, Segment *segment = 0): _context(ctx), _value(value), _segment(segment) {
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
2011-06-07 00:20:43 +04:00
|
|
|
|
2011-06-07 00:53:47 +04:00
|
|
|
inline void reset(uint16 value);
|
2011-06-07 00:20:43 +04:00
|
|
|
|
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;
|
|
|
|
}
|
2011-06-07 00:20:43 +04:00
|
|
|
|
2011-06-07 00:10:51 +04:00
|
|
|
inline uint8 &byte(unsigned index) {
|
2011-06-07 00:20:43 +04:00
|
|
|
assert(_segment != 0);
|
|
|
|
return _segment->byte(index);
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
2011-06-07 00:20:43 +04:00
|
|
|
|
2011-06-07 00:10:51 +04:00
|
|
|
inline operator uint16() const {
|
2011-06-07 00:20:43 +04:00
|
|
|
return _value;
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline WordRef word(unsigned index) {
|
2011-06-07 00:20:43 +04:00
|
|
|
assert(_segment != 0);
|
|
|
|
return _segment->word(index);
|
2011-06-05 13:38:05 +04:00
|
|
|
}
|
2011-06-07 00:53:47 +04:00
|
|
|
|
|
|
|
inline void assign(const uint8 *b, const uint8 *e) {
|
|
|
|
assert(_segment != 0);
|
|
|
|
_segment->assign(b, e);
|
|
|
|
}
|
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) {}
|
|
|
|
|
|
|
|
inline bool z() const { return _z; }
|
|
|
|
inline bool c() const { return _c; }
|
|
|
|
inline bool s() const { return _s; }
|
|
|
|
//complex flags:
|
|
|
|
inline bool g() const { return !_z && _s == _o; }
|
|
|
|
inline bool ge() const { return _z || _s == _o; }
|
|
|
|
inline bool l() const { return !_z && _s != _o; }
|
|
|
|
inline bool le() const { return _z || _s != _o; }
|
|
|
|
|
2011-06-07 22:56:13 +04:00
|
|
|
inline void update(uint8 v) {
|
2011-06-07 00:20:43 +04:00
|
|
|
bool new_s = v & 0x80;
|
|
|
|
_o = new_s != _s;
|
|
|
|
_s = new_s;
|
2011-06-05 13:38:05 +04:00
|
|
|
_z = v == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void update(uint16 v) {
|
2011-06-07 00:20:43 +04:00
|
|
|
bool new_s = v & 0x8000;
|
|
|
|
_o = new_s != _s;
|
|
|
|
_s = new_s;
|
2011-06-05 13:38:05 +04:00
|
|
|
_z = v == 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-06-07 00:35:48 +04:00
|
|
|
class Context {
|
2011-06-07 00:53:47 +04:00
|
|
|
typedef Common::HashMap<uint16, Segment> SegmentMap;
|
|
|
|
SegmentMap _segments;
|
2011-06-07 00:35:48 +04:00
|
|
|
|
|
|
|
public:
|
2011-06-07 00:56:23 +04:00
|
|
|
enum { kDefaultDataSegment = 0x1000 };
|
2011-06-07 00:53:47 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
Register ax, dx, bx, cx, si, di;
|
2011-06-07 22:52:06 +04:00
|
|
|
LowPartOfRegister al;
|
|
|
|
HighPartOfRegister ah;
|
|
|
|
LowPartOfRegister bl;
|
|
|
|
HighPartOfRegister bh;
|
|
|
|
LowPartOfRegister cl;
|
|
|
|
HighPartOfRegister ch;
|
|
|
|
LowPartOfRegister dl;
|
|
|
|
HighPartOfRegister dh;
|
2011-06-05 13:38:05 +04:00
|
|
|
|
|
|
|
SegmentRef cs, ds, es;
|
|
|
|
Flags flags;
|
|
|
|
|
2011-06-07 00:35:48 +04:00
|
|
|
inline Context(): al(ax), ah(ax), bl(bx), bh(bx), cl(cx), ch(cx), dl(dx), dh(dx), cs(this), ds(this), es(this) {
|
2011-06-07 00:53:47 +04:00
|
|
|
_segments[kDefaultDataSegment] = Segment();
|
2011-06-07 00:56:23 +04:00
|
|
|
cs.reset(kDefaultDataSegment);
|
|
|
|
ds.reset(kDefaultDataSegment);
|
|
|
|
es.reset(kDefaultDataSegment);
|
2011-06-07 00:35:48 +04:00
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-07 00:53:47 +04:00
|
|
|
SegmentRef getSegment(uint16 value) {
|
|
|
|
SegmentMap::iterator i = _segments.find(value);
|
|
|
|
assert(i != _segments.end());
|
|
|
|
return SegmentRef(this, value, &i->_value);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-07 02:26:37 +04:00
|
|
|
SegmentRef allocateSegment(uint size) {
|
|
|
|
unsigned id = kDefaultDataSegment + _segments.size();
|
|
|
|
assert(!_segments.contains(id));
|
|
|
|
Segment &seg = _segments[id];
|
|
|
|
seg.data.resize(size);
|
|
|
|
return SegmentRef(this, id, &seg);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _cmp(uint8 a, uint8 b) {
|
|
|
|
uint8 x = a;
|
|
|
|
_sub(x, b);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _cmp(uint16 a, uint16 b) {
|
|
|
|
uint16 x = a;
|
|
|
|
_sub(x, b);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _test(uint8 a, uint8 b) {
|
|
|
|
uint8 x = a;
|
|
|
|
_and(x, b);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _test(uint16 a, uint16 b) {
|
|
|
|
uint16 x = a;
|
|
|
|
_and(x, b);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _add(uint8 &dst, uint8 src) {
|
|
|
|
flags._c = dst + src < dst;
|
|
|
|
dst += src;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _add(uint16 &dst, uint16 src) {
|
|
|
|
flags._c = dst + src < dst;
|
|
|
|
dst += src;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _sub(uint8 &dst, uint8 src) {
|
|
|
|
flags._c = dst < src;
|
|
|
|
dst -= src;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _sub(uint16 &dst, uint16 src) {
|
|
|
|
flags._c = dst < src;
|
|
|
|
dst -= src;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void _and(uint8 &dst, uint8 src) {
|
|
|
|
dst &= src;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
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;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
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;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
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;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void _xor(uint8 &dst, uint8 src) {
|
|
|
|
dst ^= src;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
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;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(dst);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void _shr(uint8 &dst, uint8 src) {}
|
|
|
|
inline void _shr(uint16 &dst, uint8 src) {}
|
|
|
|
inline void _shl(uint8 &dst, uint8 src) {}
|
|
|
|
inline void _shl(uint16 &dst, uint8 src) {}
|
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;
|
|
|
|
bool s = r & 0x8000;
|
|
|
|
flags._o = s != flags._s;
|
|
|
|
flags._s = s;
|
|
|
|
}
|
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;//fixme
|
|
|
|
flags._z = r == 0;
|
|
|
|
bool s = r & 0x80000000;
|
|
|
|
flags._o = s != flags._s;
|
|
|
|
flags._s = s;
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _neg(uint8 &src) {
|
|
|
|
src = ~src;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(src);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _neg(uint16 &src) {
|
|
|
|
src = ~src;
|
|
|
|
flags._c = false;
|
|
|
|
flags.update(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void _movsb() {
|
|
|
|
es.byte(di++) = ds.byte(si++);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _movsw() {
|
|
|
|
es.word(di) = ds.word(si);
|
|
|
|
di += 2;
|
|
|
|
si += 2;
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _lodsb() {
|
|
|
|
al = ds.byte(si++);
|
|
|
|
}
|
2011-06-08 01:03:53 +04:00
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _lodsw() {
|
|
|
|
ax = ds.word(si);
|
|
|
|
si += 2;
|
|
|
|
}
|
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
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
inline void _stosw() {
|
2011-06-07 11:47:41 +04:00
|
|
|
es.word(di) = ax;
|
2011-06-05 13:38:05 +04:00
|
|
|
di += 2;
|
|
|
|
}
|
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() {
|
|
|
|
uint16 v = stack.back();
|
|
|
|
stack.pop_back();
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-06-07 00:53:47 +04:00
|
|
|
inline void SegmentRef::reset(uint16 value) {
|
|
|
|
*this = _context->getSegment(value);
|
|
|
|
}
|
|
|
|
|
2011-06-07 00:35:48 +04:00
|
|
|
}
|
|
|
|
|
2011-06-05 13:38:05 +04:00
|
|
|
#endif
|
|
|
|
|