|
|
|
|
File: [venge] / src / loopcode / LoopCore.cc
(download)
Revision: 1.1.1.1 (vendor branch), Wed Feb 2 07:48:34 2000 UTC (10 years, 7 months ago) by graydon Branch: vengeance, MAIN CVS Tags: start, HEAD Changes since 1.1: +0 -0 lines importing |
#include <iostream>
/**
* This is a cheap loopcode virtual machine
* Copyright (C) 2000 Vengeance
* written by graydon hoare <graydon@pobox.com>
* released under the terms of the GNU GPL V2.0+
**/
struct LoopCore {
typedef unsigned int LWord;
typedef unsigned short LoopId;
typedef unsigned short OpCode;
typedef struct {LWord addr; LWord count;} Loop;
enum WType {
u32, s32, f32, // literals
u32a, u64a, s32a, s64a, f32a, f64a // addresses
};
enum opCodes {
code_lup=1, code_nxt, code_hlt, code_adv,
code_anz, code_aeq, code_ale, code_alt,
code_mov=64, code_add, code_sub, code_mod,
code_mul, code_div, code_rst, code_lst,
code_not, code_and, code_ior, code_xor
};
// machine state
LWord ip;
LWord codeSz;
LWord dataSz;
LWord loopSz;
LWord *myData;
LWord *myCode;
Loop *myLoops;
protected:
/***************************
* opcode inspection methods
**************************/
inline OpCode opcode() { return (myCode[ip] >> 18) & (LWord)(16383); }
inline unsigned char argCount() { return static_cast<unsigned char>((myCode[ip] >> 16) & (LWord)(4)); }
inline LoopId arg0() { return static_cast<unsigned char>(myCode[ip] & (LWord)(65535)); }
inline bool isAddr(WType t) { return t > f32; }
template<int i> inline LWord arg() { return myCode[ip+i]; }
template<int i> inline WType ty() {
return static_cast<WType>((myCode[ip] >> (4*i)) & (LWord)(15));
}
/**********************
* control flow methods
*********************/
inline void op_adv(LWord amount) {
if (ip+amount >= codeSz) return err("advanced outside code region");
ip += amount;
}
inline void incr() { op_adv(argCount()+1); }
template <class T> inline void op_anz() {
LWord amount = get<LWord,1>();
if (static_cast<T>(0) == get<T,2>()) return incr();
if (ip+amount >= codeSz) return err("advanced outside code region");
ip += amount;
}
template <class T> inline void op_aeq() {
LWord amount = get<LWord,1>();
if (!(get<T,2>() == get<T,3>())) return incr();
if (ip+amount >= codeSz) return err("advanced outside code region");
ip += amount;
}
template <class T> inline void op_alt() {
LWord amount = get<LWord,1>();
if (!(get<T,2>() < get<T,3>())) return incr();
if (ip+amount >= codeSz) return err("advanced outside code region");
ip += amount;
}
template <class T> inline void op_ale() {
LWord amount = get<LWord,1>();
if (!(get<T,2>() <= get<T,3>())) return incr();
if (ip+amount >= codeSz) return err("advanced outside code region");
ip += amount;
}
inline void end() { end(0,0); }
inline void end(LWord start, LWord len) { exit(0); }
inline void err(char *e) {cerr << "error: " << e << endl; end();}
inline void setLoop(LoopId id, LWord len, LWord addr) {
if (id >= loopSz) return err("invalid loop ID in setLoop");
if (addr >= codeSz) return err("invalid code addr in setLoop");
myLoops[id].addr=addr; myLoops[id].count=len;
}
inline void nextLoop(LoopId id) {
if ((id < loopSz) && (myLoops[id].count > 0)) {
ip = myLoops[id].addr;
}
}
/***********************
* memory access methods
**********************/
template<class T, int i> inline T get() {
LWord a = arg<i>();
if (isAddr(ty<i>())) {
if (a >= dataSz) {
err("attempt to get outside data region");
return static_cast<T>(0); // dummy return
} else {
return *(reinterpret_cast<T*>(&(myData[a])));
}
}
void *pa = &a;
return *(reinterpret_cast<T*>(pa));
}
template <class T> inline void put(T val, LWord addr) {
if (addr >= dataSz) return err("attempt to put outsize data region");
myData[addr] = *(reinterpret_cast<LWord*>(&val));
}
/**************************
* type-sensitive operators
*************************/
template<class T> void op_mov() {put(get<T,1>(),get<T,2>());}
template<class T> void op_add() {put(get<T,1>() + get<T,2>(), get<LWord,3>());}
template<class T> void op_sub() {put(get<T,1>() - get<T,2>(), get<LWord,3>());}
template<class T> void op_mul() {put(get<T,1>() * get<T,2>(), get<LWord,3>());}
template<class T> void op_div() {
T divisor = get<T,2>();
if (divisor == static_cast<T>(0)) err("divide by zero");
put(get<T,1>() * divisor, get<LWord,3>());
}
template<class T> void op_mod() {put(get<T,1>() % get<T,2>(), get<LWord,3>());}
template<class T> void op_rst() {put(get<T,1>() >> get<T,2>(), get<LWord,3>());}
template<class T> void op_lst() {put(get<T,1>() << get<T,2>(), get<LWord,3>());}
template<class T> void op_and() {put(get<T,1>() & get<T,2>(), get<LWord,3>());}
template<class T> void op_ior() {put(get<T,1>() | get<T,2>(), get<LWord,3>());}
template<class T> void op_xor() {put(get<T,1>() ^ get<T,2>(), get<LWord,3>());}
template<class T> void op_not() {put(~get<T,1>(), get<LWord,3>());}
public:
LoopCore(int code, int data, int loop) {
myCode = new LWord[code];
codeSz = code;
myData = new LWord[data];
dataSz = data;
myLoops = new Loop[code];
loopSz = loop;
ip = 0;
}
/*******************
* inner interpreter
******************/
#define STD_OPCODE(name,arglen,argty1,argty2,argty3) ((((LWord)name) << 18) | \
((((LWord)arglen) & 3) << 16) | \
((((LWord)argty1) & 15) << 12) | \
((((LWord)argty2) & 15) << 8) | \
((((LWord)argty3) & 15) << 4))
#define PACKED_OPCODE(name,arglen) ((((LWord)name) << 18) | \
((((LWord)arglen) & 3) << 16))
void run() {
while(ip < codeSz) {
switch (myCode[ip]) {
case PACKED_OPCODE(code_lup,1): setLoop(arg0(),arg<1>(),ip+argCount()+1); incr(); break;
case PACKED_OPCODE(code_nxt,0): nextLoop(arg0()); break;
case STD_OPCODE(code_hlt,2,u32,u32,0):
case STD_OPCODE(code_hlt,2,u32a,u32,0):
case STD_OPCODE(code_hlt,2,u32,u32a,0):
case STD_OPCODE(code_hlt,2,u32a,u32a,0): end(get<LWord,1>(), get<LWord,2>()); break;
case STD_OPCODE(code_adv,1,u32,0,0):
case STD_OPCODE(code_adv,1,u32a,0,0): op_adv(get<LWord,1>()); break;
case STD_OPCODE(code_anz,2,u32,u32,0):
case STD_OPCODE(code_anz,2,u32,u32a,0): op_anz<unsigned int>(); break;
case STD_OPCODE(code_anz,2,u32,s32,0):
case STD_OPCODE(code_anz,2,u32,s32a,0): op_anz<signed int>(); break;
case STD_OPCODE(code_anz,2,u32,f32,0):
case STD_OPCODE(code_anz,2,u32,f32a,0): op_anz<float>(); break;
case STD_OPCODE(code_anz,2,u32,u64a,0): op_anz<unsigned long>(); break;
case STD_OPCODE(code_anz,2,u32,s64a,0): op_anz<signed long>(); break;
case STD_OPCODE(code_anz,2,u32,f64a,0): op_anz<double>(); break;
#define ADVANCE_VARIANT(cmp) \
case STD_OPCODE(code_## cmp,3,u32,u32,u32): \
case STD_OPCODE(code_## cmp,3,u32,u32a,u32): \
case STD_OPCODE(code_## cmp,3,u32,u32,u32a): \
case STD_OPCODE(code_## cmp,3,u32,u32a,u32a): op_## cmp<unsigned int>(); break; \
case STD_OPCODE(code_## cmp,3,u32,s32,s32): \
case STD_OPCODE(code_## cmp,3,u32,s32a,s32): \
case STD_OPCODE(code_## cmp,3,u32,s32,s32a): \
case STD_OPCODE(code_## cmp,3,u32,s32a,s32a): op_## cmp<signed int>(); break; \
case STD_OPCODE(code_## cmp,3,u32,f32,f32): \
case STD_OPCODE(code_## cmp,3,u32,f32a,f32): \
case STD_OPCODE(code_## cmp,3,u32,f32,f32a): \
case STD_OPCODE(code_## cmp,3,u32,f32a,f32a): op_## cmp<float>(); break; \
case STD_OPCODE(code_## cmp,3,u32,u64a,u64a): op_## cmp<unsigned long>(); break; \
case STD_OPCODE(code_## cmp,3,u32,s64a,s64a): op_## cmp<signed long>(); break; \
case STD_OPCODE(code_## cmp,3,u32,f64a,f64a): op_## cmp<double>(); break;
ADVANCE_VARIANT(aeq)
ADVANCE_VARIANT(ale)
ADVANCE_VARIANT(alt)
case STD_OPCODE(code_mov,2,u32,u32a,0):
case STD_OPCODE(code_mov,2,u32a,u32a,0): op_mov<LWord>(); incr(); break;
#define ALL_NUMERIC_TYPES_OPCODE(c) \
case STD_OPCODE(code_## c,3,u32,u32,u32a): \
case STD_OPCODE(code_## c,3,u32a,u32,u32a): \
case STD_OPCODE(code_## c,3,u32,u32a,u32a): \
case STD_OPCODE(code_## c,3,u32a,u32a,u32a): op_## c<unsigned int>(); incr(); break; \
case STD_OPCODE(code_## c,3,s32,s32,s32a): \
case STD_OPCODE(code_## c,3,s32a,s32,s32a): \
case STD_OPCODE(code_## c,3,s32,s32a,s32a): \
case STD_OPCODE(code_## c,3,s32a,s32a,s32a): op_## c<signed int>(); incr(); break; \
case STD_OPCODE(code_## c,3,f32,f32,f32a): \
case STD_OPCODE(code_## c,3,f32a,f32,f32a): \
case STD_OPCODE(code_## c,3,f32,f32a,f32a): \
case STD_OPCODE(code_## c,3,f32a,f32a,f32a): op_## c<float>(); incr(); break; \
case STD_OPCODE(code_## c,3,u64a,u64a,u64a): op_## c<unsigned long>(); incr(); break; \
case STD_OPCODE(code_## c,3,s64a,s64a,s64a): op_## c<signed long>(); incr(); break; \
case STD_OPCODE(code_## c,3,f64a,f64a,f64a): op_## c<double>(); incr(); break;
ALL_NUMERIC_TYPES_OPCODE(add)
ALL_NUMERIC_TYPES_OPCODE(sub)
ALL_NUMERIC_TYPES_OPCODE(mul)
ALL_NUMERIC_TYPES_OPCODE(div)
#define ALL_INTEGRAL_TYPES_OPCODE(c) \
case STD_OPCODE(code_## c,3,u32,u32,u32a): \
case STD_OPCODE(code_## c,3,u32a,u32,u32a): \
case STD_OPCODE(code_## c,3,u32,u32a,u32a): \
case STD_OPCODE(code_## c,3,u32a,u32a,u32a): op_## c<unsigned int>(); incr(); break; \
case STD_OPCODE(code_## c,3,s32,s32,s32a): \
case STD_OPCODE(code_## c,3,s32a,s32,s32a): \
case STD_OPCODE(code_## c,3,s32,s32a,s32a): \
case STD_OPCODE(code_## c,3,s32a,s32a,s32a): op_## c<signed int>(); incr(); break; \
case STD_OPCODE(code_## c,3,u64a,u64a,u64a): op_## c<unsigned long>(); incr(); break; \
case STD_OPCODE(code_## c,3,s64a,s64a,s64a): op_## c<signed long>(); incr(); break;
ALL_INTEGRAL_TYPES_OPCODE(mod)
ALL_INTEGRAL_TYPES_OPCODE(rst)
ALL_INTEGRAL_TYPES_OPCODE(lst)
ALL_INTEGRAL_TYPES_OPCODE(and)
ALL_INTEGRAL_TYPES_OPCODE(ior)
ALL_INTEGRAL_TYPES_OPCODE(xor)
ALL_INTEGRAL_TYPES_OPCODE(not)
default: err("invalid opcode"); break;
}
}
}
};
// !!FIXME!! this needs to load the code from somewhere.
// at the moment it just starts processing at a null opcode
// and exits.
void main(int argc, char **argv) {
char *rev = "$Revision: 1.1.1.1 $";
cout << "loopcode " << rev << endl;
LoopCore c(65536,65536,256);
c.run();
}
| graydon hoare |
Powered by ViewCVS 0.9.2 |