(file) Return to LoopCore.cc CVS log (file) (dir) Up to [venge] / src / loopcode

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