@moonbase-machines/c64 0.0.0-stage → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/float.js ADDED
@@ -0,0 +1,584 @@
1
+ // Commodore BASIC's floating point, moonbase's own: the five-byte numbers BASIC keeps, and its
2
+ // arithmetic on them, computing what BASIC's ROM computes, to the bit. It works where the ROM's
3
+ // does, in the zero page, so that moonbase's BASIC ROM (basic-rom.js) can answer a program's
4
+ // call into the ROM's arithmetic at its own address and leave memory as the ROM leaves it. Every
5
+ // routine here is held to Commodore's, run on the processor, from thousands of random starting
6
+ // states.
7
+ //
8
+ // const f = new Floats(memory) memory: read(address) and write(address, value)
9
+ //
10
+ // A number in memory is five bytes: its exponent (128 + the power of two, 0 for zero), then
11
+ // its 32-bit mantissa, highest byte first, whose top bit, always 1, is the sign's place. In the
12
+ // accumulator (FAC, $61 to $66) the mantissa's top bit is 1 and the sign has its own byte, $66;
13
+ // a sixth byte, $70, holds the bits below the mantissa, which an operation keeps, and only
14
+ // storing a number (or ROUND) rounds them in. The other operand (ARG, $69 to $6E) is the same,
15
+ // its own low bits at $56 while an addition lines the two up. $6F is the two signs' EOR.
16
+ //
17
+ // The ROM's routines have their ways, and these keep them: the low bits are kept, not rounded,
18
+ // until a number is stored; a shift by whole bytes brings in $68 at the top, whatever an earlier
19
+ // routine left there; a shift's length depends on the carry it is entered with. Each method
20
+ // says the ROM's address it stands for; its results are the ROM's, in memory and in the
21
+ // registers its callers read (`regs`).
22
+ export const FAC = 0x61, ARG = 0x69, FACOV = 0x70, ARGOV = 0x56, ARISGN = 0x6f, BITS = 0x68, RESHO = 0x26;
23
+
24
+ // Constants of BASIC's that its routines take from the ROM, by their place there: their values,
25
+ // as five bytes, each named as Microsoft's source names it (BASIC-M6502). A game that reads one
26
+ // reads it from moonbase's ROM image too (rom.js).
27
+ const words = ns => ns.flatMap(n => [n >>> 24 & 0xff, n >>> 16 & 0xff, n >>> 8 & 0xff, n & 0xff]);
28
+ export const CONSTANTS = {
29
+ 0xb9bc: [0x81, 0x00, 0x00, 0x00, 0x00], // 1 (Microsoft's FONE)
30
+ 0xbf11: [0x80, 0x00, 0x00, 0x00, 0x00], // 0.5 (FHALF)
31
+ 0xbaf9: [0x84, 0x20, 0x00, 0x00, 0x00], // 10 (TENZC)
32
+ // LOG's: its series' (a count, then the coefficients of x squared, highest first, for POLY1),
33
+ // the square roots of a half and of two, -0.5, and the logarithm of two (LOGCN2, SQRHLF, SQRTWO,
34
+ // NEGHLF, LOG2)
35
+ 0xb9c1: [0x03, 0x7f, 0x5e, 0x56, 0xcb, 0x79, 0x80, 0x13, 0x9b, 0x0b, 0x64, 0x80, 0x76, 0x38, 0x93, 0x16, 0x82, 0x38, 0xaa, 0x3b, 0x20],
36
+ 0xb9d6: [0x80, 0x35, 0x04, 0xf3, 0x34], // 0.707...
37
+ 0xb9db: [0x81, 0x35, 0x04, 0xf3, 0x34], // 1.414...
38
+ 0xb9e0: [0x80, 0x80, 0x00, 0x00, 0x00], // -0.5
39
+ 0xb9e5: [0x80, 0x31, 0x72, 0x17, 0xf8], // 0.693...
40
+ // EXP's: one over the logarithm of two, and its series (for POLY2) (LOGEB2, EXPCON)
41
+ 0xbfbf: [0x81, 0x38, 0xaa, 0x3b, 0x29], // 1.442...
42
+ 0xbfc4: [0x07, 0x71, 0x34, 0x58, 0x3e, 0x56, 0x74, 0x16, 0x7e, 0xb3, 0x1b, 0x77, 0x2f, 0xee, 0xe3, 0x85, 0x7a, 0x1d, 0x84, 0x1c, 0x2a,
43
+ 0x7c, 0x63, 0x59, 0x58, 0x0a, 0x7e, 0x75, 0xfd, 0xe7, 0xc6, 0x80, 0x31, 0x72, 0x18, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00],
44
+ // FOUT's: the powers of ten its digits are counted out with, and TI$'s steps of the clock (hours
45
+ // to seconds, in jiffies), each a 32-bit whole number, alternately subtracted and added (FOUTBL)
46
+ 0xbf16: words([-100000000, 10000000, -1000000, 100000, -10000, 1000, -100, 10, -1, -2160000, 216000, -36000, 3600, -600, 60]),
47
+ // and the bounds it brings a number between, 99999999.9 and 999999999 (both rounded up a
48
+ // little), and 1E9, a small number's first step up (NZ0999, NZ9999, NZMIL)
49
+ 0xbdb3: [0x9b, 0x3e, 0xbc, 0x1f, 0xfd],
50
+ 0xbdb8: [0x9e, 0x6e, 0x6b, 0x27, 0xfd],
51
+ 0xbdbd: [0x9e, 0x6e, 0x6b, 0x28, 0x00],
52
+ // SIN's and COS's: a half pi, two pi, a quarter, and SIN's series (for POLY1) (PI2, TWOPI, FR4,
53
+ // SINCON)
54
+ 0xe2e0: [0x81, 0x49, 0x0f, 0xda, 0xa2], // 1.570...
55
+ 0xe2e5: [0x83, 0x49, 0x0f, 0xda, 0xa2], // 6.283...
56
+ 0xe2ea: [0x7f, 0x00, 0x00, 0x00, 0x00], // 0.25
57
+ 0xe2ef: [0x05, 0x84, 0xe6, 0x1a, 0x2d, 0x1b, 0x86, 0x28, 0x07, 0xfb, 0xf8, 0x87, 0x99, 0x68, 0x89, 0x01, 0x87, 0x23, 0x35, 0xdf, 0xe1,
58
+ 0x86, 0xa5, 0x5d, 0xe7, 0x28, 0x83, 0x49, 0x0f, 0xda, 0xa2],
59
+ };
60
+
61
+ // a number as the five bytes BASIC stores, from JavaScript's (for tests and for constants)
62
+ export function pack(x) {
63
+ if (x === 0) return [0, 0, 0, 0, 0];
64
+ const a = Math.abs(x);
65
+ let ex = Math.floor(Math.log2(a)) + 1, f = a / 2 ** ex;
66
+ if (f >= 1) { f /= 2; ex++; } else if (f < 0.5) { f *= 2; ex--; }
67
+ let m = Math.round(f * 2 ** 32); if (m >= 2 ** 32) { m /= 2; ex++; }
68
+ return [ex + 128, (m >>> 24 & 0x7f) | (x < 0 ? 0x80 : 0), m >>> 16 & 0xff, m >>> 8 & 0xff, m & 0xff];
69
+ }
70
+ // a number into the accumulator as BASIC holds it: $61 its exponent, $62 to $65 its mantissa,
71
+ // $66 its sign, its low bits ($70) 0
72
+ export function setFac(memory, x) {
73
+ const b = pack(x);
74
+ memory.write(0x70, 0);
75
+ if (!b[0]) { for (let a = 0x61; a <= 0x66; a++) memory.write(a, 0); return; }
76
+ memory.write(0x61, b[0]); memory.write(0x62, b[1] | 0x80); memory.write(0x63, b[2]); memory.write(0x64, b[3]); memory.write(0x65, b[4]); memory.write(0x66, x < 0 ? 0xff : 0);
77
+ }
78
+ // and back: the number five bytes hold
79
+ export function unpack(b) {
80
+ if (!b[0]) return 0;
81
+ const m = ((b[1] | 0x80) * 2 ** 24) + b[2] * 65536 + b[3] * 256 + b[4];
82
+ return (b[1] & 0x80 ? -1 : 1) * m / 2 ** 32 * 2 ** (b[0] - 128);
83
+ }
84
+
85
+ export class Floats {
86
+ constructor(memory) { this.mem = memory; }
87
+ r(a) { return this.mem.read(a & 0xffff); }
88
+ w(a, v) { this.mem.write(a & 0xffff, v & 0xff); }
89
+ // a register's mantissa, four bytes from `at`, as a number, and back
90
+ mant(at) { return ((this.r(at) * 256 + this.r(at + 1)) * 256 + this.r(at + 2)) * 256 + this.r(at + 3); }
91
+ setMant(at, m) { this.w(at, m / 2 ** 24); this.w(at + 1, m / 65536); this.w(at + 2, m / 256); this.w(at + 3, m); }
92
+ // (the FAC's value, for this module's own use and for tests)
93
+ fac() { const e = this.r(FAC); return e ? (this.r(0x66) & 0x80 ? -1 : 1) * (this.mant(0x62) + this.r(FACOV) / 256) / 2 ** 32 * 2 ** (e - 128) : 0; }
94
+
95
+ // ---- moving numbers ----
96
+
97
+ // CONUPK ($BA8C): ARG from memory at A/Y; $6F the two signs' EOR; A the FAC's exponent
98
+ conupk(at) {
99
+ this.w(0x22, at); this.w(0x23, at >> 8);
100
+ const b = [0, 1, 2, 3, 4].map(i => this.r(at + i));
101
+ this.w(0x6d, b[4]); this.w(0x6c, b[3]); this.w(0x6b, b[2]); this.w(0x6e, b[1]);
102
+ this.w(ARISGN, b[1] ^ this.r(0x66)); this.w(0x6a, b[1] | 0x80); this.w(ARG, b[0]);
103
+ return { a: this.r(FAC), y: 0 };
104
+ }
105
+ // MOVFM ($BBA2): the FAC from memory at A/Y, its low bits 0; A its exponent
106
+ movfm(at) {
107
+ this.w(0x22, at); this.w(0x23, at >> 8);
108
+ const b = [0, 1, 2, 3, 4].map(i => this.r(at + i));
109
+ this.w(0x65, b[4]); this.w(0x64, b[3]); this.w(0x63, b[2]); this.w(0x66, b[1]); this.w(0x62, b[1] | 0x80); this.w(FAC, b[0]); this.w(FACOV, 0);
110
+ return { a: b[0], y: 0 };
111
+ }
112
+ // MOVMF ($BBD4): the FAC, rounded, into memory at X/Y; its low bits 0 after
113
+ movmf(at) {
114
+ this.round();
115
+ this.w(0x22, at); this.w(0x23, at >> 8);
116
+ this.w(at + 4, this.r(0x65)); this.w(at + 3, this.r(0x64)); this.w(at + 2, this.r(0x63));
117
+ this.w(at + 1, (this.r(0x66) | 0x7f) & this.r(0x62)); this.w(at, this.r(FAC)); this.w(FACOV, 0);
118
+ return { a: this.r(FAC), y: 0 };
119
+ }
120
+ // MOVFA ($BBFC): the FAC from ARG; MOVAF ($BC0C): ARG from the FAC, rounded first
121
+ movfa() { this.w(0x66, this.r(0x6e)); for (let i = 5; i >= 1; i--) this.w(0x60 + i, this.r(0x68 + i)); this.w(FACOV, 0); return { a: this.r(ARG), x: 0 }; }
122
+ movaf() { this.round(); return this.movef(); }
123
+ // ($BC0F, MOVAF after its ROUND: the FAC copied as it is)
124
+ movef() { for (let i = 6; i >= 1; i--) this.w(0x68 + i, this.r(0x60 + i)); this.w(FACOV, 0); return { a: this.r(FAC), x: 0 }; }
125
+
126
+ // ---- rounding, sign, comparing ----
127
+
128
+ // ROUND ($BC1B): the low bits' top bit added in at the mantissa's foot; the low bits shifted
129
+ // left, as the ROM leaves them; a carry out of the mantissa a power of two more
130
+ round() {
131
+ if (!this.r(FAC)) return;
132
+ const ov = this.r(FACOV); this.w(FACOV, ov << 1);
133
+ if (!(ov & 0x80)) return;
134
+ const m = this.mant(0x62) + 1;
135
+ if (m < 2 ** 32) { this.setMant(0x62, m); return; }
136
+ this.setMant(0x62, 0);
137
+ this.carryIn(1);
138
+ }
139
+ // ($B938) the exponent one more, and the mantissa and low bits shifted right with C in at the top
140
+ carryIn(c) {
141
+ const e = this.r(FAC) + 1; if (e > 255) throw overflow();
142
+ this.w(FAC, e);
143
+ const m = this.mant(0x62), ov = this.r(FACOV);
144
+ this.setMant(0x62, Math.floor(m / 2) + (c ? 2 ** 31 : 0)); this.w(FACOV, (ov >> 1) | ((m & 1) << 7));
145
+ }
146
+ // SIGN ($BC2B): 0 for zero, 1 for positive, $FF for negative
147
+ sign() { return !this.r(FAC) ? 0 : this.r(0x66) & 0x80 ? 0xff : 1; }
148
+ // FCOMP ($BC5B, the address in A and Y; $BC5D with $24 set): the FAC against a number in memory,
149
+ // 1 if the FAC is more, $FF if less, 0 if the same; the FAC's low bits, rounded, count only in
150
+ // the mantissa's last byte, as the ROM's subtraction there borrows them
151
+ fcomp(at) { return this.compare(at).a; }
152
+ // (and Y as FCOMP leaves it: the byte it decided at, 1 for the exponent or the sign, 4 if equal)
153
+ compare(at) {
154
+ this.w(0x24, at); this.w(0x25, at >> 8);
155
+ const ex = this.r(at);
156
+ if (!ex) return { a: this.sign(), y: 1 };
157
+ const b1 = this.r(at + 1), s = this.r(0x66);
158
+ const memMore = (more, y) => { const neg = s & 0x80 ? 1 : 0; return { a: (more ? neg ^ 1 : neg) ? 0xff : 1, y }; }; // more: memory > FAC in size
159
+ if ((b1 ^ s) & 0x80) return { a: s & 0x80 ? 0xff : 1, y: 1 };
160
+ if (ex !== this.r(FAC)) return memMore(ex > this.r(FAC), 1);
161
+ for (const [k, fac] of [[1, 0x62], [2, 0x63], [3, 0x64]]) {
162
+ const mb = k === 1 ? b1 | 0x80 : this.r(at + k), fb = this.r(fac);
163
+ if (mb !== fb) return memMore(mb > fb, k);
164
+ }
165
+ const borrow = this.r(FACOV) > 0x7f ? 1 : 0, d = this.r(at + 4) - this.r(0x65) - borrow;
166
+ if ((d & 0xff) === 0) return { a: 0, y: 4 };
167
+ return memMore(d >= 0, 4);
168
+ }
169
+
170
+ // ---- adding ----
171
+
172
+ // FADD ($B867, the address in A and Y: memory plus the FAC; $B86A, ARG plus the FAC, A the
173
+ // FAC's exponent): the result normalised, its low bits kept
174
+ fadd(at) { this.conupk(at); return this.faddt(); }
175
+ // FSUB ($B850): memory minus the FAC; FSUBT ($B853): ARG minus the FAC
176
+ fsub(at) { this.conupk(at); return this.fsubt(); }
177
+ fsubt() { this.w(0x66, this.r(0x66) ^ 0xff); this.w(ARISGN, this.r(0x66) ^ this.r(0x6e)); return this.faddt(); }
178
+ faddt() {
179
+ if (!this.r(FAC)) return this.movfa();
180
+ this.w(ARGOV, this.r(FACOV));
181
+ const ey = this.r(ARG);
182
+ if (!ey) return { a: 0 };
183
+ let d = (ey - this.r(FAC)) & 0xff, x = ARG, c = ey >= this.r(FAC) ? 1 : 0, a = 0;
184
+ if (d !== 0) {
185
+ if (c) { // ARG the larger: the FAC takes its exponent and sign, and is the one shifted
186
+ this.w(FAC, ey); this.w(0x66, this.r(0x6e));
187
+ d = (~d + 1) & 0xff; this.w(ARGOV, 0); x = FAC;
188
+ } else this.w(FACOV, 0);
189
+ // (under a byte by the ROM's own signed test of A - $F9, $B897: bit by bit, the first
190
+ // shifted plainly, the rest keeping the top bit, $B89B, which for a count the test misreads
191
+ // is up to 255 bits; otherwise whole bytes first, $B862)
192
+ a = ((d - 0xf9) & 0x80) ? this.shift(x, d, 0) : this.bitShift(x, d, this.r(FACOV), false);
193
+ }
194
+ if (this.r(ARISGN) & 0x80) {
195
+ // the signs differ: the one not shifted less the one shifted, into the FAC
196
+ const minus = x === ARG ? FAC : ARG;
197
+ const low = this.r(ARGOV) - a, lowByte = low & 0xff, borrow = low < 0 ? 1 : 0;
198
+ const m = this.mant(minus + 1) - this.mant(x + 1) - borrow;
199
+ this.w(FACOV, lowByte); this.setMant(0x62, (m + 2 ** 32) % 2 ** 32);
200
+ if (m < 0) this.negate();
201
+ return this.normal();
202
+ }
203
+ // the same signs: the sum, a carry out a power of two more; with the exponents the same,
204
+ // the carry their comparison left adds one more to the low bits ($B8FE)
205
+ const low = a + this.r(ARGOV) + (d === 0 ? 1 : 0), m = this.mant(0x62) + this.mant(0x6a) + (low > 255 ? 1 : 0);
206
+ this.w(FACOV, low); this.setMant(0x62, m % 2 ** 32);
207
+ if (m >= 2 ** 32) this.carryIn(1);
208
+ return { a: this.r(FAC) };
209
+ }
210
+ // the FAC's mantissa and low bits two's-complemented, its sign turned over ($B947); $B94D the
211
+ // same without the sign
212
+ negate() { this.w(0x66, this.r(0x66) ^ 0xff); this.complement(); }
213
+ complement() {
214
+ const ov = (~this.r(FACOV) & 0xff) + 1, m = 2 ** 32 - 1 - this.mant(0x62) + (ov > 255 ? 1 : 0);
215
+ this.w(FACOV, ov); this.setMant(0x62, m % 2 ** 32);
216
+ }
217
+ // NORMAL ($B8D7): the mantissa shifted up until its top bit is 1, a byte at a time and then a
218
+ // bit, the low bits coming in below it, and the exponent that much less; zero if it was zero,
219
+ // or if the exponent would go under
220
+ normal() {
221
+ let n = 0;
222
+ while (!this.r(0x62)) {
223
+ this.w(0x62, this.r(0x63)); this.w(0x63, this.r(0x64)); this.w(0x64, this.r(0x65)); this.w(0x65, this.r(FACOV)); this.w(FACOV, 0);
224
+ n += 8; if (n === 32) return this.zero();
225
+ }
226
+ while (!(this.r(0x62) & 0x80)) {
227
+ const ov = this.r(FACOV), m = this.mant(0x62);
228
+ this.w(FACOV, ov << 1); this.setMant(0x62, (m * 2 + (ov >> 7)) % 2 ** 32); n++;
229
+ }
230
+ if (n >= this.r(FAC)) return this.zero();
231
+ this.w(FAC, this.r(FAC) - n);
232
+ return { a: this.r(FAC) };
233
+ }
234
+ zero() { this.w(FAC, 0); this.w(0x66, 0); return { a: 0 }; }
235
+ // The ROM's shift right of a register (X: $61 the FAC, $69 ARG, $25 the product) by -A bits,
236
+ // A a negative count; its low bits are $70, or the A register (the return here) in a shift of
237
+ // under a byte. Whole bytes first, each bringing $68 in at the top ($B985), as long as A + 8
238
+ // (and the carry) stays under 1; then the bits, the top one kept, as for a signed number ($B9A6).
239
+ shift(x, a, c = 0) {
240
+ for (;;) {
241
+ const sum = a + 8 + c; a = sum & 0xff; c = sum > 255 ? 1 : 0;
242
+ if (a & 0x80 || !a) { this.byteShift(x); continue; }
243
+ const diff = a - 8 - (1 - c); a = diff & 0xff; c = diff >= 0 ? 1 : 0;
244
+ if (c) return this.r(FACOV);
245
+ return this.bitShift(x, a, this.r(FACOV), true);
246
+ }
247
+ }
248
+ byteShift(x) {
249
+ this.w(FACOV, this.r(x + 4)); this.w(x + 4, this.r(x + 3)); this.w(x + 3, this.r(x + 2)); this.w(x + 2, this.r(x + 1)); this.w(x + 1, this.r(BITS));
250
+ }
251
+ // bits: Y counting up from -n, each a shift right of the register's four bytes and A below them,
252
+ // the top byte's top bit kept (signed) or, for the first of an addition's, cleared
253
+ bitShift(x, y, a, signed) {
254
+ for (; y !== 0; y = (y + 1) & 0xff) {
255
+ const top = this.r(x + 1), m = this.mant(x + 1);
256
+ const keep = signed ? top & 0x80 : 0;
257
+ this.setMant(x + 1, Math.floor(m / 2) + keep * 2 ** 24);
258
+ a = (a >> 1) | ((m & 1) << 7);
259
+ signed = true;
260
+ }
261
+ return a;
262
+ }
263
+
264
+ // ---- multiplying and dividing ----
265
+
266
+ // FMULT ($BA28, memory times the FAC; $BA2B, ARG times the FAC): the mantissas multiplied a
267
+ // byte of the FAC's at a time, its low bits first, the product's bits shifted out below lost
268
+ fmult(at) { this.conupk(at); return this.fmultt(); }
269
+ fmultt() {
270
+ if (!this.r(FAC)) return { a: 0 };
271
+ const md = this.muldiv();
272
+ if (md.zero) return { a: 0 };
273
+ for (const r of [0x26, 0x27, 0x28, 0x29]) this.w(r, 0);
274
+ let c = md.c;
275
+ for (const at of [FACOV, 0x65, 0x64, 0x63, 0x62]) c = this.mltply(this.r(at), c, at === 0x62);
276
+ this.w(0x62, this.r(0x26)); this.w(0x63, this.r(0x27)); this.w(0x64, this.r(0x28)); this.w(0x65, this.r(0x29));
277
+ return this.normal();
278
+ }
279
+ // one byte of the multiplier ($BA59): a zero byte a shift of the product by bytes; another, its
280
+ // bits from the lowest, ARG's mantissa added in for each 1, the product shifted right each time
281
+ mltply(b, c, last) {
282
+ if (!b && !last) { this.byteShift(0x25); this.shift(0x25, 0, c); return 0; }
283
+ for (let bits = (b >> 1) | 0x80, bit = b & 1; ; ) {
284
+ let p = this.mant(0x26), carry = 0;
285
+ if (bit) { p += this.mant(0x6a); carry = p >= 2 ** 32 ? 1 : 0; p %= 2 ** 32; }
286
+ const ov = this.r(FACOV);
287
+ this.w(FACOV, (ov >> 1) | ((p & 1) << 7)); this.setMant(0x26, Math.floor(p / 2) + carry * 2 ** 31);
288
+ bit = bits & 1; bits >>= 1;
289
+ if (!bits) return 1;
290
+ }
291
+ }
292
+ // MULDIV ($BAB7; $BAB9 with A in place of ARG's exponent, `ey`): the exponents added for a product or quotient, and its sign. `zero` when ARG is
293
+ // zero or the sum too small (the FAC zeroed, and the caller done); too large is an overflow. An
294
+ // exponent of exactly 0 goes on, its sign 0, the caller working the mantissa out all the same.
295
+ // `c` the carry it leaves, which a product begins with.
296
+ muldiv(ey = this.r(ARG)) {
297
+ if (!ey) { this.zero(); return { zero: true }; }
298
+ const sum = ey + this.r(FAC), low = sum & 0xff;
299
+ if (sum < 256 && low < 0x80) { this.zero(); return { zero: true }; }
300
+ if (sum >= 256 && (low & 0x80)) throw overflow();
301
+ const e = (low + 0x80) & 0xff, c = sum < 256 ? 1 : 0;
302
+ this.w(FAC, e);
303
+ this.w(0x66, e ? this.r(ARISGN) : 0);
304
+ return { zero: false, c };
305
+ }
306
+ // FDIV ($BB0F, memory divided by the FAC; $BB12, ARG by the FAC): the FAC rounded first, then
307
+ // 34 bits of quotient by subtracting, 32 as the mantissa and two as the low bits' top
308
+ fdiv(at) { this.conupk(at); return this.fdivt(); }
309
+ fdivt() {
310
+ if (!this.r(FAC)) throw new FloatError(0x14); // DIVISION BY ZERO
311
+ this.round();
312
+ this.w(FAC, (0 - this.r(FAC)) & 0xff);
313
+ if (this.muldiv().zero) return { a: 0 };
314
+ const e = this.r(FAC) + 1; if (e > 255) throw overflow();
315
+ this.w(FAC, e);
316
+ let a = this.mant(0x6a), carry = 0, q = 0;
317
+ const f = this.mant(0x62);
318
+ for (let i = 0; i < 34; i++) {
319
+ const bit = carry || a >= f ? 1 : 0;
320
+ if (bit) a = (a - f + 2 ** 32) % 2 ** 32;
321
+ q = q * 2 + bit;
322
+ carry = a >= 2 ** 31 ? 1 : 0; a = (a * 2) % 2 ** 32;
323
+ }
324
+ this.setMant(0x6a, a);
325
+ this.w(FACOV, (q % 4) << 6); this.setMant(0x62, Math.floor(q / 4));
326
+ return this.normal();
327
+ }
328
+
329
+ // ---- whole numbers ----
330
+
331
+ // QINT ($BC9B): the FAC as a 32-bit whole number in $62 to $65, two's complement, its fraction
332
+ // shifted out (so, for a negative, the next whole number down); $68 0 after
333
+ qint() {
334
+ if (!this.r(FAC)) { for (const r of [0x62, 0x63, 0x64, 0x65]) this.w(r, 0); return { a: 0, y: 0 }; }
335
+ const a = (this.r(FAC) - 0xa0) & 0xff;
336
+ if (this.r(0x66) & 0x80) { this.w(BITS, 0xff); this.complement(); }
337
+ if (((a - 0xf9) & 0xff) & 0x80) this.shift(FAC, a, 0);
338
+ else {
339
+ // (under a byte: the first shift brings the sign in at the top, the rest keep it)
340
+ const m = this.mant(0x62);
341
+ this.setMant(0x62, Math.floor(m / 2) + ((this.r(0x66) & 0x80) ? 2 ** 31 : 0));
342
+ this.bitShift(FAC, (a + 1) & 0xff, 0, true);
343
+ }
344
+ this.w(BITS, 0);
345
+ return { y: 0 };
346
+ }
347
+ // INT ($BCCC): the FAC's whole part, the next whole number down, as a number again
348
+ int() {
349
+ if (this.r(FAC) >= 0xa0) return { a: this.r(FAC) };
350
+ this.qint();
351
+ this.w(FACOV, 0);
352
+ const s = this.r(0x66); this.w(0x66, 0);
353
+ return this.float32(s);
354
+ }
355
+ // ($BCDB) a 32-bit two's complement whole number in $62 to $65 as a number: negative when A's top
356
+ // bit is set, as INT and Blitz! enter it; $07 its lowest byte, as the ROM keeps it
357
+ float32(a) {
358
+ this.w(FAC, 0xa0); this.w(0x07, this.r(0x65));
359
+ if (a & 0x80) this.negate();
360
+ return this.normal();
361
+ }
362
+ }
363
+
364
+ // (the methods for building a number from its digits, FIN's: basic-rom.js)
365
+ Object.assign(Floats.prototype, {
366
+ // MUL10 ($BAE2): the FAC ten times, as the ROM does it: ARG the FAC (rounded), then ($BAED) with
367
+ // the exponent two more: five times it, doubled
368
+ mul10() {
369
+ this.movaf();
370
+ const e = this.r(FAC);
371
+ if (!e) return { a: 0 };
372
+ if (e + 2 > 255) throw overflow();
373
+ return this.addDoubled(e + 2);
374
+ },
375
+ // ($BAED) ARG added to the FAC with its exponent `a`, then doubled: FADDT entered at $B877 as if
376
+ // ARG's exponent were `a` (one or two more than its own: ARG the FAC, it is three or five times
377
+ // it), the FAC shifted right by the difference and ARG added, and the exponent one more
378
+ addDoubled(a) {
379
+ const by = (this.r(ARG) - a) & 0xff;
380
+ this.w(ARISGN, 0);
381
+ this.w(FAC, a); this.w(0x66, this.r(0x6e)); this.w(ARGOV, 0);
382
+ const low = this.bitShift(FAC, by, this.r(FACOV), false) + this.r(ARGOV), m = this.mant(0x62) + this.mant(0x6a) + (low > 255 ? 1 : 0);
383
+ this.w(FACOV, low); this.setMant(0x62, m % 2 ** 32);
384
+ if (m >= 2 ** 32) this.carryIn(1);
385
+ const e2 = this.r(FAC) + 1; if (e2 > 255) throw overflow();
386
+ this.w(FAC, e2);
387
+ return { a: e2 };
388
+ },
389
+ // DIV10 ($BAFE): the FAC a tenth: ARG the FAC (rounded), the FAC 10 (the ROM's constant at $BAF9),
390
+ // the signs' EOR 0, and ARG divided by it
391
+ div10() { this.movaf(); return this.divInto(0xbaf9, 0); },
392
+ // ($BB07) ARG divided by a number in memory: the signs' EOR `sign` (X), the FAC the number, FDIVT
393
+ divInto(at, sign) { this.w(ARISGN, sign); this.movfm(at); return this.fdivt(); },
394
+ // ($BC3C) a byte, 0 to 127, as a number in the FAC (a digit, for FIN)
395
+ byte(v) {
396
+ this.w(0x62, v); this.w(0x63, 0);
397
+ for (const at of [0x64, 0x65, FACOV, 0x66]) this.w(at, 0);
398
+ this.w(FAC, 0x88);
399
+ if (v & 0x80) this.negate();
400
+ return this.normal();
401
+ },
402
+ // ($BD7E) a digit added to the FAC: ARG the FAC (rounded), the FAC the digit, and FADDT
403
+ addDigit(d) { this.movaf(); this.byte(d); this.w(ARISGN, this.r(0x6e) ^ this.r(0x66)); return this.faddt(); },
404
+ // ---- the series and the functions on them ----
405
+
406
+ // POLY2 ($E059, the table's address in $71/$72): the FAC, x, kept at $5C (rounded), then from the
407
+ // table's count and coefficients, highest first, x times each and the next added (Horner's)
408
+ poly2(at) { this.w(0x71, at); this.w(0x72, at >> 8); return this.poly(); },
409
+ poly() {
410
+ this.movmf(0x5c);
411
+ let p = this.r(0x71) | this.r(0x72) << 8;
412
+ this.w(0x67, this.r(p)); p++; this.w(0x71, p); this.w(0x72, p >> 8);
413
+ for (let from = p; ; from = 0x5c) {
414
+ this.fmult(from);
415
+ p = (this.r(0x71) | this.r(0x72) << 8) + 5; this.w(0x71, p); this.w(0x72, p >> 8);
416
+ this.fadd(p);
417
+ this.w(0x67, this.r(0x67) - 1); if (!this.r(0x67)) return { a: this.r(FAC) };
418
+ }
419
+ },
420
+ // POLY1 ($E043): a series of x squared, x kept at $57, times x
421
+ poly1(at) { this.w(0x71, at); this.w(0x72, at >> 8); this.movmf(0x57); this.fmult(0x57); this.poly(); return this.fmult(0x57); },
422
+ // LOG ($B9EA): ILLEGAL QUANTITY for zero or less; the exponent kept, less 128 (SIGN's carry
423
+ // clear), the mantissa as a number from a half to one, and log2 of that from LOG's series of
424
+ // (sqrt 2 / (x + sqrt .5)), from 1; the exponent added (as $BD7E adds a digit), times log 2
425
+ log() {
426
+ if (this.sign() !== 1) throw new FloatError(0x0e);
427
+ const n = (this.r(FAC) - 0x80) & 0xff;
428
+ this.w(FAC, 0x80);
429
+ this.fadd(0xb9d6); this.fdiv(0xb9db); this.fsub(0xb9bc); this.poly1(0xb9c1); this.fadd(0xb9e0);
430
+ this.addDigit(n);
431
+ return this.fmult(0xb9e5);
432
+ },
433
+ // EXP ($BFED, `c` the carry it is entered with): the FAC over log 2; its low bits rounded in, a
434
+ // carry from $70 + $50 (and the carry FMULT leaves: clear for a product, as entered for a zero)
435
+ // the mantissa one more; past 2^7 an overflow, or 0 for a negative; the whole part (INT, $07
436
+ // its low byte) and the fraction, from the swapped FAC and ARG; EXP's series of the fraction, and
437
+ // 2 to the whole part, by MULDIV with that exponent ($BAB9)
438
+ exp(c = 0) {
439
+ const ex = this.r(FAC);
440
+ this.fmult(0xbfbf);
441
+ if (ex && this.r(FAC)) c = 0;
442
+ else if (ex) { const sum = 0x81 + ex; c = sum < 256 && (sum & 0xff) < 0x80 ? 0 : 1; }
443
+ const s = this.r(FACOV) + 0x50 + c;
444
+ if (s > 255) { const m = this.mant(0x62) + 1; this.setMant(0x62, m % 2 ** 32); if (m >= 2 ** 32) this.carryIn(1); }
445
+ this.w(ARGOV, s);
446
+ this.movef();
447
+ const tooBig = () => { if (!(this.r(0x66) & 0x80)) throw overflow(); return this.zero(); };
448
+ if (this.r(FAC) >= 0x88) return tooBig();
449
+ this.int();
450
+ const a = (this.r(0x07) + 0x81) & 0xff;
451
+ if (!a) return tooBig();
452
+ for (let k = 0; k < 6; k++) { const v = this.r(ARG + k); this.w(ARG + k, this.r(FAC + k)); this.w(FAC + k, v); }
453
+ this.w(FACOV, this.r(ARGOV));
454
+ this.fsubt(); this.negop();
455
+ this.poly2(0xbfc4);
456
+ this.w(ARISGN, 0);
457
+ const e = (a - 1) & 0xff;
458
+ if (!e) return this.zero();
459
+ this.muldiv(e);
460
+ return { a: 0 };
461
+ },
462
+ // FPWRT ($BF7B, ARG to the power of the FAC; `z` the Z flag it is entered with, set for a power
463
+ // of 0, `c` the carry): EXP(0) for that; 0 for a base of 0; the power kept at $4E; a negative base
464
+ // only to a whole power, its sign then dropped (as FCOMP's Y, 4, for the FAC's) and the power's
465
+ // low bit kept (in $07): EXP of the power times LOG of the base, negated for an odd power. (A
466
+ // power not whole is FCOMP's answer for the sign, its Y for the oddness: an ILLEGAL QUANTITY,
467
+ // unless INT, from the ROM's fill byte $68, made the power more.)
468
+ fpwrt(z, c) {
469
+ if (z) return this.exp(c);
470
+ if (!this.r(ARG)) { this.w(FAC, 0); this.w(0x66, 0); return { a: 0 }; }
471
+ this.movmf(0x4e);
472
+ let sign = this.r(0x6e), odd = 0;
473
+ if (sign & 0x80) {
474
+ this.int();
475
+ const { a, y } = this.compare(0x4e);
476
+ if (a) { sign = a; odd = y & 1; } else { sign = y; odd = this.r(0x07) & 1; }
477
+ }
478
+ this.w(0x66, sign); for (let i = 5; i >= 1; i--) this.w(0x60 + i, this.r(0x68 + i)); this.w(FACOV, 0);
479
+ this.log(); this.fmult(0x4e);
480
+ this.exp(0);
481
+ if (odd && this.r(FAC)) this.w(0x66, this.r(0x66) ^ 0xff);
482
+ return { a: this.r(FAC) };
483
+ },
484
+ // SIN ($E26B): the FAC over two pi; its fraction, from a quarter, and folded (a negative a half
485
+ // on, and if then positive, the TAN's flag at $12 turned over), a quarter on, its sign back; and
486
+ // SIN's series. COS ($E264): a half pi on, then SIN.
487
+ sin() {
488
+ this.movaf(); this.divInto(0xe2e5, this.r(0x6e));
489
+ this.movaf(); this.int(); this.w(ARISGN, 0); this.fsubt(); this.fsub(0xe2ea);
490
+ const s = this.r(0x66);
491
+ if (!(s & 0x80)) this.negop();
492
+ else { this.fadd(0xbf11); if (!(this.r(0x66) & 0x80)) { this.w(0x12, this.r(0x12) ^ 0xff); this.negop(); } }
493
+ this.fadd(0xe2ea);
494
+ if (s & 0x80) this.negop();
495
+ return this.poly1(0xe2ef);
496
+ },
497
+ cos() { this.fadd(0xe2e0); return this.sin(); },
498
+ // FOUT ($BDDD): the FAC as text at $0100, a zero after, as Microsoft's FOUT writes it (its
499
+ // source's steps, BASIC-M6502): its sign or a space at $0100; the number brought
500
+ // between 99999999.9 and 999999999 by tens, $5D counting them; a half added, as a whole number;
501
+ // its nine digits counted out by adding the powers of ten, each in turn, the point placed among
502
+ // them; the zeros at the end taken off, and the exponent ($5E) last. $71 where it writes, $47
503
+ // where it is in the table. A and Y the text's address.
504
+ fout() {
505
+ const buf = (y, v) => this.w(0xff + y, v);
506
+ let y = 1;
507
+ buf(y, this.r(0x66) & 0x80 ? 0x2d : 0x20);
508
+ this.w(0x66, this.r(0xff + y)); this.w(0x71, y); y++;
509
+ if (!this.r(FAC)) { buf(y, 0x30); buf(y + 1, 0); return { a: 0x00, y: 0x01 }; }
510
+ let a = 0;
511
+ if (this.r(FAC) <= 0x80) { this.fmult(0xbdbd); a = 0xf7; }
512
+ this.w(0x5d, a);
513
+ // (between the bounds: smaller by tens, or bigger; the half not added when it is exactly the top)
514
+ let step = 'FOUT4';
515
+ for (;;) {
516
+ if (step === 'FOUT4') {
517
+ const c = this.fcomp(0xbdb8);
518
+ if (c === 0) { step = 'BIGGES'; break; }
519
+ step = c === 1 ? 'FOUT9' : 'FOUT3';
520
+ } else if (step === 'FOUT3') {
521
+ const c = this.fcomp(0xbdb3);
522
+ if (c === 1) { step = 'FOUT5'; break; }
523
+ this.mul10(); this.w(0x5d, (this.r(0x5d) - 1) & 0xff);
524
+ step = this.r(0x5d) ? 'FOUT3' : 'FOUT9';
525
+ } else {
526
+ this.div10(); this.w(0x5d, (this.r(0x5d) + 1) & 0xff);
527
+ if (this.r(0x5d)) step = 'FOUT4'; else { step = 'FOUT5'; break; }
528
+ }
529
+ }
530
+ if (step === 'FOUT5') this.fadd(0xbf11);
531
+ this.qint();
532
+ // the form: E notation below 0.01 or from 1E9 ($5E the exponent), else the places before the point
533
+ let x = 1, e;
534
+ a = (this.r(0x5d) + 10) & 0xff;
535
+ if (a & 0x80) e = a - 2;
536
+ else if (a >= 11) e = a - 2;
537
+ else { x = (a - 1) & 0xff; e = 0; }
538
+ this.w(0x5e, e & 0xff); this.w(0x5d, x);
539
+ if (x === 0 || x & 0x80) {
540
+ y = this.r(0x71); y++; buf(y, 0x2e);
541
+ if (x) { y++; buf(y, 0x30); }
542
+ this.w(0x71, y);
543
+ }
544
+ // each digit: a power of ten added, or taken away, until the mantissa's sign turns
545
+ y = 0; x = 0x80;
546
+ for (;;) {
547
+ let c = 0;
548
+ for (const k of [3, 2, 1, 0]) { const v = this.r(0x62 + k) + this.r(0xbf16 + y + k) + c; this.w(0x62 + k, v & 0xff); c = v >> 8; }
549
+ x = (x + 1) & 0xff;
550
+ if (c ? x & 0x80 : !(x & 0x80)) continue;
551
+ a = x;
552
+ if (c) { const v = (a ^ 0xff) + 0x0a + 1; a = v & 0xff; c = v >> 8; }
553
+ a = (a + 0x2f + c) & 0xff;
554
+ y += 4; this.w(0x47, y);
555
+ y = this.r(0x71) + 1; x = a;
556
+ buf(y, a & 0x7f);
557
+ this.w(0x5d, (this.r(0x5d) - 1) & 0xff);
558
+ if (!this.r(0x5d)) { y++; buf(y, 0x2e); }
559
+ this.w(0x71, y);
560
+ y = this.r(0x47);
561
+ x = (x ^ 0xff) & 0x80;
562
+ if (y === 0x24 || y === 0x3c) break;
563
+ }
564
+ // the zeros at the end off, and a point left last; then the exponent
565
+ y = this.r(0x71);
566
+ let ch; do { ch = this.r(0xff + y); y--; } while (ch === 0x30);
567
+ if (ch !== 0x2e) y++;
568
+ let ex = this.r(0x5e);
569
+ if (!ex) { buf(y + 1, 0); return { a: 0x00, y: 0x01 }; }
570
+ let sign = 0x2b;
571
+ if (ex & 0x80) { ex = (0 - ex) & 0xff; sign = 0x2d; }
572
+ buf(y + 2, sign); buf(y + 1, 0x45);
573
+ let hi = 0x2f, c = 1;
574
+ do { hi++; const t = ex - 10 - (1 - c); c = t >= 0 ? 1 : 0; ex = t & 0xff; } while (c);
575
+ buf(y + 4, (ex + 0x3a) & 0xff); buf(y + 3, hi); buf(y + 5, 0);
576
+ return { a: 0x00, y: 0x01 };
577
+ },
578
+ // NEGOP ($BFB4): the FAC's sign turned over, unless it is zero
579
+ negop() { if (this.r(FAC)) this.w(0x66, this.r(0x66) ^ 0xff); return { a: this.r(0x66) }; },
580
+ });
581
+
582
+ // an overflow, and BASIC's errors by their number in its table (X for its error routine, $A437)
583
+ export class FloatError extends Error { constructor(x) { super('BASIC error ' + x); this.x = x; } }
584
+ const overflow = () => new FloatError(0x0f);
package/glyph-hash.js ADDED
@@ -0,0 +1,8 @@
1
+ // A character's eight bytes (its rows, the left dot the top bit) as a 32-bit FNV-1a hash: how
2
+ // glyph-hashes.js keeps the 64's characters, and how a cell of a picture is recognised as one of
3
+ // them.
4
+ export function glyphHash(rows) {
5
+ let h = 0x811c9dc5;
6
+ for (let i = 0; i < 8; i++) { h ^= rows[i]; h = Math.imul(h, 0x01000193) >>> 0; }
7
+ return h;
8
+ }
@@ -0,0 +1,70 @@
1
+ // The 64's 512 characters as hashes: the character ROM's first set (screen codes 0 to 255, the last 128
2
+ // reversed), then its second, each a 32-bit FNV-1a hash of its eight bytes (glyph-hash.js).
3
+ // Generated from Commodore's character ROM; numbers only, no character can be drawn from them.
4
+ // Not edited by hand.
5
+ export const GLYPH_HASHES = Uint32Array.of(
6
+ 0xa63acec9, 0xcfb72db7, 0xc1892941, 0xd80b2795, 0x1b055853, 0x733925ed, 0xb76faaf3, 0x94217edd,
7
+ 0xe71b097b, 0xcc9f3afd, 0xb1af50c7, 0x6f9d9a15, 0x61fb6d9b, 0x464b312c, 0x85f6570b, 0x96070b83,
8
+ 0xb876df6d, 0xbdd92233, 0x5295e507, 0x32cadce7, 0x4dd2b86b, 0xe0a58b69, 0xb909704f, 0x0a4ca684,
9
+ 0x090b885d, 0x391a859f, 0x1efef677, 0x3b8708c5, 0x2401ada1, 0xd655d051, 0xb19651ef, 0xeb166297,
10
+ 0x9be17165, 0xccb1980d, 0x760cedb3, 0x63e18eff, 0x0294278d, 0xa3ebed65, 0x49817fb1, 0xf278feff,
11
+ 0x987ef385, 0x52c0c411, 0x99e73ab0, 0xbed544ab, 0x730351a5, 0x93a47d1b, 0x63033875, 0x2dc56d46,
12
+ 0xf5f3b30b, 0xbe43f89b, 0xae016c73, 0x52bd07e1, 0xb6f6f3fe, 0xff3909cd, 0x557295c7, 0xade16941,
13
+ 0xf0fb1a01, 0x0161eb3b, 0x64320035, 0x8445ba4d, 0x710653c5, 0x0c491265, 0xd1adc673, 0xb34aabed,
14
+ 0xb700ca17, 0x22397953, 0x3c19df65, 0xb700ca17, 0xbe9abf9b, 0xfe689467, 0xc712d72b, 0x0ff37de5,
15
+ 0xefec4d45, 0x931ca24d, 0x62103ab3, 0xfa82e19d, 0x49efc6bb, 0xa706e569, 0xcc6ef1e5, 0x084b2e8b,
16
+ 0xa637d02d, 0xf466251d, 0xfd160a47, 0xfbed4f22, 0x1e3ba9e5, 0x03bc99db, 0x937537f9, 0x8c73847d,
17
+ 0x1df09969, 0x5d6969e5, 0x05f85cb4, 0xee667567, 0xa3db00e5, 0x3c19df65, 0xd5bf523e, 0xf607d477,
18
+ 0x9be17165, 0x99f161e5, 0xb4512201, 0xe802ca7a, 0x4ce28808, 0x58e31265, 0xb2c0a219, 0x461f842d,
19
+ 0x1d055413, 0xd33f53e4, 0x461f842d, 0xc051b967, 0x581deaa1, 0x1e2ddc7f, 0x36f8d78d, 0x4c4ff03b,
20
+ 0xa300624f, 0x4c42987f, 0x34dd1f8f, 0x6a2e9b65, 0x58e31265, 0xf5528fe5, 0x7e413aad, 0x2505bf8b,
21
+ 0x292df97c, 0x02147f26, 0xcaefc185, 0x6044a0a5, 0x940b4261, 0x099fd55d, 0xe0455ea5, 0x9c81d7e1,
22
+ 0xd4b39b79, 0xdc8da58b, 0x538ca0cd, 0xfc193485, 0x0d506237, 0x64e1ab41, 0x64f248cb, 0xd27b4ccd,
23
+ 0xf43f3a73, 0xd240f335, 0x9ae62617, 0x432d4101, 0xf2c122cf, 0xc379e674, 0x84d795e3, 0xb34cb6f7,
24
+ 0xd3fcf7ad, 0xd6841827, 0x112d3413, 0x9c712aff, 0xc43b5f63, 0xa22875e5, 0x1fb4d0cf, 0x20c02064,
25
+ 0xbf7a9239, 0x9d5ca57f, 0xf0de6067, 0xbb7ae8dd, 0xc45b03c9, 0xe2b4e829, 0x426d54d7, 0xa759948f,
26
+ 0x6cae0a5d, 0xeae53e95, 0x8f14b49b, 0xaf792ac7, 0x9a0280a1, 0x5f6a9421, 0x0f9d9745, 0x30f21787,
27
+ 0xc87f5d8d, 0xf48ead51, 0x5b0c5cb8, 0x27bf827b, 0xf389198d, 0x24c7045b, 0x038932bd, 0xf4b2cc5e,
28
+ 0xdcb56f9f, 0x353848ef, 0xe4e4cf5f, 0xf2a5976d, 0xd84a1f36, 0x8f42ce19, 0xe6e0319f, 0xcc9d583d,
29
+ 0x6061d50d, 0x74a966cf, 0x618c4ead, 0x31c82d45, 0xc7adac99, 0x581a4af1, 0x798d5a93, 0xd29d4d6d,
30
+ 0xe319f30f, 0xdbab8ea3, 0x5383376d, 0xe319f30f, 0xdf630227, 0xa95eb15f, 0xcd40fc97, 0xd6d6ff3d,
31
+ 0xe9c4fd6d, 0x1df55185, 0x1ba82113, 0x5d3b77b5, 0x26170287, 0xe26129c9, 0xc075e735, 0xbc1077b7,
32
+ 0x74c89f8d, 0xe8063525, 0xcea2193f, 0xf8fc836a, 0x12c5d25d, 0x9a04a2db, 0x8702da71, 0xcd17a8c5,
33
+ 0xdab3d03d, 0xd23a719d, 0x4f6b1528, 0xf706ca4f, 0xcfd5ec5d, 0x5383376d, 0xd9381ec2, 0xc813957f,
34
+ 0x6cae0a5d, 0x40a3e13d, 0x84bf99c1, 0x35f2d172, 0xcdaea310, 0x6ac9fbdd, 0xf6f39359, 0x3b0bc5c5,
35
+ 0x929224ef, 0xa650b140, 0x3b0bc5c5, 0x24bfc80f, 0x6905c661, 0xe6460697, 0x67b30275, 0xe75cdb87,
36
+ 0xe444ee97, 0xb889e2d7, 0x3f4d1217, 0x1f6cbaad, 0x6ac9fbdd, 0xf2c9775d, 0x273093e5, 0xac1d7c37,
37
+ 0x7eec1c74, 0x83a3362e, 0x78676dcd, 0x3158389d, 0xedfde341, 0xa33c8f45, 0x255796fd, 0x21af5301,
38
+ 0xa63acec9, 0x673c3eb9, 0xca581dfd, 0x9d3e9be5, 0x33baa295, 0x2d1fe45d, 0xcc4cbbd5, 0x285415f7,
39
+ 0xe6493f87, 0xab3ae759, 0x72d77a37, 0xae73670b, 0x7674dbb1, 0xed13a8c7, 0x57ca9f29, 0xd280ad53,
40
+ 0xf4a4184d, 0x9254bcd5, 0x9dd85cef, 0x6199a3dd, 0xb581d065, 0xab4edadb, 0x2a68d62f, 0x734fcf38,
41
+ 0x766f48fd, 0x982b9639, 0x32bbe4f9, 0x3b8708c5, 0x2401ada1, 0xd655d051, 0xb19651ef, 0xeb166297,
42
+ 0x9be17165, 0xccb1980d, 0x760cedb3, 0x63e18eff, 0x0294278d, 0xa3ebed65, 0x49817fb1, 0xf278feff,
43
+ 0x987ef385, 0x52c0c411, 0x99e73ab0, 0xbed544ab, 0x730351a5, 0x93a47d1b, 0x63033875, 0x2dc56d46,
44
+ 0xf5f3b30b, 0xbe43f89b, 0xae016c73, 0x52bd07e1, 0xb6f6f3fe, 0xff3909cd, 0x557295c7, 0xade16941,
45
+ 0xf0fb1a01, 0x0161eb3b, 0x64320035, 0x8445ba4d, 0x710653c5, 0x0c491265, 0xd1adc673, 0xb34aabed,
46
+ 0xb700ca17, 0xcfb72db7, 0xc1892941, 0xd80b2795, 0x1b055853, 0x733925ed, 0xb76faaf3, 0x94217edd,
47
+ 0xe71b097b, 0xcc9f3afd, 0xb1af50c7, 0x6f9d9a15, 0x61fb6d9b, 0x464b312c, 0x85f6570b, 0x96070b83,
48
+ 0xb876df6d, 0xbdd92233, 0x5295e507, 0x32cadce7, 0x4dd2b86b, 0xe0a58b69, 0xb909704f, 0x0a4ca684,
49
+ 0x090b885d, 0x391a859f, 0x1efef677, 0xee667567, 0xa3db00e5, 0x3c19df65, 0xf6f39359, 0x9fa87cb9,
50
+ 0x9be17165, 0x99f161e5, 0xb4512201, 0xe802ca7a, 0x4ce28808, 0x58e31265, 0xb2c0a219, 0x461f842d,
51
+ 0x1d055413, 0x3f02d529, 0x461f842d, 0xc051b967, 0x581deaa1, 0x1e2ddc7f, 0x36f8d78d, 0x4c4ff03b,
52
+ 0xa300624f, 0x4c42987f, 0x34dd1f8f, 0x6a2e9b65, 0x58e31265, 0xf5528fe5, 0x7e413aad, 0x2505bf8b,
53
+ 0x292df97c, 0x02147f26, 0xef56af2f, 0x6044a0a5, 0x940b4261, 0x099fd55d, 0xe0455ea5, 0x9c81d7e1,
54
+ 0xd4b39b79, 0x714f19f9, 0xab5825e9, 0x2e72d0e5, 0xefc916bd, 0xf026a62d, 0x7999cad1, 0xd1c47a1b,
55
+ 0xab98cd3f, 0x4ab842e1, 0x8225944b, 0x7d050287, 0x00942f29, 0xbba2f25b, 0xfebe3ab9, 0xbfcf382f,
56
+ 0x8ef2c8cd, 0x9bc42519, 0xc873ae67, 0x4eadea0d, 0xbeea2dd5, 0x9f665097, 0x7c4d047b, 0x850c239c,
57
+ 0x42907bdd, 0x2b960839, 0xed57b699, 0xbb7ae8dd, 0xc45b03c9, 0xe2b4e829, 0x426d54d7, 0xa759948f,
58
+ 0x6cae0a5d, 0xeae53e95, 0x8f14b49b, 0xaf792ac7, 0x9a0280a1, 0x5f6a9421, 0x0f9d9745, 0x30f21787,
59
+ 0xc87f5d8d, 0xf48ead51, 0x5b0c5cb8, 0x27bf827b, 0xf389198d, 0x24c7045b, 0x038932bd, 0xf4b2cc5e,
60
+ 0xdcb56f9f, 0x353848ef, 0xe4e4cf5f, 0xf2a5976d, 0xd84a1f36, 0x8f42ce19, 0xe6e0319f, 0xcc9d583d,
61
+ 0x6061d50d, 0x74a966cf, 0x618c4ead, 0x31c82d45, 0xc7adac99, 0x581a4af1, 0x798d5a93, 0xd29d4d6d,
62
+ 0xe319f30f, 0xdc8da58b, 0x538ca0cd, 0xfc193485, 0x0d506237, 0x64e1ab41, 0x64f248cb, 0xd27b4ccd,
63
+ 0xf43f3a73, 0xd240f335, 0x9ae62617, 0x432d4101, 0xf2c122cf, 0xc379e674, 0x84d795e3, 0xb34cb6f7,
64
+ 0xd3fcf7ad, 0xd6841827, 0x112d3413, 0x9c712aff, 0xc43b5f63, 0xa22875e5, 0x1fb4d0cf, 0x20c02064,
65
+ 0xbf7a9239, 0x9d5ca57f, 0xf0de6067, 0xf706ca4f, 0xcfd5ec5d, 0x5383376d, 0xb2c0a219, 0xd4d06f39,
66
+ 0x6cae0a5d, 0x40a3e13d, 0x84bf99c1, 0x35f2d172, 0xcdaea310, 0x6ac9fbdd, 0xf6f39359, 0x3b0bc5c5,
67
+ 0x929224ef, 0x402c8be1, 0x3b0bc5c5, 0x24bfc80f, 0x6905c661, 0xe6460697, 0x67b30275, 0xe75cdb87,
68
+ 0xe444ee97, 0xb889e2d7, 0x3f4d1217, 0x1f6cbaad, 0x6ac9fbdd, 0xf2c9775d, 0x273093e5, 0xac1d7c37,
69
+ 0x7eec1c74, 0x83a3362e, 0x86ee680f, 0x3158389d, 0xedfde341, 0xa33c8f45, 0x255796fd, 0x21af5301,
70
+ );