devel/debug/1/src/trace

Raw file
Back to index

   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
PACKET trace DEFINES trace: 
 
(**************************************************************) 
(*                                          Autor: G. Szalay  *) 
(*    E U M E L 0 - T R A C E                                 *) 
(*                                          Stand: 87-04-23   *) 
(**************************************************************) 
 
LET packet area = 0, stack area = 1, text opd maxlen = 14, 
    stdds = 0, info lines = 4, crlf = ""13""10"", 
    beep = ""7"", carriage return = ""13"", cursor up = ""3"", 
    std charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456 
    7890<>.,:;-_+*!""�$%&/()=?'äÄöÖüÜ#^", 
    blanks = "                                        ", 
    startindent = 10, indentincr = 2; 
BOOL VAR trap set := FALSE, trapped, initial call := TRUE, quit, 
         single step := FALSE, protocol := FALSE, cond br follows, 
         prot just started := FALSE, prot stopped := TRUE, 
         users error := FALSE, users stpdis, prot operands := TRUE, 
         nontraceable found, errorstop processing := FALSE, 
         std procs traceable := id (1) = 4 (* processor = 68000 *), 
         longcall to trace flag; 
INT VAR  aret hi := 0, aret lo := 0, ic hi, ic lo, ic h, ic l, i, 
         atrap hi, atrap lo, nail1 hi, nail1 lo, nail2 hi, nail2 lo, 
         no of nails := 1, saved instr, saved instr w2, 
         saved1, saved1 w2, saved2, saved2 w2, 
         call to trace, call2 to trace, length of call to trace,
         cmd, ilen, iclass, ilen1, iclass1, indentpos, 
         code addr modif, pbase, lbase, users lbase, 
         users errcode, users errline, old flags, flags, 
         module no, word, word1, word2, case, xpos, ypos, 
         cond br hi, cond br lo, maxlines:=12, lines,
         opad hiword, opad hi, opad lo, opdds, br param, brcomp index, 
         ic off, opd ptr, int opd, text opd len, text opd tr len, 
         heap link, root word 2, no of results:=0, 
         no of nontraceables := 0, no of long nontraceables := 0, 
         pproc modno, pproc call, pproc ic lo := 0; 
ROW 3 INT VAR res ds, res opadh, res opadl; 
INT CONST lo byte mask  := dec ("00ff"), 
          hi byte mask  := dec ("ff00"), 
          branch param mask := dec ("87ff"), 
          opcode mask0  := dec ("83ff"), 
          opcode mask1  := dec ("7c00"), 
          bf mask1      := dec ("0040"), 
          ln br mask1   := dec ("7800"), 
          stpdis mask0  := dec ("ffbf"), 
          stpdis mask1  := dec ("0040"), 
          aritu mask1   := dec ("0010"), 
          error mask1   := dec ("0080"), 
          flags mask1   := dec ("00fc"), 
          mask 8000     := dec ("8000"), 
          mask 7fff     := dec ("7fff"), 
          mask 7ffe     := dec ("7ffe"), 
          mask 7f00     := dec ("7f00"), 
          mask 0400     := dec ("0400"), 
          mask fbff     := dec ("fbff"), 
          mask 0007     := dec ("0007"), 
          mask fff8     := dec ("fff8"), 
          m l t start   := dec ("0200"), 
          ln opcode     := dec ("0000"), 
          br opcode     := dec ("7000"), 
          rtn opcode    := dec ("7f00"), 
          call opcode   := dec ("7800"), 
          longcall opcode  := dec ("ff78"), 
          pproc opcode  := dec ("7f1e"), 
          estop opcode  := dec ("7f4b"), 
          dstop opcode  := dec ("7f4c");
TEXT VAR buf, char, command, iname, iname1, ioplist, ioplist1, opd type, 
         opd buf, text opd, res types, users errmsg; 
 
 
(********* following OPs and PROCs may be used by TRACE only ***********) 
 
PROC put (TEXT CONST a): 
  out (a); out (" ") 
ENDPROC put; 
 
PROC putline (TEXT CONST a): 
  out (a); out (crlf) 
ENDPROC putline; 
 
 
(***********************************************************************) 
 
PROC eval br addr (INT CONST br para hi, br para lo, 
                   INT VAR br addr hi, br addr lo): 
  br param := dsgetw (stdds, br para hi, br para lo) 
           AND branch param mask; 
  br addr hi := br para hi; 
  br addr lo := (br para lo AND hi byte mask) 
             OR (br param AND lo byte mask); 
  IF NOT br within page 
  THEN rotate (br param, 8); 
       br param := br param AND lo byte mask; 
       rotate (br param, 1);
       IF br param > 255 
       THEN br param INCR 1; 
            br param := br param AND 255 
       FI; 
       rotate (br param, 8); 
       br addr lo INCR br param; 
       word := br addr lo AND hi byte mask; rotate (word, 8); 
       IF word >= code addr modif 
       THEN br addr lo DECR dec("1000")
       FI 
  FI.
 
  br within page: 
    br param = (br param AND lo byte mask). 
 
