-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvm.ts
383 lines (348 loc) · 11.4 KB
/
vm.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
import {Head, Prepend, Reverse, Tail} from './utils'
type No_Arg = any;
type Instruction_Address = any[]; // use array['length'] to index into Program's instructions
type B = 1 | 0;
type BITS_4 = [B, B, B, B];
type Num = BITS_4;
type Instructions =
| ["push", Num] // [h, ...t] -> [arg, h, ...t]
| ["pop", No_Arg] // [h, ...t] -> [...t]
| ["dup", No_Arg] // [h, ...t] -> [h, h, ...t]
| ["peek", No_Arg] // [h, hh, ...t] -> [hh, h, hh, ...t]
| ["replace", Num] // [h, ...t] -> [arg, ...t]
| ["inc", No_Arg] // [h, ...t] -> [++h, ...t]
| ["mod", Num] // [h, ...t] -> [h % arg, ...t]
| ["eq", Num] // [h, ...t] -> [h == arg, h, ...t]
| ["jump", Instruction_Address] // jump program to instruction at arg
| ["ifNZero", Instruction_Address] // pop head, if != 0 jump program to instruction at arg
| ["printHead", No_Arg] // copy head, covert to string then add to stdout
| ["print", string] // add arg to stdout
| ["stop", No_Arg]; // halt! returns contents of stdout
/**
* This is the main entry point to run the Virtual Machine
* @param Program - The array of instructions to execute
* @returns { stdOut: string[] }
*/
export type VM<
Program extends Instructions[],
/* variables: */
Result extends any = InnerVM<Program>
> = {
// Use a trampoline to extend TypeScript's Type Instantiation depth limit of 50
1: VM<Program, InnerVM<Program, [], Result>>;
0: Result["state"];
}[Result["tag"] extends "bounce" ? 1 : 0];
type InnerVM<
Program extends Instructions[],
Bounces extends any[] = [],
Result extends any = Tick<Program>
> = {
// Use two trampolines to further increase limit...
1: InnerVM<Program, Prepend<any, Bounces>,
Tick<Result["state"][0], Result["state"][1], Result["state"][2], Result["state"][3]>
>;
0: Result;
}[Result["tag"] extends "bounce"
? (Bounces['length'] extends 5
? 0
: 1)
: 0];
// Execute the next instruction
type Tick<
Program extends Instructions[],
PC extends any[] = [], // program-counter - length of array indexes into Instructions
Stack extends Num[] = [],
StdOut extends string[] = []
> = {
// Define all the VM instructions
'push': Tick<Program, Prepend<any, PC>, Prepend<Program[PC["length"]][1], Stack>, StdOut>;
'pop': Tick<Program, Prepend<any, PC>, Tail<Stack>, StdOut>;
'dup': Tick<Program, Prepend<any, PC>, Prepend<Head<Stack>, Stack>, StdOut>;
'peek': Tick<Program, Prepend<any, PC>, Prepend<Head<Tail<Stack>>, Stack>, StdOut>;
'replace': Tick<Program, Prepend<any, PC>, Prepend<Program[PC["length"]][1], Tail<Stack>>, StdOut>;
'inc': Tick<Program, Prepend<any, PC>, Prepend<ADD_4<Head<Stack>, N_1>, Tail<Stack>>, StdOut>;
'mod': Tick<Program, Prepend<any, PC>, Prepend<MOD_4<Head<Stack>, Program[PC["length"]][1]>, Tail<Stack>>, StdOut>;
'eq': Tick<Program, Prepend<any, PC>, Prepend<EQ_4<Head<Stack>, Program[PC["length"]][1]>, Stack>, StdOut>;
// 'jump' seems as good a natural time to bounce on the trampoline
'jump': { tag: "bounce"; state: [Program, Program[PC["length"]][1], Stack, StdOut] };
'ifNZero': Head<Stack> extends N_0
? Tick<Program, Prepend<any, PC>, Tail<Stack>, StdOut>
: Tick<Program, Program[PC["length"]][1], Tail<Stack>, StdOut>;
'printHead': Tick<Program, Prepend<any, PC>, Stack, Prepend<N_ToString<Head<Stack>>, StdOut>>;
'print': Tick<Program, Prepend<any, PC>, Stack, Prepend<Program[PC["length"]][1], StdOut>>;
'stop': { tag: "result"; state: { stdOut: Reverse<StdOut> } };
// Then index into the correct instruction based on the current program-counter (PC)
}[Program[PC["length"]][0]];
// 4-Bit Arithmetic Logic Unit (ALU)
// - handle numbers 0 to 15
// - everything constructed from 1-bit logic gates
export type N_0 = [0, 0, 0, 0];
export type N_1 = [1, 0, 0, 0];
export type N_2 = [0, 1, 0, 0];
export type N_3 = [1, 1, 0, 0];
export type N_4 = [0, 0, 1, 0];
export type N_5 = [1, 0, 1, 0];
export type N_6 = [0, 1, 1, 0];
export type N_7 = [1, 1, 1, 0];
export type N_8 = [0, 0, 0, 1];
export type N_9 = [1, 0, 0, 1];
export type N_10 = [0, 1, 0, 1];
export type N_11 = [1, 1, 0, 1];
export type N_12 = [0, 0, 1, 1];
export type N_13 = [1, 0, 1, 1];
export type N_14 = [0, 1, 1, 1];
export type N_15 = [1, 1, 1, 1];
export type False = N_0;
export type True = N_1;
type MOD_4<
numerator extends Num,
divisor extends Num,
> = AsBITS_4<DIV_4<numerator, divisor>['remainder']>;
type Divider<
remainder extends BITS_4,
divisor extends BITS_4,
count extends BITS_4
> = COMP_4<remainder, divisor>["less"] extends 1
? [count, remainder]
: [ADD_4<N_1, count>, SUB_4<remainder, divisor>];
type AsBITS_4<N> = N extends BITS_4 ? N : never;
type DIV_4<
numerator extends BITS_4,
divisor extends BITS_4,
/* variables: */
count extends BITS_4 = N_0,
remainder extends BITS_4 = numerator
> = (
Divider<remainder, divisor, count> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? Divider<AsBITS_4<R>, divisor, AsBITS_4<C>> extends [infer C, infer R]
? { count: C; remainder: R }
: never : never : never : never : never : never : never : never
: never : never : never : never : never : never : never : never
);
type MUL_4<
regA extends BITS_4,
regB extends BITS_4,
/* variables: */
sum0 extends BITS_4 = BITWISE_AND<[regA[0], regA[0], regA[0], regA[0]], regB>,
sum1 extends BITS_4 = ADD_4<
[0, AND<regA[1], regB[0]>, AND<regA[1], regB[1]>, AND<regA[1], regB[2]>],
sum0
>,
sum2 extends BITS_4 = ADD_4<
[0, 0, AND<regA[2], regB[0]>, AND<regA[2], regB[1]>],
sum1
>,
sum3 extends BITS_4 = ADD_4<[0, 0, 0, AND<regA[3], regB[0]>], sum2>
> = sum3;
type SUB_4<
regA extends BITS_4,
regB extends BITS_4,
/* variables: */
a extends SUBTRACT_RESULT = FULL_SUBTRACTOR<0, regA[0], regB[0]>,
b extends SUBTRACT_RESULT = FULL_SUBTRACTOR<a["borrow"], regA[1], regB[1]>,
c extends SUBTRACT_RESULT = FULL_SUBTRACTOR<b["borrow"], regA[2], regB[2]>,
d extends SUBTRACT_RESULT = FULL_SUBTRACTOR<c["borrow"], regA[3], regB[3]>
> = AsBITS_4<[a["diff"], b["diff"], c["diff"], d["diff"]]>;
type ADD_4<
regA extends BITS_4,
regB extends BITS_4,
/* variables: */
a extends ADDER_RESULT = FULL_ADDER<0, regA[0], regB[0]>,
b extends ADDER_RESULT = FULL_ADDER<a["carry"], regA[1], regB[1]>,
c extends ADDER_RESULT = FULL_ADDER<b["carry"], regA[2], regB[2]>,
d extends ADDER_RESULT = FULL_ADDER<c["carry"], regA[3], regB[3]>
> = AsBITS_4<[a["sum"], b["sum"], c["sum"], d["sum"]]>;
type FULL_SUBTRACTOR<
borrow extends B,
a extends B,
b extends B,
/* variables: */
subtractor1 extends SUBTRACT_RESULT = HALF_SUBTRACTOR<a, b>,
subtractor2 extends SUBTRACT_RESULT = HALF_SUBTRACTOR<
subtractor1["diff"],
borrow
>
> = {
diff: subtractor2["diff"];
borrow: OR<subtractor1["borrow"], subtractor2["borrow"]>;
};
type FULL_ADDER<
carry extends B,
a extends B,
b extends B,
/* variables: */
adder1 extends ADDER_RESULT = HALF_ADDER<a, b>,
adder2 extends ADDER_RESULT = HALF_ADDER<carry, adder1["sum"]>
> = {
sum: adder2["sum"];
carry: OR<adder2["carry"], adder1["carry"]>;
};
type SUBTRACT_RESULT = { diff: B; borrow: B };
type ADDER_RESULT = { sum: B; carry: B };
type HALF_SUBTRACTOR<a extends B, b extends B> = {
diff: XOR<a, b>;
borrow: AND<NOT<a>, b>;
};
type HALF_ADDER<a extends B, b extends B> = {
sum: XOR<a, b>;
carry: AND<a, b>;
};
type BITWISE_AND<a extends BITS_4, b extends BITS_4> = [
AND<a[0], b[0]>,
AND<a[1], b[1]>,
AND<a[2], b[2]>,
AND<a[3], b[3]>
];
type COMP_4<
a extends BITS_4,
b extends BITS_4,
/* variables: */
c0 extends COMP_RESULT = COMP<a[0], b[0]>,
c1 extends COMP_RESULT = COMP<a[1], b[1]>,
c2 extends COMP_RESULT = COMP<a[2], b[2]>,
c3 extends COMP_RESULT = COMP<a[3], b[3]>
> = {
less: OR_4<
c3["grt"],
AND<c3["eq"], c2["grt"]>,
AND_4<1, c3["eq"], c2["eq"], c1["grt"]>,
AND_4<c3["eq"], c2["eq"], c1["eq"], c0["grt"]>
>;
eq: AND_4<c0["eq"], c1["eq"], c2["eq"], c3["eq"]>;
grt: OR_4<
c3["less"],
AND<c3["eq"], c2["less"]>,
AND_4<1, c3["eq"], c2["eq"], c1["less"]>,
AND_4<c3["eq"], c2["eq"], c1["eq"], c0["less"]>
>;
};
type COMP_RESULT = { less: B; eq: B; grt: B };
type COMP<
a extends B,
b extends B,
/* variables */
aLessThanB extends B = AND<NOT<b>, a>,
aGreaterThanB extends B = AND<b, NOT<a>>,
equal extends B = NOR<aLessThanB, aGreaterThanB>
> = { less: aLessThanB; eq: equal; grt: aGreaterThanB };
type EQ_4<
a extends BITS_4,
b extends BITS_4,
/* variables */
eq0 extends B = NXOR<a[0], b[0]>,
eq1 extends B = NXOR<a[1], b[1]>,
eq2 extends B = NXOR<a[2], b[2]>,
eq3 extends B = NXOR<a[3], b[3]>,
> = [AND_4<eq0, eq1, eq2, eq3>, 0, 0, 0];
type NXOR<a extends B, b extends B> = {
1: {
1: 1;
0: 0;
};
0: {
1: 0;
0: 1
}
}[a][b];
type XOR<a extends B, b extends B> = {
1: {
1: 0;
0: 1;
};
0: {
1: 1;
0: 0
}
}[a][b];
type AND_4<a extends B, b extends B, c extends B, d extends B> = AND<
AND<a, b>,
AND<c, d>
>;
type AND<a extends B, b extends B> = {
1: {
1: 1;
0: 0;
};
0: {
1: 0;
0: 0
}
}[a][b];
type NOR<a extends B, b extends B> = {
1: {
1: 0;
0: 0;
};
0: {
1: 0;
0: 1;
}
}[a][b];
type OR_4<a extends B, b extends B, c extends B, d extends B> = OR<
OR<a, b>,
OR<c, d>
>;
type OR<a extends B, b extends B> = {
1: {
1: 1;
0: 1;
};
0: {
1: 1;
0: 0;
}
}[a][b];
type NOT<a extends B> = {
1: 0;
0: 1
}[a];
// Ideally all other gates would be built by composing NANDs,
// however this creates a TypeScript 'possible infinite loop' error
type NAND<a extends B, b extends B> = {
1: {
1: 0;
0: 1;
};
0: {
1: 1;
0: 1;
};
}[a][b];
/** Covert 4-bit number to a string for printing */
type N_ToString<n extends Num>
= n extends N_0 ? "0"
: n extends N_1 ? "1"
: n extends N_2 ? "2"
: n extends N_3 ? "3"
: n extends N_4 ? "4"
: n extends N_5 ? "5"
: n extends N_6 ? "6"
: n extends N_7 ? "7"
: n extends N_8 ? "8"
: n extends N_9 ? "9"
: n extends N_10 ? "10"
: n extends N_11 ? "11"
: n extends N_12 ? "12"
: n extends N_13 ? "13"
: n extends N_14 ? "14"
: n extends N_15 ? "15"
: "nan";
/** Given a line number return an Instruction_Address */
export type Line<line extends number, __address extends Instruction_Address = []> = {
0: Line<line, Prepend<any, __address>>;
1: Tail<__address>;
}[__address["length"] extends line ? 1 : 0];