This file is indexed.

/usr/share/tkgate/doc/menagerie.gm is in tkgate-doc 2.0~b10-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
//
//    Copyright (C) 1987-2000 by Jeffery P. Hansen
//
//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program; if not, write to the Free Software
//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//    Last edit by hansen on Fri Dec  1 14:34:44 2000
//

// Microcode memory bank declarations

microcode bank[31:0] iunit.m1;
microcode bank[63:32] iunit.m2;
map bank[7:0] iunit.map;

macrocode bank[7:0] memory.m1;

// Microcode field declarations

//
// Microcode branching.  mpcop specifies the basic operation.
//
field mpcop[1:0]={
	 next=0,	// Increment mpc
	 reinit=1,	// Restart CPU
	 jmap=2,	// Jump from map value
	 jump=3		// Jump from condition
};

//
// Specifies the condition on which to jump if mpcop is "jump".
//
field mpccond[12:10]={
	jne=0,		// Jump if not equal
	jcarry=1,	// Jump on carry
	jeq=2,		// Jump if equal
	jlt=3,		// Jump if less than
	jgt=4,		// Jump if greater than
	jle=5,		// Jump if less than or equal
	jge=6,		// Jump if greater than or equal
	jmp=7		// Jump always
};

//
// Address to jump to if mpcop is "jump" and condition specified
// by mpccond is true.  This field can not be used at the same
// time as the idata field.  
//
field mpcaddr[9:2];

//
// Specifies 8 bits of data to be used by the EUNIT.  This field
// can not be used on jump microinstructions.
//
field idata[9:2];

//
// Specifies the A and B operands of the ALU.
//
//	qreg		Use Q register
//	din		Use data in
//	idata		Use idata field from microinstruction
//	reg		Use register file
//
field aop[15:14]={qreg=0, din=1, idata=2, reg=3};
field bop[17:16]={qreg=0, din=1, idata=2, reg=3};

field ~ldir[13];	// Load instruction register
field cin[18];		// Carry in
field ~clq[19];		// Clear Q register
field ~ldq[20];		// 16-bit load of Q register
field ~lddata[21];	// Load EUNIT data from external bus
field ~ldopr[22];	// Load operand register
field ~wa[23];		// Write register file on SA
field sa[27:24];	// Register address A
field sb[31:28];	// Register address B

//
// These fields specify the ALU function.
//
field ALU_FUNC[36:32];
field ALU_SHOP[33:32]={arshift=0, lshift=1, rshift=2, roll=3};
field ALU_BCOMP[32];
field ALU_AZERO[33];
field ALU_OP[36:34]={shift=0,xor=1,and=2,or=3,mul=4,add=5,mod=6,div=7};

field ~incpc[37];	// Increment PC
field ~ldmar[38];	// Load MAR
field ~ldmdr[39];	// Load MDR
field ~ldpc[40];	// Load PC
field ~rd[41];		// Read main memory
field ~rdmdr[42];	// Read MDR onto external data bus 
field ~wrt[43];		// Write main memory
field spc[44];		// Address main memory from PC
field ~isa[45];		// Use sa address from macro instruction
field ~isb[46];		// Use sb address from macro instruction
field ~ifunc[47];	// Use function code from macro instruction
field ~icond[48];	// Use branch condition from macro instruction
field ~ldql[49];	// 8-bit load of lower half of Q register
field ~ldqh[50];	// 8-bit load of upper half of Q register
field ~dout[51];	// Output EUNIT data to external bus
field ~ldcc[52];	// Load condition code register
field ~ldhmdr[53];	// Load mdr from high byte of data bus
field ~rdpc[54];	// Read PC onto external bus
field ~incmar[55];	// Increment mar (can't use with incpc)

field extra[63:56];	// Extra bits

//////////////////////////////////////////////////////////////////////
//
// +-+-+-+-+-+-+-+-+
// |7|6|5|4|3|2|1|0|
// +-+-+-+-+-+-+-+-+
//
// Basic instruction types are encoded by the high two bits of the 
// first byte of the instruction.  For certain types (e.g., ALU
// types) some bits are masked when forming the map address.  Bits
// contributing to the map vector are marked with a *.
//
// Move Instruction
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 1 1 s|a a|b b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//  * * * * * * * *
//
//  s  = size (1 = byte, 0 = word)
//  aa = operand mode 1
//  bb = operand mode 2
//
// Single operand instruction (push, pop, call, etc.)
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 0|0| op  |b b|   | reg1  |0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//  * * * * * * * *
//
//
// Branch instruction (jmp, jne, etc.)
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 0|1|cond |b b|   | reg1  |0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//  * * *       * *
//
//
// ALU Instruction
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|  func   |b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//  * *           *
//
//  func = ALU function
//  a = operand mode
//
// Other instructions
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 0|   op    |b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//  * * * * * * * *
//
//

registers R0=0, R1=1, R2=2, R3=3, R4=4, R5=5, R6=6, R7=7, R8=8, R9=9, R10=10, R11=11, R12=12, R13=13, FP=14, SP=15;

