UMIX OS

大した理由も無いが、2年前(1年半前)に参加したICFP2006(http://icfpcontest.org/)のUMIX動作をするコードを置いてみる。そこそこ探して公開されてるルーチンを漁ったが、ベンチマークでは一応一番速く動いてくれる。なので今更やってみたいなんて人がいるんならUMIXを作った後の状態からどーぞ。

メモリ管理についてはNULLアドレス以外では

  1. 本来の容量+1をアロケートする
  2. サイズを0番目に記入
  3. +1したアドレスを返すことで普通に使える

という処理をしている。もちろんfreeするときにはアドレスを-1する必要がある。
……という点まで含めてどこかの誰か(海外)のパクり。

ちなみに、ログインのためのユーザーとかパスワードなんて知ったこっちゃない。そこは自分で探しておくれ。

追記で注意…64bit OSだと動かないですよ。ポインタとplatter(32bit unsigned int)を相互変換してるんで。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned int uint;
typedef unsigned char uchar;

uint* prog = NULL;
uint r[] = {0, 0, 0, 0, 0, 0, 0, 0};
uint pc = 0;

uint* alloc(uint size)
{
  uint* p = (uint*)calloc(size + 1, sizeof(uint));
  p[0] = size;
  return (p + 1);
}

int init(int argc, char* argv[])
{
  uint zsize, size, dsize, i;
  FILE* fp;

  if( (fp = fopen((argc > 1) ? argv[1] : "sandmark.umz", "rb")) == NULL )
    return 1;
  fseek(fp, 0, SEEK_END);
  zsize = ftell(fp);
  rewind(fp);
  printf("Program size = %d Byte\n", zsize);

  zsize *= 2;
  prog = (uint*)malloc(zsize);

  size = dsize = 0;
  do {
    size += dsize;
    dsize = fread(prog + size, 1, zsize - size, fp);
  } while( dsize > 0 );
  fclose(fp);

  size /= sizeof(uint);

  /* LE -> BE */
  for( i = 0 ; i < size ; i++ ) {
    uchar *t = (uchar*)&prog[i];
    prog[i] = ((((((uint)t[0] << 8) | t[1]) << 8) | t[2]) << 8) | t[3];
  }

  return 0;
}

int main(int argc, char* argv[])
{
  uint a, b, c, code, ope;

  if( init(argc, argv) ) {
    free(prog);
    return 1;
  }

  while( 1 ) {
    code = prog[pc++];
    ope = (code >> 28) & 15;

    if( ope == 13 ) {
      a = (code >> 25) & 7;
      r[a] = code & 0x1ffffff;
      continue;
    }

    if( ope < 7 ) {
      a = (code >> 6) & 7;
      b = (code >> 3) & 7;
      c = code & 7;

      switch( ope ) {
      case 0:
        if( r[c] ) r[a] = r[b];
        break;
      case 1:
        if( r[b] ) r[a] = ((uint*)r[b])[r[c]];
        else r[a] = prog[r[c]];
        break;
      case 2:
        if( r[a] ) ((uint*)r[a])[r[b]] = r[c];
        else prog[r[b]] = r[c];
        break;
      case 3:  r[a] = r[b] + r[c];            break;
      case 4:  r[a] = r[b] * r[c];            break;
      case 5:  r[a] = r[b] / r[c];            break;
      case 6:  r[a] = ~(r[b] & r[c]);         break;
      }
      continue;
    }

    switch( ope ) {
    case 7:  goto HALT;
    case 8:
      r[(code >> 3) & 7] = (uint)alloc(r[code & 7]);
      break;
    case 9:
      free((uint*)r[code & 7] - 1);
      break;
    case 10:
      putchar(r[code & 7]);
      fflush(stdout);
      break;
    case 11:
      r[code & 7] = getchar();
      break;
    case 12:
      b = (code >> 3) & 7;
      if( r[b] ) {
        int size = *((uint*)r[b] - 1);
        prog = (uint*)realloc((void*)prog, size * sizeof(uint));
        memcpy(prog, (void*)r[b], size * sizeof(uint));
      }
      pc = r[code & 7];
      break;
    default:
      printf("Unknown operation %u\n", ope);
      goto HALT;
    }
  }
 HALT:

  return 0;
}