external  string (255)fn  cliparam
string (255) s
integer  strad
  *SWI_16
  *STR_0,strad
  s = ""
  cycle 
    if  BYTE(strad)<=31 or  LENGTH(s)=255 then  exit 
    s = s.BYTE(strad)
    strad = strad+1
  repeat 
  result  = "" unless  s -> (" ").s
  result  = s {Command name stripped off}
end 

const  integer  blocked=0, avail=1

external  string (255) fn  ItoH(integer  i, pl)
constbytearray  HexByte(0:15) = '0', '1', '2', '3',
                                '4', '5', '6', '7',
                                '8', '9', 'a', 'b',
                                'c', 'd', 'e', 'f'
integer  shift
string (255) s = ""
  for  shift = 0, 4, pl*4-4 cycle 
    s = HexByte((i>>shift)&15).s
  repeat 
  result  = s
end 

const  integer  -
   Def Inst = 1,            { Instruction }
   Def Byte = 2,            { = byte      }
   Def Char = 4,            { = "chars"   }
   Def Word = 8,            { EQUD word   }
   Def Labelled = 16,       {DATA ...     }
   Def Branch Dest = 32,    {LAB  ...     }
   Def Call Dest = 64,      {PROC ...     }
   Def Access = 128         { B somewhere }

externalstring (255) fn   Instr Decode(integer  Pc, N)
   integer  CC, Type, Op, Rn, Rd, Shf, Shift, Imm, Offset, Operand
   integer  X, Y, Z, Printed = 0
   string (1) Sign
   switch  F(0:7), Fm(0:31)
   conststring (3)array  Fn(0:15) =  "AND", "EOR", "SUB", "RSB",
                                     "ADD", "ADC", "SBC", "RSC",
                                     "TST", "TEQ", "CMP", "CMN",
                                     "ORR", "MOV", "BIC", "MVN"
   conststring (2)array  Cond(0:15) = "EQ",  "NE",  "CS",  "CC",
                                      "MI",  "PL",  "VS",  "VC",
                                      "HI",  "LS",  "GE",  "LT",
                                      "GT",  "LE",    "",  "NV"

  string (255) result string = ""
  routine  Print string(string (255) s)
    result string = result string.s
  end 
  routine  space
    result string = result string." "
  end 
  routine  spaces(integer  n)
    result string = result string." " for  n = 1,1,n
  end 
  routine  print hex(integer  i, pl)
    result string = result string.itoh(i, pl)
  end 
  routine  print symbol(integer  i)
    result string = result string.i
  end 
  routine  Write(integer  i, pl)
    result string = result string.itos(i, pl)
  end 

   routine  Register(integer  N)
      if  N = 15 start 
         Printstring("PC")
      else 
         Printsymbol('R')
         Write(N, 0)
      finish 
   end 

   routine  F Register(integer  N)
       Printsymbol('F')
       Write(N, 0)
   end 

   routine  Put(string (255) S)
      Printstring(S)
      Printed = Printed+Length(S)
   end 

   routine  Show Label(integer  N)
      Printstring("L")
      Print Hex(N, 8)
   end 

   routine  Show Hex(integer  N, P)
      Printstring("&")
      Print Hex(N, P)
   end 

   routine  Show Shift(integer  Shift, Reg)
      integer  X, Y, Rs
      string (3) S
      switch  Sh(0:7)
      Register(Reg)
      return  if  Shift = 0
      Y = Shift>>3
      X = Shift&7
      Space
      ->Sh(X)
Sh(1):  S = "LSL";  ->Sh2
Sh(3):  S = "LSR";  ->Sh2
Sh(5):  S = "ASR";  ->Sh2
Sh(7):  S = "ROR";  ->Sh2
Sh2:    Rs = Shift>>4
        Printstring(S);  Space;  Register(Rs);  return 
Sh(0):  S = "LSL";  ->Sh1
Sh(2):  S = "LSR";  ->Sh1
Sh(4):  S = "ASR";  ->Sh1
Sh(6):  S = "ROR";  S = "" if  Y = 0
Sh1:    if  S = "" start 
           Printstring("RRX")
        else 
           Printstring(S);  Printstring(" #");  Write(Y, 0)
        finish 
   end 

   routine  Show Constreg(integer  N)
      integer  X
      X = N&7
      if  N&8 = 0 start 
         F Register(X)
      else 
         if  X <= 5 start 
            Write(X, 0);  Printstring(".0")
         else  if  X = 6
            Printstring("0.5")
         else 
            Printstring("10.0")
         finish 
      finish 
   end 

   Printed = 0
   CC   = N>>28
   Type = N>>25&7
   Rd   = (N>>12)&15
   Rn   = (N>>16)&15
   ->F(Type)

