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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
|
% learning an ISA by force of will
cpu instruction sets are one of my special interests. whitequark posted about a weird instruction set. so of course i asked for a copy of the binary. it indulged me! it's called `noes`, who knows why.
<pre class="codebox">
> ls -al noes
-rw-rw-r-- 1 iximeow iximeow 12935 May 23 18:12 noes
</pre>
so, 12.6KiB of some firmware for a headset or something, and an otherwise
unknown instruction set. this is catnip, to me.
and so here is where i started:
<pre class="codebox">
00000000 BC 60 BB 68 E4 E3 E5 ED E2 8F E3 01 28 42 99 03 43 91 05 D4 C4 BC 69 BB .`.h........(B..C.....i.
00000018 BC 26 BE E0 04 C8 41 F0 E0 44 C8 40 F0 E0 BB C8 51 F0 E0 94 C8 50 F0 EC .&....A..D.@....Q....P..
00000030 E3 ED BF D8 0E BC E0 05 BF D0 0E C8 E3 ED CC 19 B9 E0 04 C8 41 F0 E0 64 ....................A..d
00000048 C8 40 F0 E0 BB C8 51 F0 E0 77 C8 50 F0 BC 47 04 E0 01 D2 E0 72 C8 43 F0 .@....Q..w.P..G.....r.C.
00000060 E0 BC C8 42 F0 E0 BB C8 53 F0 E0 D3 C8 52 F0 E4 01 BF 90 75 BC E9 72 E8 ...B....S....R.....u..r.
00000078 99 B7 90 03 BC E9 72 E2 1C E3 00 E0 72 C8 43 F0 E0 E7 C8 42 F0 E0 BB C8 ......r.....r.C....B....
00000090 53 F0 E0 B4 C8 52 F0 BC C0 72 E0 13 C8 20 B5 E0 EC C8 1F B5 BC 59 40 E1 S....R...r... .......Y@.
000000A8 08 E8 48 B6 79 90 0A 28 C8 4C B6 C8 4B B6 BC 3C 6B E8 48 B6 90 07 C8 4C ..H.y..(.L..K..<k.H....L
000000C0 B6 28 C8 4B B6 BC BD 6B BC E4 61 E0 12 7A 28 4B 99 04 E0 12 90 07 14 71 .(.K...k..a..z(K.......q
000000D8 E8 41 B5 59 49 C8 41 B5 E1 00 C9 42 B5 00 00 BC A2 57 BF D0 0E C8 C2 B9 .A.YI.A....B.....W......
000000F0 CC C1 B9 CA C3 B9 E8 F9 B4 22 98 03 BC 2D 33 BC DA 32 86 12 76 E8 0B B4 ........."...-3..2..v...
00000108 7E 99 04 76 BC 75 BC E9 0C B4 16 79 99 03 EE 0C B4 E9 0C B4 16 59 49 76 ~..v.u.....y.........YIv
00000120 EA 0C B4 E3 00 E8 0B B4 E1 00 59 4A 72 11 4B 73 83 82 16 72 E3 00 FC 08 ..........YJr.Ks...r....
00000138 81 E1 FF 51 89 80 E0 FF 09 71 88 BF EC AC 8A 8B BF 9D AC C9 DD EE C8 DC ...Q.....q..............
00000150 EE 8E B9 E7 01 BC 2D 2E 86 E1 FF E8 ED B4 79 90 44 BF 52 32 76 90 1D E0 ......-.......y.D.R2v...
00000168 54 C8 57 F3 E0 19 C8 56 F3 28 C8 53 F3 00 C8 52 F3 71 E8 50 F3 19 C8 50 T.W....V.(.S...R.q.P...P
00000180 F3 BC 01 BD 16 74 BF B6 28 71 98 19 E1 FE E8 50 F3 21 C8 50 F3 28 C8 ED .....t..(q.....P.!.P.(..
00000198 B4 E0 08 C8 53 F3 28 C8 52 F3 BF 87 30 8E B9 E2 00 E0 04 C8 41 F0 E0 44 ....S.(.R...0.......A..D
000001B0 C8 40 F0 E0 BB C8 51 F0 E0 94 C8 50 F0 E1 01 12 19 72 E0 72 C8 43 F0 E0 .@....Q....P.....r.r.C..
000001C8 BC C8 42 F0 E0 BB C8 53 F0 E0 D3 C8 52 F0 E1 02 12 19 72 E0 40 C8 45 F0 ..B....S....R.....r.@.E.
000001E0 E0 50 C8 44 F0 E0 BB C8 55 F0 E0 F6 C8 54 F0 E1 04 12 19 72 E0 6A C8 47 .P.D....U....T.....r.j.G
000001F8 F0 E0 5E C8 46 F0 E0 BC C8 57 F0 E0 03 C8 56 F0 E1 08 12 19 72 E0 61 C8 ..^.F....W....V.....r.a.
00000210 49 F0 E0 E1 C8 48 F0 E0 BC C8 59 F0 E0 24 C8 58 F0 E1 10 12 19 72 E0 57 I....H....Y..$.X.....r.W
00000228 C8 4B F0 E0 89 C8 4A F0 E0 BC C8 5B F0 E0 27 C8 5A F0 E1 20 12 19 72 E0 .K....J....[..'.Z.. ..r.
00000240 32 C8 4D F0 E0 C8 C8 4C F0 E0 BC C8 5D F0 E0 46 C8 5C F0 E1 40 12 19 72 2.M....L....]..F.\..@..r
00000258 E0 17 C8 4F F0 E0 53 C8 4E F0 E0 BC C8 5F F0 E0 5E C8 5E F0 E1 80 12 19 ...O..S.N...._..^.^.....
00000270 72 CA 60 F0 E2 00 E0 2E C8 21 F0 E0 1C C8 20 F0 E0 BC C8 31 F0 E0 AF C8 r.`......!.... ....1....
00000288 30 F0 E1 01 12 19 72 E0 A7 C8 25 F0 E0 66 C8 24 F0 E0 A7 C8 35 F0 E0 7E 0.....r...%..f.$....5..~
</pre>
i also often think about [this lovely writeup](https://www.robertxiao.ca/hacking/dsctf-2019-cpu-adventure-unknown-cpu-reversing/) from Robert Xiao on a similar problem presented as a Dragon CTF teaser challenge a few years ago. working from an unknown data encoding all the way out to an instruction set and high level behavior is certainly _possible_, but it's not an opportunity that comes up often. it sounds fun! so i decided to chew on `noes` with as little context as i could have - the opportunity doesn't come up too often!
making heads or tails of the binary turned out to be quite a few words, which i've roughly broken up as:
<ul>
<li><a href="#which-way-is-up">which way is up?</a></li>
<li><a href="#one-instruction-to-many-instructions">one instruction, to many instructions</a></li>
<li><a href="#a-virtuous-cycle">a virtuous cycle</a></li>
<li><a href="#control-flow">control flow!!</a></li>
<li><a href="#loads-and-stores">loads and stores!!</a></li>
<li><a href="#it-does-in-fact-have-an-alu">it does, in fact, have an ALU</a></li>
<li><a href="#inc-and-dec-are-a-loops-best-friend">inc and dec are a loop’s best friend</a></li>
<li><a href="#more-subtle-loads-or-stores">more subtle loads or stores?</a></li>
<li><a href="#a-multiplier">a multiplier!</a></li>
<li><a href="#whats-left">what’s left?</a></li>
<li><a href="#whittling-down-the-last-few-opcodes">whittling down the last few opcodes…</a><ul>
<li><a href="#f"><code>48..4f</code></a></li>
<li><a href="#or-a-wild-guess-towards-58..5f"><code>59</code> … or a wild guess towards <code>58..5f</code>?</a></li>
<li><a href="#where-possible"><code>60..67</code> … where possible</a></li>
<li><a href="#ba"><code>ba</code></a></li>
<li><a href="#section"><code>00..07</code></a></li>
</ul></li>
<li><a href="#mostly-done-whats-left-in-the-encoding-space">mostly done, what’s left in the encoding space?</a></li>
<li><a href="#f-sub-or-cmp"><code>78..7f</code> … <code>sub</code> or <code>cmp</code>?</a></li>
<li><a href="#what-is-a0">what is <code>a0</code>?</a></li>
<li><a href="#what-are-c0..c7">what are <code>c0..c7</code>?</a></li>
<li><a href="#but-wait-what-happened-with-jcc">but wait! what happened with <code>jcc</code>?</a></li>
<li><a href="#last-thoughts">last thoughts</a></li>
<li><a href="#conclusion">conclusion</a><ul>
<li><a href="#summarized-materials">summarized materials</a></li>
</ul></li>
</ul>
## which way is up?
even just at the bottom of this first window it's clear there's some kind of structure to this thing. but if it's code or data, who knows. i did luck out that the terminal size i happened to open `noes` with showed some structure, otherwise i'd have resorted to the same age-old trick of "resize the window until it looks right".
so there's some structure, the file is kind of tiny, the file is notionally a firmware for a processor, so presumably the processor also is kind of tiny. the bytes here are not obviously an 8080/6502/etc. probably not a tiny ARM core, because the repetition at the end of the above is offset by 1: this processor must be OK with instructions at odd addresses.
scrolling through the file for anything else interesting and this stands out:
<pre class="codebox">
00001358 B9 80 81 82 83 84 85 E8 E6 B0 80 E8 E7 B0 80 E8 E8 B0 80 E8 E9 B0 80 E8 ........................
00001370 EA B0 80 E8 EB B0 80 E8 EC B0 80 E8 ED B0 80 E8 EE B0 80 E8 EF B0 80 E8 ........................
00001388 F0 B0 80 86 87 E1 03 E8 59 F3 21 98 3D BF 8E 31 BC 2E CF 80 81 82 83 84 ........Y.!.=..1........
000013A0 85 E8 E6 B0 80 E8 E7 B0 80 E8 E8 B0 80 E8 E9 B0 80 E8 EA B0 80 E8 EB B0 ........................
000013B8 80 E8 EC B0 80 E8 ED B0 80 E8 EE B0 80 E8 EF B0 80 E8 F0 B0 80 86 87 BF ........................
000013D0 CD DF 8F 8E 88 C8 F0 B0 88 C8 EF B0 88 C8 EE B0 88 C8 ED B0 88 C8 EC B0 ........................
000013E8 88 C8 EB B0 88 C8 EA B0 88 C8 E9 B0 88 C8 E8 B0 88 C8 E7 B0 88 C8 E6 B0 ........................
00001400 8D 8C 8B 8A 89 88 BA E8 F3 B4 C8 5C ED E8 F2 B4 C8 5B ED B9 E0 03 C8 0D ...........\.....[......
</pre>
this is different, which makes it interesting! this is a long span of bytes with very few ascii bytes, unlike the rest of the file which has a more frequent mix of bytes in `[0, 255]`. the content starts with an increasing series, `80 81 82 83 84 85 E8 E6 B0 80 E8 E7 B0 80 ...`, and towards the end has `8D 8C 8B 8A 89 88`. this might be data? maybe a lookup table?
there are other regions of clear structure, like:
<pre class="codebox">
00002478 6A F1 ED 6B F1 12 E9 6C F1 21 72 13 E9 6D F1 21 73 14 E9 6E F1 21 74 15 j..k...l.!r..m.!s..n.!t.
00002490 E9 6F F1 21 75 12 E9 25 EE 21 72 13 E9 26 EE 21 73 14 E9 27 EE 21 74 15 .o.!u..%.!r..&.!s..'.!t.
000024A8 E9 28 EE 21 75 CA 68 F1 CB 69 F1 CC 6A F1 CD 6B F1 12 1B 1C 1D 98 07 E4 .(.!u.h..i..j..k........
</pre>
but what does `21 72 13 E9` mean? or `21 73 14 E9`? `21 74 15 E9`? maybe four-byte instructions with different operands?
ok. time to break out the big tools.
<pre class="codebox">
# iximeow> xxd -ps noes | head -n 20
bc60bb68e4e3e5ede28fe30128429903439105d4c4bc69bbbc26bee004c8
41f0e044c840f0e0bbc851f0e094c850f0ece3edbfd80ebce005bfd00ec8
e3edcc19b9e004c841f0e064c840f0e0bbc851f0e077c850f0bc4704e001
d2e072c843f0e0bcc842f0e0bbc853f0e0d3c852f0e401bf9075bce972e8
99b79003bce972e21ce300e072c843f0e0e7c842f0e0bbc853f0e0b4c852
f0bcc072e013c820b5e0ecc81fb5bc5940e108e848b679900a28c84cb6c8
4bb6bc3c6be848b69007c84cb628c84bb6bcbd6bbce461e0127a284b9904
e01290071471e841b55949c841b5e100c942b50000bca257bfd00ec8c2b9
ccc1b9cac3b9e8f9b4229803bc2d33bcda32861276e80bb47e990476bc75
bce90cb416799903ee0cb4e90cb416594976ea0cb4e300e80bb4e100594a
72114b7383821672e300fc0881e1ff518980e0ff097188bfecac8a8bbf9d
acc9ddeec8dcee8eb9e701bc2d2e86e1ffe8edb4799044bf523276901de0
54c857f3e019c856f328c853f300c852f371e850f319c850f3bc01bd1674
bfb628719819e1fee850f321c850f328c8edb4e008c853f328c852f3bf87
308eb9e200e004c841f0e044c840f0e0bbc851f0e094c850f0e101121972
e072c843f0e0bcc842f0e0bbc853f0e0d3c852f0e102121972e040c845f0
e050c844f0e0bbc855f0e0f6c854f0e104121972e06ac847f0e05ec846f0
e0bcc857f0e003c856f0e108121972e061c849f0e0e1c848f0e0bcc859f0
e024c858f0e110121972e057c84bf0e089c84af0e0bcc85bf0e027c85af0
e120121972e032c84df0e0c8c84cf0e0bcc85df0e046c85cf0e140121972
</pre>
more structure to this, highlighting helps..
<pre class="codebox">
308eb9e200e004<span class=yellow>c8</span>41f0e044<span class=yellow>c8</span>40f0e0bb<span class=yellow>c8</span>51f0e094<span class=yellow>c8</span>50f0e101121972
e072<span class=yellow>c8</span>43f0e0bc<span class=yellow>c8</span>42f0e0bb<span class=yellow>c8</span>53f0e0d3<span class=yellow>c8</span>52f0e102121972e040<span class=yellow>c8</span>45f0
e050<span class=yellow>c8</span>44f0e0bb<span class=yellow>c8</span>55f0e0f6<span class=yellow>c8</span>54f0e104121972e06a<span class=yellow>c8</span>47f0e05e<span class=yellow>c8</span>46f0
e0bc<span class=yellow>c8</span>57f0e003<span class=yellow>c8</span>56f0e108121972e061<span class=yellow>c8</span>49f0e0e1<span class=yellow>c8</span>48f0e0bc<span class=yellow>c8</span>59f0
e024<span class=yellow>c8</span>58f0e110121972e057<span class=yellow>c8</span>4bf0e089<span class=yellow>c8</span>4af0e0bc<span class=yellow>c8</span>5bf0e027<span class=yellow>c8</span>5af0
e120121972e032<span class=yellow>c8</span>4df0e0<span class=yellow>c8</span><span class=yellow>c8</span>4cf0e0bc<span class=yellow>c8</span>5df0e046<span class=yellow>c8</span>5cf0e140121972
</pre>
if `c8` marks the start of some instruction or sequence, the those sequences are something like:
<pre class="codebox">
c841f0e044 c840f0e0bb c851f0e094 c850f0e101 ...
... c843f0e0bc c842f0e0bb c853f0e0d3 c852f0e1 ...
</pre>
and so seeing `41f0`, `40f0`, `51f0`, `50f0`, `43f0`, `42f0`, `53f0`, `52f0`, and others like it, immediately suggests something little-endian is happening. those might be offsets for a memory access? `e044`, `e0bb`, etc could be other immediates or operand selectors. maybe `c8` is an opcode itself?
this is a great start: there's some kind of structure, something that looks like a workable guess for how at least one instruction is strucutred, values that look like addresses - or at least relative offsets. even if this is more data than code, there's enough structure here to chew on and learn more about the firmware.
## one instruction, to many instructions
if i were stumped at this point i'd have started looking for common byte sequences, working through a list to guess what might be function prologues or epilogues, and go from there. but, being neither stumped nor interested in switching away from the next most advanced tool i have on hand - `xxd -ps noes | vim -` - i stuck with eyeballing common bytes. `8e` stuck out:
<pre class="codebox">
75bffce2fe0671fe0272fe0373f219d2<span class=yellow>8e</span>8fb98786ca56ef147615771674
1775bffce2ea56eff674bfe444<span class=yellow>8e</span>8fb9878628c857eec856eee412bf14e9
761177e010de03e20016741775bf5f05<span class=yellow>8e</span>8fb9e<span class=yellow>8e</span>9ed9803bccfe2e85aee
e95bee19982de855eec84befc94defe85aeec84cefe26<span class=yellow>8e</span>3eee461e5eebf
dfe3ea5aeeeb5beefa079026c85beec85aeebcc0e3e854eec84befe859ee
c84defe85<span class=yellow>8e</span>ec84cefe26<span class=yellow>8e</span>3eee461e5eebfdfe3e001c84befe85deec84d
</pre>
and in fact the longer common sequences are `8e8fb98786`:
<pre class="codebox">
75bffce2fe0671fe0272fe0373f219d2<span class=yellow>8e8fb98786</span>ca56ef147615771674
1775bffce2ea56eff674bfe444<span class=yellow>8e8fb98786</span>28c857eec856eee412bf14e9
761177e010de03e20016741775bf5f058e8fb9e8e9ed9803bccfe2e85aee
e95bee19982de855eec84befc94defe85aeec84cefe268e3eee461e5eebf
dfe3ea5aeeeb5beefa079026c85beec85aeebcc0e3e854eec84befe859ee
c84defe858eec84cefe268e3eee461e5eebfdfe3e001c84befe85deec84d
</pre>
this shows up across the file, but `8786` is only sometimes present. so maybe this is the epilogue of one function, and the prologue of the next? in which case the epilogue would be `8e8fb9` and the prologue is `8786`. then `b9` is `ret`? `8e8f` and `8786` are `pop` and `push` respectively? lets see if that gives us reasonably-sized functions. as some examples:
<pre class="codebox">
... <span class=yellow>8e8fb9</span>
8786cae5eecce6eee412bf14e9761177e8e6eede03e8e5eede04e20016741775bf5f05<span class=yellow>8e8fb9</span>
e200e45390d4b9e4f5e5edbf82c3e0d4c85cefe0e8c85bef28c85eefe003
[ 210 bytes ]
bf2bd7<span class=yellow>8e8fb9</span>
e500e406e260e3ed14e1005272110b73f27215527504e118
[ 240 bytes ]
19e0f2c8ecee177116c0c9eeeec8edeee1fff65172e412bf4bd4<span class=yellow>8e8fb9</span>
cc86f2cd87f2e004c882f2b928c855f3e01ac854f3e1fee850f321c850f3e0
[ 420 bytes ]
75bf8cdaea0aef02ca0aefe19912799181<span class=yellow>8e8fb9</span>
</pre>
nothing huge, seems like a workable assumption.
## a virtuous cycle
with a guess of function prologues ane epilogues, i can guess at the instructions around the entry/exit of these "theoriezed functions".
some more looking around, `c8` is pretty common and seems to be followed by two bytes that might be an address?
<pre class="codebox">
52e8ec76edbfdee6e876ed9805e401bc52e8b928<span style="background-color: "background-color: yellow;";">c8</span><span style=green>06ee</span><span class=yellow>c8</span><span style=green>05ee</span><span class=yellow>c8</span>47eee8
03f3619016e003<span class=yellow>c8</span><span style=green>4bee</span>e001<span class=yellow>c8</span><span style=green>4aee</span>e140e8a3f919<span class=yellow>c8</span>a3f9bc3b60e102e8
4aee799026e003<span class=yellow>c8</span>4beee8eded9805e008<span class=yellow>c8</span><span style=green>03f3</span>e008<span class=yellow>c8</span>8cf971e898f919
<span class=yellow>c8</span>98f9e1bfe8a3f921<span class=yellow>c8</span>a3f9b9e010<span class=yellow>c8</span><span style=green>03f3</span>bf9f5ce108e898f919<span class=yellow>c8</span>98f9
e1bfe8a3f921<span class=yellow>c8</span>a3f9e001<span class=yellow>c8</span>46eeb98786e101e847ee79902c28<span class=yellow>c8</span>47eee4
05e5eebf82c3e0<span class=yellow>c8</span><span class=yellow>c8</span>52b9e071<span class=yellow>c8</span>51b9e001<span class=yellow>c8</span>54b9e0f4<span class=yellow>c8</span>53b9e201e400
bf9513c906ee<span class=yellow>c8</span>05eee102e8e6ed799003bf2dc2e2cce342e85bede95ced
</pre>
there are definitely other `c8`s here that don't make sense yet, but `06ee .. 05ee` and `4bee .. 4aee` look like sequential addresses, and `03f3` shows up a few times which suggests these addresses are probably absolute.
in-between there are several `e0` followed by a relatively low byte, `e001` between two `c8` sequences, `e008`, `e010`, an `e071` once. the second byte might be an immediate, maybe an offset? the values tend towards bitmasks, for whatever reason. this also happens with `e1` and an `e2` in the same region:
<pre class="codebox">
52e8ec76edbfdee6e876ed9805e401bc52e8b928c806eec805eec847eee8
03f3619016e003c84beee001c84aeee140e8a3f919c8a3f9bc3b60e102e8
4aee799026e003c84beee8eded9805e008c803f3e008c88cf971e898f919
c898f9e1bfe8a3f921c8a3f9b9e010c803f3bf9f5ce108e898f919c898f9
e1bfe8a3f921c8a3f9e001c846eeb98786e101e847ee79902c28c847eee4
05e5eebf82c3e0c8c852b9e071c851b9e001c854b9e0f4c853b9<span class=yellow>e201</span>e400
bf9513c906eec805eee102e8e6ed799003bf2dc2<span class=green>e2cc</span>e342e85bede95ced
</pre>
so maybe `eX` is a whole range of instructions with one-byte immediates?
with this, lets see how a hypothesized function breaks apart..
<pre class="codebox">
87 86
14761577f698 19e0f2
c8ecee 177116c0 c9eeee c8edee e1ff f65172 e412 bf4bd4
8e 8f b9
</pre>
7X is another one-byte instruction maybe? 1X too? calling `86` "push A" and `87` "push B", similarly with `8e 8f`, that gives us:
<pre class="codebox">
87 86 <span class=blue>; push B; push A</span>
14 76 15 77 f698 19e0f2
c8ecee 17 71 16 c0 c9eeee c8edee e1ff f651 72 e412 bf4bd4
8e 8f b9 <span class=blue>; pop A; pop B; ret</span>
</pre>
checking that other blocks seem to break apart reasonably as "functions", this is how vim starts to look. knowing `c8XXXX` is an instruction in turn makes other instructions more clear:
<pre class="codebox">
87 86
28 c809ef 72 e461 e5ee bf29e3 <span class=blue>; 28 looks like something, 72 looks like something, bf<rel16>?</span>
e200 e468 e5ee bf29e3 bf2ae0 bffedc <span class=blue>; bf<rel16>?</span>
28 76 77 e84cee e94dee e201a
6939384290fac923f5c822f5e101e826f519c826f5c981f1e850f1649806 <span class=blue>; dunno about these</span>
28c878ed9818e803f3619807e001c809ef900bc6e1081679e107174991bc <span class=blue>; dunno about these</span>
bf4fdde826f56090fabf33e1e0072f9008e0082e9003bf2dc2e809ef9803 <span class=blue>; dunno about these</span>
bf2bd7
8e 8f b9 <span class=blue>; but an epilogue</span>
</pre>
lots that would be too early to guess about, but `28` seems like a functional instruction, as does `72`. `bf` might be a relative load or store?
if this is a vaguely normal 8-bit CPU, there ought to be conditional relative branches around somewhere too, which can help point towards instruction boundaries. most relative branches are short, either in the positive or negative direction (for loops), so that's worth keeping in mind. keeping an eye out is the best option, not really sure how to proactively find them. at the very least, it's probably not `e0..e7` as the conditional branches, because the following byte is sometimes `ff` (branch `$-1`??) or `00` (branch `$`???)
continuing on, picking function boundaries somewhat arbitrarily on "seen `b9`", this is illustrative:
<pre class="codebox">
... snip ...
b9
; new function?
e500 e406 e260 e3ed 14 e100 52 72 <span class=blue>; 14, 52, also 72 instructions?</span>
110b 73f2 7215 52 7504 e118 <span class=blue>; not sure if this makes sense</span>
14 79 91e8 15
b9 <span class=blue>; ret</span>
; new function?
28 c83bb5 e0fc c83cb5 28 c83db5 c83eb5 c842b5 e017 c841b5
e0ed c840b5 e061 c83fb5 bfded5 c865ed bf314d 71 9003 e006 b9
28 b9 <span class=blue>; something, ret</span>
; new prologue
86 ...more...
</pre>
`28 b9` seems too short to be a function (why call to `28`? if you want `28` just inline it), so that's noteworthy. but 9003 is 3 bytes before it. 9003 as a `jz $+3`? and `28 b9` is an alternate ret? that skips over `e006; ret`? seems workable.
so 90XX as conditional branch... here's a function i'd guessed at instruction boundaries for early on, and i'd gotten wrong:
<pre class="codebox">
87 86
cc27efcd28ef28 c8f1b0 e002 c863ef e05a c862ef
cd65ef 14 cc64ef e201 e400 bf83e9
76 11 77 71 16 19 90 03 bf420b e8f1b0 <span class=blue>; 9003 is one instruction, not two</span>
98fb
8e 8f b9
</pre>
fixing that up with what i know now it looks more like...
<pre class="codebox">
87 86
cc27efcd28ef28 c8f1b0 e002 c863ef e05a c862ef
cd65ef 14 cc64ef
e201 e400 bf83e9
76 11 77 71 16 19
9003 bf420b <span class=blue>; jCC $+3</span>
e8f1b0
98fb <span class=blue>; is this jCC $-5?</span>
8e 8f b9
</pre>
so maybe 9X is a whole family of conditional branches? plausible...
<pre class="codebox">
e008 c803f3 bf52d8 28 c8e6ed c8eeed
8eb9e8eded9001 <span class=blue>; hadn't noticed this 9001 at first. jcc over a ret?</span>
b9 28 c8eeed c8eded
e4f1 e5ed bf82c3 bffedc bf106f
</pre>
adjusting that a bit:
<pre class="codebox">
e008 c803f3 bf52d8 28 c8e6ed c8eeed
8eb9e8eded
9001 b9
28 c8eeed c8eded
e4f1 e5ed bf82c3 bffedc bf106f
</pre>
finding other interesting patterns around 9Xs, this function:
<pre class="codebox">
87 86 15 71 14 e304 53 9101 0176 <span class=blue>; 91XX as jCC?</span>
1177 e101 fe01 79 e104 f679 9034 e102 fe01
79 9006 bf3cd5bccdc7e101fe01 <span class=blue>; 79 is a test or cmp or sub maybe?</span>
79 9803 bccdc7e1f7e854f121c854f1e400bffa48e1fde856f121c856f1bf
17d5bccdc7e110f6799034e850f164986c e101 fe01
79 900f e401 bf67c5
e200 e41f bf2b31 bccdc7 e102 fe01 79 904f
e200 e423 bf2b31 e850f1 62 983d e400 983b e102 f679 90 38 e850f1 64 9832 fe01 79 9018 e108 e854f1 19 c854f1
e401 bf67c5 e852f1 60 9819 e400 9812 e101 fe01 79 900e e1f7 e854f1 21 c854f1
e401 bf67c5
8e8fb9
</pre>
following offsets for the proposed jCC in the third and fourth lines yields:
<pre class="codebox">
79 9006 bf3cd5bccdc7 e101 fe01 <span class=blue>; so fe01 is something (`feXX`?)</span>
79 9803 bccdc7 e1f7 e854f1 21 c854f1 e400 <span class=blue>; bcXXXX (or more?) is something</span>
bffa48e1fde856f121c856f1bf
</pre>
incidentally in the literal next function that knowledge of `bf` breaks things up into another pattern,
<pre class="codebox">
86
e406 bf551b 76 980b e406 bf551b 76 9803 bf420b e406
bf8f4d 71 9003 bf420b e0ee c840b5 e0f3 c83fb5 28 c842b5 e016 c841b5
bf114d 71 9003 bf420b e812b1 e913b1 ea14b1 eb15b1
ecfcee 7c 9012 e8fdee 79900c
e8feee 7a 9006
e8ffee 7b 9803 bf420b e80db1 e90eb1 ea0fb1 eb10b1
ec05ef 7c 9012
e806ef 79 900c
e807ef 7a 9006
e808ef 7b 9803
bf420b 8eb9e400bf
</pre>
this is great; `7x` definitely seems like it generates some kind of branch condition, and `9xXX` seems like a conditional branch based on that result.
## control flow!!
from this point onward, i'll be marking up approximate level of nesting with indentation. for each branch over a byte of code, it will be indented an additional level. when the branch target is reached, unindent. for simple control flow this gives a general idea of how PC moves through a region.
revisiting the above with this additional structure is immediately informative!
<pre class="codebox">
86
e406 bf551b <span class=blue>; this and the 76 after are the same as the one two lines down</span>
76 980b
e406 bf551b <span class=blue>; doing something to r4? getting a condition out? does bf551b reference memory?</span>
76 9803
bf420b
e406 bf8f4d
71 9003
bf420b
e0ee c840b5
e0f3 c83fb5 28 c842b5
e016 c841b5
bf114d 71 9003
bf420b
e812b1 e913b1 ea14b1 eb15b1 ecfcee
7c 9012
e8fdee
79 900c
e8feee
7a 9006
e8ffee
7b 9803
bf420b
e80db1 e90eb1 ea0fb1 eb10b1 ec05ef
7c 9012
e806ef
79 900c
e807ef
7a 9006
e808ef
7b 9803
bf420b
<span class=blue>; note 8e b9 here, some kind of early ret?</span>
<span class=blue>; missed that at first!</span>
8eb9 e400bf
52e8ec76edbfdee6e876ed9805e401bc52e8b928c806eec805eec847eee8
03f3619016e003c84beee001c84aeee140e8a3f919c8a3f9bc3b60e102e8
4aee799026e003c84beee8eded9805e008c803f3e008c88cf971e898f919
c898f9e1bfe8a3f921c8a3f9b9e010c803f3bf9f5ce108e898f919c898f9
e1bfe8a3f921c8a3f9e001c846ee
b9
</pre>
reconsidering other lines, there's this from early on which is not obviously wrong but now clearly has an error:
<pre class="codebox">
79 9009 fe07 72 fe08 73 e015 d216 74 17 75 bfead9 bc3bdb 16 74 17 75 bfe605
^ ^
$+9 is an instruction is $+9, the split was wrong
</pre>
so this should be
<pre class="codebox">
79 9009 fe07 72 fe08 73 e015 d2 16 74 17 75 bfead9 bc3bdb 16 74 17 75 bfe605
^ ^
$+9 is an instruction is $+9d
</pre>
`16` is an instruction on its own, and so is `d2`.
back to looking for interesting structures, and here's part of a larger function:
<pre class="codebox">
e108
e8d5ee
79 9113
e1f8 51 72 e8d6ee e100
9802 <span class=blue>; jump forward to 42..</span>
50 31 42
99fb <span class=blue>; jump backwards to 50..</span>
bc45eb
e9d5ee e008 59 49 71 e8d6ee bc40eb 69 38 41 99fb e100 76 11 77 e9d7ee
16 79 e9d8ee 17 49
9959
</pre>
so there's a short loop, the loop's body is `50 31 42`, and some condition means the loop is entered skipping `50 31`.
different topic for a moment, there are lots of e8XXXX/c8XXXX. what's going on with that? something to orient with...
<pre class="codebox">
87 86
28
c8f4b0
bf03bd
e013 c820b5
e0ec c81fb5
bfbfe6
e0ce c8c2b4
e0af c8c1b4
e434 bf8f4d
71 9003
bc87c0
e83bb5 c807ee <span class=blue>; the immediates here are interesting actually</span>
e83cb5 c808ee <span class=blue>; incrementing by 1</span>
e83db5 c809ee <span class=blue>; on the first and second instruction</span>
e83eb5 c80aee <span class=blue>; 0xb53e, 0xee0a ?</span>
bf2fd6
bfdcdb
bfc62e
e101 799803bc38c0e803f3609809e841b6e942b6
</pre>
## loads and stores!!
`e8 XXXX` is probably a load! then `c8 XXXX` is a store! might be an absolute 16b address then? does that suggest `e0` is a relative load? maybe some kind of banked load.
seems like `c9` is also a store, probably all c8-cf and e8-ef are store/load?
<pre class="codebox">
bf8ac0 e1fe e850f3 21 c850f3
b9 28 c8feed c8fded 72 e449 bcc2d4
e829b4 c863ef <span class=blue>; another 32b copy</span>
e828b4 c862ef
e825b4 c865ef
e824b4 c864ef
e200 e400
bf83e9
c9f2ed c8f1ed e8f1ed e9f2ed <span class=blue>; [edf2]->r1; [edf1]->r0; r0->[edf1]; r1->[edf2]? this is wrong</span>
bc8ad9
e40e
bf4204
c929b4 c828b4 <span class=blue>; again, storing and then loading later?</span>
e00d
ea28b4 eb29b4 <span class=blue>; but ea/eb would be r4, r5 maybe</span>
</pre>
elsewhere is another interesting sequence, annotating by the theory so far,
<pre class="codebox">
e1bf <span class=blue>; r1<-[...0xbf]</span>
e823f2 <span class=blue>; r0<-[0xf223]</span>
21 <span class=blue>; ???</span>
c823f2 <span class=blue>; [0xf223]<-r0</span>
</pre>
this is great: control flow, loads/stores, this is enough to start finding
where registers are read and written, and start figuring out arithmetic or
other operations.
## it does, in fact, have an ALU
so `21` is maybe, `op r0, r1`? `21` can't encode two registers (would be `001y yzzz`? not enough space to say `r4, r5` here). so might be an implicit r0.
`28` is a different `op2 r0, r0`? consider
<pre class="codebox">
e803f3 <span class=blue>; r0<-[0xf303]</span>
60 9009 <span class=blue>; also 60: generates a status from r0?</span>
28 <span class=blue>; definitely an instruction</span>
c83dee <span class=blue>; [0xee3d]<-r0</span>
e001 <span class=blue>; r0<-[..0x01]</span>
c85aed <span class=blue>; [0xed5a]<-r0</span>
bfd547
71
98fa
</pre>
`28` might be `xor r0, r0`, it's often precedes a `c8` store:
<pre class="codebox">
87 86
28 c8f4b0 <span class=blue>; xor r0, r0 (?); [0xb0f4]<-r0</span>
bf03bd
e013 c820b5
... ...
b9 <span class=blue>; ret</span>
28 <span class=blue>; first instruction in the block? function?</span>
c8feed c8fded <span class=blue>; [0xedfe]<-r0; [0xedfd]<-r0</span>
72 e449 bcc2d4 <span class=blue>; op r0, r2; r4<-[..0x49]; ??</span>
e829b4 c863ef
e828b4 c862ef
e825b4 c865ef
e824b4 c864ef
</pre>
`78` is not present as an instruction it seems, `79` is?
<pre class="codebox">
bfc62e <span class=blue>; unknown</span>
e101 <span class=blue>; r1<-[..0x01]</span>
79 9803 <span class=blue>; op r0, r1?; jCC $+3</span>
bc38c0 <span class=blue>; unknown</span>
e803f3 <span class=blue>; r0<-[0xf303]</span>
</pre>
`7a` is a single-byte instruction, as is `74` and `b4`:
<pre class="codebox">
29 4c 912d
ea5bed eb5ced e048 e120 <span class=blue>; r2<-[0xed5b]; r3<-[0xed5c]; r0<-[..0x48]; r1<-[..0x20]</span>
7a e080 2b <span class=blue>; 28 seems like xor r0, r0, so 2b is xor r0, r3?</span>
74 e080 29 <span class=blue>; 29 as xor r0, r1?</span>
4c 9118
e850f1
64 9012
bf2bd7
28 c810f2 c885f2 c884f2
74 75 bf03d7
bfc62e e101
79 981b
e10f e8b0b4
79 9009
e8b1 b4 62 9803 61 900a
</pre>
fishing around to find more about the `1X` and `2X` opcodes, this region is interesting:
<pre class="codebox">
62 9811
e108 e854f1 <span class=blue>; r1<-[..0x08]; r0<-[0xf154]</span>
19 <span class=blue>; op r0, r1? ;</span>
c854f1 <span class=blue>; [0xf154]<-r0; maybe 0001_1xxx is add?</span>
e852f1 <span class=blue>; r0<-[0xf152]</span>
60 <span class=blue>; something on r0 producing a condition..</span>
9802
e600 <span class=blue>; 1110_0xxx yyyyyyyy may actually be "load imm8 into rX"</span>
16 <span class=blue>;</span>
74 bf67c5
<span class=blue>; the sequence here is eventful</span>
e18f <span class=blue>; r1<-0x8f</span>
e825f2 <span class=blue>; r0<-[0xf225]</span>
21 <span class=blue>; op r0, r1</span>
e170 <span class=blue>; r1<-0x70</span>
19 <span class=blue>; op r0, r1</span>
c825f2 <span class=blue>; [0xf225]<-r0</span>
e008 c803f3 bf52d8
28 c8e6ed c8eeed
</pre>
some evidence that `21` may be and specifically:
<pre class="codebox">
e1bf <span class=blue>; r1<-0xbf</span>
e823f2 <span class=blue>; r0<-[0xf223]</span>
21 <span class=blue>; op r0, r1 ; if op were add, presumably there is a sub, why not sub 0x40?</span>
c823f2 <span class=blue>; [0xf223]<-r0 ; and masks bits, makes somewhat more sense...</span>
</pre>
is `78`..`7f` is `cmp/test/sub r0, rN`:
<pre class="codebox">
e812b1 e913b1 ea14b1 eb15b1
ecfcee
7c 9012 <span class=blue>; is [0xeefc] == [0xb112]?</span>
e8fdee
79 900c <span class=blue>; is [0xeefd] == [0xb113]?</span>
e8feee
7a 9006 <span class=blue>; is [0xeefe] == [0xb114]?</span>
e8ffee
7b 9803 <span class=blue>; is [0xeeff] == [0xb115]?</span>
bf420b
e80db1 e90eb1 ea0fb1 eb10b1
ec05ef
7c 9012 <span class=blue>; is the same for [0xb10d..0xb110] == [0xef05..0xef08]</span>
e806ef
79 900c
e807ef
7a 9006
e808ef
7b 9803
bf420b
8e b9
</pre>
notably `78` does not seem to appear as an instruction. preference for `xor r0, r0 (0x28)`? or not sub?
this may help make sense of operand ordering as well,
<pre class="codebox">
87 86 <span class=blue>; push r7; push r6</span>
14 76 15 77 f698 <span class=blue>; mov r4, r0; sub r0, r6, r6; mov r5, r0; sub r0, r7, r7</span>
19 e0f2 c8ecee <span class=blue>; mov r0->r1; r0<-0xf2; r0->[0xeeec]</span>
17 <span class=blue>; this is why it's likely that the selected register is a destination, 17 would</span>
<span class=blue>; be mov r0, r7. if 77 modified r0, r7 would be unmodified, and 77 would be dead</span>
<span class=blue>; code. instead if 77 modifies r7, this moves `r7_in - r5` into r0</span>
71 <span class=blue>; then this subtracts from r1, preservation of r0 after f698 (or 15)</span>
<span class=blue>; otherwise 19 would be pointless</span>
16 <span class=blue>; r6->r0</span>
c0 <span class=blue>; ???</span>
c9eeee <span class=blue>; why it would modify from r1, `[0xeeee]<-r1`</span>
c8edee <span class=blue>; and `[0xeeed]<-r0`</span>
e1ff f651
72 e412 bf4bd4
8e 8f b9
</pre>
but does any of this mean:
<pre class="codebox">
c83bef <span class=blue>; [0xef3b]<-r0</span>
c93cef <span class=blue>; [0xef3c]<-r1</span>
ca3def <span class=blue>; [0xef3d]<-r2</span>
cb3eef <span class=blue>; [0xef3e]<-r3</span>
e825ee <span class=blue>; r0<-[0xee25]</span>
e93bef <span class=blue>; r1<-[0xef3b]</span>
19 c825ee <span class=blue>; op r0, r1; [0xee25]<-r0 ; 18..1f is likely not add, sub, could be adc/sbc, maybe `or`</span>
e826ee <span class=blue>; r0<-[0xee26]</span>
e93cef <span class=blue>; r0<-[0xef3c]</span>
19 c826ee <span class=blue>; op r0, r1; [0xee26]<-r0 ; if 19 is `or`, this is computing or of two 32 regions</span>
e827ee <span class=blue>; r0<-[0xee27]</span>
e93def <span class=blue>; r1<-[0xef3d]</span>
19 c827ee <span class=blue>; op r0, r1; [0xee27]<-r0</span>
e828ee <span class=blue>; r0<-[0xee28]</span>
e93eef <span class=blue>; r1<-[0xef3f]</span>
19 c828ee <span class=blue>; op r0, r1; [0xee28]<-r0</span>
ea3bef <span class=blue>; r2<-[0xef3b] ; then .. something?</span>
eb3cef <span class=blue>; r3<-[0xef3c]</span>
ec3def <span class=blue>; r4<-[0xef3d]</span>
ed3eef <span class=blue>; r5<-[0xef3e]</span>
80 e837ef <span class=blue>; op; r0<-[0xef37]</span>
2280 <span class=blue>; op r0, r2; op</span>
e838ef <span class=blue>; r0<-[0xef38]</span>
2373 <span class=blue>; op r0, r3; op r0, r3</span>
e839ef <span class=blue>; r0<-[0xef39]</span>
2474 <span class=blue>; op r0, r4; op r0, r4</span>
e83aef <span class=blue>; r0<-[0xef3a]</span>
2575 <span class=blue>; op r0, r5; op r0, r5</span>
</pre>
or this:
<pre class="codebox">
e876b4 <span class=blue>; r0<-[0xb476]</span>
e977b4 <span class=blue>; r1<-[0xb476]</span>
c8e6b0 <span class=blue>; [0xb0e6]<-r0</span>
c9e7b0 <span class=blue>; [0xb0e7]<-r1</span>
28 c8e8b0 <span class=blue>; [0xb0e8]<-0</span>
c8e9b0 <span class=blue>; [0xb0e9]<-0</span>
72 73
e9d8ee <span class=blue>; r1<-[0xeed8]</span>
e8d7ee <span class=blue>; r0<-[0xeed7]</span>
bff5ec <span class=blue>; ?</span>
ecd5ee <span class=blue>; r4<-[0xeed5]</span>
bc63ea
<span class=blue>; so this loop is... do { X r1, X r3, X r2, X r1, X r0, X r4 } while cond(r4)?</span>
69 3b 3a 39 38 44
99f8
ecd3ee 5474 e8d4ee 097114
c999b4
c898b4
e8daee
c877b4
e8d9ee
c876b4
</pre>
`18..1f` seem like `r0 |= rX`:
<pre class="codebox">
e835ef e932ef 19 e933ef 19 e934ef 19
9019
</pre>
where `19` would mean this `or`s all four bytes and checking for.. zero? non-zero?
## inc and dec are a loop's best friend
and maybe 4X is dec? shr? `40` agrees, here's a branch table or smth?
<pre class="codebox">
9814
11 19
9810
40 98b6
40 98ba
40 98d8
40 98db
40 98df
40
bf57d0 bfbfcf
</pre>
seems like `40` is `dec r0`, consider this loop:
<pre class="codebox">
e103
e87fb4
21 <span class=blue>; op r1</span>
74 <span class=blue>; op r4</span>
e500 <span class=blue>; r5<-0x00</span>
e00b <span class=blue>; r0<-0x0b</span>
loop:
69 34 35 40 <span class=blue>; op r1?; op? r4; op? r5; dec r1</span>
90 fa <span class=blue>; jnz loop</span>
</pre>
so 0100_0XXX seems like `dec rN`. 0011_0XXX may be `inc rN`? and what is 0x69.
some more about the low 7Xs:
<pre class="codebox">
86
14 76 e8e2ed <span class=blue>; r4->r0? ; ...??? r6; r0<-[0xede2] .. maybe 76 is xchg r0, r6?</span>
7e 9817 <span class=blue>; 7e is maybe "compare r0 and r6"; jz?</span>
e003 c858ef e0ff c859ef ce5aefe458e5efbfded6cee2ed
8e b9
</pre>
since other ops seem oriented around operations on r0 and modifying r0, the low `7x`'s might be moving from `r0` to a different register? in contrast to low `1x` which move into r0. for example in the partially-disassembled snippet,
<pre class="codebox">
r1 <- 0x04
r0 <- r2
r0 |= r1
op7x.lo r0, r2
r0 <- 0x32
[0xf029] <- r0
</pre>
it's loaded `r0`, modified it, and would clobber it after the unknown op. `op7x.lo` must at least read `r0` and write `r2` or other state. there aren't any other instructions to read flags or anything before the next `op7x.lo`,
<pre class="codebox">
r1 <- 0x10
r0 <- r2
r0 |= r1
op7x.lo r0, r2
</pre>
so it could be an add/sub to store back into r2, but the `or` wouldn't make sense. if the `r0` is the only register that can be modified by arithmetic instructions - instructions seem small so there's not much encoding space - then modifying a value would look like "copy to r0, modify, copy back".
meanwhile `78..7f` is probably a `cmp` (rather than `sub`): in a sequence like
<pre class="codebox">
r1 <- 0x03
r0 <- [0xb475]
op7xhi r0, r1 <span class=blue>; byte 0x79</span>
jcc.lo.0 $+0x10 <span class=blue>; bytes 9010, destination `dest`</span>
r1 <- 0x04
r0 <- [0xeed2]
op7xhi r0, r1
jcc.hi.0 $+0x08
r0 <- 0x03
[0xeed2] <- r0
op.bc ec2c
dest:
r1 <- 0x03
</pre>
so if `op7xhi r0, r1` modified the destination, that modification is clobbered. it generates flags (consumed by `jcc.lo.0`). `79` is a very common prefix to `90xx` or `98xx` branches, but uncommon to stand alone.
counterpoint though, sequences like
<pre class="codebox">
e100 <span class=blue>; r1 <- 0x00</span>
bfecac <span class=blue>; unknown</span>
c9dfee c8deee <span class=blue>; [0xeedf] <- r1; [0xeede] <- r0</span>
e8eded 902f <span class=blue>; r0 <- [0xeded]; jcc $+0x2f?</span>
</pre>
have a useful branching condition with only loads (barring `bfecac` generating a status). and even if `bfecac` did generate a status, the next code if this is taken would be
<pre class="codebox">
e8e8ed 9841 <span class=blue>; r0 <- [0xede8]; jcc $+0x41</span>
</pre>
so either the `e8` load is enough to generate a status or the `98` branch is fully determined from the ealier `bfecac`. it's possible; the branches could be a pair like `jnz` and `ja`, where there is a third reasonable condition (`jb`) that becomes the implicit third outcome. but in that case why `e8e8ed` before the branch?
so perhaps the `90`/`98` conditions are predicated fully on the contents of `r0`?
ah, still unsure about `bf`, but this seems useful:
<pre class="codebox">
86
14 76 e8e2ed
7e 9817
e003 c858ef <span class=blue>; [0xef58] <- 0</span>
e0ff
c859ef ce5aef <span class=blue>; [0xef59] <- 0; [0xef5a] <- 0xff</span>
e458 <span class=blue>; r4 <- 0x58</span>
e5ef <span class=blue>; r5 <- 0xef ; so r5 and r4 together hold `ef58`, just assigned</span>
bfded6 <span class=blue>; consumes r4, r5, writes r6?</span>
cee2ed <span class=blue>; [0xed2e] <- r6</span>
8e b9
</pre>
## more subtle loads or stores?
distracted by `fe01`. found this:
<pre class="codebox">
87 86 <span class=blue>; push r7; push r6</span>
28 c83df3 <span class=blue>; xor r0, r0; [0xf33d] <- r0</span>
e00a c83cf3 <span class=blue>; r0 <- 0x0a; [0xf33c] <- r0</span>
28 c8c2ee <span class=blue>; xor r0, r0; [0xeec2] <- r0</span>
e6ca e7ee <span class=blue>; r6<-ca; r7<-ee ; r7:r6 = 0xeeca</span>
fe02 c837f3 <span class=blue>; fe02 ; [0xf337] <- r0</span>
fe01 c836f3 <span class=blue>; fe01 ; [0xf336] <- r0</span>
fe03 c838f3 <span class=blue>; fe03 ; [0xf338] <- r0</span>
fe04 c839f3 <span class=blue>; fe04 ; [0xf339] <- r0</span>
fe05 c83af3 <span class=blue>; fe05 ; [0xf33a] <- r0</span>
fe06 c83bf3 <span class=blue>; fe06 ; [0xf33b] <- r0</span>
f6 9827 <span class=blue>;</span>
</pre>
so `fe0X` writes to `r0`. before `feXX` are issued, `r6` and `r7 are often loaded with values that are also similar to nearby pointer values. so `r7:r6` usually forms a valid pointer. `fe00` does not exist in the image. is there a shorter instruction for a load of `[r7:r6 + 0]`?
separately, looks like `deXX` is `store r0 to [r7:r6 + XX]`. consider this code:
<pre class="codebox">
87 86 <span class=blue>; push r7; push r6</span>
ca40ef cc41ef <span class=blue>; [0xef40] <- r2; [0xef41] <- r4</span>
e412 bf14e9 76 11 77 <span class=blue>; r4 <- 0x12; call? ; r0->r6; r1->r0; r0->r7</span>
e072 <span class=blue>; r0 <- 0x72</span>
de03 <span class=blue>; hmm</span>
e841ef de04 <span class=blue>; r0 <- [0xef41]; hmm</span>
e840ef de05 <span class=blue>; r0 <- [0xef40]; hmm</span>
e83eee de06 <span class=blue>; r0 <- [0xee3e]; hmm</span>
e200 16 74 17 75 bf5f05 <span class=blue>; e2 <- 00; r6->r0; r0->r4; r7->r0; r0->r5; call?</span>
8e 8f b9 <span class=blue>; pop r6; pop r7; ret</span>
</pre>
so if the move of `r1:r0` to `r7:r6` is for a reason, that likely means:
* the calling convention returns pointers as `r1:r0`
* `deXX` might use `r7:r6`?
then between each `deXX` the program only loads `r0` with an `e8XXXX`, so `deXX` does not modify `r0`. if it modifies other registers, it's not `r2` (clobbered later), not `r4`, `r5` (clobbered later). if it's an indirect store through `r7:r6` it doesn't seem to increment (if it does, this is a .... very strange access pattern).
most likely seems to be `r0 -> [r7:r6 + imm8]`. that seems like a plausible function:
<pre class="codebox">
push r7; push r6;
[0xef40] <- r2; [0xef41] <- r4;
r4 <- 0x12; call 0xe914;
r1:r0 -> r7:r6 <span class=blue>; grouped a few moves together for this overall effect</span>
r0 <- 0x72; [r7:r6 + 3] <- r0
r0 <- [0xef41]; [r7:r6 + 4] <- r0
r0 <- [0xef40]; [r7:r6 + 5] <- r0
r0 <- [0xee3e]; [r7:r6 + 6] <- r0
r2 <- 0x00; r7:r6 -> r5:r4; call 0x055f ; eliding more movs
pop r6; pop r7;
ret
</pre>
and `18..1f` is `or`! here's another region:
<pre class="codebox">
e400 bf4204 <span class=blue>; r4 <- 0x00; call</span>
76 11 77 <span class=blue>; r1:r0 -> r7:r6 ; similar to before: exact movs are r0->r6; r1->r0; r0->r7</span>
71 16 <span class=blue>; r0 -> r1; r6 -> r0</span>
19 <span class=blue>; unknown</span>
9003 <span class=blue>; jcc $+3</span>
bf420b <span class=blue>; call</span>
e0ff de03 <span class=blue>; r0 <- 0xff; [r7:r6 + 3] <- r0</span>
28 de04 <span class=blue>; xor r0, r0; [r7:r6 + 4] <- r0</span>
e005 de05 <span class=blue>; r0 <- 0x05; [r7:r6 + 5] <- r0</span>
28 de06 <span class=blue>; xor r0, r0; [r7:r6 + 6] <- r0</span>
</pre>
`bf4204` returned a pointer that would be used in `de03` and later, below. before it is used there though, `71 16 19` does something with the two bytes of pointer before conditionally calling(?) something(?). there aren't many useful operations on the two bytes.
it's probably `or`, meaning `71 16 19` forms a null check, and there are likely other hits for that sequence... there are seven. four have the condition branch over a `bf420b`, so maybe `0xb42` is a fault handler? reset? some kind of trap. it probably doesn't return here since i'm certain that `r7:r6` is not useful for writing anyway.
also, that tells us `90` is `jnz`. `98` then is probably `jz`. that's consistent with sequences from earlier, like
<pre class="codebox">
11 19 9810 <span class=blue>; r0 <- r1; r0 |= r1 ; jz $+10</span>
40 98b6 <span class=blue>; dec r0 ; jz $-0x4a</span>
40 98ba <span class=blue>; dec r0 ; jz $-0x46</span>
40 98d8 <span class=blue>; dec r0 ; jz $-0x28</span>
40 98db <span class=blue>; dec r0 ; jz $-0x25</span>
40 98df <span class=blue>; dec r0 ; jz $-0x21</span>
</pre>
implementing a branch table for `i` in `0..5`?
## a multiplier!
`69` and `38..3f` make more sense from this loop:
<pre class="codebox">
28 c8e8b0 c8e9b0 <span class=blue>; xor r0, r0; [0xb0e8] <- r0; [0xb0e9] <- r0;</span>
72 73 <span class=blue>; r0 -> r2; r0 -> r3</span>
e9d8ee e8d7ee <span class=blue>; r1:r0 <- [0xeed7:0xeed8]</span>
bff5ec <span class=blue>; call</span>
ecd5ee <span class=blue>; r4 <- [0xee5d]</span>
bc63ea <span class=blue>; dunno</span>
69 3b 3a 39 38 44 <span class=blue>; ??? but r3, r2, r1, r0, then dec r4</span>
99f8 <span class=blue>; conditional branch to ???</span>
</pre>
so for each of `3b..38` it operates on `rN`, maybe `r0`. but if it accumulates into `r0`, why loop `r4` times? if `3b` mutates only `r3`, then there are few operations that make sense for all four registers:
* not `adc/sbc` (add/sub X to each byte?)
* could be `ror/rol` (operates on each byte independently)
* `rcr` could be it, high bytes carry into lower
* `rcl` could be it if endianness were such that the value is `r0:r1:r2:r3`
* since it only rotates by one bit it may actually be called a shift through carry?
if it's `rcr/rcl` then `69` clears the carry flag between loops so the loop implements a shift rather than rotate.
assuming `38..3f` is `rcr` since `r3:r2:r1:r0` matches endianness seen elsewhere.
seems like `fa` is similar to `fe`, but loading through `r3:r2` instead of `r7:r6`.
<pre class="codebox">
fe07 72 fe08 73 fa03 c872ed fa02 c871ed <span class=blue>; [r7:r6 + 7..8] -> r3:r2; fa03; store [0xed72]; fa02; store [0xed71]</span>
fe07 72 fe08 73 e004 d2 bceacc
fe07 72 fe08 73 e873ed da02 <span class=blue>; [r7:r6 + 7..8] -> r3:r2; load [0xed73]; da02</span>
fe07 72 fe08 73 e875ed da04 e874ed da03 <span class=blue>; [r7:r6 + 7..8] -> r3:r2; load [0xed73]; da02</span>
</pre>
`fa` might clobber `r3:r2`? again if it was "load and increment" or "store and increment" then the immediate offsets are very odd. could just be redundant loads of `r3:r2`?
also from this, `da` looks similar to `de`: `store r0 to [r3:r2 + XX]`.
`21` might be `and r0, r1`? `r1` seem to often have some immediate consecutive bitmasky thing loaded shortly before `21`. same for `22`. check this out:
<pre class="codebox">
f2 74
e001 e100 e200 e300 ; r3:r2:r1:r0 <- 0
9804 <span class=blue>; ???</span>
50 31 32 33 <span class=blue>; op ?r0?; op r1, op r2, op r3 - maybe</span>
<span class=blue>; `<op> r0; rcl r1; rcl r2; rcl r3</span>
44 <span class=blue>; dec r4</span>
99f9 <span class=blue>; conditional loop</span>
ec2eef 24 80 <span class=blue>; load r4; op r4; push r0</span>
e82fef 21 71 <span class=blue>; load r0; op r2; r0->r1</span>
e830ef 22 72 <span class=blue>; load r0; op r2; r0->r2</span>
e831ef 23 73 <span class=blue>; load r0; op r3; r0->r3</span>
88 <span class=blue>; pop r0</span>
c832ef c933ef ca34ef cb35ef <span class=blue>; store r3:r0 -> [0xef32:0xef35]</span>
</pre>
looks like the loop is building up a 32b bitmask, `and`ing, then storing back?
ok, different function:
<pre class="codebox">
e408 <span class=blue>; r4 <- 8</span>
back:
69 3d <span class=blue>; ccf; rcr r5</span>
911d <span class=blue>; jcc.lo.1 forward</span>
back:
e8eab0 56 c8eab0 <span class=blue>; r0 <- [0xb0ea]; op5x r0, r6; [0xb0ea] <- r0</span>
e8ebb0 09 c8ebb0 <span class=blue>; r0 <- [0xb0eb]; op0x r0, r1; [0xb0eb] <- r0</span>
e8ecb0 0a c8ecb0 <span class=blue>; r0 <- [0xb0ec]; op0x r0, r2; [0xb0ec] <- r0</span>
e8edb0 0b c8edb0 <span class=blue>; r0 <- [0xb0ed]; op0x r0, r3; [0xb0ed] <- r0</span>
69 <span class=blue>; ccf</span>
forward:
36 31 32 33 44 <span class=blue>; something on r6, r1, r2, r3; dec r4</span>
90d8 <span class=blue>; jnz back</span>
b9 <span class=blue>; ret</span>
</pre>
first observation: `91` is probably `jnc`. if it's `jc` then the loop would be entered with a carry flag set ... only on the first iteration. it seems more likely this is relying on knowing `cf` is unset to not execute `ccf` needlessly at the jump target. compared with other codegen, maybe this is a hand-written intrinsic?
second observation: `30..37` might be `rcl`? whatever `56 .. 09 .. 0a .. 0b` does, the surrounding load/stores suggest that there's a 32b value in `r3:r2:r1:r6`. meanwhile, the loop operates on `r6:r1:r2:r3`. each op would then carry out to the next most significant byte, and this is similar to `rcr` already knwon to be `38..3f`.
then if `30..37` is `rcl`, the loop implements `<u32> << 8`. why is TBD, but it seems like a plausible high-level behavior.
elsewhere, this helps explain `50`:
<pre class="codebox">
f6 74 <span class=blue>; <op>; r0 -> r4</span>
e001 e100 e200 e300 <span class=blue>; r3:r2:r1:r0 <- 00_00_00_01</span>
9804 <span class=blue>; jcc $+4</span>
50 31 32 33 <span class=blue>; <op>; rcl r1; rcl r2; rcl r3</span>
44 <span class=blue>; dec r4</span>
99f9 <span class=blue>; jcc $-7</span>
c83bef c93cef ca3def cb3eef <span class=blue>; [0xef3b:0xef3e] <- r3:r2:r1:r0</span>
</pre>
if `50` were `add r0, r0`, this implements `1u32 << r4` - `add r0, r0` is
functionally the same as shifting `r0` left by 1 with highest bit carried
out. it seems unlikely to be `adc`, because in other places `50` is used it
seems that `cf` is indeterminate.
this region also reinforces that `99` is `jnc`. if `99` were `jc` the loop would be taken at most once, but as `jnc` it is taken until `r4 == 0`.
this in turn helps explain `08..0f`:
<pre class="codebox">
e408 <span class=blue>; r4 <- 8</span>
bit:
69 3d 911d <span class=blue>; ccf; rcr r5; jc clear</span>
e8eab0 56 c8eab0 <span class=blue>; add [0xb0ea], r6 ; (taking creative liberties with the isa)</span>
e8ebb0 09 c8ebb0 <span class=blue>; op [0xb0eb], r1</span>
e8ecb0 0a c8ecb0 <span class=blue>; op [0xb0ec], r2</span>
e8edb0 0b c8edb0 <span class=blue>; op [0xb0ed], r3</span>
clear:
69 36 31 32 33 44 <span class=blue>; ccf; rcl r6:r1:r2:r3; dec r4</span>
90d8 <span class=blue>; jnz bit</span>
b9 <span class=blue>; ret</span>
</pre>
so... this would be a 32b by 8b multiply.. but only if `op` is `adc`. for each set bit in `r5`, add `r6:r1:r2:r3` into `0xb0ea`. shift `r6:r1:r2:r3` left 1 regardless of bit being set in `r5`. repeat 8 times for each bit in `r5`.
... that said, the calling convention for this is different from every other function, and is moderately unhinged: why is `r4` unused? why is `r0` unused? why is `r6` *used*??? either way. `08..0f` is `adc`.
but this function is weird enough to try figuring that out sooner than later. looking for the memory address referenced here, `0xb0ea` there's this region i'd looked at very early on that seems relevant:
<pre class="codebox">
c870ef c971ef
e878b4 e979b4 ec70ef 59 4c 74 11 e971ef 49 71 14 c977b4
c876b4 28 c8beb9 e0ea c8c0b9 e00d c8bfb9 e201 e405 bcc632 e105 e875b4
79 9004
28 c8d2ee
b98485 86 e600 <span class=blue>; something; push r6; r6 <- 0</span>
ceeab0 <span class=blue>; [0xb0ea] <- 0</span>
ceebb0 <span class=blue>; [0xb0eb] <- 0</span>
ceecb0 <span class=blue>; [0xb0ec] <- 0</span>
ceedb0 <span class=blue>; [0xb0ed] <- 0</span>
76 ede6b0 <span class=blue>; r0 -> r6 ; r5 <- [0xb0e6]</span>
bf 2f <span class=blue>; op; op</span>
ed ed e7b0bf 2f <span class=blue>; ??</span>
ed ed e8b0bf 2f <span class=blue>; ??</span>
ed ed e9b0bf 2f <span class=blue>; ??</span>
ed <span class=blue>; ??</span>
e8eab0 <span class=blue>; [0xb0ea:0xbeed] <- r3:r2:r1:r0</span>
e9ebb0
eaecb0
ebedb0
8e 8d 8c b9
</pre>
but the whole thing in the middle is nonsense. taking a much closer look, though, this was before i'd learned... many things about the instruction set. first, on line 6 the first instruction is not `b98485`! it is just `b9` - `ret`. so this region is actually the end of one function and start of the next. `84 85 86` are pushes in the prologue of the real function of interest.
additionally, `bf` is not a standalone instruction, it takes two bytes as an immediate to `call`. and `ed` is not an instruction on its own, it is `r5 <- [imm16]`. so lets delineate that correctly...
<pre class="codebox">
84 85 86 e600 <span class=blue>; push r4; push r5; push r6; r6 <- 0</span>
ceeab0 <span class=blue>; [0xb0ea] <- 0</span>
ceebb0 <span class=blue>; [0xb0eb] <- 0</span>
ceecb0 <span class=blue>; [0xb0ec] <- 0</span>
ceedb0 <span class=blue>; [0xb0ed] <- 0</span>
76 <span class=blue>; r0 -> r6</span>
ede6b0 bf2fed <span class=blue>; r5 <- [0xb0e6]; call 32x8b multiply?</span>
ede7b0 bf2fed <span class=blue>; r5 <- [0xb0e7]; call 32x8b multiply?</span>
ede8b0 bf2fed <span class=blue>; r5 <- [0xb0e8]; call 32x8b multiply?</span>
ede9b0 bf2fed <span class=blue>; r5 <- [0xb0e9]; call 32x8b multiply?</span>
e8eab0 <span class=blue>; [0xb0ea:0xbeed] <- r3:r2:r1:r0</span>
e9ebb0
eaecb0
ebedb0
8e 8d 8c b9
</pre>
and so here we are: this function implements a 32b x 32 multiply of the integers in `b0ea:b0ed` and `b0e6:b0e9`, storing the result in `b0ea:b0ed`. notable mention to `r0`, which happens to be the low byte of the last round of multiplication, so the `e8eab0: [0xb0ea] <- r0` is in fact correctly storing the low byte of this whole thing to the output region. notable mention, too, to `76: r0 -> r6`, because by leaving `r0` free for clobber the inner multiply routine does not need to move the `r0` argument elsewhere to free `r0` for use in `add/adc`. and loads from memory are no more expensive (in terms of code size) when loading to an alternate register, so it's simple enough to load directly to `r6` for the to-multiply byte of reach step.
## what's left?
OK. this is great progress so far. many instructions make sense, composition of those instructions seems reasonable. the only remaining encoding regions that are unknown are:
* `00..07`
* `48..4f`
* `58..5f`
* `60..6f`, except `69` (`ccf`)
* `78..7f`: might be `cmp`, might be `sub`. need to find evidence one way or the other!
* `a0..af`, seems not-present
* `b0..b7`, seems not-present, except `b4`
* `b8..bf`, except `b9`, `bc` (maybe jump?), `bf`
* `c0..c7`, which is remarkably rare
* `d0..df`, except `da`, `de`. seen but not understood: `db`, `dc`
* `f0..ff`, except `fa`, `fe`. seen but not understood: `f0`, `f2`, `f3`, `f4`, `f6`
and as a bonus, knowing the relationship of the last two functions i'd looked at, i know the base address of this rom (finally!!): the inner multiply routine starts at `0xedf2`, so the first byte of this image is at address `0xed2f (mapped) - 0x31c3 (file) == 0xbb5c`.
theory for `d2`, `d4`, `d6`, as well as `e2`, `e4`, `e6`: like their `d<high>` counterparts but with no immediate offset. that is, `d4` is `[r5:r4] <- r0`? heres a hex region to help inform this theory:
<pre class="codebox">
900d <span class=blue>; jcc later</span>
ea15ee eb16ee <span class=blue>; r4<-[0xee15]; r5<-[0xee16]</span>
fa01 dc01 <span class=blue>; r0<-[r3:r2+1]; [r5:r4+1]<-r0</span>
f2 d4 <span class=blue>; ?? ??</span>
b9 <span class=blue>; ret</span>
later:
ea15ee eb16ee <span class=blue>; r4<-[0xee15]; r5<-[0xee16]</span>
fa03 dc01 <span class=blue>; r0<-[r3:r2+3]; [r5:r4+1]<-r0</span>
fa02 d4 <span class=blue>; r0<-[r3:r2+2]; ??</span>
b9 <span class=blue>; ret</span>
</pre>
so, this seems like a conditional branch to move 16b from one part of a struct or another, to a single destination location. `d4` probably stores the lower byte being copied, evidenced by `fa02` to load it in the later branch. then `f2` is probably a load of the lower byte, to store it in the earlier case. there is no `dc00` or `fa00` or similar.... probably because for offset-by-zero cases, there are these shorter instructions for the same outcome. this happens to make for a neat pattern as well for opcodes like `0b11x1_iNNN`:
* `x` picks between "load" and "store" - this is the difference between `0xde` and `0xfe`
* `i` picks between offset `0` and offset `imm8` - this is the difference between `0xd4` and `0xdc`
* `NNN` picks which register pair to indirect through - `d2` uses `r3:r2`, `d4` uses `r5:r4`, `d6` uses `r7:r6`
and so this opens more questions than it answers! what happens if `NNN` an odd register? can this machine indirect through a register pair like `r4:r3`? why is the pair `r1:r0` never used? what about `r7:r6`? in fact `rEven:rOdd` seems never used, are those instructions entirely different?
... [week long pause here. Destiny 2: The Final Shape launched, and everything else ground to a halt] ...
## whittling down the last few opcodes...
OK. short list of remaining instructions. motivation and optimism are starting to fade.. but i want to figure out as many as possible.
### `48..4f`
seems like `48..4f` has some kind of a lead here:
<pre class="codebox">
e878b4 e979b4 ec70ef 59 4c 74 11 e971ef 49 71 14 c977b4
</pre>
which at first only looks interesting for its use of `4c`, not used much at all in this program. structuring that slightly differently makes some of the relationships a little clearer:
<pre class="codebox">
e878b4 e979b4 <span class=blue>; r0:r1 <- [0xb478:0xb479]</span>
ec70ef 59 4c 74 11 <span class=blue>; r4 <- [0xef70]; ???; ???; r0 -> r4; r1 -> r0</span>
e971ef 49 71 14 <span class=blue>; r1 <- [0xef71]; ???; r0 -> r1; r4 -> r0</span>
c977b4 c876b4 <span class=blue>; [0xb477:0xb478] <- r0:r1</span>
</pre>
the `4c` and `49` operations clearly modify r0. `59` might modify a register or so something else; if it modifies a register, it's probably `r1` which *is* used later. it seems like r1 is the high byte of a 16b integer, so an operation directly on that byte seems a little unlikely. `59` might be a mirror of `69` (clear carry flag), setting the carry flag instead? as for `49` and `4c`, best guesses are heavily informed by what i already know: this isn't `adc`, `or`, `and`, `add`, rotate left or right, ... but given the seeming 16b value being operated on, maybe these are `sbc`. that would mean with `59` being `set cf`, this is computing something like `*0xb479 -= *0xef70 + 1`.
this isn't a lot to go on for `sbc`, but double-checking a different function, it's at least coherent:
<pre class="codebox">
e8e8ed 9841
e103 fe01 79 9807
e102 fe01 79
9022
ea03ee eb04ee
e058 e11b
59 4a 72 <span class=blue>; ??? ; sbc r0, r2; r0 -> r2</span>
11 4b 73 <span class=blue>; r1 -> r0 ; sbc r0, r3; r0 -> r3</span>
e8deee 7a e8dfee 4b 9108 <span class=blue>; r0 <- [0xeede]; r0 -= r2; r0 <- [0xeedf]; sbc r0, r3; jc $+8</span>
bf27c5 e400 bff4dd
e102 fe01 79 9803
bc05c7
28 c8e8ed bc05c7
e101 fe01
79 9008
</pre>
i've marked up the most relevant lines: `59` is a leader again, and `r1` is used here, but if `59` modifies `r1` then, again, it's something that makes sense to do first and only to the upper byte of a 16bit number. `r2:r3` seem subtracted into, and with the `load; sub; load; sbc; jc` sequence this implements something like `if (r2:r3 - 0x1b58 >= [0xeede:0xeedf])`
### `59` ... or a wild guess towards `58..5f`?
going to also assume that `59` is `set carry flag`, since no other `58..5f` instructions seem to be present here.. this mirrors `69` as well.
### `60..67` ... where possible
`61` shows up before conditional branches, usually after loading from `0xf303`..? is that maybe a gpio address?
`60` and `62` are also present .... here:
<pre class="codebox">
fe07 72 fe08 73 fa04 c875ed fa03 c874ed e850f1 62 9003 bceacc e852f1 60 9003 bceacc e400 bf67c5 bceacc
</pre>
... is `60..67` something like "extract bit N of r0"? r0 is typically loaded before it's executed, and conditional branches are always present after. probably not consuming an `rN` and probably modifies r0 for the condition. difficult to imagine another purpose for a 3-bit field at that point.
### `ba`
another region i looked at very early on has a "ba" in it at least. it's a remarkably rare opcode, it seems:
<pre class="codebox">
8f 8e 88
c8f0b0 88 c8efb0 88 c8eeb0 88 c8edb0 88
c8ecb0 88 c8ebb0 88 c8eab0 88 c8e9b0 88
c8e8b0 88 c8e7b0 88 c8e6b0
8d 8c 8b 8a 89 88
bae8f3 b4 c85ced e8f2b4 c85bed
b9
</pre>
... is actually split up wrong, rather than `bae8f3 b4`, this is `ba e8f3b4`! matching with the `e8f2b4` to load one byte lower a few instructions later. fixed up that looks like this:
<pre class="codebox">
[elided restore of 0xb0e6:0xb0f0]
8d 8c 8b 8a 89 88
ba
e8f3b4 c85ced e8f2b4 c85bed
b9
</pre>
so then this routine is restoring the region of bytes used for 32b x 32b multiply, all registers, then almost-but-not-ret. given the full-restore including scratch memory, this seems like the end of an interrupt routine. so `ba` is `iret`? consistent with what might be an ISR return at least. there happens to be another small routine directly after.
### `00..07`
turning all the way back, this pattern gives an idea for `00..07`:
<pre class="codebox">
e850ef e951ef <span class=blue>; r1:r0 <- [0xef51]:[0xef50]</span>
e404 <span class=blue>; r4 <- 0x04</span>
54 <span class=blue>; r0 += r4</span>
9101 <span class=blue>; jnc $+1</span>
01 <span class=blue>; ???</span>
80 <span class=blue>; push r0</span>
f0 <span class=blue>; r0 <- [r1:r0]</span>
74 <span class=blue>; r4 <- r0</span>
88 <span class=blue>; pop r0</span>
f801 <span class=blue>; r0 <- [r1:r0 + 1]</span>
75 <span class=blue>; r5 <- r0</span>
</pre>
or this,
<pre class="codebox">
15 71 14 <span class=blue>; r1:r0 <- r5:r4</span>
e304 <span class=blue>; r3 <- 0x04</span>
53 <span class=blue>; r0 += r3</span>
9101 <span class=blue>; jnc $+1</span>
01 <span class=blue>; ???</span>
76 11 77 <span class=blue>; r7:r6 <- r1:r0</span>
</pre>
so here, `01` is only conditionally executed if adding produced a carry out. `r0` and `r1` seem to be operated on together, so the two might be logically a 16-bit integer. so `01` might be `inc rN`? in that case the carry out is being conditionally added into the higher byte. nothing else has seemed obviously like an `inc` yet. this seems a little odd on the whole in the first snippet, since the result of addition doesn't seem to be preserved.. `r0` is clobbered in the last load. could that whole region have been `f805 74 f806 75`? might be missing some additional behavior.
other uses of `00..07` don't obviously disagree with this though. for example, `00`:
<pre class="codebox">
e8eeed 00 c8eeed <span class=blue>; [0xedee] += 1</span>
...
fa03 00 da03 <span class=blue>; [r3:r2 + 3] += 1</span>
...
fe04 00 de04 <span class=blue>; [r7:r6 + 4] += 1</span>
...
e8c0ee 00 c8c0ee <span class=blue>; [0xeec0] += 1</span>
</pre>
so, maybe `00` actually is inc.
## mostly done, what's left in the encoding space?
this all is some progress, not much unknown left. from the earlier list:
* `00..07`
- `inc rN`
* `48..4f`
- `sbc r0, rN`
* `58..5f`, except `59` (`scf`) - might be flags manipulation? not present, either way
* `60..68`
- `bit r0, N`
* `68..6f`, except `69` (`ccf`) - might be flags manipulation? not present, either way
* `78..7f`: might be `cmp`, might be `sub`. need to find evidence one way or the other!
* `a0..af`, seems not-present
- `a0` is present.. once.
* `b0..b7`, seems not-present
* `b8..bf`, except `b9`, `ba`, `bc` (maybe jump?), `bf`
* `c0..c7`, which is remarkably rare. `c0`, `c4`, `c6`?
* `d0..df`, ~except `da`, `de`. seen but not understood: `db`, `dc`~
`d0..d7`, evens, are `[rN+1:rN] <- r0`
`d8..df`, evens, are `[rN+1:rN + imm] <- r0`
`db` is not actually present, was a misreading of the program
* `f0..ff`, ~except `fa`, `fe`. seen but not understood: `f0`, `f2`, `f3`, `f4`, `f6`~
`f0..f7`, evens, are `r0 <- [rN+1:rN]`
`f8..ff`, evens, are `r0 <- [rN+1:rN + imm]`
`f3` is not actually present, was a misreading of the program
so.. last questions:
* is `78..7f` actually `sub` or `cmp`?
* what is `a0`?
* what are `c0..c7`?
## `78..7f` ... `sub` or `cmp`?
the question really is, "does this instruction modify `r0`?" - it's possible that the instruction computes `sub`, stores the result, and the program never actually uses that result, either because substraction isn't often used or because of a compiler deficiency, something else, whatever. so the best guess here is, "is `r0` ever preserved after a `78..7f`?" or asked differently, "does `r0` get preserved/restored around a `78..7f`?"
the only hint that `78..7f` might clobber `r0` comes from regions like this:
<pre class="codebox">
e103 fe01 79 9807 <span class=blue>; r1 <- 3; r0 <- [r7:r6]; sub r0, r1; jz ...</span>
e102 fe01 79 9022 <span class=blue>; r1 <- 2; r0 <- [r7:r6]; sub r0, r1; jnz ...</span>
ea03ee eb04ee e058 e11b ...
</pre>
if `79` were `cmp` and did not modify `r0`, there wouldn't be a need to reload it in `fe01`. ... but this may be poor code, and the reload may actually be redundant. since this seems to implement `if ([r7:r6] == 3 || [r7:r6] == 2) { .. load registers }`, and there are no other signs that `78..7f` clobbers `r0`, this might actually be `cmp`.
## what is `a0`?
this seems to be the only place `a0` is present:
<pre class="codebox">
14 71
bcabe6
bfd00e <span class=blue>; call 0xed0 (???)</span>
c8bcee <span class=blue>; [0xeebc] <- r0</span>
a0 <span class=blue>; ???</span>
72 11 73 <span class=blue>; r3:r2 <- r1:r0</span>
fa0b c8bfee <span class=blue>; [0xeebf] <- [r3:r2 + 0x0b]</span>
fa0a c8beee <span class=blue>; [0xeebe] <- [r3:r2 + 0x0a]</span>
e046 40 <span class=blue>; r0 <- 0x46; dec r0 (???)</span>
da0a <span class=blue>; [r3:r2 + 0x0a] <- r0</span>
e0e6 9901 <span class=blue>; r0 <- 0xe6; jc $+01</span>
40 <span class=blue>; dec r0 (???)</span>
da0b <span class=blue>; [r3:r2 + 0x0b] <- r0</span>
b9
</pre>
whatever it is, it presumably operates on at least `r0`, writes to `r0` and `r1`. the routine at `0xed0` (outside the image?) may say more about what the registers are at its return, but from this alone it's hard to guess. it is interesting and remarkable that only `r0` is saved to `[0xeebc]`, not `r1`!
## what are `c0..c7`?
seems like the most informative region to hint at these instructions:
<pre class="codebox">
e81ff8 61 903c
ea29ef eb2aef <span class=blue>; r5:r4 <- [0xef2a]:[0xef29]</span>
fa08 71 fa07 <span class=blue>; r1:r0 <- [r5:r4 + 8]:[r5:r4 + 7]</span>
c0 <span class=blue>; ??</span>
74 11 75 <span class=blue>; r5:r4 <- r1:r0</span>
12 <span class=blue>; r0 <- r2</span>
e92aef <span class=blue>; r1 <- [0xef2a]</span>
e307 53 9101 <span class=blue>; r3 <- 0x07; add r0, r3; jnc $+1</span>
01 <span class=blue>; inc r1</span>
80 f0 72 88 <span class=blue>; r2 <- [r1:r0]</span>
f801 73 <span class=blue>; r3 <- [r1:r0 + 1]</span>
f2 <span class=blue>; r0 <- [r3:r2]</span>
e1ff 51 <span class=blue>; r0 += 0xff</span>
77 <span class=blue>; r7 <- r0</span>
e600 <span class=blue>; r6 <- 0</span>
9806 <span class=blue>;</span>
f4 c88cf8 <span class=blue>; [0xf88c] <- [r5:r4]</span>
c4 <span class=blue>; ??</span>
06 <span class=blue>; inc r6</span>
16 7f <span class=blue>; r0 <- r6; cmp r0, r7</span>
91f6 <span class=blue>; jb $-0x0a</span>
</pre>
the ending loop makes some sense: load from a 16-bit pointer, store to maybe-IO-register(?), increment `r6`, repeat until `r6 == r7`. in other contexts where `c0` is used, `r1:r0` is recently populated with a 16-bit integer too. so it seems likely that `c[0-7]` operates on at least `rN`, maybe `rN+1` if it's more like the `d_` or `f_` two-registers-as-an-address instructions.
if `c4` were a load or store it would probably operate with respect to `r0` and `r4`, but `r0` is immediately clobbered, so it's probably not a load or otherwise leaving a result in `r0`. if it were a store this might overwrite a buffer.. somewhere.. with `0, 1, 2, 3, 4, .. <r7>`.
looking at the `c0` earlier in this block `r1:r0` is loaded immediately before, and then read (copied to `r5:r4`) immediately after. `r5:r4` is used for the `f4` load, so those registers form something like a pointer.
compare with the other use of `c4` in this program here:
</pre>
e4e3 e5ed <span class=blue>; r4 <- 0xe3; r5 <- 0xed</span>
e28f e301 <span class=blue>; r2 <- 0x8f; r3 <- 0x01</span>
28 <span class=blue>; xor r0, r0</span>
loop:
42 9903 <span class=blue>; dec r2; jnc body</span>
43 9105 <span class=blue>; dec r3; jc exit</span>
body:
d4 <span class=blue>; [r5:r4] <- r0</span>
c4 <span class=blue>; ???</span>
bc69bb <span class=blue>; jmp loop</span>
exit:
bc26be <span class=blue>; jmp ... somewhere ...</span>
</pre>
`r5:r4` is written through, but the combined `dec r2; jnc body; dec r3; jc exit; ... jmp loop` forms a a loop that repeats until `r3:r2` is decremented past zero. the loop body is simply `[r5:r4] <- r0`, `r0` set to zero, `c4` probably operates on `r5:r4`, and if it modifies `r0` then `r0` is left in that modified state for the next store through `[r5:r4]`.
looking at other 8-bit processors for inspiration regarding `c[0246]`, it seems plausible that it is in fact an increment for a register pair. in that case, the loop forms a memset, clearing `0x1c0` bytes of memory. this is also almost at the start of the image - not knowing where execution begins, it still seems likely enough that this is related to initialization.
there might not be a corresponding 16-bit decrement instruction? or if there is, like the 8080, it might not set flags, and so would not be useful to decrement `r3:r2` in this loop.
looking back at the other loop earlier:
<pre class="codebox">
e600 <span class=blue>; r6 <- 0</span>
9806 <span class=blue>;</span>
f4 c88cf8 <span class=blue>; [0xf88c] <- [r5:r4]</span>
c4 <span class=blue>; inc r5:r4</span>
06 <span class=blue>; inc r6</span>
16 7f <span class=blue>; r0 <- r6; cmp r0, r7</span>
91f6 <span class=blue>; jc $-0x0a</span>
</pre>
then taking `c4` to be `inc r5:r4` makes this a loop writing the bytes from a buffer `r7` bytes long at `r5:r4` into the address `f88c`. why not decrement `r7` instead of the inc/mov/compare??
## but wait! what happened with `jcc`?
in writing this up i flip-flopped on the meaning of `91` and `99` jumps without entirely realizing it. two different regions of code suggest different semantics!
first, the inner multiply loop from earlier:
<pre class="codebox">
e408 <span class=blue>; r4 <- 8</span>
back:
69 3d <span class=blue>; ccf; rcr r5</span>
911d <span class=blue>; jcc.lo.1 forward</span>
back:
e8eab0 56 c8eab0 <span class=blue>; add [0xb0ea], r6</span>
e8ebb0 09 c8ebb0 <span class=blue>; add [0xb0eb], r1</span>
e8ecb0 0a c8ecb0 <span class=blue>; add [0xb0eb], r2</span>
e8edb0 0b c8edb0 <span class=blue>; add [0xb0eb], r3</span>
69 <span class=blue>; ccf</span>
forward:
36 31 32 33 44 <span class=blue>; ccf; rcl r6:r1:r2:r3; dec r4</span>
90d8 <span class=blue>; jnz back</span>
b9 <span class=blue>; ret</span>
</pre>
where `91` seems like `jnc` - "jump past adding in the multiplier if the next bit in the multiplicand was 0". but a different loop suggests the opposite reading:
<pre class="codebox">
e4e3 e5ed <span class=blue>; r4 <- 0xe3; r5 <- 0xed</span>
e28f e301 <span class=blue>; r2 <- 0x8f; r3 <- 0x01</span>
28 <span class=blue>; xor r0, r0</span>
loop:
42 9903 <span class=blue>; dec r2; jnc body</span>
43 9105 <span class=blue>; dec r3; jc exit</span>
body:
d4 <span class=blue>; [r5:r4] <- r0</span>
c4 <span class=blue>; ???</span>
bc69bb <span class=blue>; jmp loop</span>
exit:
bc26be <span class=blue>; jmp ... somewhere ...</span>
</pre>
where instead it's `99` that looks like a `jnc` - "if decrementing r2 did not borrow, do not decrement r3 and continue another loop iteration". and `91` is what looks like a `jc`- "if decrementing r3 borrowed, skip past the loop body".
either "jc" and "jnc" are conditional on more than it first seems, or perhaps more likely, `dec` produces a carry bit any time the result is not zero. as an example:
| r0 | r0-after-dec | carry |
|-------|--------------|-------|
| 0x00 | ff + 0 = ff | 0 |
| 0x01 | ff + 1 = 00 | 1 |
| 0x02 | ff + 2 = 01 | 1 |
| 0xff | ff + ff = fe | 1 |
that would bring this all back together: `99` is `jc`, `91` is `jnc`. it's rare that there's a `dec; jcc` (one other instance in this program at `0x16db`), so it's hard to cross-check this interpretation.
## last thoughts
in looking at this i was very surprised by how informative loops - especially
short loops - are for finding bounds of what a program may or likely does not
do. this isn't very surprising in retrospect; short programs don't have
opportunities to do very much, and doing the same not-very-much in a loop has
even fewer opportunities to do something useful. _and_ loops are usually
conditioned on a relatively simple predicate: `while x < 10 do { ... }`, or
`do { ... } while x > 10`, or `while x != 0 { x = loop_body() }`. a _lot_ of
behavior fell out of finding short loops and making sense of the instructions
used to drive them.
this definitely applies when you *do* know the instruction set but are trying
to make sense of a larger program - it's just good advice when reverse
engineering a program. it's neat to see the idea carry through when you're
figuring out the instruction set itself.
additionally: this is doable! what's totally unknown at this point is mostly
instructions that don't appear in this program (at which point it's hard to
guess about behavior...)
## conclusion
that seems to be the ISA, at least as used in this program. this architecture seems like an outsider art re-envisioning of the 8080, with fewer register to register movs, and more indexed memory accesses. it seems interesting that this architecture has loads like `[r7:r6]` and `[r7:r6 + N]` but not `[r7:r6 + rN]`. having non-offset load/store through a register pair seems a bit out of place in its own right: it's a lot of encoding space to reserve for a relatively rare operation. maybe it's more common in some reference program, and this firmware is the odd one?
`a0..af` are almost nonexistent here, and might be other 8080-style instructions. `b0..b8` are not represented in this program, and would be prime encoding space for conditional returns. it wouldn't be terribly shocking if a compiler didn't know to use conditional returns and instead conditionally branched over returns.
the moment _i_, at least, have been waiting for, after describing as much of the ISA as possible, is to compare notes with others who have looked at this CPU or programs for it:
* whitequark's binja plugin: [https://github.com/whitequark/binja-avnera](https://github.com/whitequark/binja-avnera)
* several years ago: [https://github.com/Prehistoricman/AV7300](https://github.com/Prehistoricman/AV7300)
... we almost entirely agree! it seems that Prehistoricman tested with a physical CPU, and has some notes for opcodes that are otherwise not present: [https://github.com/Prehistoricman/AV7300/blob/master/Instruction%20set%20notes.txt#L195-L198](https://github.com/Prehistoricman/AV7300/blob/master/Instruction%20set%20notes.txt#L195-L198)
whitequark records `58..5f` and `68..6f` as `set` and `clr` respectively, which i suspect are the same as i'd understood: set (or clear) bit in status register. this is also what Prehistoricman understood them to mean.
i'm pretty surprised how much can be reasonably guessed out from just a 12kb firmware! there are plenty of operational semantics missing in my descriptions above - for example, i know basically nothing about memory addressing: lots of the above leaned on assuming a flat 64kb address space is a decnt approximation. segmentation would be annoying to figure out! if the ISA were anything more complex it probably would have required more than just staring really hard at notes. an ARM-style encoding with more aggressive packing of bits certainly would have been harder to discover.
if you happen to want to disassemble programs for Avnera processors - it's not at all clear to me which models may have different or extended instruction sets - i've published a disassembler based on the above notes as [yaxpeax-avnera](link). from whitequark's note [here](https://github.com/whitequark/binja-avnera/tree/main?tab=readme-ov-file#devices) it does seem likely this instruction set is common across many models!
### summarized materials
there are a few more programs reportedly for this architecture here, from Prehistoricman:
[link 1, sha256]
[link 2, sha256]
the program i reference heavily in this post is here:
[link 3, sha256]
* [noes](./noes)
[mirror]
whitequark's excellent cheatsheet of the encoding space:
* https://github.com/whitequark/binja-avnera/tree/main?tab=readme-ov-file#cheatsheet
this last one i find interesting as history for what i guessed right, wrong,
and revisited how early on - my notes as i touched up and revisited `noes` with
increasingly-better understanding:
* [yax/avnera/disasm/](./disasm/)
|