ENDPROC eval br addr; 
 
 
PROC eval opd addr (INT CONST ic offset): 
  word := dsgetw (stdds, ic hi, ic lo PLUS ic offset); 
  IF ic offset = 0 
  THEN word := word AND opcode mask0 
  FI; 
  IF global
  THEN eval global addr
  ELIF local 
  THEN eval local addr 
  ELSE eval ref addr 
  FI.
 
  global: (word AND mask 8000) = 0. 
 
  local: (word AND 1) = 0. 
 
  eval global addr: 
    opdds := stdds; 
    opad hi := packet area; 
    opad hiword := opad hi;
    opad lo := pbase PLUS word; 
    perhaps put opad. 
 
  eval local addr: 
    opdds := stdds; 
    opad hi := stack area; 
    opad hiword := opad hi;
    word := word AND mask 7ffe; rotate (word, -1); 
    opad lo := users lbase PLUS word; 
    perhaps put opad. 
 
  eval ref addr: 
    eval local addr; 
    opad hiword := dsgetw (stdds, stack area, opad lo PLUS 1); 
    opad lo := dsgetw (stdds, stack area, opad lo); 
    opdds := opad hiword AND hi byte mask; rotate (opdds, 8); 
    opad hi := opad hiword AND lo byte mask; 
    perhaps put opad. 
 
perhaps put opad: 
 (* put("opad=" CT hex(opad hiword) CT hex(opad lo)) *) . (*for tests*) 
 
ENDPROC eval opd addr; 
 
 
PROC out int opd: 
  out (txt (int opd)); 
  IF int opd < 0 OR int opd > 9 
  THEN out ("("); out (hex (int opd)); out (")") 
  FI 
ENDPROC out int opd; 
 
 
PROC fetch text opd: 
  root word 2 := dsgetw (opdds, opad hi, opad lo PLUS 1); 
  opd buf := subtext (blanks, 1, text opd maxlen + 2); 
  IF text on heap 
  THEN eval text from heap 
  ELSE eval text from root 
  FI; 
  convert nonstd chars; 
  text opd := """"; 
  text opd CAT subtext (opd buf, 1, text opd tr len); 
  text opd CAT """"; 
  IF text opd len > text opd tr len 
  THEN text opd CAT "(..."; 
       text opd CAT txt (text opd len); 
       text opd CAT "B)" 
  FI. 
 
text on heap:
  (root word 2 AND lo byte mask) = 255.
 
eval text from root: 
  text opd len := root word 2 AND lo byte mask; 
  text opd tr len := min (text opd len, text opd maxlen); 
  FOR i FROM 1 UPTO text opd tr len DIV 2 + 1 REP 
    replace (opd buf, i, dsgetw (opdds, opad hi, opad lo PLUS i)) 
  PER; 
  opd buf := subtext (opd buf, 2, text opd tr len + 1). 
 
eval text from heap: 
  rotate (root word 2, 8); 
  text opd len := root word 2 AND lo byte mask 
               OR (dsget2b (opdds, opad hi, opad lo PLUS 2) AND hi byte mask); 
  text opd tr len := min (text opd len, text opd maxlen); 
  heap link := dsgetw (opdds, opad hi, opad lo); 
  rotate (heap link, 15); 
  opad hi := heap link AND mask 0007; 
  opad lo := heap link AND mask fff8; 
  IF opdds = stdds THEN opad lo INCR 2 FI; 
  FOR i FROM 1 UPTO text opd tr len DIV 2 REP 
    replace (opd buf, i, dsgetw (opdds, opad hi, opad lo PLUS i)) 
  PER; 
  opd buf := subtext (opd buf, 1, text opd tr len). 
 
