%include "inc:util.imp" {for PAM}

%begin  {ARM disassembler - RWT October 1988}

%integer pc=0,op

%routine cond
%conststring(2)%array c(0:15)=
"EQ","NE","CS","CC","MI","PL","VS","VC",
"HI","LS","GE","LT","GT","LE","","NV"
  printstring(c(op>>28))
%end

%routine lit(%integer n)
  printsymbol('#')
  %if -4095<=n<=4095 %then write(n,0) %elsestart
    printstring("16_"); phex(n)
  %finish
%end

%routine register(%integer n)
  n = op>>n&15
  %if n=15 %then printstring("PC") %else-
  %if n=14 %then printstring("LINK") %elsestart
    printsymbol('R'); write(n,0)
  %finish
%end

%routine shift(%integer full)
%integer code
%conststring(3)%array s(0:3)=
"LSL","LSR","ASR","ROR"
  register(0)
  code = op>>4&255
  %returnif code=0
  printsymbol(',')
  %if code=6 %then printstring("RRX") %elsestart
    printstring(s(code>>1&3)); space
    %if code&1=0 %start
      %if code>>3=0 %start
        code = code+256 %unless 0#code>>1&3#3
      %finish
      lit(code>>3)
    %elseif code&15=1 %and full#0
      space; register(8)
    %else
      printstring(" invalid shift specifier")
    %finish
  %finish
%end

%routine dataproc
%conststring(3)%array c(0:15)=
"AND","EOR","SUB","RSB","ADD","ADC","SBC","RSC",
"TST","TEQ","CMP","CMN","ORR","MOV","BIC","MVN"
%constinteger dest = 2_1111000011111111,
       two sources = 2_0101111111111111
%integer code = op>>21&15
  printstring(c(code)); cond
  code = 1<<code
  %if op&1<<20#0 %start
    %if code&dest#0 %then printsymbol('S') %elsestart
      printsymbol('P')
      printsymbol('?') %and register(12) %unless op>>12&15=15
    %finish
  %finish
  space
  %if code&dest#0 %start
    register(12); printsymbol(',')
  %finish
  %if code&twosources#0 %start
    register(16); printsymbol(',')
  %finish
  %if op&1<<25#0 %start
    code = op&255; op = op>>8&15
    op = op-1 %and code = code>>2+code<<30 %while op#0
    lit(code)
  %else
    shift(1)
  %finish
%end

%routine multiply
  %if op&1<<21=0 %then printstring("MUL") %else printstring("MLA")
  cond; printsymbol('S') %if op&1<<20#0; space
  register(16); printsymbol(',')
  register(0); printsymbol(',')
  register(8)
  %if op&1<<21=0 %start
    %returnif op>>12&15=0
    printsymbol(','); register(12); printsymbol('?')
  %else
    printsymbol(','); register(12)
  %finish
%end

%routine single
  %if op&1<<20=0 %then printstring("STR") %else printstring("LDR")
  cond; printsymbol('B') %if op&1<<22#0
  printsymbol('T') %if op&16_01200000=16_00200000; space
  register(12); printsymbol(',')
  %if op&16_030F0000=16_010F0000 %start
    printstring("16_")
    %if op&1<<23=0 %then phex(pc+8-op&4095) %else phex(pc+8+op&4095)
  %else
    printsymbol('['); register(16)
    printsymbol(']') %if op&1<<24=0
    %unless op&16_02000FFF=0 %start
      printsymbol(',')
      %if op&16_02000000=0 %start
        %if op&1<<23=0 %then lit(-(op&4095)) %else lit(op&4095)
      %else
        printsymbol('-') %if op&1<<23=0
        shift(0)
      %finish
    %finish
    %if op&1<<24#0 %start
      printsymbol(']'); printsymbol('!') %if op&16_01200000=16_01200000
    %finish
  %finish
%end

%routine block
%integer i=0,b=1,m,start,stop
  %if op&1<<20=0 %then printstring("STM") %else printstring("LDM")
  cond
  %if op&1<<23=0 %then printsymbol('D') %else printsymbol('I')
  %if op&1<<24=0 %then printsymbol('A') %else printsymbol('B')
  space; register(16); printsymbol('!') %if op&1<<21#0
  printstring(",{"); m = op&16_FFFF
  %while m#0 %cycle
    i = i+1 %and b = b<<1 %while m&b=0; start = i
    m = m-b %and i = i+1 %and b = b<<1 %until m&b=0; stop = i-1
    printsymbol('R'); write(start,0)
    %if stop#start %start
      printstring("-R"); write(stop,0)
    %finish
    printsymbol(',') %unless m=0
  %repeat
  printsymbol('}')
  printsymbol('^') %if op&1<<22#0
%end

%routine branch
  printsymbol('B')
  printsymbol('L') %if op&1<<24#0
  cond
  printstring(" 16_")
  phex((pc+8+op<<2)&16_3FFFFFC)
%end
  
%routine disass
  phex(pc); space; phex(op); space
  %if op&16_0FC000F0=16_00000090 %start
    multiply
  %elseif op&16_0C000000=0
    dataproc
  %elseif op&16_0F000090=16_01000090
    printstring("Undefined")
  %elseif op&16_0E000010=16_06000010
    printstring("Undefined")
  %elseif op&16_0C000000=16_04000000
    single
  %elseif op&16_0E000000=16_08000000
    block
  %elseif op&16_0E000000=16_0A000000
    branch
  %elseif op&16_0E000000=16_0C000000-
      %or op&16_0F000000=16_0E000000
    printstring("Coprocessor instruction")
  %elseif op&16_0F000000=16_0F000000
    printstring("SWI"); cond; printstring(" 16_")
    phex(op&16_ffffff)
  %finish
  pc = pc+4; newline
%end

%routine extend(%string(255)%name s,%string(3)x)
%string(255)aft,temp
  temp = s
  temp = aft %while temp -> (":").aft
  s = s.".".x %unless s -> (".").aft
%end

%string(255)infile,outfile=""
%integer i,k

%on 9 %start
  %stop
%finish

  defineparam("Binary file",infile,pamnodefault)
  defineparam("Listing file",outfile,pamnewgroup)
  processparameters(cliparam)
  outfile = infile.".dis" %if outfile=""
  extend(infile,"obj")
  extend(outfile,"dis")
  openinput(1,infile); selectinput(1)
  openoutput(1,outfile); selectoutput(1)

  op = 0
  %cycle
    %for i = 1,1,4 %cycle
      readsymbol(k)
      op = op<<8+k
    %repeat
    disass
  %repeat
%end
