Page 1 of 1

Super Hack VM sources

Posted: Wed May 21, 2014 10:54 pm
by SemmZemm
Hi,

I can't understand how the threads in Super HVM work and the sources seem unaccessible. Could some of admins fix it please?

Posted: Thu May 22, 2014 2:31 am
by CodeX
My memory can be a little bit fuzzy but I think the PHP class for handling SuperHack went something exactly like this

Code: Select all

<?php
class SHVM {
  public $MAX_CYCLES = 10000;
  private $movin = array(array(1, 0), array(0, -1), array(-1, 0), array(0, 1));
  //  public $MEM_HEIGHT = 8;
  public $MEM_HEIGHT = 128;
  public $MEM_WIDTH = 1024;
  public $MAX_THREADS = 32;
  private $timeToQuit = false;
  
  public $Memory = array();
  public $Threads = array();
  public $Code = array();
  public $user_input = array();
  public $trace = false;
  private $t = NULL;
  public $cycle_count = 0;
			 
  private function InitStuff() {
    $this->timeToQuit = false;
    $this->Code = array();
    $this->Memory = array();
    for ($i = 0; $i < $this->MEM_HEIGHT; $i++) {
      $this->Memory[$i] = array_fill(0, $this->MEM_WIDTH, 0);
	 }
    $this->Threads = array();
    $this->t = array();
    $this->t['pcX'] = 0; $this->t['pcY'] = 0;
    $this->t['mX'] = -1; $this->t['mY'] = 0;
    $this->t['dir'] = 0;
    $this->t['cs'] = array();
    $this->Threads[0] = $this->t;
  }
  
  private function Push($v) {
    if ($v > 2147483647 || $v < -2147483648) throw new Exception("integer overflow: '$v'");
    $this->t['mX'] += 1;
    $this->Memory[$this->t['mY']][$this->t['mX']] = $v;
  }
  
    private function Pop() {
      if ($this->t['mX'] < 0) throw new Exception("stack underflow");
      $v = $this->Memory[$this->t['mY']][$this->t['mX']];
      $this->t['mX'] -= 1;
      return $v;
    }

   private function MoveOneStep() {
     $this->t['pcX'] += $this->movin[$this->t['dir']][0];
     $this->t['pcY'] += $this->movin[$this->t['dir']][1];
   }
  
