This repository has been archived by the owner on Dec 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 91
/
cpuops.js
7666 lines (7289 loc) · 262 KB
/
cpuops.js
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
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @fileoverview Implements PDP-10 opcode handlers.
* @author <a href="mailto:[email protected]">Jeff Parsons</a>
* @copyright © 2012-2020 Jeff Parsons
*
* This file is part of PCjs, a computer emulation software project at <https://www.pcjs.org>.
*
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCjs. If not,
* see <http://www.gnu.org/licenses/gpl.html>.
*
* You are required to include the above copyright notice in every modified copy of this work
* and to display that copyright notice when the software starts running; see COPYRIGHT in
* <https://www.pcjs.org/modules/shared/lib/defines.js>.
*
* Some PCjs files also attempt to load external resource files, such as character-image files,
* ROM files, and disk image files. Those external resource files are not considered part of PCjs
* for purposes of the GNU General Public License, and the author does not claim any copyright
* as to their contents.
*/
"use strict";
if (typeof module !== "undefined") {
var Str = require("../../shared/lib/strlib");
var Component = require("../../shared/lib/component");
var PDP10 = require("./defines");
}
/*
From the "PDP-10 System Reference Manual", May 1968, p. 1-4:
1.1 NUMBER SYSTEM
The program can interpret a data word as a 36-digit, unsigned binary number, or the left and right
halves of a word can be taken as separate 18-bit numbers. The PDP-10 repertoire includes instructions
that effectively add or subtract one from both halves of a word, so the right half can be used for
address modification when the word is addressed as an index register, while the left half is used to
keep a control count.
The standard arithmetic instructions in the PDP-10 use twos complement, fixed point conventions to do
binary arithmetic. In a word used as a number, bit 0 (the leftmost bit) represents the sign, 0 for positive,
1 for negative. In a positive number the remaining 35 bits are the magnitude in ordinary binary notation.
The negative of a number is obtained by taking its twos complement. If x is an n-digit binary number, its
twos complement is 2^n - x, and its ones complement is (2^n - 1) - x, or equivalently (2^n - x) - 1.
Subtracting a number from 2^n - 1 (ie, from all 1s) is equivalent to performing the logical complement,
ie changing all 0s to 1s and all 1s to 0s. Therefore, to form the twos complement one takes the logical
complement (usually referred to merely as the complement) of the entire word including the sign, and adds
1 to the result. In a negative number the sign bit is 1, and the remaining bits are the twos complement
of the magnitude.
Zero is represented by a word containing all 0s. Complementing this number produces all 1s, and adding
1 to that produces all 0s again. Hence there is only one zero representation and its sign is positive.
Since the numbers are symmetrical in magnitude about a single zero representation, all even numbers both
positive and negative end in 0, all odd numbers in 1 (a number all 1s represents -1). But since there are
the same number of positive and negative numbers and zero is positive, there is one more negative number
than there are nonzero positive numbers. This is the most negative number and it cannot be produced by
negating any positive number (its octal representation is 400000 000000 and its magnitude is one greater
than the largest positive number).
If ones complements were used for negatives one could read a negative number by attaching significance
to the as instead of the 1s. In twos complement notation each negative number is one greater than the
complement of the positive number of the same magnitude, so one can read a negative number by attaching
significance to the rightmost 1 and attaching significance to the 0s at the left of it (the negative number
of largest magnitude has a 1 in only the sign position). In a negative integer, 1s may be discarded at the
left, just as leading 0s may be dropped in a positive integer. In a negative fraction, 0s may be discarded
at the right. So long as only 0s are discarded, the number remains in twos complement form because it
still has a 1 that possesses significance; but if a portion including the rightmost 1 is discarded, the
remaining part of the fraction is now a ones complement.
The computer does not keep track of a binary point - the programmer must adopt a point convention and shift
the magnitude of the result to conform to the convention used. Two common conventions are to regard a number
as an integer (binary point at the right) or as a proper fraction (binary point at the left); in these two
cases the range of numbers represented by a single word is -2^35 to 2^35 - 1, or -1 to 1 - 2^35. Since
multiplication and division make use of double length numbers, there are special instructions for performing
these operations with integral operands.
SIDEBAR: Multiplication produces a double length product, and the programmer must remember that discarding
the low order part of a double length negative leaves the high order part in correct twos complement form
only if the low order part is null.
...
2.5 FIXED POINT ARITHMETIC
For fixed point arithmetic the PDP-10 has instructions for arithmetic shifting (which is essentially
multiplication by a power of 2) as well as for performing addition, subtraction, multiplication and division
of numbers in fixed point format [§ 1.1]. In such numbers the position of the binary point is arbitrary
(the programmer may adopt any point convention). The add and subtract instructions involve only single length
numbers, whereas multiply supplies a double length product, and divide uses a double length dividend. The high
and low order words respectively of a double length fixed point number are in accumulators A and A+1 (mod 20),
where the magnitude is the 70-bit string in bits 1-35 of the two words and the signs of the two are identical.
There are also integer multiply and divide instructions that involve only single length numbers and are
especially suited for handling smaller integers, particularly those of eighteen bits or less such as addresses
(of course they can be used for small fractions as well provided the programmer keeps track of the binary point).
For convenience in the following, all operands are assumed to be integers (binary point at the right).
The processor has four flags, Overflow, Carry 0, Carry 1 and No Divide, that indicate when the magnitude of a
number is or would be larger than can be accommodated. Carry 0 and Carry 1 actually detect carries out of bits
0 and 1 in certain instructions that employ fixed point arithmetic operations: the add and subtract instructions
treated here, the move instructions that produce the negative or magnitude of the word moved [§ 2.2], and the
arithmetic test instructions that increment or decrement the test word [§ 2.7]. In these instructions an
incorrect result is indicated - and the Overflow flag set - if the carries are different, ie if there is a carry
into the sign but not out of it, or vice versa. The Overflow flag is also set by No Divide being set, which
means the processor has failed to perform a division because the magnitude of the dividend is greater than or
equal to that of the divisor, or in integer divide, simply that the divisor is zero. In other overflow cases
only Overflow itself is set: these include too large a product in multiplication, and loss of significant bits
in left arithmetic shifting.
SIDEBAR: Overflow is determined directly from the carries, not from the carry flags, as their states may reflect
events in previous instructions.
*/
/**
* opKA10(op)
*
* Originally, we received the full opcode (36 bits), then only the upper half-word (18 bits),
* and now we receive only the upper 13 bits. However, the octal values shown in the table and
* function comments below still include all 18 bits of the original upper half-word, so that
* you don't have to mentally un-shift them 5 bits.
*
* @this {CPUStatePDP10}
* @param {number} op (the top 13 bits of the original opcode, shifted right to bit 0)
*/
PDP10.opKA10 = function(op)
{
/*
* We shift op right 4 more bits, leaving only the 9 bits required for the table index. Those
* 4 bits are normally an accumulator index, which we also mask and pass along, since most instructions
* will use an accumulator, and those that don't simply ignore it.
*/
PDP10.aOpXXX_KA10[op >> 4].call(this, op, op & PDP10.OPCODE.A_MASK);
};
/**
* opUUO(0o0NN000): Unimplemented User Operation
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-64:
*
* Store the instruction code, A and the effective address E in bits 0-8, 9-12 and 18-35 respectively of
* location 40; clear bits 13-17. Execute the instruction contained in location 41. The original contents
* of location 40 are lost.
*
* All of these codes are equivalent when they occur in the Monitor or when time sharing is not in effect.
* But when a UUO appears in a user program, a code in the range 001-037 uses relocated locations 40 and 41
* (ie 40 and 41 in the user's block) and is thus entirely a part of and under control of the user program.
*
* A code in the range 040-077 on the other hand uses unrelocated 40 and 41, and the instruction in the latter
* location is under control of the Monitor; these codes are thus specifically for user communication with
* the Monitor, which interprets them (refer to the Monitor manual for the meanings of the various codes).
*
* The code 000 executes in the same way as 040-077 but is not a standard communication code: it is included
* so that control returns to the Monitor should a user program wipe itself out.
*
* For a second processor connected to the same memory, the UUO trap is locations 140-141 instead of 40-41.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opUUO = function(op, ac)
{
this.opUndefined(op);
};
/**
* opUFA(0o130000): Unnormalized Floating Add
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-37:
*
* Floating add the contents of location E to AC. If the double length fraction in the sum is zero, clear
* accumulator A+1. Otherwise normalize the sum only if the magnitude of its fractional part is >= 1, and place
* the high order part of the result in AC A+1. The original contents of AC and E are unaffected.
*
* NOTE: The result is placed in accumulator A+1. T his is the only arithmetic instruction that stores the result
* in a second accumulator, leaving the original operands intact.
*
* If the exponent of the sum following the one-step normalization is > 127, set Overflow and Floating Overflow;
* the result stored has an exponent 256 less than the correct one.
*
* SIDEBAR: The exponent of the sum is equal to that of the larger summand unless addition of the fractions
* overflows, in which case it is greater by 1. Exponent overflow can occur only in the latter case.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opUFA = function(op, ac)
{
this.opUndefined(op);
};
/**
* opDFN(0o131000): Double Floating Negate
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-37:
*
* Negate the double length floating point number composed of the contents of AC and location E with AC on the left.
* Do this by taking the twos complement of the number whose sign is AC bit 0, whose exponent is in AC bits 1-8, and
* whose fraction is the 54-bit string in bits 9-35 of AC and location E. Place the high order word of the result
* in AC; place the low order part of the fraction in bits 9-35 of location E without altering the original contents
* of bits 0-8 of that location.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opDFN = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSC(0o132000): Floating Scale
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-34:
*
* If the fractional part of AC is zero, clear AC. Otherwise add the scale factor given by E to the exponent part
* of AC (thus multiplying AC by 2^E), normalize the resulting word bringing 0s into bit positions vacated at the
* right, and place the result back in AC.
*
* NOTE: A negative E is represented in standard twos complement notation, but the hardware compensates for this
* when scaling the exponent.
*
* If the exponent after normalization is > 127, set Overflow and Floating Overflow; the result stored has an
* exponent 256 less than the correct one. If < -128, set Overflow, Floating Overflow and Floating Underflow;
* the result stored has an exponent 256 greater than the correct one.
*
* SIDEBAR: This instruction can be used to float a fixed number with 27 or fewer significant bits. To float an
* integer contained within AC bits 9-35,
*
* FSC AC,233
*
* inserts the correct exponent to move the binary point from the right end to the left of bit 9 and then normalizes
* (233 [base 8] = 155 [base 10] = 128 + 27).
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSC = function(op, ac)
{
this.opUndefined(op);
};
/**
* opIBP(0o133000): Increment Byte Pointer
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
*
* Increment the byte pointer in location E as explained [below]. The pointer has the format:
*
* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* P P P P P P S S S S S S - I X X X X Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
*
* where S is the size of the byte as a number of bits, and P is its position as the number of bits
* remaining at the right of the byte in the word (eg if P is 3 the rightmost bit of the byte is bit 32
* of the word). The rest of the pointer is interpreted in the same way as in an instruction: I, X and Y
* are used to calculate the address of the location that is the source or destination of the byte.
*
* To facilitate processing a series of bytes, several of the byte instructions increment the
* pointer, ie, modify it so that it points to the next byte position in a set of memory locations.
* Bytes are processed from left to right in a word, so incrementing merely replaces the current value
* of P by P - S, unless there is insufficient space in the present location for another byte of the
* specified size (P - S < 0). In this case Y is increased by one to point to the next consecutive
* location, and P is set to 36 - S to point to the first byte at the left in the new location.
*
* CAUTION: Do not allow Y to reach maximum value. The whole pointer is incremented, so if Y is 2^18 - 1
* it becomes zero and X is also incremented. The address calculation for the pointer uses the original X,
* but if a priority interrupt should occur before the calculation is complete, the incremented X is used
* when the instruction is repeated.
*
* SPECIAL CONSIDERATIONS: If S is greater than P and also greater than 36, incrementing produces a new
* P equal to 100 - S rather than 36 - S. For S > 36 the byte is at most the entire word; for P >= 36 no
* byte is processed (loading merely clears AC). If both P and S are less than 36 but P + S > 36,
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
* in position P.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opIBP = function(op, ac)
{
var inc = 0;
var w = this.readWord(this.regEA);
var p = (w / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
var s = (w >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
p -= s;
if (p < 0) {
inc++;
p = 36 - s;
if (p < 0) p = 100 - s; // see SPECIAL CONSIDERATIONS and NOTE above
}
/*
* Since the documentation above makes clear that the effect of the increment (of w) extends past the Y
* bits and into (at least) the X bits, we first re-assemble a new pointer with updated P bits (along with
* the original S bits and the remaining bits covered by PTR_MASK) and then increment as needed.
*
* Yes, PTR_MASK could have included the S bits as well and made the following expression a TINY bit simpler,
* but I would like to keep PTR_MASK distinct from both the P and S fields.
*/
w = (p * PDP10.OPCODE.P_SCALE) + (s << PDP10.OPCODE.S_SHIFT) + (w & PDP10.OPCODE.PTR_MASK);
if (inc) w = (w + inc) % PDP10.WORD_LIMIT;
this.writeWord(this.regEA, w);
};
/**
* opILDB(0o134000): Increment Pointer and Load Byte
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
*
* Increment the byte pointer in location E as explained above. Then retrieve a byte of S bits from the
* location and position specified by the newly incremented pointer, load it into the right end of AC,
* and clear the remaining AC bits. The location containing the byte is unaffected, the original contents
* of AC are lost.
*
* SPECIAL CONSIDERATIONS: If S is greater than P and also greater than 36, incrementing produces a new
* P equal to 100 - S rather than 36 - S. For S > 36 the byte is at most the entire word; for P >= 36 no
* byte is processed (loading merely clears AC). If both P and S are less than 36 but P + S > 36,
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
* in position P.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opILDB = function(op, ac)
{
/*
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
* is with regEA containing the address of the bits to be loaded.
*
* We can implement this as a simple combination of opIBP() and opLDB(), but taking care that we only call
* opIBP() on phase 1 (and only if the BIS flag is not set).
*/
if (!(this.regPS & PDP10.PSFLAG.BIS)) {
PDP10.opIBP.call(this, op, ac);
this.regPS |= PDP10.PSFLAG.BIS;
}
PDP10.opLDB.call(this, op, ac);
};
/**
* opLDB(0o135000): Load Byte
*z
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
*
* Retrieve a byte of S bits from the location and position specified by the pointer contained in location E,
* load it into the right end of AC, and clear the remaining AC bits. The location containing the byte is
* unaffected, the original contents of AC are lost.
*
* SPECIAL CONSIDERATIONS: If S is greater than P and also greater than 36, incrementing produces a new
* P equal to 100 - S rather than 36 - S. For S > 36 the byte is at most the entire word; for P >= 36 no
* byte is processed (loading merely clears AC). If both P and S are less than 36 but P + S > 36,
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
* in position P.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opLDB = function(op, ac)
{
/*
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
* is with regEA containing the address of the bits to be loaded.
*/
var w = this.readWord(this.regEA);
if (this.regBP < 0) {
this.regBP = w;
this.regRA = this.regEA | PDP10.OPCODE.I_FIELD;
return;
}
var p = (this.regBP / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
var s = (this.regBP >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
if (p + s < 32) {
/*
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
* positive.
*/
w = ((w >> p) & ((1 << s) - 1)) >>> 0;
} else {
/*
* Regarding the SPECIAL CONSIDERATIONS above, even if the P ("shift") and/or S ("mask") values are
* over-large, that should be fine, because nothing but additional zero bits will be included (provided
* our memory is working properly and didn't give us more than 36 bits of unsigned data).
*/
w = Math.trunc(w / Math.pow(2, p)) % Math.pow(2, s);
}
this.writeWord(ac, w);
this.regPS &= ~PDP10.PSFLAG.BIS;
this.regBP = -1;
};
/**
* opIDPB(0o136000): Increment Pointer and Deposit Byte
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
*
* Increment the byte pointer in location E as explained above. Then deposit the right S bits of AC into
* the location and position specified by the newly incremented pointer. The original contents of the bits
* that receive the byte are lost, AC and the remaining bits of the deposit location are unaffected.
*
* SPECIAL CONSIDERATIONS: If S is greater than P and also greater than 36, incrementing produces a new
* P equal to 100 - S rather than 36 - S. For S > 36 the byte is at most the entire word; for P >= 36 no
* byte is processed (loading merely clears AC). If both P and S are less than 36 but P + S > 36,
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
* in position P.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opIDPB = function(op, ac)
{
/*
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
* is with regEA containing the address of the bits to be stored.
*
* We can implement this as a simple combination of opIBP() and opDDB(), but taking care that we only call
* opIBP() on phase 1 (and only if the BIS flag is not set).
*/
if (!(this.regPS & PDP10.PSFLAG.BIS)) {
PDP10.opIBP.call(this, op, ac);
this.regPS |= PDP10.PSFLAG.BIS;
}
PDP10.opDPB.call(this, op, ac);
};
/**
* opDPB(0o137000): Deposit Byte
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
*
* Deposit the right S bits of AC into the location and position specified by the pointer contained
* in location E. The original contents of the bits that receive the byte are lost, AC and the remaining
* bits of the deposit location are unaffected.
*
* SPECIAL CONSIDERATIONS: If S is greater than P and also greater than 36, incrementing produces a new
* P equal to 100 - S rather than 36 - S. For S > 36 the byte is at most the entire word; for P >= 36 no
* byte is processed (loading merely clears AC). If both P and S are less than 36 but P + S > 36,
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
* in position P.
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opDPB = function(op, ac)
{
/*
* We're called in two phases: phase 1 is with regEA containing the address of the pointer, and phase 2
* is with regEA containing the address of the bits to be stored.
*/
var w = this.readWord(this.regEA);
if (this.regBP < 0) {
this.regBP = w;
this.regRA = this.regEA | PDP10.OPCODE.I_FIELD;
return;
}
var p = (this.regBP / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
var s = (this.regBP >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
/*
* Regarding the SPECIAL CONSIDERATIONS above, even if the P ("shift") and/or S ("mask") values are
* over-large, we "mask" the resulting byte value (b) to 36 bits, so that when we re-assemble the final
* result (w), there shouldn't be any overlap or overflow.
*/
var b = ((this.readWord(ac) % Math.pow(2, s)) * Math.pow(2, p)) % PDP10.WORD_LIMIT;
w = (w - (w % Math.pow(2, p + s))) + b + (w % Math.pow(2, p));
this.writeWord(this.regEA, w);
this.regPS &= ~PDP10.PSFLAG.BIS;
this.regBP = -1;
};
/**
* opFAD(0o140000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFAD = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADI(0o141000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADM(0o142000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADB(0o143000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADR(0o144000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADR = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADRI(0o145000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADRI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADRM(0o146000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADRM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFADRB(0o147000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFADRB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSB(0o150000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBI(0o151000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBM(0o152000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBB(0o153000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBR(0o154000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBR = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBRI(0o155000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBRI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBRM(0o156000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBRM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFSBRB(0o157000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFSBRB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMP(0o160000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMP = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPI(0o161000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPM(0o162000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPB(0o163000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPR(0o164000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPR = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPRI(0o165000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPRI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPRM(0o166000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPRM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFMPRB(0o167000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFMPRB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDV(0o170000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDV = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVI(0o171000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVM(0o172000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVB(0o173000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVR(0o174000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVR = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVRI(0o175000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVRI = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVRM(0o176000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVRM = function(op, ac)
{
this.opUndefined(op);
};
/**
* opFDVRB(0o177000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opFDVRB = function(op, ac)
{
this.opUndefined(op);
};
/**
* opMOVE(0o200000): Move
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Move one word from the source to the destination specified by M. The source is unaffected,
* the original contents of the destination are lost.
*
* NOTE: This is a "Basic" mode instruction: the source is [E] and the destination is [A] (opposite of "Memory").
*
* Equivalents: opSETM(0o414000) and opSETMB(0o417000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVE = function(op, ac)
{
this.writeWord(ac, this.readWord(this.regEA));
};
/**
* opMOVEI(0o201000): Move Immediate
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Move one word from the source to the destination specified by M. The source is unaffected,
* the original contents of the destination are lost.
*
* SIDEBAR: MOVEI loads the word 0,E into AC and is thus equivalent to HRRZI.
*
* NOTE: This is an "Immediate" mode instruction: the source is the word 0,E and the destination is [A].
*
* Equivalents: opSETMI(0o415000)
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVEI = function(op, ac)
{
this.writeWord(ac, this.regEA);
};
/**
* opMOVEM(0o202000): Move to Memory
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Move one word from the source to the destination specified by M. The source is unaffected,
* the original contents of the destination are lost.
*
* NOTE: This is a "Memory" mode instruction: the source is [A] and the destination is [E] (opposite of "Basic").
*
* Equivalents: opSETAM(0o426000) and opSETAB(0o427000).
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVEM = function(op, ac)
{
this.writeWord(this.regEA, this.readWord(ac));
};
/**
* opMOVES(0o203000): Move to Self
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Move one word from the source to the destination specified by M. The source is unaffected,
* the original contents of the destination are lost.
*
* SIDEBAR: If A is zero, MOVES is a no-op; otherwise it is equivalent to MOVE.
*
* NOTE: This is a "Self" mode instruction: the source AND destination is [E] (and also [A] if A is non-zero).
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVES = function(op, ac)
{
if (ac) this.writeWord(ac, this.readWord(this.regEA));
};
/**
* opMOVS(0o204000): Move Swapped
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Interchange the left and right halves of the word from the source specified by M and move it to the
* specified destination. The source is unaffected, the original contents of the destination are lost.
*
* NOTE: This is a "Basic" mode instruction: the source is [E] and the destination is [A] (opposite of "Memory").
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVS = function(op, ac)
{
var src = this.readWord(this.regEA);
src = ((src / PDP10.HALF_SHIFT)|0) + ((src & PDP10.HALF_MASK) * PDP10.HALF_SHIFT);
this.writeWord(ac, src);
};
/**
* opMOVSI(0o205000): Move Swapped Immediate
*
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-11:
*
* Interchange the left and right halves of the word from the source specified by M and move it to the
* specified destination. The source is unaffected, the original contents of the destination are lost.
*
* SIDEBAR: Swapping halves in immediate mode loads the word E,0 into AC. MOVSI is thus equivalent to HRLZI.
*
* NOTE: This is an "Immediate" mode instruction: the source is the word 0,E and the destination is [A].
*
* @this {CPUStatePDP10}
* @param {number} op
* @param {number} ac
*/
PDP10.opMOVSI = function(op, ac)
{
this.writeWord(ac, this.regEA * PDP10.HALF_SHIFT);
};
/**
* opMOVSM(0o206000): Move Swapped to Memory