/
GdbARMAlien.class.st
1862 lines (1589 loc) · 58.2 KB
/
GdbARMAlien.class.st
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
"
I am a wrapper around the ARMulator CPU instance and emulator routines and I give access to disassembling using libopcodes. My C-part must be compiled with -DMODET, because otherwise my offsets are wrong by one field.
"
Class {
#name : #GdbARMAlien,
#superclass : #CogProcessorAlien,
#type : #bytes,
#classVars : [
'BadCPUInstance',
'ExecutionError',
'InstructionPrefetchError',
'LongConstReg',
'LongConstStep',
'LongConstValue',
'MemoryLoadBoundsError',
'MemoryWriteBoundsError',
'NoError',
'PanicError',
'PostBuildStackDelta',
'SomethingLoggedError',
'UnsupportedOperationError'
],
#category : #'Cog-Processors'
}
{ #category : #'instance creation' }
GdbARMAlien class >> dataSize [
^1792
]
{ #category : #'instance creation' }
GdbARMAlien class >> implementationClass [
^Smalltalk wordSize = 8 ifTrue: [GdbARMAlien64] ifFalse: [self]
]
{ #category : #'class initialization' }
GdbARMAlien class >> initialize [
"GdbARMAlien initialize"
PostBuildStackDelta := 0.
"Return errors from GdbARMPlugin.h"
NoError := 0.
ExecutionError := 1.
BadCPUInstance := 2.
MemoryLoadBoundsError := 3.
MemoryWriteBoundsError := 4.
InstructionPrefetchError := 5.
PanicError := 6.
UnsupportedOperationError := 7.
SomethingLoggedError := 8
]
{ #category : #primitives }
GdbARMAlien class >> primitiveNewCPU [
"Answer the address of a new ARMulator C type ARMul_State instance."
<primitive: 'primitiveNewCPU' module: 'GdbARMPlugin'>
^self primitiveFailed
]
{ #category : #'Cog API' }
GdbARMAlien >> abstractInstructionCompilerClass [
^CogARMCompiler
]
{ #category : #'Cog API' }
GdbARMAlien >> bitsInWord [
^32
]
{ #category : #opcodes }
GdbARMAlien >> byteSwappedNopOpcode [
"For the Tsts class which keeps filling BitMaps with nop, provide one swapped so it turns out correct when disassembled
mov r0, r0 swapped -> "
^ 16r00000A0E1
]
{ #category : #'accessing-abstract' }
GdbARMAlien >> cResultRegister [
^self r0
]
{ #category : #'accessing-abstract' }
GdbARMAlien >> cResultRegister: aValue [
self r0: aValue
]
{ #category : #accessing }
GdbARMAlien >> cflag [
"The ARM cpsr flags are kept as individual fields in the Alien structure. The address here is the 1-based byte offset into the ARMul_State structure"
^self unsignedLongAt: 573
]
{ #category : #accessing }
GdbARMAlien >> cflag: unsignedInteger [
"The ARM cpsr flags are kept as individual fields in the Alien structure. The address here is the 1-based byte offset into the ARMul_State structure"
^self unsignedLongAt: 573 put: unsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d0 [
^self unsignedLongLongAt: 1533
]
{ #category : #accessing }
GdbARMAlien >> d0: anUnsignedInteger [
^self unsignedLongLongAt: 1533 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d1 [
^self unsignedLongLongAt: 1541
]
{ #category : #accessing }
GdbARMAlien >> d10 [
^self unsignedLongLongAt: 1613
]
{ #category : #accessing }
GdbARMAlien >> d10: anUnsignedInteger [
^self unsignedLongLongAt: 1613 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d11 [
^self unsignedLongLongAt: 1621
]
{ #category : #accessing }
GdbARMAlien >> d11: anUnsignedInteger [
^self unsignedLongLongAt: 1621 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d12 [
^self unsignedLongLongAt: 1629
]
{ #category : #accessing }
GdbARMAlien >> d12: anUnsignedInteger [
^self unsignedLongLongAt: 1629 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d13 [
^self unsignedLongLongAt: 1637
]
{ #category : #accessing }
GdbARMAlien >> d13: anUnsignedInteger [
^self unsignedLongLongAt: 1637 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d14 [
^self unsignedLongLongAt: 1645
]
{ #category : #accessing }
GdbARMAlien >> d14: anUnsignedInteger [
^self unsignedLongLongAt: 1645 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d15 [
^self unsignedLongLongAt: 1653
]
{ #category : #accessing }
GdbARMAlien >> d15: anUnsignedInteger [
^self unsignedLongLongAt: 1653 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d16 [
^self unsignedLongLongAt: 1661
]
{ #category : #accessing }
GdbARMAlien >> d16: anUnsignedInteger [
^self unsignedLongLongAt: 1661 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d17 [
^self unsignedLongLongAt: 1669
]
{ #category : #accessing }
GdbARMAlien >> d17: anUnsignedInteger [
^self unsignedLongLongAt: 1669 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d18 [
^self unsignedLongLongAt: 1677
]
{ #category : #accessing }
GdbARMAlien >> d18: anUnsignedInteger [
^self unsignedLongLongAt: 1677 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d19 [
^self unsignedLongLongAt: 1685
]
{ #category : #accessing }
GdbARMAlien >> d19: anUnsignedInteger [
^self unsignedLongLongAt: 1685 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d1: anUnsignedInteger [
^self unsignedLongLongAt: 1541 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d2 [
^self unsignedLongLongAt: 1549
]
{ #category : #accessing }
GdbARMAlien >> d20 [
^self unsignedLongLongAt: 1693
]
{ #category : #accessing }
GdbARMAlien >> d20: anUnsignedInteger [
^self unsignedLongLongAt: 1693 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d21 [
^self unsignedLongLongAt: 1701
]
{ #category : #accessing }
GdbARMAlien >> d21: anUnsignedInteger [
^self unsignedLongLongAt: 1701 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d22 [
^self unsignedLongLongAt: 1709
]
{ #category : #accessing }
GdbARMAlien >> d22: anUnsignedInteger [
^self unsignedLongLongAt: 1709 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d23 [
^self unsignedLongLongAt: 1717
]
{ #category : #accessing }
GdbARMAlien >> d23: anUnsignedInteger [
^self unsignedLongLongAt: 1717 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d24 [
^self unsignedLongLongAt: 1725
]
{ #category : #accessing }
GdbARMAlien >> d24: anUnsignedInteger [
^self unsignedLongLongAt: 1725 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d25 [
^self unsignedLongLongAt: 1733
]
{ #category : #accessing }
GdbARMAlien >> d25: anUnsignedInteger [
^self unsignedLongLongAt: 1733 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d26 [
^self unsignedLongLongAt: 1741
]
{ #category : #accessing }
GdbARMAlien >> d26: anUnsignedInteger [
^self unsignedLongLongAt: 1741 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d27 [
^self unsignedLongLongAt: 1749
]
{ #category : #accessing }
GdbARMAlien >> d27: anUnsignedInteger [
^self unsignedLongLongAt: 1749 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d28 [
^self unsignedLongLongAt: 1757
]
{ #category : #accessing }
GdbARMAlien >> d28: anUnsignedInteger [
^self unsignedLongLongAt: 1757 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d29 [
^self unsignedLongLongAt: 1765
]
{ #category : #accessing }
GdbARMAlien >> d29: anUnsignedInteger [
^self unsignedLongLongAt: 1765 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d2: anUnsignedInteger [
^self unsignedLongLongAt: 1549 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d3 [
^self unsignedLongLongAt: 1557
]
{ #category : #accessing }
GdbARMAlien >> d30 [
^self unsignedLongLongAt: 1773
]
{ #category : #accessing }
GdbARMAlien >> d30: anUnsignedInteger [
^self unsignedLongLongAt: 1773 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d31 [
^self unsignedLongLongAt: 1781
]
{ #category : #accessing }
GdbARMAlien >> d31: anUnsignedInteger [
^self unsignedLongLongAt: 1781 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d3: anUnsignedInteger [
^self unsignedLongLongAt: 1557 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d4 [
^self unsignedLongLongAt: 1565
]
{ #category : #accessing }
GdbARMAlien >> d4: anUnsignedInteger [
^self unsignedLongLongAt: 1565 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d5 [
^self unsignedLongLongAt: 1573
]
{ #category : #accessing }
GdbARMAlien >> d5: anUnsignedInteger [
^self unsignedLongLongAt: 1573 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d6 [
^self unsignedLongLongAt: 1581
]
{ #category : #accessing }
GdbARMAlien >> d6: anUnsignedInteger [
^self unsignedLongLongAt: 1581 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d7 [
^self unsignedLongLongAt: 1589
]
{ #category : #accessing }
GdbARMAlien >> d7: anUnsignedInteger [
^self unsignedLongLongAt: 1589 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d8 [
^self unsignedLongLongAt: 1597
]
{ #category : #accessing }
GdbARMAlien >> d8: anUnsignedInteger [
^self unsignedLongLongAt: 1597 put: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> d9 [
^self unsignedLongLongAt: 1605
]
{ #category : #accessing }
GdbARMAlien >> d9: anUnsignedInteger [
^self unsignedLongLongAt: 1605 put: anUnsignedInteger
]
{ #category : #disassembly }
GdbARMAlien >> decorateDisassembly: anInstructionString for: aSymbolManager fromAddress: address [
"Decode what we can of the instruction and decorate it with useful stuff"
| word opcode rotate mode operand memory addressinatorBlock|
addressinatorBlock :=
[:value| | string |
(value notNil
and: [(string := aSymbolManager lookupAddress: value) notNil])
ifTrue: [ ' = ', value hex, ' = ', string]
ifFalse: ['']].
word := (memory:= aSymbolManager objectMemory) longAt: address.
(self instructionIsAnyB: word)
ifTrue:
[((self instructionIsB: word) or: [self instructionIsBL: word]) ifTrue:
["We can extract the offset from a plain B/BL instruction"
operand := self extractOffsetFromBL: word..
operand := operand + address + 8 bitAnd: aSymbolManager addressSpaceMask].
"We can't extract the offset from a BX/BLX instructions register, unless we're at the current pc,
because otherwise its current value has nothing to do with the value when this instruction is executed."
(self pc = address
and: [(self instructionIsBX: word) or: [self instructionIsBLX: word]]) ifTrue:
[operand := (self perform: (self registerStateGetters at: (word bitAnd: 15) + 1))]]
ifFalse:
[(self instructionIsAnyLoadStore: word)
ifTrue:
[|baseR lit|
"first see if this is a load via the varBase register - quick access globals. We'll trust
that nobody makes a nasty instruction that uses this reg in a mean way"
operand := (baseR := (word >> 16 bitAnd: 15)) = CogARMCompiler VarBaseReg
ifTrue: [aSymbolManager varBaseAddress + (word bitAnd: 1 << 12 - 1)]
ifFalse: [self pc = address ifTrue:
[(self register: baseR) + (self extractOffsetFromLoadStore: word)]].
"See if this is a pc-relative literal load"
baseR = CogARMCompiler PCReg ifTrue:
[lit := memory longAt: (aSymbolManager backEnd pcRelativeAddressAt: address).
^(aSymbolManager lookupAddress: lit)
ifNotNil: [:label| anInstructionString, ' ', label]
ifNil: [anInstructionString, ' ', lit hex]].
"look for SP operations -pop/push"
(self instructionIsPush: word) ifTrue: "push - "
[|srcR|
srcR := word >>12 bitAnd: 16rF.
^ (anInstructionString readStream upTo: $}), '}', (self pc = address ifTrue: [' (', (self register: srcR) hex, ') to ', (self sp - 4) hex] ifFalse: [''])].
(self instructionIsPop: word) ifTrue: "pop - "
[^ (anInstructionString readStream upTo: $}), '}', (self pc = address ifTrue: [' (', (memory longAt: self sp) hex, ') ' , ' from ' , self sp hex] ifFalse: [''])].
"look for a ld/st of the sp"
(self instructionIsLDRSP: word) ifTrue:
[^anInstructionString, '; Load SP from ', (addressinatorBlock value: operand)].
(self instructionIsSTRSP: word) ifTrue:
[^anInstructionString, '; Save SP to ', (addressinatorBlock value: operand)]]
ifFalse:
["check for SP changers not relating to read/writing data"
(self instructionIsAlignSP: word) ifTrue:
[^anInstructionString, ' ALIGN SP ', (self pc = address ifTrue: [self sp hex] ifFalse: [''])].
(self instructionIsAddSP: word) ifTrue:
[^anInstructionString, ' ADD ', (word bitAnd: 16rFF) asString,' to SP ', (self pc = address ifTrue: ['= ' , self sp hex] ifFalse: [''])].
"check for the end of a mov/orr/orr/orr set filling a reg with a const"
opcode := word >> 21 bitAnd: 16rF.
(opcode ~= CogARMCompiler orOpcode
or: [aSymbolManager cogit backEnd literalLoadInstructionBytes = 4]) ifTrue:
[^anInstructionString].
rotate := word >> 8 bitAnd: 16rF.
mode := word >> 25 bitAnd: 7.
"CogARMCompiler always uses a 0 rotate in the last operand of the final ORR when building long constants."
(mode = 1 and: [rotate ~= 0]) ifTrue:
[^anInstructionString].
operand := aSymbolManager backEnd literalBeforeFollowingAddress: address + 4]].
"is there an interesting address with this?"
^anInstructionString, (addressinatorBlock value: operand)
]
{ #category : #disassembly }
GdbARMAlien >> disassembleFrom: startAddress to: endAddress in: memory for: aSymbolManager "<Cogit>" labels: labelDictionary on: aStream [
| address |
address := startAddress.
[address <= endAddress] whileTrue:
[[:sizeArg :stringArg| | size string index offset |
size := sizeArg.
string := stringArg.
(aSymbolManager labelForPC: address) ifNotNil:
[:label| aStream nextPutAll: label; nextPut: $:; cr].
(labelDictionary at: address ifAbsent: []) ifNotNil:
[:label|
self printLabel: label on: aStream at: address for: aSymbolManager.
label isArray ifTrue:
[string := nil.
size := label third]].
string ifNotNil:
[aStream nextPutAll: (self decorateDisassembly: string for: aSymbolManager fromAddress: address).
(string includesSubstring: ': ldr ') ifTrue:"i.e. colon space 'ldr' tab"
[(index := string indexOfSubCollection: ' [pc, #' startingAt: 1) > 0
ifTrue:
[offset := Integer readFrom: (ReadStream on: string from: index + 7 to: (string indexOf: $] startingAt: index + 7) - 1)]
ifFalse:
[(string indexOfSubCollection: ' [pc]' startingAt: 1) > 0 ifTrue:
[offset := 0]].
offset ifNotNil:
[offset := address + 8 + offset.
labelDictionary
at: offset
ifPresent:
[:entry|
entry isString
ifTrue: [labelDictionary at: offset put: {#literal. offset. 4. entry}]
ifFalse: [self assert: (entry isArray and: [entry first == #literal])]]
ifAbsentPut: [{#literal. offset. 4}]]]].
aStream cr; flush.
address := address + size]
valueWithArguments: (self
primitiveDisassembleAt: address
inMemory: memory)].
(labelDictionary at: address ifAbsent: []) ifNotNil:
[:label| self printLabel: label on: aStream at: address for: aSymbolManager]
]
{ #category : #accessing }
GdbARMAlien >> eflags [
^ (((self nflag << 5 bitOr: self zflag << 4)
bitOr: self cflag << 3)
bitOr: self vflag << 2)
bitOr: self ifflags
]
{ #category : #accessing }
GdbARMAlien >> eflags: anUnsignedInteger [
"set the processor flags from the integer"
self nflag: (anUnsignedInteger >> 5 bitAnd: 1).
self zflag: (anUnsignedInteger >> 4 bitAnd: 1).
self cflag: (anUnsignedInteger >> 3 bitAnd: 1).
self vflag: (anUnsignedInteger >> 2 bitAnd: 1).
self ifflags: (anUnsignedInteger bitAnd: 3)
]
{ #category : #accessing }
GdbARMAlien >> endCondition [
"why did the simulator stop?"
^self unsignedLongAt: 5
]
{ #category : #'accessing-abstract' }
GdbARMAlien >> endianness [
^#little
]
{ #category : #accessing }
GdbARMAlien >> errorCode [
"simulator error code"
^self unsignedLongAt: 9
]
{ #category : #testing }
GdbARMAlien >> extractOffsetFromBL: instr [
"we are told this is a BL <offset> instruction, so work out the offset it encodes"
| relativeJump |
relativeJump := instr bitAnd: 16r00FFFFFF.
relativeJump := (relativeJump bitAt: 24) = 1
ifTrue: [((relativeJump bitOr: 16r3F000000) << 2) signedIntFromLong]
ifFalse: [relativeJump << 2].
^relativeJump
]
{ #category : #'accessing-abstract' }
GdbARMAlien >> extractOffsetFromLoadStore: instr [
"work out the address offset implied by instr.
We assume it has been determined it is actually a load store before attaching any meaning to the result.
If it is post-indexed, then the offset must be 0, no matter what else is encoded.
If the instr is immediate-offset, pull the relevent bits out of instr.
If it is register-offset, pull the value from the indicated register."
|offset shiftAmt shiftType |
"post-indexed means no offset to the read address"
(instr bitAnd: 1 << 24) = 0 ifTrue:[^0].
(self instructionIsImmediateOffsetLoadStore: instr)
ifTrue:["two cases apply - a 12bit immediate for 010 group instructions and an 8bit for 000 group ldrh stuff"
(instr >> 25 bitAnd: 7) = 2
ifTrue:[ "immed word or byte op, with 12bit offset"
offset := instr bitAnd: 16rFFF]
ifFalse:["halfword 8bit offset"
offset := (instr bitAnd: 16rF00)>>4 bitOr: (instr bitAnd: 16rF)]].
(self instructionIsRegisterOffsetLoadStore: instr)
ifTrue:["both forms use same offset-reg encoding"
offset := self perform:(self registerStateGetters at:(instr bitAnd: 16rF) + 1).
(instr >> 25 bitAnd: 7) = 3
ifTrue:[ "register offset with assorted modifiers"
"sort out modifiers"
shiftType := instr >> 5 bitAnd: 3.
shiftAmt := instr >>7 bitAnd: 16r1F.
shiftType = 0"lsl" ifTrue:[offset := offset << shiftAmt.].
shiftType = 1"lsr" ifTrue:[offset := offset >> shiftAmt].
shiftType = 2"asr" ifTrue:[offset := offset >>> shiftAmt].
"I refuse to countenance using ROR or RRX here. Just Say No" ]
"halfword stuff register offset uses no modifiers in the form we suport. See ARM DDI0406A p. A8-156"].
"all forms have the bit 23 up/down flag to account for"
(instr bitAnd: 1<<23) = 0
ifTrue:["-ve offset" ^offset negated]
ifFalse:["+ve offset" ^offset]
]
{ #category : #execution }
GdbARMAlien >> flushICacheFrom: startAddress "<Integer>" to: endAddress [ "<Integer>"
self primitiveFlushICacheFrom: startAddress To: endAddress
]
{ #category : #accessing }
GdbARMAlien >> fp [
"fp is r11"
^self r11
]
{ #category : #accessing }
GdbARMAlien >> fp: anUnsignedInteger [
^self r11: anUnsignedInteger
]
{ #category : #accessing }
GdbARMAlien >> fpCPSR [
"The VFP cpsr flags are kept as a single word in the Alien structure. Return just the top 4 bits, the actual flags"
^(self unsignedLongAt: 1789) >>28
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleBasicDoubleArithmetic: instr at: pc [
"Emulate a basic math - add/sub/mul/div - VFP instruction."
| rn rd rm vn vm |
rn := instr >> 16 bitAnd: 15.
rd := instr >> 12 bitAnd: 15.
rm := instr bitAnd: 15.
vn := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rn + 18)). "Assume accesses fp regs"
vm := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rm + 18)). "Assume accesses fp regs"
"simplest to match the entire instruction pattern rather than mess around shifting and masking and merging"
(instr bitAnd: 16rFF00FF0)
caseOf: {
[16rE200B00 "FMULD"] ->
[| r |
r := vn * vm.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
[16rE300B00 "FADDD"] ->
[| r |
r := vn + vm.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
[16rE300B40 "FSUBD"] ->
[| r |
r := vn - vm.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
[16rE800B00"FDIVD"] ->
[| r |
r := vn / vm.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].}
otherwise: [self reportPrimitiveFailure].
self pc: pc + 4
]
{ #category : #'error handling' }
GdbARMAlien >> handleExecutionPrimitiveFailureAt: pc "<Integer>" in: memoryArray [ "<Bitmap|ByteArray>"
"Handle an execution primitive failure for an otherwise unhandled opcode."
^self reportPrimitiveFailure
]
{ #category : #'error handling' }
GdbARMAlien >> handleExecutionPrimitiveFailureIn: memoryArray "<Bitmap|ByteArray>" minimumAddress: minimumAddress [ "<Integer>"
"Handle an execution primitive failure. Convert out-of-range call and absolute
memory read into register instructions into ProcessorSimulationTrap signals."
"self printRegistersOn: Transcript"
| pcOnEntry pc instr |
pc := pcOnEntry := self pc.
self endCondition = InstructionPrefetchError ifTrue:
[pc := self pc: self priorPc].
(pc between: minimumAddress and: memoryArray byteSize - 1) ifTrue:
[instr := memoryArray unsignedLongAt: pc + 1 bigEndian: false.
(self endCondition = InstructionPrefetchError) ifTrue:
[^self handleFailingBranch: instr to: pcOnEntry at: pc].
(self instructionIsAnyLoadStore: instr) ifTrue:
[^self handleFailingLoadStore: instr at: pc].
(self instructionIsAnyFPArithmetic: instr) ifTrue:
[^self handleFailingFPArithmetic: instr at: pc].
^self handleExecutionPrimitiveFailureAt: pc in: memoryArray].
^self reportPrimitiveFailure
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleExtendedDoubleArithmetic: instr at: pc [
"Emulate an extended math - cmp/sqrt/sitod - VFP instruction."
| rn rd rm vn vm vd |
rn := instr >> 16 bitAnd: 15.
rd := instr >> 12 bitAnd: 15.
rm := instr bitAnd: 15.
vn := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rn + 18)). "Assume accesses fp regs"
vm := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rm + 18)). "Assume accesses fp regs"
"simplest to match the entire instruction pattern rather than mess around shifting and masking and merging"
(instr bitAnd: 16rFF00FF0)
caseOf: {
[16rEB80B80 "FCMPD"] ->
["read rd, compare with rm (ignore rn) and set FPSCR NZCV flags. Sigh"
vd := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rd + 18)).
self break].
[16rEB80BC0 "FSITOD"] ->
[| r |
r := vm asFloat.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
[16rEB10BC0 "FSQRTD"] ->
[| r |
r := vm sqrt.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
}
otherwise: [self reportPrimitiveFailure].
self pc: pc + 4
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleFPLoadStore: instr at: pc [
"Emulate a VFP load/store instruction."
| rn rd offset |
rn := instr >> 16 bitAnd: 15.
rd := instr >> 12 bitAnd: 15.
offset := instr bitAnd: 16rFF.
"examine the U and Lbits"
(instr >>20 bitAnd: 16rF)
caseOf: {
[0"Store neg"] ->
[| r addr|
addr := (self register: rn) - (offset<<2).
r := self perform: (self registerStateGetters at: rd + 18).
self unsignedLongLongAt: addr put: r].
[1"Load neg"] ->
[| r addr|
addr := (self register: rn) - (offset<<2).
r := self unsignedLongLongAt: addr.
self perform: (self registerStateSetters at: rd + 18) with: r ].
[8"Store pos"] ->
[| r addr|
addr := (self register: rn) + (offset<<2).
r := self perform: (self registerStateGetters at: rd + 18).
self unsignedLongLongAt: addr put: r].
[9"Load pos"] ->
[| r addr|
addr := (self register: rn) + (offset<<2).
r := self unsignedLongLongAt: addr.
self perform: (self registerStateSetters at: rd + 18) with: r ].}
otherwise: [self reportPrimitiveFailure].
self pc: pc + 4
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleFPStatus: instr at: pc [
"Emulate transferring the FP status to the ARM CPSR."
| fpcpsr |
fpcpsr := self fpCPSR.
self vflag: (fpcpsr bitAnd: 1).
self cflag: ((fpcpsr >>1) bitAnd: 1).
self zflag: ((fpcpsr >>2) bitAnd: 1).
self nflag: ((fpcpsr >>3) bitAnd: 1).
self pc: pc + 4
]
{ #category : #'error handling' }
GdbARMAlien >> handleFailingBranch: instr to: address at: pc [
(self instructionIsBL: instr) ifTrue:
[self assert: address = (pc + 8 + (self extractOffsetFromBL: instr)) signedIntToLong.
^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (pc + 8 + (self extractOffsetFromBL: instr)) signedIntToLong
type: #call)
signal].
(self instructionIsBLX: instr) ifTrue:
[self assert: address = (self perform: (self registerStateGetters at: (instr bitAnd: 15) + 1)).
^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: (self registerStateGetters at: (instr bitAnd: 15) + 1))
type: #call)
signal].
(self instructionIsBX: instr) ifTrue:
[self assert: address = (self perform: (self registerStateGetters at: (instr bitAnd: 15) + 1)).
^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: (self registerStateGetters at: (instr bitAnd: 15) + 1))
type: #jump)
signal].
(self instructionIsB: instr) ifTrue:
[self assert: address = (pc + 8 + (self extractOffsetFromBL: instr)) signedIntToLong.
^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (pc + 8 + (self extractOffsetFromBL: instr)) signedIntToLong
type: #jump)
signal].
(self instructionIsReturnViaLR: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: self lr
type: #return)
signal].
^self reportPrimitiveFailure
]
{ #category : #'error handling' }
GdbARMAlien >> handleFailingFPArithmetic: instr at: pc [
"basic arithmetic"
(instr bitAnd: 16rF400FB0) = 16rE000B00 ifTrue:
[^self handleBasicDoubleArithmetic: instr at: pc].
"extension instructions sqrt/cmp/sitod"
(instr bitAnd: 16rFF00F70) = 16rEB00B40 ifTrue:
[^self handleExtendedDoubleArithmetic: instr at: pc].
"move ARM reg to coproc reg. "
(instr bitAnd: 16rFF00FFF) = 16rE000A10 ifTrue:
[^self handleRegToDoubleTransfer: instr at: pc].
"move FPSCR reg to ARM CPSR"
(instr bitAnd: 16rFFFFFFF) = 16rEF1FA10 ifTrue:
[^self handleFPStatus: instr at: pc].
"load and store ops. All doubles; we only use FLDD & FSTD"
(instr bitAnd: 16rF600F00) = 16rD000B00 ifTrue:
[^self handleFPLoadStore: instr at: pc].
^self reportPrimitiveFailure
]
{ #category : #'error handling' }
GdbARMAlien >> handleFailingLoadStore: instr at: pc [
"See e.g. ARM DDI0406A pp. A8-120, 124, 128, 132, 152, 156, etc. etc"
| baseReg destReg srcReg offset |
"find the register used as the base of the address and the register to load into or store from"
baseReg := self registerStateGetters at: (instr >> 16 bitAnd: 15)+ 1.
srcReg := self registerStateGetters at: (instr >> 12 bitAnd: 15)+ 1.
destReg := self registerStateSetters at: (instr >> 12 bitAnd: 15) + 1.
"work out the relevant offset, whether an immediate or register value"
offset := self extractOffsetFromLoadStore: instr.
(self instructionIsLDR: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #read
accessor: destReg)
signal].
(self instructionIsLDRB: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #read
accessor: destReg)
signal].
(self instructionIsLDRH: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #read
accessor: destReg)
signal].
(self instructionIsSTR: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #write
accessor: srcReg)
signal].
(self instructionIsSTRB: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #write
accessor: srcReg)
signal].
(self instructionIsSTRH: instr) ifTrue:
[^(ProcessorSimulationTrap
pc: pc
nextpc: pc + 4
address: (self perform: baseReg) + offset
type: #write
accessor: srcReg)
signal].
self error: 'handleFailingLoadStore:at: invoked for non-load/store?'
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleOneRegTransferDoubleArithmetic: instr at: pc [
"Emulate a one-register transfer VFP instruction."
| rn rd rm vn vm |
rn := instr >> 16 bitAnd: 15.
rd := instr >> 12 bitAnd: 15.
rm := instr bitAnd: 15.
vn := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rn + 18)). "Assume accesses fp regs"
vm := Float fromIEEE64BitWord: (self perform: (self registerStateGetters at: rm + 18)). "Assume accesses fp regs"
(instr >> 18 bitAnd: 31)
caseOf: {
[8 "FMULD"] ->
[| r |
r := vn * vm.
self perform: (self registerStateSetters at: rd + 18) with: r asIEEE64BitWord].
[12"FADDD/FSUBD"] ->
[self shouldBeImplemented].
[32"FDIVD"] ->
[self shouldBeImplemented].
[45"FCMPD"] ->
[self shouldBeImplemented]. }
otherwise: [self reportPrimitiveFailure].
self pc: pc + 4
]
{ #category : #'floating-point emulation' }
GdbARMAlien >> handleRegToDoubleTransfer: instr at: pc [
"Emulate an ARM to VFP instruction."
| rn rd vn |
rn := (instr >> 16 bitAnd: 15) << 1 bitOr: (instr >>6 bitAnd: 1).
rd := instr >> 12 bitAnd: 15.
vn := self register: rn.
self perform: (self registerStateSetters at: rd + 18) with: vn.
self pc: pc + 4
]
{ #category : #accessing }
GdbARMAlien >> ifflags [
"The ARM cpsr flags are kept as individual fields in the Alien structure. The address here is the 1-based byte offset into the ARMul_State structure"
^self unsignedLongAt: 581
]
{ #category : #accessing }
GdbARMAlien >> ifflags: unsignedInteger [
"The ARM cpsr flags are kept as individual fields in the Alien structure. The address here is the 1-based byte offset into the ARMul_State structure"
^self unsignedLongAt: 581 put: unsignedInteger
]
{ #category : #'processor setup' }
GdbARMAlien >> initializeStackFor: aCogit [
"Different cpus need different stack alignment etc, so handle the details here."
aCogit setStackAlignment: 8 expectedSPOffset: 0 expectedFPOffset: 0.
PostBuildStackDelta := 0
]
{ #category : #testing }
GdbARMAlien >> instructionIsAddSP: instr [
"is this an add sp, sp, #? - instruction?"
^instr >> 28 < 16rF "test for allowed condcode - 0xF is extension" and: [(instr bitAnd: (16rFFFFF00)) = (16r28DD000)]
]
{ #category : #testing }
GdbARMAlien >> instructionIsAlignSP: instr [
"is this a subs sp, sp, #4 - instruction?"
^instr >> 28 < 16rF "test for allowed condcode - 0xF is extension" and: [(instr bitAnd: (16rFFFFFFF)) = (16r2DDD004)]
]
{ #category : #testing }
GdbARMAlien >> instructionIsAnyB: instr [
"is this any of the B BX BL or BLX <offset> instructions?"
^ (self instructionIsB: instr)
or: [self instructionIsBL: instr]
or: [self instructionIsBLX: instr]