F(2_000):
F(2_001):   Op = (N>>21)&15
            Shf = (N>>8)&15
            Shift = (N>>4)&255
            Put(Fn(Op));  Put(Cond(CC))
            Put("S") if  N&2_0000 000 0000 1 0000 0000 000000000000 # 0
            Put("P") if  Rd = 15 and  8 <= Op <= 11
            Spaces(8-Printed)
            Register(Rd) and  Printstring(", ") unless  8 <= Op <= 11
            Register(Rn) and  Printstring(", ") if  Op # 13 and  Op # 15
            if  N&16_0200 0000 # 0 start     {Shf Imm}
               X = 2*Shf
               Imm = N&255
               if  X > 8 start 
                  X = X-8
                  Y = (Imm<<24)>>X
               else 
                  Y = (Imm<<(32-X)) ! (Imm>>X)
               finish 
               Printstring("#")
               if  -16_FFFF <= Y <= 16_FFFF start 
                  if  ' ' <= Y <= 126 start 
                     Write(Y, 0)
                     Printstring("; '")
                     Printsymbol(Y)
                     Printsymbol('''')
                  else 
                    Write(Y, 0)
                  finish 
               else 
                 Show Hex(Y, 8)
               finish 
            else                            {Shift Rm}
               Show Shift(Shift, N&15)
            finish 
            ->Done


F(2_010):
F(2_011):   Type = N>>24&15
            if  N&16_0010 0000 = 0 then  Put("STR") else  Put("LDR")
            Put(Cond(CC))
            Put("B") if  N&16_0040 0000 # 0
            Put("T") if  N&16_0020 0000 # 0 and  Type&1 = 0
            Spaces(8-Printed)
            Register(Rd)
            Printstring(", ")
            Offset = N&4095
            Sign = "";  Sign = "-" if  N&16_0080 0000 = 0
            Printsymbol('[');  Register(Rn)
            if  Type = 2_0100 start 
               Printsymbol(']')
               if  Offset # 0 start 
                  Printstring(", #");  Printstring(Sign);  Show Hex(Offset, 3)
               finish 
            else  if  Type = 2_0101
               if  Offset # 0 start 
                  Printstring(", #");  Printstring(Sign);  Show Hex(Offset, 3)
               finish 
               Printsymbol(']')
               Printsymbol('!') if  N&16_0020 0000 # 0
            else  if  Type = 2_0110
               Printstring("]")
               if  Offset # 0 start 
                  Printstring(", ")
                  Printstring(Sign)
                  Show Shift(Offset>>4, N&15)
               finish 
            else {%if Type = 2_0111}
               Printsymbol(',')
               Printstring(Sign)
               Show Shift(Offset>>4, N&15)
               Printsymbol(']')
               Printsymbol('!') if  N&16_0020 0000 # 0 and  Offset # 0
            finish 
            ->Done

F(2_100):   if  N&16_0010 0000 = 0 then  Put("STM") else  Put("LDM")
            Put(Cond(CC))
            X = N>>23&3
            if  X&1 # 0 then  Put("I") else  Put("D")
            if  X&2 # 0 then  Put("B") else  Put("A")
            Spaces(8-Printed)
            Register(Rn)
            Printsymbol('!') if  N&16_0020 0000 # 0
            Y = 1
            Z = 1
            Printstring(", {")
            for  X = 0, 1, 15 cycle 
               if  N&Y # 0 start 
                  Printsymbol(',') if  Z = 0
                  Register(X)
                  Z = 0
               finish 
               Y = Y<<1
            repeat 
            Printsymbol('}')
            Printsymbol('^') if  N&16_0040 0000 # 0
            ->Done

F(2_101):   Put("B");  Put("L") if  N&16_0100 0000 # 0
            Put(Cond(CC))
            Spaces(8-Printed)
            X = N&16_00FF FFFF
            X = X!16_FF00 0000 if  X&16_0080 0000 # 0
            Show Label(Pc+(2+X)*4)
            ->Done

F(2_110):   if  N&16_0010 0000 = 0 then  Put("STF") else  Put("LDF")
            Put(Cond(CC))
            if  N&16_0040 0000 = 0 start 
               if  N&16_0000 8000 = 0 then  Put("S") else  Put("D")
            else 
               if  N&16_0000 8000 = 0 then  Put("E") else  Put("P")
            finish 
            Spaces(8-Printed)
            F Register(N>>12&7)
            Printstring(", [")
            Register(N>>16&15)
            X = (N&255)<<2
            if  N&16_0100 0000 = 0 start 
               Printstring("]")
               if  X # 0 start 
                  Printstring(", #")
                  Printsymbol('-') if  N&16_0080 0000 = 0
                  Show Hex(X, 3)
               finish 
            else 
               if  X # 0 start 
                  Printstring(", #")
                  Printsymbol('-') if  N&16_0080 0000 = 0
                  Show Hex(X, 3)
               finish 
               Printstring("]")
            finish 
            Printsymbol('!') if  N&16_0020 0000 # 0
            ->Done

F(2_111):   if  N&16_0100 0000 # 0 start 
               Put("SWI");  Put(Cond(CC));  Spaces(8-Printed)
               Show Hex(N&16_00FF FFFF, 6)
               ->Done
            finish 
            unless  N>>8&15 = 1 start 
              Print string("EQUD    "); Show Hex(N,8)
              -> Done
            finish 

            {this leaves the floating point stuff}

            if  N&16_0000 0010 = 0 start      {CPDO}
               X = (N>>19)&2_11110 ! (N>>15)&1
               ->Fm(X)
Fm(2_00000):     Put("ADF");  ->FnOP
Fm(2_00010):     Put("MUF");  ->FnOP
Fm(2_00100):     Put("SUF");  ->FnOP
Fm(2_00110):     Put("RSF");  ->FnOP
Fm(2_01000):     Put("DVF");  ->FnOP
Fm(2_01010):     Put("RDF");  ->FnOP
Fm(2_01100):     Put("POW");  ->FnOP
Fm(2_01110):     Put("RPW");  ->FnOP
Fm(2_10000):     Put("RMF");  ->FnOP
Fm(2_10010):     Put("FML");  ->FnOP
Fm(2_10100):     Put("FDV");  ->FnOP
Fm(2_10110):     Put("FRD");  ->FnOP
Fm(2_11000):     Put("POL");  ->FnOP

FnOP:          Put(Cond(CC))
               if  N&16_0008 0000 = 0 start 
                  if  N&16_0000 0080 = 0 then  Put("S") else  Put("D")
               else 
                  if  N&16_0000 0080 = 0 then  Put("E") else  Put("?")
               finish 
               X = N>>5&3
               if  X # 0 start 
                  if  X = 2_01 then  Put("P") else  -
                  if  X = 2_10 then  Put("M") else  Put("Z")
               finish 
               Spaces(8-Printed)
               F Register(N>>12&7)
               Printstring(", ")
               F Register(N>>16&7)
  Op Rest:     Printstring(", ")
               Show ConstReg(N&15)
               ->Done

Fm(2_00001):     Put("MVF");  ->FnOP1
Fm(2_00011):     Put("MNF");  ->FnOP1
Fm(2_00101):     Put("ABS");  ->FnOP1
Fm(2_00111):     Put("RND");  ->FnOP1
Fm(2_01001):     Put("SQT");  ->FnOP1
Fm(2_01011):     Put("LOG");  ->FnOP1
Fm(2_01101):     Put("LGN");  ->FnOP1
Fm(2_01111):     Put("EXP");  ->FnOP1
Fm(2_10001):     Put("SIN");  ->FnOP1
Fm(2_10011):     Put("COS");  ->FnOP1
Fm(2_10101):     Put("TAN");  ->FnOP1
Fm(2_10111):     Put("ASN");  ->FnOP1
Fm(2_11001):     Put("ACS");  ->FnOP1
Fm(2_11011):     Put("ATN");  ->FnOP1

Fm(*):           Put("???")

FnOP1:         Put(Cond(CC))
               if  N&16_0008 0000 = 0 start 
                  if  N&16_0000 0080 = 0 then  Put("S") else  Put("D")
               else 
                  if  N&16_0000 0080 = 0 then  Put("E") else  Put("?")
               finish 
               X = N>>5&3
               if  X # 0 start 
                  if  X = 2_01 then  Put("P") else  -
                  if  X = 2_10 then  Put("M") else  Put("Z")
               finish 
               Spaces(8-Printed)
               F Register(N>>12&7)
               ->Op Rest
            else  if  N&16_0010F000 = 16_0010F000  {CPST}
               X = N>>21&7
               if  X = 2_100 start 
                  Put("CMF")
               else  if  X = 2_101
                  Put("CNF")
               else  if  X = 2_110
                  Put("CMFE")
               else  if  X = 2_111
                  Put("CNFE")
               else 
                  Put("???")
               finish 
               Put(Cond(CC))
               Spaces(8-Printed)
               F Register(N>>16&7)
               ->Op Rest
            else                        {CPRT}
               X = N>>20&15
               if  X = 0 start 
                  Put("FLT")
               else  if  X = 1
                  Put("FIX")
               else  if  X = 2
                  Put("WFS")
               else  if  X = 3
                  Put("RFS")
               else  if  X = 4
                  Put("WFC")
               else  if  X = 5
                  Put("RFC")
               else 
                  Put("???")
               finish 
               Put(Cond(CC))
               if  N&16_0008 0000 = 0 start 
                  if  N&16_0000 0080 = 0 then  Put("S") else  Put("D")
               else 
                  if  N&16_0000 0080 = 0 then  Put("E") else  Put("?")
               finish 
               Y = N>>5&3
               if  Y # 0 start 
                  if  Y = 2_01 then  Put("P") else  -
                  if  Y = 2_10 then  Put("M") else  Put("Z")
               finish 
               Spaces(8-Printed)
               if  X = 0 start        {FLT}
                  F Register(N>>16&7)
                  Printstring(", ")
                  Register(N>>12&15)
               else  if  X = 1        {FIX}
                  Register(N>>12&15)
                  Printstring(", ")
                  Show Constreg(N&15)
               else 
                  Register(N>>12&15)
               finish 
            finish 

Done:
  result  = Result string
end 

!###########################################################################

const  integer  Data = 0, Instr = 1, B = 2, BL = 4, Swi = 8

externalintegerfn  Get Simple Type(integer  Pc, N, integer  name  Dest, Access)
const  integer  Always = 14, AddOp=4, MovOp = 1, pcreg = 15
   integer  CC, Type, Op, Rn, Rd, Rs, Shf, Shift, Imm, Offset, Operand
   integer  X, Y, Z
   switch  F(0:7), Fm(0:31)

   Access = Avail

   CC   = N>>28
   Type = N>>25&7
   Rd   = (N>>12)&15
   Rn   = (N>>16)&15
   ->F(Type)

   F(2_000): F(2_001):
   !%begin
     Op = (N>>21)&15
     if  (Op=AddOp or  Op=MovOp) and  Rd=pc reg and  cc=always start 
       Access = blocked
     finish 
     if  op#13 and  op#15 and  c 
         Rd=pc reg and  Rn#pc reg and  cc=always then  access=blocked

     if  N&16_0200 0000 = 0 start 
       Shift = (N>>4)&255
       Rs = Shift >> 4
       result =Data if  Rs=pc reg and  Shift&1 # 0
     finish 

     result  = Instr
   !%end

   F(2_010): F(2_011):
   !%begin
     result =Instr
   !%end

   F(2_100):
   !%begin
     if  N&16_0000 ffff = 0 then  result =Data ;! LDM Rn!,{} for instance
     if  N&16_0010 0000 = 0 then  result =Instr
     if  N&(1<<15)#0 and  cc=always then  Access=blocked
     result  = Instr
   !%end

   F(2_101):
   !%begin
     Type = B;  Type = BL if  N&16_0100 0000 # 0
     X = N&16_00FF FFFF
     X = X!16_FF00 0000 if  X&16_0080 0000 # 0
     Dest = Pc+(2+X)*4
     if  type=B and  CC=Always then  Access=Blocked
     result  = Type
   !%end

   F(2_110):
   !%begin
     result  = Instr
   !%end

   F(2_111):
   !%begin
     if  N&16_0100 0000 # 0 start 
       Dest = N&16_00FF FFFF
       result  = SWI
     finish 

     result  = Data if  N>>8&15 # 1

     {this leaves the floating point stuff}

     if  N&16_0000 0010 = 0 start      {CPDO}
       -> Fm((N>>19)&2_11110 ! (N>>15)&1)

       Fm(2_00000): Fm(2_00010): Fm(2_00100): Fm(2_00110):
       Fm(2_01000): Fm(2_01010): Fm(2_01100): Fm(2_01110):
       Fm(2_10000): Fm(2_10010): Fm(2_10100): Fm(2_10110):
       Fm(2_11000):

       Fm(2_00001): Fm(2_00011): Fm(2_00101): Fm(2_00111):
       Fm(2_01001): Fm(2_01011): Fm(2_01101): Fm(2_01111):
       Fm(2_10001): Fm(2_10011): Fm(2_10101): Fm(2_10111):
       Fm(2_11001): Fm(2_11011):

       if  N&16_0008 0000 # 0 and  c 
           N&16_0000 0080 # 0 then  result =Data
       result  = Instr

       Fm(*):
       result =Data

     else  if  N&16_0010F000 = 16_0010F000  {CPST}
       X = N>>21&7
       result  = Data unless  2_100 <= X <= 2_111
       result  = Instr

     else                        {CPRT}
       X = N>>20&15
       result  = Data unless  0 <= X <= 5
       if  N&16_0008 0000 # 0 and  c 
           N&16_0000 0080 # 0 then  result  = Data
       result  = Instr
     finish 
   !%end
end 
!###########################################################################

external  predicate   Valid Instr(integer  PC)
  integer  Type, Dest, Access
  Type = Get Simple type(PC, INTEGER(PC), Dest, Access)
  if  Type#Data then  true  else  false 
end 

begin 
routine   Decode(integer  from, to, start, end)
byte  array  tag(from:to)

  routine  Text(string (255) S)
    print string(S)
    newline
  end 

  string (4) fn  sanitised(integer  is)
    string  (4) s = ""
    integer  i

    i = (is)&255
    i = '.' unless  ' '<=i<='~'; s = s.i

    i = (is >> 8)&255
    i = '.' unless  ' '<=i<='~'; s = s.i

    i = (is >> 16)&255
    i = '.' unless  ' '<=i<='~'; s = s.i

    i = (is >> 24)&255
    i = '.' unless  ' '<=i<='~'; s = s.i

    result =s
  end 

  routine  Print Decode(integer  from, to)

    predicate  pr(integer  a)
      true  if  ' '<=BYTE(a)<='~'
      false 
    end 

    string (255) fn  CharStr(integer  a)
      string (255) guts
          if  tag(a)&Def char#0 and  pr(a) start 
            guts  = """".BYTE(a).""""
          else 
            guts  = itos(BYTE(a), 0)
            guts  = " ".guts while  LENGTH(guts)<3
          finish 
      result  = guts
    end 
    string (10) Lab
    string (255) Guts
    const  integer  max guts = 50
    integer  a = from, type, dest, access
    cycle 
      if  tag(a)&Def labelled#0 start 
        if  tag(a)&Def Call Dest#0 then  lab = "P" -
        else  if  tag(a)&Def Branch Dest#0 then  Lab = "L" -
        else  lab = "D"
        Lab = Lab.Itoh(a, 8)." "
      else 
        Lab = "          "
      finish 

      if  tag(a)&Def Inst#0 start 
        guts = Instr decode(a, INTEGER(a))
        Type = Get Simple type(a, INTEGER(a), Dest, Access)
        if  Type&(B!BL)#0 start 
          unless  from <= dest <= to start 
            guts = guts."   ; Outside module???"
          finish 
        finish 
        guts <- guts."                                                "
      elseif  tag(a)&Def Word#0
        guts = "EQUD    &".itoh(INTEGER(a),8)."                       ".
                                "                                     "
      elseif  tag(a)&(Def Byte!Def Char)#0
        guts = "=       "
        if  pr(a) and  pr(a+1) and  pr(a+2) and  pr(a+3) start 
          guts = "=       """.BYTE(a).BYTE(a+1).BYTE(a+2).BYTE(a+3).""""
        else 
          guts = guts.CharStr(a).", "
          guts = guts.CharStr(a+1).", "
          guts = guts.CharStr(a+2).", "
          guts = guts.CharStr(a+3)
        finish 
        guts = guts."                                                "
        LENGTH(guts) = 20
      else 
        ! Unknown - could be data or instr...
        if  Valid Instr(a) start 
          guts = Instr decode(a, INTEGER(a))
          guts <- guts."                                            "
        else 
          guts = "EQUD    &".itoh(INTEGER(a),8)."                      ".
                                   "                                "
        finish 
        LENGTH(guts) = Max guts-6
        guts = guts."; ".sanitised(INTEGER(a))
      finish 
      LENGTH(guts) = max guts
      text(Lab.guts."; ".itoh(a,7).": ".itoh(INTEGER(a),8))
      a = a+4
      return  if  a >= to
    repeat 

  end 

  string (255) fn  StringAt(integer  Str addr)
    string  (255) Title
    Title = ""
    cycle 
      if  BYTE(Str addr)=0 then  result =Title
      Title = Title.BYTE(Str addr)
      Str addr = Str addr+1
    repeat 
  end 

  routine  Mark string(integer  str start)
    return  if  BYTE(str start)=0
    tag(str start) = tag(str start)!Def labelled
    cycle 
      tag(str start) = tag(str start)!Def Char
      if  BYTE(str start) = 0 then  tag(Str start)=tag(Str start)! c 
                                                     Def byte and  return 
      str start=str start+1
    repeat 
  end 

  routine  Mark word(integer  ad)
    tag(ad) = tag(ad)!Def word
    tag(ad+1) = Def word
    tag(ad+2) = Def word
    tag(ad+3) = Def word
  end 

  routine  Mark Byte(integer  ad)
    tag(ad) = tag(ad)!Def Byte
  end 

  routine  Mark Jump(integer  ad)
    tag(ad) = tag(ad)!Def Inst!Def Labelled!Def Branch dest
  end 

  routine  Mark Proc(integer  ad)
    tag(ad) = tag(ad)!Def Inst!Def Labelled!Def Call dest
  end 

  routine  spec  Decode Branch Search(integer  Entry, From, To)
  routine  spec  Decode Proc Search(integer  Entry, From, To)

  routine  Decode Search(integer  Entry, from, to)
    integer  Type, Dest, Access=avail
    return  unless  From <= Entry < To and  Entry&3=0
    return  if  tag(Entry)&Def Inst#0 {Already searched}
    cycle 
      exit  if  tag(Entry)&(Def Char!Def Byte!Def Inst)#0 or  Entry >= To
      Type = Get Simple type(Entry, INTEGER(Entry), Dest, Access)
      if  Type=Data then  start 
        ! Somehow missed end of instr seq.
        ! Backtrack and undo?
        return 
      finish 
      tag(Entry) = tag(Entry)!Def Inst
      if  Type&B # 0 start 
        unless  from <= dest < To start 
!!!          tag(Entry) = tag(Entry)&(\Def Inst)
!!!          %return
        finish 
        Decode Branch Search(dest, from, to)
        tag(entry)=tag(Entry)!Def access and  return  if  Access=blocked
        Entry = Entry+4
      else  if  Type&BL # 0
        unless  from <= dest < To start 
!!          tag(Entry) = tag(Entry)&(\Def Inst)
!!          %return
        finish 
        Decode Proc Search(dest, from, to)
        Entry = Entry+4
      else  if  Type&SWI # 0
        if  Dest&(\16_20000)=1 start 
          ! Skip in-line string
          tag(Entry)=tag(Entry)!Def access
          Entry=Entry+4
          Mark String(Entry)
          while  BYTE(Entry)#0 cycle 
            Entry = Entry+1
          repeat 
          Entry = (Entry+4)&(\3)
        else 
          Entry = Entry + 4
        finish 
      else 
        tag(entry)=tag(Entry)!Def access and  return  if  Access=blocked
        Entry = Entry+4
      finish 
    repeat 
  end 

  routine  Decode Branch Search(integer  Entry, From, To)
    return  unless  From <= Entry <= To and  Entry&3=0
    tag(Entry) = tag(Entry)!Def labelled!Def branch dest
    Decode Search(Entry, From, To)
  end 

  routine  Decode Proc Search(integer  Entry, From, To)
    return  unless  From <= Entry <= To and  Entry&3=0
    tag(Entry) = tag(Entry)!Def labelled!Def call dest
    Decode Search(Entry, From, To)
  end 

  predicate  Decode Title String(integer  Str addr, string (*) name  Title)
    Title = ""
    cycle 
      if  BYTE(Str addr)=0 then  true 
      unless  '!' <= BYTE(Str addr) <= '~' then  false 
      Title = Title.BYTE(Str addr)
      Str addr = Str addr+1
    repeat 
  end 

  predicate  Decode Help String(integer  Str addr, integer  name  Help length)
    Help length = 0
    cycle 
       if  BYTE(Str addr) = 0 then  true 
       if  BYTE(Str addr) >= 127 then  false 
       str addr = Str addr+1; Help length = Help length+1
    repeat 
  end 

  routine  Decode Help Table(integer  Start)
  record  format   Help info fm(integer  code,
                                byte  min params, flags0, max params, flags 1,
                                integer  syntax, text)
  string (255) fn   Params(integer  Low, High)
    result  = "" if  low=High=0
    result  = " (".itos(High,0)." param)" if  low=high=1
    result  = " (".itos(High,0)." params)" if  low=high
    result  = " (".itos(low,0)."-".itos(high,0)." params)" 
  end 

  record  (Help info fm) name  Help info
  string  (255) Help param
    cycle 
      Help param = StringAt(Start)
      Mark string(start)
      return  if  Help param = ""
      Start = (Start + LENGTH(Help param) + 1 + 3) & (\3)
      Help info == RECORD(Start)
      Mark Word(start)
      Mark Byte(start+4); Mark Byte(start+5)
      Mark Byte(start+6); Mark Byte(start+7)
      Mark word(start+8); Mark word(start+12)
      if  Help info_code = 0 start 
        Text("Help on: ".help param.
             Params(Help info_min params,
                    Help info_max params))
      else 
        Decode proc search(from+Help info_code, from, to)
        Text("Entry:   ".help param.
             Params(Help info_min params,
                    Help info_max params))
      finish 
      Mark string(from+Help info_syntax)
      Mark string(from+Help info_text)
      start = start+16
    repeat 
  end 

  routine  Decode SWI Table(integer  Start)
    cycle 
      cycle 
        exit  if  BYTE(Start)=0
        tag(Start)=Def char
        Start=Start+1
      repeat 
      tag(Start)=tag(start)!Def char
      Start=Start+1
    repeat  until  BYTE(start)=0
    tag(start)=tag(start)!Def char
  end 

  routine  Scan branches(integer  from, to)
  integer  address, Type, Dest, Access
    for  address = From, 4, To-4 cycle 
      if  tag(address)!tag(address+1)!tag(address+2)!tag(address+3)=0 start 
        Type = Get Simple type(address, INTEGER(address), Dest, Access)
        if  Type&(B!BL)#0 start 
          if  from < dest <= to and  Access=Blocked start 
            tag(address)=tag(address)!Def Inst
            Decode branch search(Dest, from, to)
          else 
! Leave undecided...  tag(address)=tag(address)!Def word
          finish 
        finish 
      finish 
    repeat 
  end 

  predicate  stringch(integer  i)
    i = BYTE(i)
    true  if  i=0 or  i=10 or  i=13 or  ' '<=i<='~'
    false 
  end 

  routine  Scan strings(integer  from, to)
  integer  a, Type, Dest, Access
    for  a = From, 4, To-4 cycle 
      if  tag(a)!tag(a+1)!tag(a+2)!tag(a+3)=0 start 
        if  stringch(a-4) and  stringch(a-3) c 
        and  stringch(a-2) and  stringch(a-1) c 
        and  stringch(a) and  stringch(a+1) c 
        and  stringch(a+2) and  stringch(a+3) c 
        and  stringch(a+4) and  stringch(a+4) c 
        and  stringch(a+6) and  stringch(a+7) c 
        start 
          if  INTEGER(a)=0 then  tag(a)=tag(a)!Def Word else  start 
            tag(a)=tag(a)!Def Char;tag(a+1)=tag(a+1)!def char
            tag(a+2)=tag(a+2)!Def Char;tag(a+3)=tag(a+3)!def Char
          finish 
          if  BYTE(a+2)=BYTE(a+3)=0 then  tag(a)=tag(a)!Def Word
        finish 
      finish 
    repeat 
  end 

  routine  Scan data(integer  from, to)
  integer  a
    for  a = From, 4, To-4 cycle 
      if  tag(a)!tag(a+1)!tag(a+2)!tag(a+3)=0 start 
        if  16_ffff0000 <= INTEGER(a) <= 16_0000ffff start 
          tag(a) = Def Word
        finish 
      finish 
    repeat 
  end 

  routine  Confirm(integer  first, last, from, to)
    ! if all the words between first and last can take the
    ! same type as them, set them to that...
  end 

  routine  Patch up alternatives(integer  from, to)
  integer  a, start
    for  a = From, 4, To-4 cycle 
      if  tag(a)!tag(a+1)!tag(a+2)!tag(a+3)=0 start 
        start=a+4
        while  tag(start)!tag(start+1)!tag(start+2)!tag(start+3)=0 cycle 
          start=start+4
        repeat 
        Confirm(a-4, start, from, to)
      finish 
    repeat 
  end 

  predicate   printable(integer  ad)
    true  if  ' ' <= BYTE(ad) <= '~'
    false 
  end 

  predicate   all printable(integer  ad)
    if  printable(ad) and  printable(ad+1) c 
    and  printable(ad+2) and  printable(ad+3) then  true 
    false 
  end 

  routine  Undo wrong instructions(integer  From, to)
  integer  Dest, Access, Type, a
    for  a = to-4, -4, from+4 cycle 
      if  tag(a)&Def Char#0 and  tag(a-4)=0 start 
        Type = Get Simple type(a-4, INTEGER(a-4), Dest, Access)
        if  Type&(Instr!BL)#0 and  access#blocked start 
          tag(a-4) = Def Char
        finish 
        continue 
      elseif  tag(a)&def char#0 and  tag(a-4)&Def word#0
        tag(a-4) = tag(a-4)&(\Def Word)!Def char if  all printable(a-4)
      elseif  tag(a)&Def Word#0 and  tag(a-4)=0
        Type = Get Simple type(a-4, INTEGER(a-4), Dest, Access)
        if  Type&(Instr!BL!SWI)#0 and  access#blocked start 
          if  all printable(a-4) start 
            tag(a-4) = Def Char
          else 
            tag(a-4) = Def Word
          finish 
        finish 
        continue 
      finish 
      if  (tag(a)&Def Inst=0 or  (tag(a)=0 and  not  valid instr(a))) c 
       and  (tag(a-4)=0 or  c 
       (tag(a-4)&Def Inst#0 {%and Dubious branch})) start 
        ! if a-4 can drop through then it is not an instr...
        ! Give it DATA?
        Type = Get Simple type(a-4, INTEGER(a-4), Dest, Access)
        if  Type&Data=0 c 
        and  Access#blocked and  tag(a-4)&Def Labelled#0 start 
          tag(a)=Def Word if  tag(a)=0
          tag(a-4)=tag(a-4)&(\Def Inst)!(tag(a)&(Def char!Def Word!Def Byte))
        finish 
      finish 
    repeat 
  end 

  routine  Grab more strings(integer  from, to)
  integer  a
    for  a = from, 4, to-4 cycle 
      if  tag(a) & Def char # 0 and  tag(a+4) & Def word # 0 start 
        if  all printable(a+4) start 
          tag(a+4) = tag(a+4) & (\def word) ! def char
        finish 
      finish 
    repeat 
  end 

  routine  Set any illegal instrs to DATA(integer  from, to)
  integer  a
    for  a = from, 4, to cycle 
      if  tag(a)=0 and  tag(a+1)=0 and  tag(a+2)=0 and  tag(a+3)=0 start 
        if  not  valid instr(a) then  tag(a)=Def Word
      finish 
    repeat 
  end 

  integer  i
  tag(i) = 0 for  i = from, 1, to

  ! Determine type - module or file: Follow entry points as appropriate.
  record  format  Module Header Fm( c 
    integer  Start Code, Init Code, Final Code, Service Handler,
             Title String, Help String, Help table, SWI Chunk,
             SWI Handler, SWI Table, SWI Decode)
  record  (Module Header Fm) name  Module Header

  integer  Code extent = to - from

  Module Header == RECORD(from)

  if   0 <= Module Header_Init Code  < Code extent c 
  and  0 <= Module Header_Final Code < Code extent c 
  and  0 <= Module Header_Service Handler < Code extent c 
  and  0 <= Module Header_Title String < Code extent c 
  and  0 <= Module Header_Help String < Code extent c 
  and  0 <= Module Header_Help Table  < Code extent c 
  then  start 

    ! Good chance of it being a module.

    string  (255) Title

    if  Decode Title String(from+Module Header_Title String, Title) start 
      Mark string(from+Module Header_title string)
      Text("*** Decoding relocatable module '".Title."' ***")
    else 
      Text("*** This appears to be a module but the title string is invalid")
    finish 

    Mark Word(i) for  i = from, 4, from+16_18

    integer  Help Length
    if  Decode Help String(from+Module Header_Help String, Help Length) start 
      Mark string(from+Module Header_Help String)
      ! Help text marked. Possibly also print here too...
    finish 

    if  Module Header_Help Table#0 start 
      Decode Help Table(from+Module Header_Help Table)
      ! Table entries marked appropriately; entry points recursively decoded
    finish 

    if  Module Header_SWI Handler < Code extent start 
      if  Module Header_SWI Handler#0 c 
      and  Module Header_SWI Handler&2_11111100 00000000 00000000 00000011=0 c 
      then  start 
        Mark Word(ADDR(Module Header_SWI Handler))
        Decode Proc Search(from+Module header_SWI Handler, from, to)
      finish 

      ! Only list SWI no's if SWIs valid.
      if  Module Header_SWI Chunk&2_11111111 00000000 00000000 00011111=0 c 
      then  start 
        Mark Word(ADDR(Module Header_SWI Chunk))
        Text("Module handles SWIs from ".
              itoh(Module Header_SWI Chunk,6)." to ".
              itoh(Module Header_SWI Chunk+64-1,6))
      finish 

    if  Module Header_SWI Table < Code extent start 
      if  Module Header_SWI Table#0 c 
      and  Module Header_SWI Table&2_11111100 00000000 00000000 00000011=0 c 
      then  start 
        Mark Word(ADDR(Module Header_SWI Table))
        Decode SWI Table(from+Module Header_SWI Table)
      finish 

    if  Module Header_SWI Decode < Code extent start 
      if  Module Header_SWI Decode#0 c 
      and  Module Header_SWI decode&2_11111100 00000000 00000000 00000011=0 c 
      then  start 
        Mark Word(ADDR(Module Header_SWI Decode))
        Decode Proc Search(from+Module header_SWI Decode, from, to)
      finish 

    finish ;finish ;finish 

    ! do main entry last as it is special...

    if   0 < Module Header_Start Code < Code extent start 
      Text("Entry point is offset.")
      Decode Proc Search(from+Module header_Start Code, from, to)
    elseif  Module header_start code = 0
      ! No language entry
    else 
      if  Valid Instr(from) start 
        Decode Proc Search(from, from, to)
        ! First word is an instruction, not an offset
      else 
        Text("*** First word not valid instruction ***")
      finish 
    finish 
    Decode Proc Search(from+Module header_Init Code, from, to) c 
      unless  Module header_Init Code=0
    Decode Proc Search(from+Module header_Final Code, from, to) c 
      unless  Module header_Final Code=0
    Decode Proc Search(from+Module header_Service Handler, from, to) c 
      unless  Module header_Service Handler=0
  else 
    ! Probably not a module - treat as a file
    Decode Proc Search(from, from, to)
  finish 

  Scan branches(From, to)
  Scan strings(From, to)
  Scan data(from, to)
  Undo wrong instructions(from, to) {Inst (not jump) followed by Data}
  Grab more strings(from, to)
  Set any illegal instrs to DATA(from, to)
  Undo wrong instructions(from, to) {Iterative process!}
  Patch up alternatives(from, to)   {If DATA, data!inst, DATA then DATA}
  Undo wrong instructions(from, to) {Iterative process!}
  Print decode(start, end)

end 

! Decode (Module/code start, Module/code end, decode start, decode end)
! decode(16_8000, 16_DA50, 16_8000, 16_DA50)
string (255) s = cli param

  if  s = "MOS" start 
    decode(16_3800000, 16_380837C, 16_3800000, 16_380837C)
  elseif  s = "NFS"
    decode(16_18B2A64, 16_18C9304, 16_18B2A64, 16_18C9304)
  elseif  s = "UtilityModule"
    decode(16_3806428, 16_38195E8, 16_3806428, 16_38195E8)
  elseif  s = "FileSwitch"
    decode(16_38195E8, 16_381EC34, 16_38195E8, 16_381EC34)
  elseif  s = "BASIC"
    decode(16_381EC34, 16_382A5C4, 16_381EC34, 16_382A5C4)
  elseif  s = "ADFS"
    decode(16_382A5C4, 16_38325A4, 16_382A5C4, 16_38325A4)
  elseif  s = "Econet"
    decode(16_38325A4, 16_3834184, 16_38325A4, 16_3834184)
  elseif  s = "NetFS"
    decode(16_3834184, 16_3837F60, 16_3834184, 16_3837F60)
  elseif  s = "WindowManager"
    decode(16_3837F60, 16_383C558, 16_3837F60, 16_383C558)
  elseif  s = "SpriteUtils"
    decode(16_383C558, 16_383CE30, 16_383C558, 16_383CE30)
  elseif  s = "SoundDMA"
    decode(16_383CE30, 16_383D8A8, 16_383CE30, 16_383D8A8)
  elseif  s = "SoundChannels"
    decode(16_383D8A8, 16_383ED58, 16_383D8A8, 16_383ED58)
  elseif  s = "SoundScheduler"
    decode(16_383ED58, 16_383F588, 16_383ED58, 16_383F588)
  else 
    if  s # "" and  s#"-help" then  print string("Error: a") else  print string("A")
    print string(c 
"llowed parameters are:

  NFS
  MOS           UtilityModule FileSwitch ADFS          Econet         NetFS
  WindowManager SpriteUtils   SoundDMA   SoundChannels SoundScheduler

")
  finish 
endofprogram