Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / branch.c
diff --git a/interpreters/bocfel/branch.c b/interpreters/bocfel/branch.c
new file mode 100644 (file)
index 0000000..2af3d29
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * Copyright 2010-2012 Chris Spiegel.
+ *
+ * This file is part of Bocfel.
+ *
+ * Bocfel is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version
+ * 2 or 3, as published by the Free Software Foundation.
+ *
+ * Bocfel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Bocfel.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include "branch.h"
+#include "memory.h"
+#include "process.h"
+#include "stack.h"
+#include "util.h"
+#include "zterp.h"
+
+void branch_if(int do_branch)
+{
+  uint8_t branch;
+  uint16_t offset;
+
+  branch = BYTE(pc++);
+
+  if(!do_branch) branch ^= 0x80;
+
+  offset = branch & 0x3f;
+
+  if((branch & 0x40) == 0)
+  {
+    offset = (offset << 8) | BYTE(pc++);
+
+    /* Get the sign right. */
+    if(offset & 0x2000) offset |= 0xc000;
+  }
+
+  if(branch & 0x80)
+  {
+    if(offset > 1)
+    {
+      pc += (int16_t)offset - 2;
+      ZASSERT(pc < memory_size, "branch to invalid address 0x%lx", (unsigned long)pc);
+    }
+    else
+    {
+      do_return(offset);
+    }
+  }
+}
+
+void zjump(void)
+{
+  /* -= 2 because pc has been advanced past the jump instruction. */
+  pc += (int16_t)zargs[0];
+  pc -= 2;
+
+  ZASSERT(pc < memory_size, "@jump to invalid address 0x%lx", (unsigned long)pc);
+}
+
+void zjz(void)
+{
+  branch_if(zargs[0] == 0);
+}
+
+void zje(void)
+{
+  if     (znargs == 1) branch_if(0);
+  else if(znargs == 2) branch_if(zargs[0] == zargs[1]);
+  else if(znargs == 3) branch_if(zargs[0] == zargs[1] || zargs[0] == zargs[2]);
+  else                 branch_if(zargs[0] == zargs[1] || zargs[0] == zargs[2] || zargs[0] == zargs[3]);
+}
+
+void zjl(void)
+{
+  branch_if((int16_t)zargs[0] < (int16_t)zargs[1]);
+}
+
+void zjg(void)
+{
+  branch_if((int16_t)zargs[0] > (int16_t)zargs[1]);
+}