Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / math.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 "math.h"
22 #include "branch.h"
23 #include "process.h"
24 #include "stack.h"
25 #include "util.h"
26 #include "zterp.h"
27
28 void zinc(void)
29 {
30   store_variable(zargs[0], variable(zargs[0]) + 1);
31 }
32
33 void zdec(void)
34 {
35   store_variable(zargs[0], variable(zargs[0]) - 1);
36 }
37
38 void znot(void)
39 {
40   store(~zargs[0]);
41 }
42
43 void zdec_chk(void)
44 {
45   int16_t new;
46   int16_t val = zargs[1];
47
48   zdec();
49
50   /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */
51   if(zargs[0] == 0) new = *stack_top_element();
52   else              new = variable(zargs[0]);
53
54   branch_if(new < val);
55 }
56
57 void zinc_chk(void)
58 {
59   int16_t new;
60   int16_t val = zargs[1];
61
62   zinc();
63
64   /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */
65   if(zargs[0] == 0) new = *stack_top_element();
66   else              new = variable(zargs[0]);
67
68   branch_if(new > val);
69 }
70
71 void ztest(void)
72 {
73   branch_if( (zargs[0] & zargs[1]) == zargs[1] );
74 }
75
76 void zor(void)
77 {
78   store(zargs[0] | zargs[1]);
79 }
80
81 void zand(void)
82 {
83   store(zargs[0] & zargs[1]);
84 }
85
86 void zadd(void)
87 {
88   store(zargs[0] + zargs[1]);
89 }
90
91 void zsub(void)
92 {
93   store(zargs[0] - zargs[1]);
94 }
95
96 void zmul(void)
97 {
98   store(zargs[0] * zargs[1]);
99 }
100
101 void zdiv(void)
102 {
103   ZASSERT(zargs[1] != 0, "divide by zero");
104   store((int16_t)zargs[0] / (int16_t)zargs[1]);
105 }
106
107 void zmod(void)
108 {
109   ZASSERT(zargs[1] != 0, "divide by zero");
110   store((int16_t)zargs[0] % (int16_t)zargs[1]);
111 }
112
113 void zlog_shift(void)
114 {
115   int16_t places = zargs[1];
116
117   /* Shifting more than 15 bits is undefined (as of Standard 1.1), but
118    * do the most sensible thing.
119    */
120   if(places < -15 || places > 15)
121   {
122     store(0);
123     return;
124   }
125
126   if(places < 0) store(zargs[0] >> -places);
127   else           store(zargs[0] <<  places);
128 }
129
130 void zart_shift(void)
131 {
132   int16_t number = zargs[0], places = zargs[1];
133
134   /* Shifting more than 15 bits is undefined (as of Standard 1.1), but
135    * do the most sensible thing.
136    */
137   if(places < -15 || places > 15)
138   {
139     store(number < 0 ? -1 : 0);
140     return;
141   }
142
143   /* Shifting a negative value in C has some consequences:
144    * • Shifting a negative value left is undefined.
145    * • Shifting a negative value right is implementation defined.
146    *
147    * Thus these are done by hand.  The Z-machine requires a right-shift
148    * of a negative value to propagate the sign bit.  This is easily
149    * accomplished by complementing the value (yielding a positive
150    * number), shifting it right (zero filling), and complementing again
151    * (flip the shifted-in zeroes to ones).
152    *
153    * For a left-shift, the result should presumably be the same as a
154    * logical shift, so do that.
155    */
156   if(number < 0)
157   {
158     if(places < 0) store(~(~number >> -places));
159     else           store(zargs[0]  <<  places);
160   }
161   else
162   {
163     if(places < 0) store(zargs[0] >> -places);
164     else           store(zargs[0] <<  places);
165   }
166 }