convert nonstd chars: 
  i := 1; 
  WHILE i <= LENGTH opd buf REP 
    char := opd buf SUB i; 
    IF pos (std charset, char) = 0 
    THEN buf := txt (code (char)); 
         opd buf := subtext (opd buf, 1, i-1) CT 
                    """" CT buf CT """" CT 
                    subtext (opd buf, i+1); 
         i INCR 2 + length (buf); 
    ELIF char = """" 
    THEN opd buf := subtext (opd buf, 1, i-1) CT """""" CT 
                    subtext (opd buf, i+1); 
         i INCR 2 
    ELSE i INCR 1 
    FI 
  PER; 
  text opd tr len := LENGTH opd buf. 
 
END PROC fetch text opd; 
 
 
INT OP PLUS (INT CONST a, b):
  unsigned arith;
  a + b
ENDOP PLUS;

PROC trace: 
  ROW 40 INT VAR dummy space for 20 pps; 
  get return address; 
  IF initial call 
  THEN save call to trace 
  ELSE process regular call 
  FI. 
 
get return address: 
  lbase:=local base; 
  users lbase := dsgetw (stdds, stack area, lbase); 
  aret lo := dsgetw (stdds, stack area, lbase+1); 
  word := dsgetw (stdds, stack area, lbase+2); 
  aret hi := word AND 3; 
  flags := word AND flags mask1; 
  ic hi := aret hi; ic lo := aret lo. 
 
save call to trace: 
  call to trace := dsgetw (stdds, aret hi, aret lo - 1); 
  IF (call to trace AND opcode mask1) = call opcode 
  THEN length of call to trace := 1;
       longcall to trace flag := FALSE 
  ELSE call2 to trace := call to trace; 
       call to trace := dsgetw (stdds, aret hi, aret lo - 2); 
       length of call to trace := 2;
       longcall to trace flag := TRUE; 
       putline ("WARNING: call to trace needs 2 words!!!") 
  FI; 
  initial call := FALSE. 
 
process regular call: 
  IF protocol 
  THEN pull old nails 
  ELSE indentpos := startindent; cond br follows := FALSE 
  FI; 
  get users error state and set modes for trace; 
  IF NOT errorstop processing 
  THEN normal processing of instructions 
  ELSE errorstop processing := FALSE 
  FI; 
  handle possible trace errors; 
  IF NOT protocol THEN restore users error state FI.  
 
normal processing of instructions: 
  trapped := trap set AND atrap lo = ic lo - length of call to trace
           AND atrap hi = ic hi;
  IF protocol THEN postprocess protocol FI; 
  IF trapped THEN handle trap FI; 
  IF protocol OR trapped
  THEN ic lo DECR length of call to trace;
       update icount on stack
  FI; 
  IF trapped OR NOT protocol OR single step OR incharety <> "" 
     OR lines >= maxlines
  THEN quit := FALSE; protocol := FALSE; single step := FALSE; lines := 0;
       REP ask for next action; 
           execute command 
       UNTIL quit PER 
  FI; 
  IF protocol THEN protocol instruction and set nails FI. 
 
get users error state and set modes for trace: 
  signed arith; 
  IF NOT protocol 
  THEN users error  := (flags AND error mask1) <> 0; 
       users stpdis := (flags AND stpdis mask1) <> 0; 
       IF users error 
       THEN save users error state; clear error; 
            line; putline ("trace called with user error " CT 
                            txt (users errcode) CT ": " CT users errmsg) 
       ELSE disable stop 
       FI 
  ELIF is error 
  THEN IF first occurrence 
       THEN users error := TRUE; 
            save users error state; 
            line; 
            putline ("trace detected user error " CT 
                     txt (users errcode) CT ": " CT users errmsg); 
            IF users stpdis 
            THEN out ("(stop disabled)") 
            ELSE errorstop processing := TRUE; stop op; 
                 IF protocol THEN set nail1 FI 
            FI 
       ELSE line; 
            putline ("trace detected user error " CT 
                     txt (error code) CT ": " CT error message); 
            out ("(ignored because of previous error(s)) "); 
       FI; 
       clear error 
  ELSE IF (flags AND stpdis mask1) = 0 
       THEN set stpdis flag on stack; disable stop 
       FI 
  FI. 
 
first occurrence: NOT users error. 
 
save users error state: 
  users errmsg := error message; 
  users errline := error line; 
  users errcode := error code. 
 
handle possible trace errors: 
  IF is error 
  THEN line; 
       putline ("TRACE error " CT txt (error code) 
                 CT " at line " CT txt (error line) 
                 CT ": " CT error message); 
       clear error 
  FI. 
 
restore users error state: 
  IF users error 
  THEN error stop (users errcode, users errmsg); 
       users error := FALSE 
  FI; 
  restore users stpdis flag on stack. 
 
handle trap: 
  put trap message; 
  restore instruction; 
  trap set := FALSE. 
 
put trap message: 
  putline ("trap at address " CT txt (atrap hi) CT hex (atrap lo)). 
 
restore instruction: 
  dsputw (stdds, atrap hi, atrap lo, saved instr); 
  IF longcall to trace flag 
  THEN dsputw (stdds, atrap hi, atrap lo PLUS 1, saved instr w2) 
  FI. 
 
postprocess protocol: 
  IF prot operands THEN protocol result operands FI; 
  line; lines INCR 1;
  IF cond br follows THEN protocol cond br op; cond br follows := FALSE FI. 
 
protocol cond br op: 
  outsubtext (blanks, 1, indentpos); 
  out (txt (cond br hi)); out (hex (cond br lo)); out (": "); 
  word := dsget2b (stdds, cond br hi, cond br lo); 
  IF (word AND bf mask1) <> 0 
  THEN out ("BF       ") 
  ELSE out ("BT       ") 
  FI; 
  putline (hex (word)); lines INCR 1.
 
pull old nails: 
  dsputw (stdds, nail1 hi, nail1 lo, saved1); 
  IF longcall to trace flag 
  THEN dsputw (stdds, nail1 hi, nail1 lo PLUS 1, saved1 w2) 
  FI; 
  IF no of nails = 2 
  THEN dsputw (stdds, nail2 hi, nail2 lo, saved2); 
       IF longcall to trace flag 
       THEN dsputw (stdds, nail2 hi, nail2 lo PLUS 1, saved2 w2) 
       FI; 
       no of nails := 1 
  FI. 
 
update icount on stack: 
  dsputw (stdds, 1, lbase + 1, ic lo). 
 
ask for next action: 
  putline (""15"" CT
          "TRACE: step, more, trap, regs, lines, info, disasm, or quit"14""); 
  inchar (command). 
 
execute command: 
  cmd := pos ("tidqmsrl", command); 
  SELECT cmd OF 
    CASE 1: set address trap;                        prot stopped := TRUE 
    CASE 2: info (stdds, ic hi, ic lo, info lines);  prot stopped := TRUE 
    CASE 3: disasm (ic hi, ic lo);                   prot stopped := TRUE 
    CASE 4: quit := TRUE;                            prot stopped := TRUE 
    CASE 5: initialize protocol; single step := FALSE; 
            quit := TRUE 
    CASE 6: initialize protocol; single step := TRUE; 
            quit := TRUE 
    CASE 7: show registers;                          prot stopped := TRUE 
    CASE 8: set new line count;                      prot stopped := TRUE
    OTHERWISE out(beep CT carriage return CT cursor up) 
  ENDSELECT. 
 
set new line count:
  out ("lines="); gethex (buf); maxlines := dec (buf).

set address trap: 
  IF trap set 
  THEN putline ("current trap address: " CT txt (atrap hi) CT hex (atrap lo));
       out ("type <CR> to confirm, or ")
  ELSE out ("type ")
  FI;
  out ("new trap addr ("); 
  IF std procs traceable THEN out ("2") ELSE out ("3") FI; 
  out ("0000...3ffff), or 0 for no trap:"); 
  gethex (buf); 
  IF buf <> "" 
  THEN IF trap set THEN restore instruction; trap set := FALSE FI; 
       buf:="0000" CT buf; 
       atrap hi := dec (subtext (buf, LENGTH buf-7, LENGTH buf-4)); 
       atrap lo := dec (subtext (buf, LENGTH buf-3)); 
       IF atrap hi=3 OR atrap hi=2 AND std procs traceable 
       THEN saved instr := dsgetw (stdds, atrap hi, atrap lo); 
            dsputw (stdds, atrap hi, atrap lo, call to trace); 
            IF longcall to trace flag 
            THEN saved instr w2 := dsgetw (stdds, atrap hi, atrap lo PLUS 1); 
                 dsputw (stdds, atrap hi, atrap lo PLUS 1, call2 to trace); 
            FI; 
            trap set := TRUE 
       ELIF NOT (atrap hi=0 AND atrap lo=0) 
       THEN out (beep); putline ("address not in above range") 
       FI 
  ELSE IF NOT trap set THEN out (beep); putline ("no trap specified") FI 
  FI. 
 
initialize protocol: 
  pbase := dsgetw (stdds, stack area, lbase + 2) AND hi byte mask; 
  code addr modif := dsgetw (stdds, stack area, lbase + 3) 
                  AND lo byte mask; 
  set stpdis flag on stack; 
  prot just started := TRUE; 
  protocol := TRUE. 
 
set stpdis flag on stack: 
  word := dsgetw (stdds, stack area, lbase + 2); 
  dsputw (stdds, stack area, lbase + 2, word OR stpdis mask1). 
 
restore users stpdis flag on stack: 
  word := dsgetw (stdds, stack area, lbase + 2) AND stpdis mask0; 
  IF users stpdis THEN word := word OR stpdis mask1 FI; 
  dsputw (stdds, stack area, lbase + 2, word). 
 
protocol instruction and set nails: 
  protocol instr; 
  SELECT iclass OF 
    CASE 0:  standard ops 
    CASE 1:  cond branch ops 
    CASE 2:  branch ops 
    CASE 3:  comp branch op 
    CASE 4:  call op 
    CASE 5:  exec op 
    CASE 6:  pcall op 
    CASE 7:  return ops 
    CASE 8:  penter op 
    CASE 9:  pp ops 
    CASE 10: line ops 
    CASE 11: stop ops 
    CASE 12: ke op 
    CASE 13: clrerr op
    OTHERWISE: wrong ops 
  ENDSELECT; 
  IF protocol THEN set nail1 FI. 
 
protocol instr: 
  word1 := dsgetw (stdds, ic hi, ic lo); 
  disa (ic hi, ic lo, iname, ioplist, ilen, iclass); 
  protocol this instr. 
 
protocol this instr: 
  possibly delete command line; 
  outsubtext (blanks, 1, indentpos); 
  ic h := ic hi; ic l := ic lo; 
  out (txt (ic h)); out (hex (ic l)); out (": "); 
  out (iname); out (" "); 
  IF ilen > 0 
  THEN FOR i FROM 1 UPTO ilen 
       REP out (hex (dsget2b (stdds, ic h, ic l))); out (" "); 
           ic l INCR 1 PER 
  ELSE out (hex (dsget2b (stdds, ic h, ic l))); out (" ") 
  FI; 
  IF prot operands THEN protocol operands FI. 

possibly delete command line: 
  IF prot just started 
  THEN prot just started := FALSE; 
       IF prot stopped 
       THEN prot stopped := FALSE 
       ELSE delete command line 
       FI 
  FI. 
 
delete command line: 
  get cursor (xpos, ypos); cursor (1, ypos-1); out(""4""). 
 
protocol operands: 
  out ("  "); 
  IF (word1 AND mask 7f00) = mask 7f00 
  THEN ic off := 1 
  ELSE ic off := 0 
  FI; 
  res types := ""; 
  no of results := 0; 
  FOR opd ptr FROM 1 UPTO LENGTH ioplist REP 
    opd type := ioplist SUB opd ptr; 
    IF opd type <> " " 
    THEN case := pos ("irtdpahIRTDPEH", opd type); 
         IF case > 0 
         THEN eval opd addr (ic off); 
              SELECT case OF 
                CASE 1: prot int rd opd 
                CASE 2: prot real rd opd 
                CASE 3: prot text rd opd 
                CASE 4: prot dataspace rd opd 
                CASE 5: prot task rd opd 
                CASE 6: prot virt addr 
                CASE 7: prot hex rd opd 
                OTHERWISE save res type 
              ENDSELECT 
         FI; 
         ic off INCR 1 
    FI 
  UNTIL opd type = " " PER. 
 
save res type: 
  res types CAT opd type; 
  no of results INCR 1; 
  res ds    (no of results) := opdds; 
  res opadh (no of results) := opad hi; 
  res opadl (no of results) := opad lo. 
 
protocol result operands: 
  FOR opd ptr FROM 1 UPTO no of results REP prot this result PER.
 
prot this result: 
  opdds   := res ds    (opd ptr); 
  opad hi := res opadh (opd ptr); 
  opad lo := res opadl (opd ptr); 
  opd type := res types SUB opd ptr; 
  SELECT pos ("IRTDPEH", opd type) OF 
    CASE 1: prot int result 
    CASE 2: prot real result 
    CASE 3: prot text result 
    CASE 4: prot dataspace result 
    CASE 5: prot task result 
    CASE 6: prot eva result 
    CASE 7: prot hex result 
    OTHERWISE out (opd type CT "(???) ") 
  ENDSELECT. 
 
prot int rd opd: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out (">"); out int opd; out (" "). 
 
prot int result: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out int opd; out ("> "). 
 
prot hex rd opd: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out (">"); out (hex (int opd)); out (" "). 
 
prot hex result: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out (hex (int opd)); out ("> ").
 
prot real rd opd: 
  out (">"); 
  out (hex (dsget2b (opdds, opad hi, opad lo))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 1))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 2))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 3))); out (" "). 
 
prot real result: 
  out (hex (dsget2b (opdds, opad hi, opad lo))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 1))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 2))); 
  out (hex (dsget2b (opdds, opad hi, opad lo PLUS 3))); 
  out ("> "). 
 
prot text rd opd: 
  fetch text opd; 
  out (">"); out (text opd); out (" "). 
 
prot text result: 
  fetch text opd; 
  out (text opd); out ("> "). 
 
prot dataspace rd opd: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out (">"); out (hex (int opd)); out (" "). 
 
prot dataspace result: 
  int opd := dsgetw (opdds, opad hi, opad lo); 
  out (hex (int opd)); out ("> "). 
 
prot task rd opd: 
  out (">"); out (hex (dsgetw (opdds, opad hi, opad lo))); 
  out ("/"); out (hex (dsgetw (opdds, opad hi, opad lo PLUS 1))); out (" "). 
 
prot task result: 
  out (hex (dsgetw (opdds, opad hi, opad lo))); out ("/"); 
  out (hex (dsgetw (opdds, opad hi, opad lo PLUS 1))); out ("> "). 
 
prot virt addr: 
  out (">"); out (hex (opad hiword)); out (hex (opad lo)); out (" "). 
 
prot eva result: 
  out (hex (dsgetw (opdds, opad hi, opad lo PLUS 1))); 
  out (hex (dsgetw (opdds, opad hi, opad lo))); 
  out (">").  
 
standard ops: 
  nail1 hi := ic hi; nail1 lo := ic lo PLUS ilen. 
 
set nail1: 
  saved1 := dsgetw (stdds, nail1 hi, nail1 lo); 
  dsputw (stdds, nail1 hi, nail1 lo, call to trace); 
  IF longcall to trace flag 
  THEN saved1 w2 := dsgetw (stdds, nail1 hi, nail1 lo PLUS 1); 
       dsputw (stdds, nail1 hi, nail1 lo PLUS 1, call2 to trace) 
  FI. 
 
set nail2: 
  saved2 := dsgetw (stdds, nail2 hi, nail2 lo); 
  dsputw (stdds, nail2 hi, nail2 lo, call to trace); 
  IF longcall to trace flag 
  THEN saved2 w2 := dsgetw (stdds, nail2 hi, nail2 lo PLUS 1); 
       dsputw (stdds, nail2 hi, nail2 lo PLUS 1, call2 to trace) 
  FI. 
 
cond branch ops: 
  cond br follows := TRUE; 
  cond br hi := ic hi; cond br lo := ic lo PLUS ilen; 
  nail1 hi := cond br hi; nail1 lo := cond br lo PLUS 1; 
  eval br addr (cond br hi, cond br lo, nail2 hi, nail2 lo); 
  no of nails := 2; set nail2. 
 
branch ops: 
  eval br addr (ic hi, ic lo, nail1 hi, nail1 lo). 
 
comp branch op: 
  eval opd addr (1); 
  brcomp index := dsgetw (stdds, opad hi, opad lo); 
  IF brcomp index < 0 OR brcomp index >= dsgetw (stdds, ic hi, ic lo PLUS 2) 
  THEN brcomp index := -1 
  FI; 
  nail1 hi := ic hi; 
  nail1 lo := ic lo PLUS ilen PLUS brcomp index PLUS 1. 
 
call op: 
  eval module no; 
  call or exec. 
 
call or exec: 
  IF module no < 1280 AND NOT std procs traceable 
  THEN possibly append proc head; 
       out (" (*n.t.*)"); 
       nontraceable found := TRUE 
  ELSE check for nontraceable 
  FI; 
  IF NOT nontraceable found 
  THEN restore users stpdis flag on stack; 
       get proc address via module link table; 
       possibly append proc head; 
       indentpos INCR indentincr; 
       nail1 hi := ic hi; nail1 lo := ic lo PLUS 1 (*nail behind head*) 
  ELIF call to trace found 
  THEN skip instruction 
  ELIF possibly call to bool proc 
  THEN cond branch ops 
  ELSE standard ops 
  FI. 
 
eval module no: 
  IF word1 = longcall opcode
  THEN module no := dsgetw (stdds, ic hi, ic lo PLUS 1)
  ELSE module no := word1 AND opcode mask0; 
       IF (module no AND mask 8000) <> 0 
       THEN module no := module no AND mask 7fff OR mask 0400 
       FI
  FI. 
 
check for nontraceable: 
  nontraceable found := FALSE; 
  IF word1 = longcall opcode 
  THEN word2 := dsgetw (stdds, ic hi, ic lo PLUS 1); 
       FOR j FROM 1 UPTO no of long nontraceables REP 
         IF word 2 = call2 to nontraceables (j) 
         THEN out (names of long nontraceables (j)); 
              nontraceable found := TRUE 
         FI 
       UNTIL nontraceable found PER 
  ELSE FOR j FROM 1 UPTO no of nontraceables REP 
         IF word1 = calls to nontraceables (j) 
         THEN out (names of short nontraceables (j)); 
              nontraceable found := TRUE 
         FI 
       UNTIL nontraceable found PER 
  FI. 
 
get proc address via module link table: 
  IF module no < 1280 THEN ic hi := 2 ELSE ic hi := 3 FI; 
  ic lo := dsgetw (stdds, packet area, m l t start + module no). 
 
possibly append proc head: 
  out (proc head (module no)). 
 
skip instruction: 
  ic lo INCR ilen; update icount on stack; 
  nail1 hi := ic hi; nail1 lo := ic lo. 
 
possibly call to bool proc: 
  word := dsgetw (stdds, ic hi, ic lo PLUS ilen) AND ln br mask1; 
  word = ln opcode OR word = br opcode. 
 
exec op: 
  eval opd addr (1); 
  module no := dsgetw (stdds, opad hi, opad lo); 
  call or exec. 
  
pcall op: 
  eval opd addr (1); 
  IF opad lo = 2 AND NOT std procs traceable 
  THEN out (" (*n.t.*)"); 
       nontraceable found := TRUE 
  ELSE check for nontraceable pproc 
  FI; 
  IF NOT nontraceable found 
  THEN restore users stpdis flag on stack; 
       possibly append proc head for pproc; 
       indentpos INCR indentincr; 
       nail1 hi := opad hi; nail1 lo := opad lo PLUS 1 (*nail behind head*) 
(*ELIF word1 = call to trace 
  THEN skip instruction *) 
  ELIF possibly call to bool proc 
  THEN cond branch ops 
  ELSE standard ops 
  FI. 
 
check for nontraceable pproc: 
  nontraceable found := FALSE; 
  IF opad lo = pproc ic lo 
  THEN FOR j FROM 1 UPTO no of nontraceables REP 
         IF pproc call = calls to nontraceables (j) 
         THEN out (names of nontraceables (j)); 
              nontraceable found := TRUE 
         FI 
       UNTIL nontraceable found PER 
  ELSE nontraceable found := TRUE  (*to be on the secure side*) 
  FI. 
 
possibly append proc head for pproc: 
  IF opad lo = pproc ic lo 
  THEN out (proc head (pproc modno)) 
  FI. 
 
return ops: 
  fetch eumel0 regs of caller from users stack; 
  out ("--> ");
  put users flags; 
  IF (old flags AND aritu mask1) <> 0
  THEN put ("ARITU")
  ELSE put ("ARITS")
  FI;
  IF nontraceable caller 
  THEN line; putline ("trace ended by returning to nontraceable caller"); 
       protocol := FALSE; prot stopped := TRUE 
  ELIF users error AND NOT users stpdis
  THEN stop op
  ELSE set nail for return ops 
  FI. 
 
set nail for return ops: 
  IF word1 = rtn opcode 
  THEN nail1 hi := ic hi; nail1 lo := ic lo 
  ELSE nail1 hi := ic hi; nail1 lo := ic lo PLUS 1; 
       eval br addr (ic hi, ic lo, nail2 hi, nail2 lo); 
       no of nails := 2; set nail2 
  FI. 
 
penter op: 
  pbase := word1 AND lo byte mask; rotate (pbase, 8); 
  standard ops. 
  
line ops: 
  standard ops. 
 
stop ops: 
  IF word1 = estop opcode 
  THEN users stpdis := FALSE; 
       IF users error THEN stop op ELSE standard ops FI 
  ELIF word1 = dstop opcode 
  THEN users stpdis := TRUE; standard ops 
  ELSE stop op 
  FI. 
 
clrerr op:
  users error := FALSE; standard ops.

ke op: 
  skip instruction; 
  line; putline ("INFO: ke"); 
  info (stdds, ic hi, ic lo, info lines);
  single step := TRUE.

pp ops: 
  save modno and ic lo if pproc; 
  look at next instr; 
  WHILE iclass1 = 9 REP 
    ic lo INCR ilen; iname := iname1; ioplist := ioplist1; 
    ilen := ilen1; iclass := iclass1; 
    line; lines INCR 1;
    protocol this instr; 
    save modno and ic lo if pproc; (*only the first one will be saved!!!*) 
    look at next instr 
  PER; 
  standard ops. 
 
save modno and ic lo if pproc: 
  IF word1 = pproc opcode 
  THEN pproc modno := dsgetw (stdds, ic hi, ic lo PLUS 1); 
       IF pproc modno < 256 
       THEN putline ("*** this looks like a compiler error ***"); 
            protocol := FALSE; prot stopped := TRUE; users error := TRUE; 
            users errcode := 0; users errmsg := ("maybe a compiler error"); 
            LEAVE normal processing of instructions 
       ELIF (pproc modno AND mask 0400) <> 0 
       THEN word := (pproc modno AND mask fbff) OR mask 8000 
       ELSE word := pproc modno 
       FI; 
       pproc call := word OR opcode mask1; 
       pproc ic lo := dsgetw (stdds, packet area, m l t start + pproc modno) 
  FI. 
   
look at next instr: 
    word1 := dsgetw (stdds, ic hi, ic lo PLUS ilen); 
    disa (ic hi, ic lo PLUS ilen, iname1, ioplist1, ilen1, iclass1). 
 
wrong ops: 
  putline ("**** das kann ich (noch) nicht!!! ***"); 
  info (stdds, ic hi, ic lo, info lines); 
  protocol := FALSE. 
 
show registers: 
  pbase := dsgetw (stdds, stack area, lbase + 2) AND hi byte mask; 
  code addr modif := dsgetw (stdds, stack area, lbase + 3) 
                  AND lo byte mask; 
  putline ("----------------- EUMEL0-registers: ------------------"); 
  put ("icount=" CT txt (ic hi) CT hex (ic lo) CT 
       " lbase=1" CT hex (users lbase) CT " pbase=" CT hex (pbase)); 
  put users flags;
  IF (flags AND aritu mask1) <> 0
  THEN putline ("ARITU")
  ELSE putline ("ARITS")
  FI.

put users flags:
  IF users stpdis 
  THEN put ("STPDIS") 
  ELSE put ("STOPEN") 
  FI; 
  IF users error 
  THEN put ("ERROR") 
  ELSE put ("NOERR") 
  FI. 
 
ENDPROC trace; 
 
 
PROC stop op: 
  line; 
  suppress result protocolling; 
  REP outsubtext (blanks, 1, indentpos); 
      fetch eumel0 regs of caller from users stack; 
      out ("stop/error induced return to addr "); 
      out (txt (ic hi)); out (hex (ic lo)); 
      IF users stpdis 
      THEN putline (" (STPDIS)")
      ELSE putline (" (STOPEN)") 
      FI; 
      lines INCR 1;
      IF nontraceable caller 
      THEN putline ("trace ended by returning to nontraceable caller"); 
           protocol := FALSE; prot stopped := TRUE 
      ELIF users stpdis 
      THEN copy stack of disabled caller to tracers stack 
      ELSE users lbase := dsgetw (stdds, stack area, users lbase) 
      FI 
  UNTIL users stpdis OR NOT protocol PER; 
  nail1 hi := ic hi; nail1 lo := ic lo. 
 
suppress result protocolling: 
  no of results := 0. 
 
copy stack of disabled caller to tracers stack: 
  FOR i FROM 1 UPTO 4 REP 
    word := dsgetw (stdds, stack area, users lbase + i - 1); 
    dsputw (stdds, stack area, lbase + i - 1, word) 
  PER. 
 
ENDPROC stop op; 
 
 
i n i t i a l i z e   t r a c e. 
 
nontraceable caller: 
  ic hi = 2 AND NOT std procs traceable 
   OR (old flags AND aritu mask1) <> 0 AND (flags AND aritu mask1) = 0. 
 
fetch eumel0 regs of caller from users stack: 
  indentpos DECR indentincr; 
  ic lo := dsgetw (stdds, stack area, users lbase + 1); 
  word := dsgetw (stdds, stack area, users lbase + 2); 
  ic hi := word AND 3; 
  old flags := word AND flags mask1; 
  users stpdis := (old flags AND stpdis mask1) <> 0;
  pbase := word AND hi byte mask; 
  code addr modif := dsgetw (stdds, stack area, users lbase + 3) 
                     AND lo byte mask. 
 
initialize trace: 
  LET maxno of nontraceables = 20; 
  INT VAR int, j; 
  TEXT VAR text; 
  ROW maxno of nontraceables TEXT VAR names of nontraceables; 
  ROW maxno of nontraceables TEXT VAR names of short nontraceables; 
  ROW maxno of nontraceables TEXT VAR names of long nontraceables; 
  ROW maxno of nontraceables INT VAR calls to nontraceables; 
  ROW maxno of nontraceables INT VAR call2 to nontraceables; 

  putline("initializing ""trace"" ...");
  names of nontraceables (1) := "disa (I,I,T,T,I,I) (*n.t.*)"; 
  names of nontraceables (2) := "disasm (I,I) (*n.t.*)"; 
  names of nontraceables (3) := "info (I,I,I,I) (*n.t.*)";
  names of nontraceables (4) := "dec (T) (*n.t.*)"; 
  names of nontraceables (5) := "hex (I) (*n.t.*)"; 
  names of nontraceables (6) := "dsget2b (I,I,I) (*n.t.*)"; 
  names of nontraceables (7) := "trace (*ignored*)"; 
  trace; (* initialize 'call to trace', 'ic hi' and 'ic lo' *) 
  IF FALSE THEN 
     disa (int, int, text, text, int, int); 
     disasm (int, int); 
     info (int, int, int, int); 
     int := dec (text); 
     text := hex (int); 
     int  := dsget2b (int, int, int); 
     trace   (****** must be the last one !!! *****) 
   FI; 
   FOR j FROM 1 UPTO maxno of nontraceables REP 
     REP ic lo INCR 1; 
         word1 := dsgetw (stdds, ic hi, ic lo) 
     UNTIL call opcode found PER; 
     IF word1 <> longcall opcode 
     THEN no of nontraceables INCR 1; 
          calls to nontraceables (no of nontraceables) := word1; 
          names of short nontraceables (no of nontraceables) := 
               names of nontraceables (j)
     ELSE no of long nontraceables INCR 1; 
          word2 := dsgetw (stdds, ic hi, ic lo PLUS 1); ic lo INCR 1; 
          call2 to nontraceables (no of long nontraceables) := word2;
          names of long nontraceables (no of long nontraceables) := 
               names of nontraceables (j) 
     FI 
   UNTIL call to trace found 
         OR no of nontraceables = maxno of nontraceables 
         OR no of long nontraceables = maxno of nontraceables PER; 
   putline ("""trace"" initialized:");
   putline ("        " CT txt (no of nontraceables)
                       CT " nontraceable shortcalls");
   putline ("        " CT txt (no of long nontraceables)
                       CT " nontraceable longcalls"); 
   IF no of nontraceables = maxno of nontraceables 
      OR no of long nontraceables = maxno of nontraceables 
   THEN errorstop ("too many nontraceables") 
   ELSE test trace 
   FI. 
 
call opcode found: 
  (word1 AND opcode mask1) = call opcode OR word1 = longcall opcode. 
 
call to trace found: 
  IF word1 = call to trace 
  THEN IF longcall to trace flag 
       THEN word2 = call2 to trace 
       ELSE TRUE 
       FI 
  ELSE FALSE 
  FI. 
 
test trace:.

END PACKET trace;