1 /* MIX simulator, copyright 1994 by Darius Bacon */
2 /* Corrections to multiply and divide, Nov. 1998, Larry Gately */
3 #include "mix.h"
4
5 #include <stdio.h>
6
ulong_to_cell(unsigned long n)7 Cell ulong_to_cell(unsigned long n)
8 {
9 if (CELL_MAX < n) {
10 warn("Value out of range: %lu", n);
11 return CELL_MAX;
12 } else
13 return n;
14 }
15
16 /* --- Field operations --- */
17
get_byte(unsigned F,Cell cell)18 Byte get_byte(unsigned F, Cell cell)
19 {
20 assert(F != 0);
21 return (Byte) field(make_field_spec(F, F), cell);
22 }
23
set_byte(Byte value,unsigned F,Cell into)24 Cell set_byte(Byte value, unsigned F, Cell into)
25 {
26 assert(F != 0);
27 return set_field((Cell) value, make_field_spec(F, F), into);
28 }
29
30 static Flag bad_field[64]; /* 64 = number of byte values */
31 static unsigned shift[64];
32 static long mask[64];
33
field(Byte F,Cell cell)34 Cell field(Byte F, Cell cell)
35 {
36 if (bad_field[F])
37 error("Bad field spec: %02o", F);
38 if (F < 8) /* if F is of the form (0:R), retain the sign of -cell- */
39 return ((cell & mask[F]) >> shift[F]) | sign_bit(cell);
40 else
41 return (cell & mask[F]) >> shift[F];
42 }
43
set_field(Cell value,Byte F,Cell into)44 Cell set_field(Cell value, Byte F, Cell into)
45 {
46 long m = mask[F];
47 if (bad_field[F])
48 error("Bad field spec: %02o", F);
49 if (F < 8) /* if F is of the form (0:R), use the sign of -value- */
50 return (into & ~m & ~the_sign_bit) | ((value << shift[F]) & m) | sign_bit(value);
51 else
52 return (into & ~m) | ((value << shift[F]) & m);
53 }
54
precompute_field_data(void)55 void precompute_field_data(void)
56 {
57 unsigned L, R;
58 for (L = 0; L < 8; ++L)
59 for (R = 0; R < 8; ++R) {
60 unsigned F = 8 * L + R;
61 bad_field[F] = R < L || 5 < R;
62 if (bad_field[F])
63 shift[F] = 0, mask[F] = 0;
64 else {
65 unsigned width = R - (L == 0 ? 1 : L) + 1;
66 shift[F] = 6 * (5 - R);
67 mask[F] = ((1L << (6 * width)) - 1) << shift[F];
68 }
69 }
70 }
71
make_field_spec(unsigned L,unsigned R)72 Byte make_field_spec(unsigned L, unsigned R)
73 {
74 unsigned F = 8 * L + R;
75 assert(!bad_field[F]);
76 return F;
77 }
78
assert_valid_field(Cell field_spec)79 void assert_valid_field(Cell field_spec)
80 {
81 if (is_negative(field_spec)
82 || 64 <= magnitude(field_spec)
83 || bad_field[(unsigned)magnitude(field_spec)]) {
84 char buffer[12];
85 unparse_cell(buffer, field_spec);
86 error("Invalid field specifier: %s", buffer);
87 }
88 }
89
90 /* --- Arithmetic --- */
91
92 Flag overflow = false;
93
add(Cell x,Cell y)94 Cell add(Cell x, Cell y)
95 { /* This is kinda clumsy. Should I combine code at the cost (?) of speed */
96 /* and functional style? */
97 if (sign_bit(x) == sign_bit(y)) {
98 long sum = magnitude(x) + magnitude(y);
99 long magnitude_of_sum = magnitude(sum);
100 if (magnitude_of_sum != sum) overflow = true;
101 return sign_bit(x) | magnitude_of_sum;
102 } else {
103 long diff = magnitude(x) - magnitude(y);
104 return diff < 0 ? sign_bit (y) | -diff : sign_bit (x) | diff;
105 }
106 }
107
sub(Cell x,Cell y)108 Cell sub(Cell x, Cell y)
109 {
110 return add(x, negative(y)); /* should inline this, maybe */
111 }
112
multiply(Cell x,Cell y,Cell * high_word,Cell * low_word)113 void multiply(Cell x, Cell y, Cell *high_word, Cell *low_word)
114 {
115 unsigned long sign = sign_bit(x) ^ sign_bit(y);
116
117 /*
118 x = x0 + x1 * 2 ^ 10 + x2 * 2 ^ 20
119 y = y0 + y1 * 2 ^ 10 + y2 * 2 ^ 20
120 x0, x1, x2, y0, y1, y2 are < 2 ^ 10
121 */
122 unsigned long x0 = (x & 0x000003FF);
123 unsigned long x1 = (x & 0x000FFC00) >> 10;
124 unsigned long x2 = (x & 0x3FF00000) >> 20;
125 unsigned long y0 = (y & 0x000003FF);
126 unsigned long y1 = (y & 0x000FFC00) >> 10;
127 unsigned long y2 = (y & 0x3FF00000) >> 20;
128
129 /*
130 x * y = partial0 +
131 partial1 * 2 ^ 10 +
132 partial2 * 2 ^ 20 +
133 partial3 * 2 ^ 30 +
134 partial4 * 2 ^ 40
135 partial0 and partial4 are < 2 ^ 20
136 partial1 and partial3 are < 2 ^ 21
137 partial2 is < 3 * 2 ^ 20
138 */
139 unsigned long partial0 = x0 * y0;
140 unsigned long partial1 = x0 * y1 + x1 * y0;
141 unsigned long partial2 = x0 * y2 + x1 * y1 + x2 * y0;
142 unsigned long partial3 = x1 * y2 + x2 * y1;
143 unsigned long partial4 = x2 * y2;
144
145 /* sum1 has a place value of 1 and is < 2 ^ 32 */
146 unsigned long sum1 = partial0 + (partial1 << 10);
147 unsigned long carry1 = (sum1 & 0xFFF00000) >> 20;
148
149 /* sum2 has a place value of 2 ^ 20 and is < 2 ^ 32 */
150 unsigned long sum2 = partial2 + (partial3 << 10) + carry1;
151 unsigned long carry2 = (sum2 & 0xFFF00000) >> 20;
152
153 /* sum3 has a place value of 2 ^ 40 and is < 2 ^ 20 */
154 unsigned long sum3 = partial4 + carry2;
155
156 sum1 &= ~0xFFF00000;
157 sum2 &= ~0xFFF00000;
158
159 /*
160 Now paste the three values back into two.
161 */
162 *low_word = sum1 | ((sum2 & 0x000003FF) << 20);
163 *low_word |= sign;
164 *high_word = ((sum2 & 0x000FFC00) >> 10) | (sum3 << 10);
165 *high_word |= sign;
166
167 }
168
mul(Cell x,Cell y)169 Cell mul(Cell x, Cell y)
170 {
171 Cell lo, hi;
172 multiply(x, y, &hi, &lo);
173 if (magnitude(hi) != 0) overflow = true;
174 return lo;
175 }
176
divide(Cell n1,Cell n0,Cell d,Cell * quotient,Cell * remainder)177 void divide(Cell n1, Cell n0, Cell d, Cell *quotient, Cell *remainder)
178 {
179 long magn1 = magnitude(n1);
180 long magd = magnitude(d);
181 if (magd == 0) {
182 overflow = true;
183 *quotient = *remainder = zero; /* just so they have -some- valid value */
184 } else if (magn1 == 0) { /* special-cased for speed */
185 *quotient = (sign_bit(n1) ^ sign_bit(d)) | (magnitude(n0) / magd);
186 *remainder = sign_bit(n1) | (magnitude(n0) % magd);
187 } else if (magd <= magn1) {
188 overflow = true;
189 *quotient = *remainder = zero;
190 } else {
191 long q = magnitude(n0);
192 long r = magn1;
193 unsigned i;
194 for (i = 30; i != 0; --i) {
195 r <<= 1;
196 if (q & (1L << 29))
197 ++r;
198 q = (q << 1) & ((1L << 30) - 1);
199 if (magd <= r)
200 ++q, r -= magd;
201 }
202 *quotient = (sign_bit(n1) ^ sign_bit(d)) | q;
203 *remainder = sign_bit(n1) | r;
204 }
205 }
206
slash(Cell x,Cell y)207 Cell slash(Cell x, Cell y) /* the name 'div' is taken... */
208 {
209 Cell quotient, remainder;
210 divide(sign_bit(x), x, y, "ient, &remainder);
211 return quotient;
212 }
213
214 /* --- Shift operations --- */
215
shift_right(Cell A,Cell X,unsigned long count,Cell * pA,Cell * pX)216 void shift_right(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX)
217 {
218 *pX = sign_bit(X);
219 *pA = sign_bit(A);
220 if (count < 5) {
221 *pA |= magnitude(A) >> (6 * count);
222 *pX |= CELL_MAX & (magnitude(X) >> (6 * count))
223 & (A << (30 - 6 * count));
224 } else if (count < 10)
225 *pX |= magnitude(A) >> (6 * count - 30);
226 else
227 ;
228 }
229
shift_left(Cell A,Cell X,unsigned long count,Cell * pA,Cell * pX)230 void shift_left(Cell A, Cell X, unsigned long count, Cell *pA, Cell *pX)
231 {
232 *pX = sign_bit(X);
233 *pA = sign_bit(A);
234 if (count < 5) {
235 *pX |= CELL_MAX & (X << (6 * count));
236 *pA |= CELL_MAX & (A << (6 * count))
237 & (magnitude(X) >> (30 - 6 * count));
238 } else if (count < 10)
239 *pA |= CELL_MAX & (X << (6 * count - 30));
240 else
241 ;
242 }
243
244 /* Pre: count < 10 */
shift_left_circular(Cell A,Cell X,unsigned count,Cell * pA,Cell * pX)245 void shift_left_circular(Cell A, Cell X, unsigned count, Cell *pA, Cell *pX)
246 {
247 Cell A1 = count < 5 ? A : X;
248 Cell X1 = count < 5 ? X : A;
249 unsigned c = 6 * (count < 5 ? count : count - 5);
250 *pX = sign_bit(X)
251 | (CELL_MAX & (X1 << c) & (magnitude(A1) >> (30 - c)));
252 *pA = sign_bit(A)
253 | (CELL_MAX & (A1 << c) & (magnitude(X1) >> (30 - c)));
254 }
255
256 /* --- Printable representation --- */
257
print_cell(Cell cell)258 void print_cell(Cell cell)
259 {
260 printf("%s%010lo", sign_bit(cell) == 0 ? " " : "-", magnitude(cell));
261 }
262
unparse_cell(char * buffer,Cell cell)263 void unparse_cell(char *buffer, Cell cell)
264 {
265 sprintf(buffer, "%s%010lo", sign_bit(cell) == 0 ? " " : "-", magnitude(cell));
266 }
267
268 /* --- Addresses --- */
269
address_to_cell(Address addr)270 Cell address_to_cell(Address addr) { return addr; }
271
cell_to_address(Cell cell)272 Address cell_to_address(Cell cell)
273 {
274 if ((sign_bit(cell) != 0 && magnitude(cell) != 0)
275 || memory_size <= magnitude(cell)) {
276 char buffer[12];
277 unparse_cell(buffer, cell);
278 error("Value is not an address: %s", buffer);
279 return 0;
280 }
281 return (Address) magnitude(cell);
282 }
283