Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / branch.c
1 /*-
2  * Copyright 2010-2012 Chris Spiegel.
3  *
4  * This file is part of Bocfel.
5  *
6  * Bocfel is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version
8  * 2 or 3, as published by the Free Software Foundation.
9  *
10  * Bocfel is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Bocfel.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdint.h>
20
21 #include "branch.h"
22 #include "memory.h"
23 #include "process.h"
24 #include "stack.h"
25 #include "util.h"
26 #include "zterp.h"
27
28 void branch_if(int do_branch)
29 {
30   uint8_t branch;
31   uint16_t offset;
32
33   branch = BYTE(pc++);
34
35   if(!do_branch) branch ^= 0x80;
36
37   offset = branch & 0x3f;
38
39   if((branch & 0x40) == 0)
40   {
41     offset = (offset << 8) | BYTE(pc++);
42
43     /* Get the sign right. */
44     if(offset & 0x2000) offset |= 0xc000;
45   }
46
47   if(branch & 0x80)
48   {
49     if(offset > 1)
50     {
51       pc += (int16_t)offset - 2;
52       ZASSERT(pc < memory_size, "branch to invalid address 0x%lx", (unsigned long)pc);
53     }
54     else
55     {
56       do_return(offset);
57     }
58   }
59 }
60
61 void zjump(void)
62 {
63   /* -= 2 because pc has been advanced past the jump instruction. */
64   pc += (int16_t)zargs[0];
65   pc -= 2;
66
67   ZASSERT(pc < memory_size, "@jump to invalid address 0x%lx", (unsigned long)pc);
68 }
69
70 void zjz(void)
71 {
72   branch_if(zargs[0] == 0);
73 }
74
75 void zje(void)
76 {
77   if     (znargs == 1) branch_if(0);
78   else if(znargs == 2) branch_if(zargs[0] == zargs[1]);
79   else if(znargs == 3) branch_if(zargs[0] == zargs[1] || zargs[0] == zargs[2]);
80   else                 branch_if(zargs[0] == zargs[1] || zargs[0] == zargs[2] || zargs[0] == zargs[3]);
81 }
82
83 void zjl(void)
84 {
85   branch_if((int16_t)zargs[0] < (int16_t)zargs[1]);
86 }
87
88 void zjg(void)
89 {
90   branch_if((int16_t)zargs[0] > (int16_t)zargs[1]);
91 }