operands basic {
    %1,%2 = { +0[0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
    %1,#2 = { +0[0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
};

operands runiop {
    %1     = { +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=0; };
    #1     = { +0[1:0] = 1; +1=0; +2=#1[7:0]; +3=#1[15:8]; };
    (%1)   = { +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=0; };
    #2(%1) = { +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
};

operands wuniop {
    %1     = { +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=0; };
    (%1)   = { +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=0; };
    #2(%1) = { +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
};

//
// Operands for move instructions
//
operands movoprs {
    %1,%2         = { +0[3:2] = 0; +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
    %1,#2         = { +0[3:2] = 0; +0[1:0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
    %1,(%2)       = { +0[3:2] = 0; +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=%2; };
    %1,#3(%2)     = { +0[3:2] = 0; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
    %1,(#2)       = { +0[3:2] = 0; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };


    (%1),%2       = { +0[3:2] = 2; +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
    (%1),#2       = { +0[3:2] = 2; +0[1:0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
    (%1),(%2)     = { +0[3:2] = 2; +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=%2; };
    (%1),#3(%2)   = { +0[3:2] = 2; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
    (%1),(#2)     = { +0[3:2] = 2; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };

    #1(%2),%3     = { +0[3:2] = 3; +0[1:0] = 0; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; };
    #1(%2),#3     = { +0[3:2] = 3; +0[1:0] = 1; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };
    #1(%2),(%3)   = { +0[3:2] = 3; +0[1:0] = 2; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; };
    #1(%2),#4(%3) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; +4=#4[7:0]; +5=#4[15:8]; };
    #1(%2),(#3) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };

    (#1),%2     = { +0[3:2] = 3; +0[1:0] = 0; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; };
    (#1),#2     = { +0[3:2] = 3; +0[1:0] = 1; +1[7:4]=0; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
    (#1),(%2)   = { +0[3:2] = 3; +0[1:0] = 2; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; };
    (#1),#3(%2) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };
    (#1),(#2)   = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=0; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 0|1 1 1 1 1|0|   |0 0 0 0|0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
//
op nop {
  map nop : 0x3e;
  +0=0x3e;
  operands {
    - = { +1=0; };
  };
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 0|0 0 0 0 0|0|   |0 0 0 0|0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
//
op halt {
  map halt : 0x0;
  +0=0;
  operands {
    - = { +1=0; };
  };
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 0|0 0 0 0 1|0|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
//
op cmp {
  map cmp_rr : 0x2;
  map cmp_ri : 0x3;
  +0[7:1]=0x1;
  operands basic;
};

// Generic branch operation
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 0|1|x x x|b b|   |0 0 0 0| reg1  |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
// Example:
//    br  #7, loop
//
// Jump always to loop.  7 is a code indicating the condition always.
//
op jp {
  map br_r : 0xa0;
  map br_i : 0xa1;
  map br_d : 0xa2;
  map br_x : 0xa3;
  +0[7:5] = 0x5;
  operands {
    #1,%2     = { +0[1:0] = 0; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; };
    #1,#2     = { +0[1:0] = 1; +0[4:2] = #1; +1=0; +2=#2[7:0]; +3=#2[15:8]; };
    #1,(%2)   = { +0[1:0] = 2; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; };
    #1,#3(%2) = { +0[1:0] = 3; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; +2=#3[7:0]; +3=#3[15:8]; };
  };
};

op jne {
  +0[7:5] = 0x5;
  +0[4:2] = 0x0;
  operands runiop;
};

op jcarry {
  +0[7:5] = 0x5;
  +0[4:2] = 0x1;
  operands runiop;
};

op jeq {
  +0[7:5] = 0x5;
  +0[4:2] = 0x2;
  operands runiop;
};

op jlt {
  +0[7:5] = 0x5;
  +0[4:2] = 0x3;
  operands runiop;
};

op jgt {
  +0[7:5] = 0x5;
  +0[4:2] = 0x4;
  operands runiop;
};

op jle {
  +0[7:5] = 0x5;
  +0[4:2] = 0x5;
  operands runiop;
};

op jge {
  +0[7:5] = 0x5;
  +0[4:2] = 0x6;
  operands runiop;
};

op jmp {
  +0[7:5] = 0x5;
  +0[4:2] = 0x7;
  operands runiop;
};


// Generic ALU operation
//
// Note this is not a real instruction but is here for illustrative
// purposes only.  Map entries must be made for each function code
// to use this instruction for real.
//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|x x x x x|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
// Example:
//    alu #0x14, R1, R2
//
// Does ALU operation 0x14 (addition) on R1 and R2, storing result in R1.
//
//op alu {
//  map alu_rr : 0x40;
//  map alu_ri : 0x41;
// +0[7:6] = 0x1;
//  operands {
//    #1,%2,%3 = { +0[0] = 0; +0[5:1]=#1; +1[7:4]=%2; +1[3:0]=%3; };
//    #1,%2,#3 = { +0[0] = 1; +0[5:1]=#1; +1[7:4]=0; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
//  };
//};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|1 0 1 0 0|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op add {
  map alu_rr : 0x68;
  map alu_ri : 0x69;
 +0[7:0]=0x68;
  operands basic;
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|1 0 1 0 1|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op sub {
  map alu_rr : 0x6a;
  map alu_ri : 0x6b;
 +0[7:0]=0x6a;
  operands basic;
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|1 0 0 0 0|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op mul {
  map xalu_rr : 0x60;
  map xalu_ri : 0x61;
 +0[7:0]=0x60;
  operands basic;
};

//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|1 1 1 0 0|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op div {
  map xalu_rr : 0x78;
  map xalu_ri : 0x79;
 +0[7:0]=0x78;
  operands basic;
};


//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|1 1 0 0 0|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op mod {
  map xalu_rr : 0x70;
  map xalu_ri : 0x71;
 +0[7:0]=0x70;
  operands basic;
};


//
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 1|0 1 0 0 0|b|   | reg1  |  reg2 |
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
op and {
  map alu_rr : 0x50;
  map alu_ri : 0x51;
 +0[7:0]=0x50;
  operands basic;
};


// Call subroutine
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 0|0|0 0 0|b b|   | reg1  |0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
// Example:
//
//   call	foo, #8
//
// This will perform the following actions:
//   sp = sp - 2
//   [sp] = pc
//   sp = sp - 2
//   [sp] = fp
//   fp = sp
//   sp = sp+8
//   pc = foo
//
op call {
  map call_ri : 0x80;
  map call_ii : 0x81;
  map call_di : 0x82;
  map call_xi : 0x83;
  +0[7:4] = 0x8;
  operands {
    #1,%2     = { +0[1:0] = 0; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; };
    #1,#2     = { +0[1:0] = 1; +1=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
    #1,(%2)   = { +0[1:0] = 2; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; };
    #1,#2(%3) = { +0[1:0] = 3; +1[7:4]=%3; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };

    #1        = { +0[1:0] = 1; +1=0; +2=0; +3=0; +4=#1[7:0]; +5=#1[15:8]; };
  };
};

// Return from subroutine
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |0 0|0 0 0 1 0|0|   |0 0 0 0|0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
// Example:
//
//    ret
//
// This will perform the following actions:
//    sp = fp
//    fp = [sp]
//    sp = sp + 2
//    pc = [sp]
//    sp = sp + 2
//    
//
op ret {
  map ret : 0x4;
  +0=4;
  operands {
    - = { +1=0; };
  };
};

// Push a word on the stack
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  
// |1 0|0|0 0 1|b b|   | reg1  |0 0 0 0|
// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
//
// Example:
//
//    pushw	R1
//
op pushw {
  map pushw_r : 0x84;
  map pushw_i : 0x85;
  map pushw_d : 0x86;
  map pushw_x : 0x87;
  +0[7:2]=0x21;
  operands runiop;
};


op movb {
  map movb_rr : 0xf0;
  map movb_ri : 0xf1;
  map movb_rd : 0xf2;
  map movb_rx : 0xf3;

  map movb_dr : 0xf8;
  map movb_di : 0xf9;
  map movb_dd : 0xfa;
  map movb_dx : 0xfb;

  map movb_xr : 0xfc;
  map movb_xi : 0xfd;
  map movb_xd : 0xfe;
  map movb_xx : 0xff;

  +0[7:4]=0xf;
  operands movoprs;
};

op movw {
  map movw_rr : 0xe0;
  map movw_ri : 0xe1;
  map movw_rd : 0xe2;
  map movw_rx : 0xe3;

  map movw_dr : 0xe8;
  map movw_di : 0xe9;
  map movw_dd : 0xea;
  map movw_dx : 0xeb;

  map movw_xr : 0xec;
  map movw_xi : 0xed;
  map movw_xd : 0xee;
  map movw_xx : 0xef;

  +0[7:4]=0xe;
  operands movoprs;
};

/////////////////////////////////////////////////////////////////////////////
//
// The microcode for the Menagerie CPU begins here.
//
// The CPU begins executing microinstuctions at address 0.  The instructions
// in the start block are executed only once.  The next block consists of
// the instuction fetch sequnce.  The multiple labels account for partial
// fetches that are done by some of the macrocode routines.
//
// For macro instructions which have no operands or have only only one operand,
// there is usually a plain label for that instruction.  For example the
// microinstruction labeled 'ret' implements the 'ret' macroinstruction.  This
// mapping is defined by the 'map ret : 0x4;' line in the operand declaration
// for the ret macroinstruction.
//
// For macro instructions with multiple addressing modes, labels are generally
// of the form 'op_??' where each character after the '_' denotes an addressing
// mode for an operand.  By convension, the characters:
//
//     r	register direct
//     i	immediate
//     d	register indirect
//     x	indexed
//
// are used.
//
begin microcode @ 0
start:	clq;								// Q <- 0
	idata=0x1 ALU_AZERO ALU_OP=add bop=idata ldqh;			// Q.H <- 1
	ALU_AZERO ALU_OP=add bop=qreg dout ldpc;			// PC <- Q
	mpcop=jump mpccond=jmp mpcaddr=fetch;				// jump to 'fetch'
	mpcop=next;

fetch: 	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
fetch1: incpc spc rd ldmdr rdmdr ldir;					// mdr <- [PC]; PC++; ir <- mdr;
fetch2:	mpcop=jmap rdmdr ldopr;						// opr <- mdr; jump to opcode
	mpcop=next;

halt:	mpcop=jump mpccond=jmp mpcaddr=halt extra=0x1;
	mpcop=jump mpccond=jmp mpcaddr=halt extra=0x1;

//
// Standard ALU operations (add, sub, and, or, etc.)
//
alu_rr:	mpcop=jump mpccond=jmp mpcaddr=fetch2 ifunc
		isa isb wa aop=reg bop=reg ldcc incpc spc rd ldmdr;	// Ra = Ra (op) Rb; CC; jump to fetch
	incpc spc rd ldmdr rdmdr ldir;

alu_ri:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch ifunc
		aop=reg bop=qreg wa isa ldcc;				// Ra = Ra (op) Q;  CC; jump to fetch
	mpcop=next;

//
// 2-cycle ALU operations (mul, div, mod).  These are the same as the alu_??
// ops except the ALU inputs and function code are held for 2 clock cycles
// due to the longer delay in computing these functions.
//
xalu_rr: mpcop=next ifunc isa isb aop=reg bop=reg;			// Ra (op) Rb;
	mpcop=jump mpccond=jmp mpcaddr=fetch2 ifunc
		isa isb wa aop=reg bop=reg ldcc incpc spc rd ldmdr;	// Ra = Ra (op) Rb; CC; jump to fetch
	incpc spc rd ldmdr rdmdr ldir;

xalu_ri: incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	mpcop=next ifunc isa isb aop=reg bop=qreg;			// Ra (op) Q;
	mpcop=jump mpccond=jmp mpcaddr=fetch ifunc
		aop=reg bop=qreg wa isa ldcc;				// Ra = Ra (op) Q;  CC; jump to fetch
	mpcop=next;

cmp_rr:	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_BCOMP extra=0x22	
		isa isb aop=reg bop=reg ldcc;				// Ra - Rb; CC; jump to fetch
	mpcop=next;

cmp_ri:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_BCOMP
		aop=reg bop=qreg isa ldcc;				// Ra - Q; CC; jump to fetch
	mpcop=next;

br_i:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;

btest:	mpcop=jump mpcaddr=bdojmp icond;				// jump to bdojmp if cond
	mpcop=next;
	mpcop=jump mpccond=jmp mpcaddr=fetch;				// jump to fetch
	mpcop=next;
bdojmp:	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO ALU_OP=add
		bop=qreg dout ldpc;					// PC <- Q, jump to fetch
	mpcop=next;


br_r:	mpcop=jump mpccond=jmp mpcaddr=btest extra=0x10
		isa aop=reg sb=0 bop=reg ALU_OP=add ldq;		// Q <- Ra; jump to btest
	mpcop=next;

br_d:	mpcop=jump mpccond=jmp mpcaddr=btest;
	mpcop=next;

br_x:	mpcop=jump mpccond=jmp mpcaddr=btest;
	mpcop=next;

call_ii:
	// Push the PC
	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
		dout ldmar wa extra=0x11;				// SP-2 -> mar; SP = SP - 2;
	rdpc lddata aop=din bop=idata idata=4 ALU_OP=add ldq;		// Q = PC+4
	ALU_AZERO ALU_OP=add bop=qreg dout ldmdr;			// Q.L -> mdr
	wrt;								// [mar] <- mdr;
	incmar ALU_AZERO ALU_OP=add bop=qreg dout ldhmdr;		// Q.H -> mdr; mar++; 
	mpcop=next;
	wrt;								// [mar] <- mdr;
	mpcop=next;

	// Push the FP
	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
			dout ldmar wa;					// SP-2 -> mar; SP = SP - 2;
	ALU_AZERO bop=reg sb=0xe ALU_OP=add dout ldmdr;			// FP.L -> mdr
	wrt;								// [mar] <- mdr;
	incmar ALU_AZERO  bop=reg sb=0xe ALU_OP=add dout ldhmdr; 	// SP.H -> mdr; mar++; 
	mpcop=next;
	wrt;								// [mar] <- mdr;

	aop=reg sa=0xe bop=reg sb=0xf
		ALU_AZERO ALU_OP=add wa;				// FP <- SP

	// Dec SP
	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	aop=reg sa=0xf bop=qreg ALU_OP=add wa;				// SP = SP + Q

	// PC = branch address
	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO bop=qreg
		ALU_OP=add dout ldpc;					// PC <- Q
	mpcop=next;

call_ri: mpcop=jump mpccond=jmp mpcaddr=fetch;
	mpcop=next;

call_di: mpcop=jump mpccond=jmp mpcaddr=fetch;
	mpcop=next;

call_xi: mpcop=jump mpccond=jmp mpcaddr=fetch;
	mpcop=next;

ret:	ALU_AZERO bop=reg sb=0xe ALU_OP=add sa=0xf wa dout ldmar extra=0x12;	// SP <- FP; mar <- FP;
	aop=reg sa=0xf bop=idata idata=4 ALU_OP=add wa rd incmar ldmdr;	// SP <- SP+4; mdr <- [mar++]
	ALU_AZERO bop=din lddata ALU_OP=add ldql rd rdmdr incmar ldmdr;	// Q.L <- mdr; mdr <- [mar++]
	ALU_AZERO bop=din lddata ALU_OP=add ldqh rdmdr;			// Q.H <- mdr;
	ALU_AZERO bop=qreg ALU_OP=add sa=0xe wa rd incmar ldmdr;	// FP <- Q; mdr <- [mar++]
	ALU_AZERO bop=din lddata ALU_OP=add ldql rd incmar rdmdr ldmdr;	// Q.L <- mdr; mdr <- [mar++]
	ALU_AZERO bop=din lddata ALU_OP=add ldqh rdmdr;			// Q.H <- mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch1 
		ALU_AZERO bop=qreg ALU_OP=add dout ldpc;		// PC <- Q; jump fetch1
 	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;


pushw_d: mpcop=next;
pushw_x: mpcop=next;

pushw_r: aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
		extra=0x13 dout ldmar wa;				// mar <- SP-2; SP = SP - 2;
	aop=reg isa bop=idata idata=0 ALU_OP=add dout ldmdr;		// mdr <- Rb.L;
	wrt;								// [mar] <- mdr;
	aop=reg isa bop=idata idata=0 ALU_OP=add dout ldhmdr incmar;	// mdr <- Rb.H; mar++;
	mpcop=next;
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

pushw_i: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
		extra=0x13 dout ldmar wa;				// mar <- SP-2; SP = SP - 2;
	aop=qreg bop=idata idata=0 ALU_OP=add dout ldmdr;		// mdr <- Q.L;
	wrt;								// [mar] <- mdr;
	aop=qreg bop=idata idata=0 ALU_OP=add dout ldhmdr incmar;	// mdr <- Q.H; mar++;
	mpcop=next;
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

movw_rr: mpcop=jump mpccond=jmp mpcaddr=fetch2 ALU_AZERO ALU_OP=add
		isa isb wa aop=reg bop=reg ldcc extra=1 
		incpc spc rd ldmdr;					// Ra <- Rb; jump to fetch2; mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldir;					// mdr <- [PC]; PC++; ir <- mdr;

movb_rr: ALU_AZERO ALU_OP=add isb aop=reg bop=reg ldcc extra=1 ldql;	// Q.L <- Rb;
	mpcop=jump mpccond=jmp mpcaddr=fetch2 aop=idata bop=idata
		ALU_OP=add ldqh incpc spc rd ldmdr;			// Q.H <- 0; jump to fetch2;mdr <- [PC]; PC++;
	ALU_AZERO ALU_OP=add bop=qreg isa wa 
		incpc spc rd ldmdr rdmdr ldir;				// Ra <- Q; mdr <- [PC]; PC++; ir <- mdr;


movw_ri: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_AZERO
		aop=reg bop=qreg wa isa ldcc;				// Ra = Q;  CC; jump to fetch
	mpcop=next;

movb_ri:incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO bop=reg sb=0;			// Q.H = 0;
	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_AZERO
		aop=reg bop=qreg wa isa ldcc;				// Ra = Q;  CC; jump to fetch
	mpcop=next;

movb_rd:isb aop=idata bop=reg idata=0 ALU_OP=add ldmar dout  extra=3;	// mar <- Rb
_mbrd:	rd ldmdr;							// mdr <- [mar]
	mpcop=jump mpccond=jmp mpcaddr=fetch lddata rdmdr isa wa;	// Ra <- mdr
	ALU_OP=add idata=0 bop=idata aop=reg isa ldcc;			// CC

movw_rd: isb aop=idata bop=reg idata=0 ALU_OP=add ldmar dout  extra=3;	// mar <- Rb
_mwrd:	rd ldmdr incmar;						// mdr <- [mar++]
	rd ldmdr lddata rdmdr bop=din ALU_AZERO ALU_OP=add ldql;	// Q.L <- mdr; mdr <- [mar++]
	lddata rdmdr bop=din ALU_AZERO ALU_OP=add ldqh;			// Q.H <- mdr;
	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO bop=qreg
		ALU_OP=add isa wa ldcc;					// Ra <- Q; CC
	mpcop=next;

movb_rx: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mbrd rdmdr ldqh
		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mbrd
	isb aop=qreg bop=reg
		ALU_OP=add ldmar dout;					// mar <- Rb+Q;

movw_rx: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql
		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mwrd rdmdr ldqh ALU_OP=add
		 ALU_AZERO lddata bop=din;				// Q.H = mdr;
	isb aop=qreg bop=reg ALU_OP=add
		ldmar dout;						// mar <- Rb+Q

movb_dr: isa aop=reg bop=idata idata=0 ALU_OP=add ldmar dout ldcc;	// mar <- Ra
_mbdr:	isb aop=idata bop=reg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Rb
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

movw_dr: isa aop=reg bop=idata idata=0 ALU_OP=add ldmar dout ldcc;	// mar <- Ra
_mwdr:	isb aop=idata bop=reg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Rb.L
	wrt;								// [mar] <- mdr;
	isb aop=idata bop=reg idata=0 ALU_OP=add ldhmdr dout incmar;	// mdr <- Rb.H; mar++;
	mpcop=next;
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

movb_xr: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mbdr rdmdr ldqh ALU_OP=add
		 ALU_AZERO lddata bop=din;				// Q.H = mdr; jump to _mbdr
	isa aop=reg bop=qreg ALU_OP=add	ldmar dout ldcc;		// mar <- Ra+Q


movw_xr: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mwdr rdmdr ldqh ALU_OP=add
		 ALU_AZERO lddata bop=din;				// Q.H = mdr; jump to _mwdr
	isa aop=reg bop=qreg ALU_OP=add	ldmar dout ldcc;		// mar <- Ra+Q

movw_xx: mpcop=next  extra=7;
movb_xx: mpcop=next  extra=7;
movw_xd: mpcop=next  extra=7;
movb_xd: mpcop=next  extra=7;
movw_dd: mpcop=next  extra=7;
movb_dd: mpcop=next  extra=7;
movw_dx: mpcop=next  extra=7;
movb_dx: mpcop=next  extra=7;
	mpcop=next  extra=7;

movw_di: isa bop=idata idata=0 ALU_OP=add dout ldmar;			// mar <- Ra
_mwdi:	incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
	aop=idata bop=qreg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Q.L
	wrt;								// [mar] <- mdr;
	aop=idata bop=qreg idata=0 ALU_OP=add ldhmdr dout incmar;	// mdr <- Q.H; mar++;
	mpcop=next;
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

movb_di: aop=reg isa bop=idata idata=0 ALU_OP=add dout ldmar extra=0x21;// mar <- Ra
_mbdi:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	aop=idata bop=qreg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Q.L
	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
	mpcop=next;

movw_xi: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mwdi rdmdr ldqh
		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mwdi
	isa aop=reg bop=qreg ALU_OP=add dout ldmar;			// mar <- Ra+Q

movb_xi: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++; 
	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
	mpcop=jump mpccond=jmp mpcaddr=_mbdi rdmdr ldqh
		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mwdi
	isa aop=reg bop=qreg ALU_OP=add dout ldmar;			// mar <- Ra+Q



nop:	mpcop=jump mpccond=jmp mpcaddr=fetch extra=0x15;
	mpcop=next;
end

/////////////////////////////////////////////////////////////////////////////
//
// General notes on assembler
// Registers are not saved accross function calls unless explicitly saved.
// Functions return values in R1.
// The register R0 is a special "always 0" register.  Writing to R0 will have no
//  effect other than to set condition codes.
//
//
begin macrocode @ 0x100
ttydata:	.symbol	0x11	// tty data in/out register
ttystatus:	.symbol	0x10	// tty status register

//
// Nodes have the format (note that pointers are two bytes):
//
// struct node {
//   struct node *yes_b;
//   struct node *no_b; 
//   char text[100];
// };
//
nsize:	.symbol 104		// Size of a tree node.  That is "sizeof(struct node)".
yes_b:	.symbol	0		// Pointer to yes side
no_b:	.symbol	2		// Pointer to no side
text:	.symbol 4		// Text of node (animal name or question)

//
// Execution starts here.
//
start:
	movw	SP, 0		// Initialize stack pointer
	movw	FP, 0		// Initialize frame pointer

	call	main		// Call main program

sdone:	jmp	sdone		// Infinite loop when main ends


////////////////////
//	main()
//
.proc main
	movw	R13, mend	// Use R13 as a sort of heap pointer

	pushw	welcome		// Push the "Welcome to" message
	call	printf		// Print the message
	add	SP,2		// Restore stack pointer

	movw	(root),top_node	// Initialize root node
	movw	(known),1	// Know one animal

loop:
	pushw	think		// Push the "Think of an animal..." message
	call	printf		// Print the message
	add	SP,2		// Restore stack pointer

	movw	R1, (known)	// Put number of known animals in R1
	pushw	R1		// Push that number on the stack
	pushw	numk		// Push the "I know %d animals" message
	call	printf		// Call printf to print message
	add	SP,4		// Restore stack

	movw	R1,(root)	// Put the root pointer in R1
	pushw	R1		// Push the pointer on the stack
	call	find_animal	// Ask questions to find animal
	add	SP,2		// Restore the stack
	movw	(root),R1	// Save new root

	jmp	loop		// Go back and guess another animal

	ret			// Return to call (actually we should never get here)
.end

////////////////////
//	find_animal(p)		Find the animal. p is the root node in question tree 
//
.proc find_animal
tree:	.symbol	-2		// Local variable for tree pointer
	sub	SP,2		// Allocate space for local variables

	movw	R1, 4(FP)	// Get the pointer to top node
	movw	tree(FP),R1	// Store it in "tree"

	movw	R2,yes_b(R1)	// Get pointer in "yes" branch of tree
	cmp	R2,0		// Compare against 0
	jne	get_response	// If not 0, then treat as question node

	pushw	R1		// Push pointer to top node
	call	get_final	// As the final question, and insert new node if necessary 
	add	SP,2		// Restore stack
	movw	tree(FP),R1	// Save new root node in "tree"

	jmp	done		// All done, go to final cleanup 

get_response:
	movw	R1,tree(FP)	// Put current node pointer in R1
	movw	R4,R1		// R4 = R1
	add	R4,text		// Add offset to make R4 pointer to question
	pushw	R4		// Push text of question
	call	print		// Print question in tree node
	add	SP,2		// Restore stack

	pushw	qprompt		// Push "?" prompt
	call	print		// Print the "? "
	add	SP,2		// Restore stack

	pushw	buf		// Push address of buffer in which to get response
	call	gets		// Read response from user
	add	SP,2		// Restore stack

	pushw	buf		// Push users response on stack
	pushw	yes		// Push "yes" on stack
	call	strcmp		// Compare the strings
	add	SP,4		// Restore stack
	cmp	R1,0		// Check if R1 was 0
	jeq	say_yes		// If so, user answered "yes", goto say_yes

	pushw	buf		// Push users response on stack
	pushw	no		// Push "no" on stack
	call	strcmp		// Compare the strings
	add	SP,4		// Restore stack
	cmp	R1,0		// Check if R1 was 0
	jeq	say_no		// If so, user answered "no", goto say_no

	pushw	yesno		// Push the "yes or no" error message
	call	print		// Print error message
	add	SP,2		// Restore stack
	jmp	get_response	// Go back and ask again

say_yes:
	movw	R1,tree(FP)	// Put current tree pointer in R1           
	movw	R2,yes_b(R1)	// Put "yes" branch pointer in R2           
	pushw	R2		// Push the yes branch on the stack         
	call	find_animal	// Recursively ask the next question        
	add	SP,2		// Restore the stack                        
	movw	R2,tree(FP)	// Get tree pointer again                   
	movw	yes_b(R2),R1	// Update the "yes" branch                  
	jmp	done		// Finish up and prepare to return to caller 
say_no:
	movw	R1,tree(FP)	// Put current tree pointer in R1           
	movw	R2,no_b(R1)	// Put "no" branch pointer in R2           
	pushw	R2		// Push the no branch on the stack         
	call	find_animal	// Recursively ask the next question        
	add	SP,2		// Restore the stack                        
	movw	R2,tree(FP)	// Get tree pointer again                   
	movw	no_b(R2),R1	// Update the "no" branch                  
	jmp	done		// Finish up and prepare to return to caller

done:
	movw	R1,tree(FP)	// Put new root node in R1
	ret			// Return to caller
.end

////////////////////
//	get_final(p)		Ask final question (at node p), and update tree if necessary.
//
.proc get_final
tree:	.symbol	-2		// Local variable for tree pointer
animal_node:	.symbol	-4	// Local variable for new animal node pointer
discrim_node:	.symbol	-6	// Local variable for new question node pointer
	sub	SP,6		// Allocate space for local variables

get_response:
	movw	R1, 4(FP)	// Get pointer to current node
	movw	tree(FP),R1	// Save it in the 'tree' variable

	movw	R1, 4(FP)	// Put pointer to tree in R1
	add	R1,text		// Advance R1 to animal name text 
	pushw	R1		// Push pointer to animal name on stack
	pushw	isita		// Push the "is it a..." string pointer
	call	printf		// Print the final question
	add	SP,4		// Restore stack

	pushw	buf		// Push buffer for response
	call	gets		// Get the response
	add	SP,2		// Restore the stack

	pushw	buf		// Push response on stack      
	pushw	yes		// Push "yes" on stack         
	call	strcmp		// Compare strings            
	add	SP,4		// Restore stack               
	cmp	R1,0		// See if a 0 was returned     
	jeq	win		// If so, we guessed the animal

	pushw	buf		// Push response on stack      
	pushw	no		// Push "no" on stack         
	call	strcmp		// Compare strings            
	add	SP,4		// Restore stack               
	cmp	R1,0		// See if a 0 was returned     
	jeq	loose		// If so, we did not guess the animal

	pushw	yesno		// Push the "yes or no" error message 
	call	print		// Print it                           
	add	SP,2		// Restore stack                      
	jmp	get_response	// Go back and ask again              

win:
	pushw	winmsg		// Push the (computer) win message
	call	printf		// Print it
	add	SP,2		// Restore stack
	jmp	done		// All done, go finish up and return

loose:
	pushw	loosemsg	// Push the (computer) loose message
	call	printf		// Print it
	add	SP,2		// Restore stack

	pushw	nsize			// Push number of bytes in a node
	call	malloc			// Allocate memory for new animal node
	add	SP,2			// Restore stack
	movw	animal_node(FP),R1	// Put address of new node in animal_node

	movw	yes_b(R1),0		// Intialize yes branches
	movw	no_b(R1),0		// Intialize no branches
	add	R1,text			// Move R1 to point to text area
	pushw	R1			// Push text buffer
	call	gets			// Get animal name
	add	SP,2			// Restore stack

	movw	R1,tree(FP)		// Put pointer to exiting node in R1
	add	R1,text			// Advance to the text field
	pushw	R1			// Push pointer to old animal name
	movw	R1,animal_node(FP)	// Put pointer to new node in R1
	add	R1,text			// Advance to the text field
	pushw	R1			// Push new animal name on stack
	pushw	dscrim			// Push "what is difference" question 
	call	printf			// Print the question 
	add	SP,6			// Restore pointer

	pushw	nsize			// Allocate memory for discrimination node
	call	malloc			// Allocate memory for new discrimination node
	add	SP,2			// Restore stack
	movw	discrim_node(FP),R1	// Put address of new node in discrim_node

	add	R1,text			// Advance pointer to text field of discrimination node
	pushw	R1			// Push pointer to text buffer to input question 
	call	gets			// Input the question
	add	SP,2			// Restore pointer

	movw	R1, (known)		// Put number of known animals in R1
	add	R1,1			// Increment R1
	movw	(known),R1		// Store number of known animals back in "known"

L1:	movw	R1,animal_node(FP)	// Put pointer to new animal node in R1
	add	R1,text			// Advance R1 to the text field
	pushw	R1			// Push new animal name on stack
	pushw	which			// Push the "..correct answer for..." message.
	call	printf			// Print the message
	add	SP,4			// Restore stack

	pushw	buf			// Push text buffer on stack
	call	gets			// Input a "yes" or "no"
	add	SP,2			// Restore stack

	pushw	buf			// Push user response                            
	pushw	yes			// Push string "yes"                             
	call	strcmp			// Compare strings                               
	add	SP,4			// Restore stack                                 
	cmp	R1,0			// Is the result 0?                              
	jeq	L2			// If so, goto L2.  New animal is on "yes" branch

	pushw	buf			// Push user response                            
	pushw	no			// Push string "no"                             
	call	strcmp			// Compare strings                               
	add	SP,4			// Restore stack                                 
	cmp	R1,0			// Is the result 0?                              
	jeq	L3			// If so, goto L3.  New animal is on "no" branch

	pushw	yesno			// Push the "yes or no" error message 
	call	printf			// Print it                           
	add	SP,2			// Restore stack                      
	jmp	L1			// Go back and ask again              

//
// Insert new animal on yes branch of new question
//
L2:	movw	R1,discrim_node(FP)	// Put new question node in R1 
	movw	R2,tree(FP)		// Put old animal node in R2   
	movw	R3,animal_node(FP)	// Put new animal node in R3   
	movw	yes_b(R1),R3		// Set yes branch to new node  
	movw	no_b(R1),R2		// Set no branch to old node   
	movw	tree(FP),R1		// Save R1 to tree pointer     
	jmp	done			// Finish up and return        

//
// Insert new animal on no branch of new question
//
L3:	movw	R1,discrim_node(FP)	// Put new question node in R1 
	movw	R2,tree(FP)		// Put old animal node in R2   
	movw	R3,animal_node(FP)	// Put new animal node in R3   
	movw	yes_b(R1),R2		// Set yes branch to old node  
	movw	no_b(R1),R3		// Set no branch to new node   
	movw	tree(FP),R1		// Save R1 to tree pointer     
	jmp	done			// Finish up and return        

done:
	movw	R1,tree(FP)		// Put tree pointer into return register R1
	ret				// Return to caller
.end

////////////////////
//	malloc(n) -> p	Allocate n bytes and return address in R1.  Allocated memory
//			can not be freed.
//
.proc malloc
	movw	R2, 4(FP)	// Get number of bytes
	movw	R1,R13		// Pointer to block of memory
	add	R13,R2		// Update heap pointer
	ret
.end

////////////////////
//	print(s)	Print the string s
//
.proc print
	movw	R1, 4(FP)	// Get parameter (string address)
loop:	movb	R2, (R1)	// Put character R1 is pointing to in R2
	jeq	done		// If it was a 0, this is the end of the string
	movb	(ttydata),R2	// Move char to the tty data register
	movb	(ttystatus),#1	// Signal tty controller to print character
	add	R1, #1		// Move pointer to next char
	jmp	loop		// Go back and print more
done:	ret
.end

////////////////////
//	printf(s,...)	Print the format string 
//
.proc printf
ptr:	.symbol	-2		// Local var for string pointer
arg:	.symbol -4		// Local var for argument pointer
	sub	SP,4		// Allocate 4 bytes for local variables

	movw	R3,FP		// Assign R3 and add an offset so that it points 
	add	R3,6		//   to the argument after the control string

	movw	R1, 4(FP)	// Put the control string pointer in R1
loop:	movb	R2, (R1)	// Get the next char from control string
	jeq	done		// If it was a 0, this is the end of the string

	cmp	R2, '%'		// See if it is the '%' character
	jne	cout		// If not goto cout, and simply print it

	add	R1,1		// Advance the string pointer
	movb	R2,(R1)		// Get the next char
	add	R1,1		// Advance the string pointer again

//switch (R2)
L1:	cmp	R2,'s'		// See if this is a "%s" conversion
	jne	L2		// If not, goto L2

// case 's' :
	movw	ptr(FP),R1	// Save the string pointer value
	movw	arg(FP),R3	// Save the argument pointer value
	movw	R2,(R3)		// Get address of string (from arguments) to print
	pushw	R2		// Push it on the stack
	call	print		// Print the string
	add	SP,2		// Restore stack pointer
	movw	R1,ptr(FP)	// Restore string pointer value
	movw	R3,arg(FP)	// Restore argument pointer value
	add	R3,2		// Advance argument pointer to next argument
	jmp	loop		// Go back and print more

L2:	cmp	R2,'d'		// See if this is a "%d" conversion
	jne	loop		// If not, ignore unknown conversion

// case 'd' :
	movw	ptr(FP),R1	// Save the string pointer value
	movw	arg(FP),R3	// Save the argument pointer value
	movw	R2,(R3)		// Get number (from arguments) to print
	pushw	R2		// Push it on the stack
	call	nprint		// Go print the decimal number 
	add	SP,2		// Restore stack pointer
	movw	R1,ptr(FP)	// Restore string pointer value
	movw	R3,arg(FP)	// Restore argument pointer value
	add	R3,2		// Advance argument pointer to next argument
	jmp	loop		// Go back and print more

cout:
	movb	(ttydata),R2	// Put character in tty data register
	movb	(ttystatus),#1	// Signal tty controller to print character
	add	R1, #1		// Advance to next char in control string
	jmp	loop		// Go back and print more

done:	ret			// All done, return to caller 
.end

////////////////////
//	nprint(d)	Print the number d in decimal
//
.proc nprint
	movw	R1, 4(FP)	// Move argument value to R1
	jeq	zprint		// If it was zero, goto zprint

	pushw	R1		// Push value to print on stack
	call	nprint_aux 	// Call aux function to print number
	add	SP,2		// Restore stack pointer
	ret			// All done, return to caller 

zprint:	movb	(ttydata), '0'	// Put the ascii value of '0' in tty data register
	movb	(ttystatus), #1	// Signal tty controller to print character
	ret			// All done, return to caller 
.end

////////////////////
//	nprint_aux(d)	Print the number d in decimal (but prints nothing if d is zero)
//
.proc nprint_aux
digit:	.symbol	-2		// Digit to print
	sub	SP, 2		// Allocate space for local variables

	movw	R1, 4(FP)	// Get argument
	jeq	done		// If zero, return

	// To print the number n we compute
	//     R2 = n / 10, and 
	//     R3 = n % 10
	// We can then recursively call nprint_aux to print all
	// but the lowest digit, then print the lowest digit ourselves
	//
	movw	R2, R1		// R2 = R1
	div	R2, 10		// R2 = R2 / 10
	movw	R3, R1		// R3 = R1
	mod	R3, 10		// R3 = R3 % 10
	movw	digit(FP),R3	// save lowest digit value

	pushw	R2		// Push the higher digits
	call	nprint_aux	// Recursively call ourselves to print them
	add	SP,2		// Restore stack pointer

	movw	R3,digit(FP)	// Restore digit value
	add	R3, '0'		// Add ascii for '0' to get ascii for digit
	movb	(ttydata),R3	// Put char in tty data register
	movb	(ttystatus),#1	// Signal tty controller to print character
done:
	ret			// All done, resturn to caller
.end

////////////////////
//	strcmp(a,b)		Compare strings a and b
//
.proc	strcmp
	movw	R2,4(FP)	// Get pointer to first string
	movw	R3,6(FP)	// Get pointer to second string

loop:	movb	R1,(R2)		// Get next char from R2
	jeq	eos		// If end of string, goto eos
	movb	R4,(R3)		// Get next char from R3
	jeq	eos		// If end of string, goto eos

	sub	R1,R4		// Compute difference in R1
	jne	done		// If difference was not 0, we are done

	add	R2,1		// Advance to next char in R2
	add	R3,1		// Advance to next char in R3
	jmp	loop		// Go compare more

eos:
	movb	R4,(R3)		// Get next char from R3 again (in case R1 was eos)
	sub	R1,R4		// Compute difference in R1

done:
	ret			// Return to caller, result is in R1
.end


////////////////////
//	gets(b)		Reads chars from tty into b.
//
.proc gets
	movw	R1, 4(FP)	// Get pointer to buffer
	movw	R4,R1		// Save starting pointer in R4

	//
	// Poll for a characcter
	//
cwait:	movb	R2,(ttystatus)	// Get ready status
	and	R2, #2		// Test if a char is ready
	jeq	cwait		// If not, go back and wait some more

	movb	R3,(ttydata)	// Get char from tty data register
	movb	(ttystatus),#2	// Signal char received
	cmp	R3,'\r'		// Compare against return char
	jeq	done		// Exit if return received

	cmp	R3,'\b'		// Compare against backspace char
	jeq	del_char	// Delete char if backspace

	cmp	R3,0x7f		// Compare against delete char
	jeq	del_char	// Delete char if delete character

	movb	(ttydata),R3	// Put char to echo in tty data register
	movb	(ttystatus),#1	// Signal tty controller to print character

	movb	(R1),R3		// Save in buffer
	add	R1,1		// increment pointer

	jmp	cwait		// Go back and get another char

del_char:
	cmp	R1,R4		// Compare current pointer against start of line
	jle	bell		// If already at start of line, ring bell

	movb	R3, 0x7f	// Make sure delete char is in R3
	sub	R1,1		// Decrement pointer
	movb	(ttydata),R3	// Echo backspace
	movb	(ttystatus),#1	// Signal tty controller to print character

	jmp	cwait		// Go back and get another char

bell:	
	movb	R3, 7		// Put bell char in R3
	movb	(ttydata),R3	// Echo bell
	movb	(ttystatus),#1	// Signal tty controller to print character
	jmp	cwait		// Go back and get another char

done:
	movb	(ttydata),'\n'	// Output newline
	movb	(ttystatus),#1	// Signal tty controller to print character
	movb	(R1),0		// Put eos in the string we just read
	ret			// Return to caller
.end

buf:	.bss	128		// Buffer for input
known:	.bss	2		// Number of animals known
root:	.bss	2		// root of animals tree

top_node:
	.short	0		// Pointer to "yes" node
	.short	0		// Pointer to "no" node
	.byte	"aardvark",0	// Animal name or question text

welcome: .byte	"\nWelcome to Animals.\n", 0
think:	.byte	"\nThink of an animal and I will try to guess what it is.\n", 0
numk:	.byte	"I currently know %d animals.\n\n", 0
isita: 	.byte	"Is the animal you are thinking of a %s? ",0
yes:	.byte	"yes",0
no:	.byte	"no",0
yesno:	.byte	"Please type 'yes' or 'no'.\n",0
winmsg:	.byte	"I guessed your animal!!!\n\n",0
loosemsg: .byte	"I could not guess your animal.  What was your animal? ",0
dscrim:	.byte	"Enter a question that would distinguish a %s from a %s.\n> ",0
which:	.byte	"The correct answer for a %s is? ",0
nl:	.byte	"\n",0
qprompt: .byte	"? ",0
mend:

end