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, &quotient, &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