  function Run($code, $mem_init, $traceIt = false) {
    $this->InitStuff();

    $output = "";
    $message = "";
    $result = 0;
    
    $lines = preg_split('/[\n\r]+/', $code);
	 //	 print_r($lines);
    for ($y = 0; $y < count($lines); $y++) {
		$this->Code[$y] = array();
      for ($x = 0; $x < strlen($lines[$y]); $x++) {
		  $c = $lines[$y][$x];
		  $this->Code[$y][$x] = $c;
		  if ($c == '%') {
			 $this->Threads[0]['pcX'] = $x;
			 $this->Threads[0]['pcY'] = $y;
		  }
      }
    }

    // initialize the memory
    $mem_init_cells = explode(",", $mem_init);
    for ($i=0; $i<count($mem_init_cells); $i++) {
      $this->user_input[$i] = (int)trim($mem_init_cells[$i]);
    }
	 $this->user_input = array_reverse($this->user_input);
    
    // run loop
    try {
      while (!$this->timeToQuit) {
        // check that we don't exceed the max
        if ($this->cycle_count++ > $this->MAX_CYCLES) throw new Exception('too many cycles: ' . $this->cycle_count);
		  for ($tindex = 0; $tindex < count($this->Threads); $tindex++) {
			 $this->t =& $this->Threads[$tindex];
			 // some convenience vars
			 $t =& $this->t;
			 $pcX =& $t['pcX']; $pcY =& $t['pcY'];
			 $mX =& $t['mX']; $mY =& $t['mY'];
			 $mem =& $this->Memory;
			 $dir =& $t['dir'];
			 //			 print_r($this->t);
			 if ($pcY < 0 || $pcX < 0) throw new Exception('out of code bounds');
			 
			 if (!isset($this->Code[$pcY])) {
				$s = 'undefined code vert: ' . $mX.",xxxxxx". $pcX;
				throw new Exception($s);
			 }
			 if (!isset($this->Code[$pcY][$pcX])) throw new Exception('undefined code: ' . $pcY.",". $pcX);
			 $instruction = $this->Code[$t['pcY']][$pcX];
			 $ox = $pcX; $oy = $pcY;

			 if ($traceIt) echo "[Thread $tindex] <b>$instruction</b> @$ox,$oy [".implode(',', array_slice($this->Memory[$mY], 0, $mX + 1) )."]\n<br>";
			 //			 if ($traceIt) echo "[Thread $tindex] <b>$instruction</b> @$ox,$oy [".implode(',', array_splice(0, $this->Memory[$this->t['mY']], $mX + 1))."]\n<br>";

			 // instruction dispatch
			 switch ($instruction) {
			 case ' ': break;
			 case '0': $this->Push(0); break;
			 case '1': $this->Push(1); break;
			 case '2': $this->Push(2); break;
			 case '3': $this->Push(3); break;
			 case '4': $this->Push(4); break;
			 case '5': $this->Push(5); break;
			 case '6': $this->Push(6); break;
			 case '7': $this->Push(7); break;
			 case '8': $this->Push(8); break;
			 case '9': $this->Push(9); break;
			 case '+': $this->Push($this->Pop()+$this->Pop()); break;

			 case '-': $a = $this->Pop(); $b = $this->Pop(); $this->Push($b-$a); break;
			 case '*': $this->Push($this->Pop()*$this->Pop()); break;
			 case 'd': $a = $this->Pop(); $b = $this->Pop(); $this->Push(floor($b/$a)); break;
			 case '\\': $dir = ($dir ^ 3); break;
			 case '/': $dir = ($dir ^ 1); break;
			 case 'p': $output .= $this->Pop(); break;
			 case 'P': $output .= chr($this->Pop()&0x7F); break;
			 case ':': $a = $this->Pop(); $b = $this->Pop(); if ($b<$a) $dir = ($dir + 1) % 4; else if ($b > $a) $dir = ($dir + 3) % 4; break;
				//	case ':': $a = $this->Pop(); $b = $this->Pop(); $this->Push( ($b<$a)?-1:(($b==$a)?0:1)); break;
			 case ',': if (count($this->user_input) > 0) $this->Push(array_pop($this->user_input)); else $this->Push(0); break;
			 case 's': $this->MoveOneStep(); break;
			 case '?': $a = $this->Pop(); if ($a == 0) $this->MoveOneStep(); break;
			 case '@':
				array_push($this->t['cs'], array($pcX, $pcY, $dir));
				break;
			 case '$':
				if (count($this->t['cs']) == 0) throw new Exception("call stack underflow");
				$c = array_pop($this->t['cs']);
				$pcX = $c[0]; $pcY = $c[1]; $dir = $c[2];
				$this->MoveOneStep();
				break;
			 case '<':
				$x = $this->Pop(); $y = $this->Pop();
				if ($x < 0 || $y < 0) throw new Exception('memory read access violation @'.$x.",".$y);
				if ($y >= count($this->Memory))
				  $this->Push(0);
				else {
				  $this->Push($this->Memory[$y][$x]);
				}
				break;
			 case '>':
				$x = $this->Pop(); $y = $this->Pop();
				if ($x < 0 || $y < 0) throw new Exception('memory read access violation @'.$x.",".$y);
				$val = $this->Pop();
				$this->Memory[$y][$x] = $val;
				//	  print_r($mem);
				break;
			 case '[': $i = $this->Pop(); $mX -= $i; break; 
			 case ']': $i = $this->Pop(); $mX += $i; break; 
			 case '{': $mY--; if ($mY < 0) throw new Exception("mem cannot go neg"); break;
			 case '}': $mY++; if ($mY == $this->MEM_HEIGHT) throw new Exception("mem too big"); break; 
			 case 'x': $a = $this->Pop(); $this->Push($a); $this->Push($a); break; 
			 case '^': $a = $this->Pop(); 
				if ($a < 0 || $mX < $a) throw new Exception("out of mem bounds: $a, $mX");
				$this->Push($this->Memory[$mY][$mX - $a]); break;
			 case 'v':
				$a = $this->Pop(); 
				if ($a < 0 || $mX < $a) throw new Exception("out of mem bounds: $a, $mX");
				$v = array_splice($this->Memory[$mY], $mX - $a, 1);
				array_splice($this->Memory[$mY], $mX, 0, $v[0]); // insert value at mem
				break;
			 case 'g':
				$x = $this->Pop(); $y = $this->Pop();
				$v = ord($this->Code[$y][$x]);
				$this->Push($v);
				break;
			 case 'w':
				$x = $this->Pop(); $y = $this->Pop(); $c = $this->Pop();
				$this->Code[$y][$x] = chr($c & 0x7f);
				break;
			 case '&':
				if (count($this->Threads) == $this->MAX_THREADS) throw new Exception("max threads exceeded: " . $this->MAX_THREADS);
				$nt = array();
				$nt['pcX'] = $pcX; $nt['pcY'] = $pcY;
				$nt['mX'] = $mX; $nt['mY'] = $mY;
				$nt['dir'] = $dir;
				$nt['cs'] = array();
				$nt['pcX'] += $this->movin[$dir][0];
				$nt['pcY'] += $this->movin[$dir][1];
				array_push($this->Threads, $nt);
				$this->MoveOneStep();
				break;
			 case '!': $this->timeToQuit = true; break;
			 default: break;
			 }
			 
			 $this->MoveOneStep();
		  }
      }
    } catch (Exception $e) {
      $message = $e->getMessage() . " (PC=" . ($this->t['pcX'] . ", " . $this->t['pcY']) . ")";
      $result = -1;
      //      print_r($this);
    }
    
    return array("result" => $result, "message" => $message, "cycles" => $this->cycle_count, "output" => $output);
  }
}
?>

Posted: Thu May 22, 2014 7:04 pm
by SemmZemm
thanks a lot!