Skip to content

Instantly share code, notes, and snippets.

@DrakiaXYZ
Created August 30, 2012 03:47
Show Gist options
  • Save DrakiaXYZ/3522117 to your computer and use it in GitHub Desktop.
Save DrakiaXYZ/3522117 to your computer and use it in GitHub Desktop.
Stack Machine Emulator
<?php
class StackMachine {
public $PC;
public $SP;
public $IR;
public $SIR;
public $fault;
public $halt;
public $MEM;
public $step = 0;
public $callStack;
function __construct() {
$this->MEM = array_fill(0, pow(2, 16) - 1, '00000000');
$this->reset();
}
function readFile($file) {
$fh = fopen($file, 'r');
$i = 0;
while (!feof($fh)) {
$line = fgets($fh);
if ($line == '') continue;
$this->MEM[$i] = substr($line, 0, 8);
$i++;
}
fclose($fh);
}
function run() {
while (!$this->halt && !$this->fault) {
$this->step();
}
}
function step() {
if ($this->fault || $this->halt) return;
// Safety measure for infinite loops.
$this->step++;
if ($this->step > 10000) {
$this->fault = 1;
$this->halt = 1;
print 'Inifite loop! Ending program execution!'."\n\n";
return;
}
// End safety measure.
$this->IR = $this->MEM[$this->PC];
$this->set_fault();
if (!$this->fault) {
$this->PC += 1;
$this->callStack[] = $this->IR;
$this->exec();
}
}
function set_fault() {
$tmp = base_convert($this->IR, 2, 10);
$this->fault = intval($tmp <= 0 || $tmp > 13);
if ($this->fault) {
print 'Fault on line '.$this->PC."\n";
print 'Line Contents: '.$this->MEM[$this->PC]."\n";
}
}
function set_flags() {
$this->N(substr($this->s1(), 0, 1));
$this->Z(($this->s1() == '00000000') ? '1' : '0');
}
function reset() {
$this->PC = 0;
$this->SP = 0xFFFA;
$this->halt = 0;
$this->fault = 0;
}
function exec() {
switch($this->IR) {
case '00000001': // HALT
$this->halt = 1;
break;
case '00000010': // PUSHIMM
$this->MEM[$this->SP] = $this->MEM[$this->PC];
$this->SP -= 1;
$this->PC += 1;
break;
case '00000011': // PUSHEXT
$this->MEM[$this->SP] = $this->MEM[$this->ext()];
$this->SP -= 1;
$this->PC += 2;
break;
case '00000100': // POPINH
$this->SP += 1;
break;
case '00000101': // POPEXT
$this->MEM[$this->ext()] = $this->s1();
$this->SP += 1;
$this->PC += 2;
break;
case '00000110': // JNZ
if ($this->Z() == '0')
$this->PC = $this->ext();
else
$this->PC += 2;
break;
case '00000111': // ADD
$tmp = base_convert($this->s1(), 2, 10) + base_convert($this->s2(), 2, 10);
$tmp = str_pad(base_convert($tmp, 10, 2), 8, '0', STR_PAD_LEFT);
$this->MEM[$this->SP + 2] = $tmp;
$this->SP += 1;
$this->set_flags();
break;
case '00001000': // SUB
$tmp = base_convert($this->s1(), 2, 10) - base_convert($this->s2(), 2, 10);
$tmp = str_pad(base_convert($tmp, 10, 2), 8, '0', STR_PAD_LEFT);
$this->MEM[$this->SP + 2] = $tmp;
$this->SP += 1;
$this->set_flags();
break;
case '00001001': // NOR
$tmp = $this->NOR($this->s1(), $this->s2());
$this->MEM[$this->SP + 2] = $tmp;
$this->SP += 1;
break;
case '00001010': // JNN
if ($this->N() == '0')
$this->PC = $this->ext();
else
$this->PC += 2;
break;
case '00001011': // SIRSP
$this->SIR = $this->SP;
break;
case '00001100': // PUSHIND
$this->MEM[$this->SP] = $this->MEM[$this->SIR + base_convert($this->ii, 2, 10)];
$this->PC += 1;
$this->SP -= 1;
break;
case '00001101': // POPIND
$this->SP += 1;
$this->PC += 1;
$this->MEM[$this->SIR + base_convert($this->ii, 2, 10)] = $this->MEM[$this->SP];
break;
}
}
function ii() {
return $this->MEM[$this->PC];
}
function s1() {
return $this->MEM[$this->SP + 1];
}
function s2() {
return $this->MEM[$this->SP + 2];
}
function ext() {
return base_convert($this->MEM[$this->PC].$this->MEM[$this->PC+1], 2, 10);
}
function PSW() {
return $this->MEM[0xFFFB];
}
function A() {
return $this->MEM[0xFFFC];
}
function B($val) {
$this->MEM[0xFFFD] = $val;
}
function C() {
return $this->MEM[0xFFFE];
}
function D($val) {
$this->MEM[0xFFFF] = $val;
}
function Z($set = -1) {
if ($set != -1) {
$this->MEM[0xFFFB][0] = $set;
} else {
return $this->MEM[0xFFFB][0];
}
}
function N($set = -1) {
if ($set != -1) {
$this->MEM[0xFFFB][1] = $set;
} else {
return $this->MEM[0xFFFB][1];
}
}
function status() {
print 'A: '.$this->A()."\n";
print 'C: '.$this->C()."\n";
print 'N: '.$this->N()."\n";
print 'Z: '.$this->Z()."\n";
print 'Fault: '.$this->fault."\n";
print 'Halt: '.$this->halt."\n\n";
}
function stackDump() {
print "\nStack Dump\n------------\n";
for ($i = ($this->SP + 1); $i <= 0xFFFA; $i++) {
$stackLoc = str_pad((0xFFFA - $i), 3, ' ');
print '| '.$this->MEM[$i].' |'."\n";
}
print "------------\n\n";
}
function callStack() {
print "\nCall Stack\n------------\n";
for ($i = 0; $i < count($this->callStack); $i++) {
print '| '.$this->callStack[$i].' |'."\n";
}
print "------------\n\n";
}
function NOR($a, $b, $len = 8) {
$a = str_pad($a, $len, '0', STR_PAD_LEFT);
$b = str_pad($b, $len, '0', STR_PAD_LEFT);
$res = str_pad('', $len, '1');
for ($i = 0; $i < $len; $i++) {
if ($a[$i] == '1' || $b[$i] == '1')
$res[$i] = '0';
}
return $res;
}
}
$quit = false;
$sm = new StackMachine();
$sm->readFile('mac');
while (!$quit) {
printMenu();
$sel = fgets(STDIN);
$sel = $sel[0];
print "\n";
switch($sel) {
case 'R':
$sm->reset();
break;
case 's':
$sm->step();
break;
case 'r':
$sm->run();
break;
case 'A':
print 'The value at Port A is:'."\n".$sm->A()."\n\n";
break;
case 'B':
print 'Enter the value for Port B (in decimal):'."\n";
$val = str_pad(base_convert(fgets(STDIN), 10, 2), 8, '0', STR_PAD_LEFT);
$sm->B($val);
print "\n";
break;
case 'C':
print 'The value at Port C is:'."\n".$sm->C()."\n\n";
break;
case 'D':
print 'Enter the value for Port D (in decimal):'."\n";
$val = str_pad(base_convert(fgets(STDIN), 10, 2), 8, '0', STR_PAD_LEFT);
$sm->D($val);
print "\n";
break;
case 's':
$sm->status();
break;
case 'd':
$sm->stackDump();
break;
case 'c':
$sm->callStack();
break;
case 'q':
$quit = true;
continue;
break;
default:
print "Invalid command.\n\n";
break;
}
}
function printMenu() {
print "R: RESET\n";
print "s: STEP\n";
print "r: RUN\n";
print "A: READ PORT A\n";
print "B: WRITE PORT B\n";
print "C: READ PORT C\n";
print "D: WRITE PORT D\n";
print "s: STATUS\n";
print "d: STACK DUMP\n";
print "c: CALL STACK\n";
print "q: Quit\n\n";
print "Enter menu selection: \n";
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment