! (Intel etc) 8048 family disassembler
! (c) 1989 RWT - all rights reserved

%include "inc:util.imp"

%routine phex3(%integer x)
  phex2(x>>4); phex1(x)
%end

%begin

%constinteger {FLAGS} -
  mbmask = 4_03, mbu = 4_00, mbc = 4_01, mb0 = 4_02, mb1 = 4_03,
  rbmask = 4_30, rbu = 4_00, rbc = 4_10, rb0 = 4_20, rb1 = 4_30,
  beenmask = 4_300, untouched = 0, pass1 = 4_100, pass2 = 4_200, pass3 = 4_300,
  labelmask = 4_3000, jump = 4_1000, call = 4_2000

%recordformat f(%byte value,flags,%short line,to,link,head)
%record(f)%array program(0:4095)

%integer maxpc,i

%conststring(11)%array mnemonic(-1:255) =    "DATA  #",-
   "NOP",        "*??*",       "OUTL  BUS,A","ADD   A,#",
   "JMP   ",     "EN    I",    "*??*",       "DEC   A",
   "INS   A,BUS","IN    A,P1", "IN    A,P2", "*??*",
   "MOVD  A,P4", "MOVD  A,P5", "MOVD  A,P6", "MOVD  A,P7",
   "INC   @R0",  "INC   @R1",  "JB0   $",    "ADDC  A,#",
   "CALL  ",     "DIS   I",    "JTF   $",    "INC   A",
   "INC   R0",   "INC   R1",   "INC   R2",   "INC   R3",
   "INC   R4",   "INC   R5",   "INC   R6",   "INC   R7",
   "XCH   A,@R0","XCH   A,@R1","*??*",       "MOV   A,#",
   "JMP   ",     "EN    TCNTI","JNT0  $",    "CLR   A",
   "XCH   A,R0", "XCH   A,R1", "XCH   A,R2", "XCH   A,R3",
   "XCH   A,R4", "XCH   A,R5", "XCH   A,R6", "XCH   A,R7",
   "XCHD  A,@R0","XCHD  A,@R1","JB1   $",    "*??*",
   "CALL  ",     "DIS   TCNTI","JT0   $",    "CPL   A",
   "*??*",       "OUTL  P1,A", "OUTL  P2,A", "*??*",
   "MOVD  P4,A", "MOVD  P5,A", "MOVD  P6,A", "MOVD  P7,A",
   "ORL   A,@R0","ORL   A,@R1","MOV   A,T",  "ORL   A,#",
   "JMP   ",     "STRT  CNT",  "JNT1  $",    "SWAP  A",
   "ORL   A,R0", "ORL   A,R1", "ORL   A,R2", "ORL   A,R3",
   "ORL   A,R4", "ORL   A,R5", "ORL   A,R6", "ORL   A,R7",
   "ANL   A,@R0","ANL   A,@R1","JB2   $",    "ANL   A,#",
   "CALL  ",     "STRT  T",    "JT1   $",    "DA    A",
   "ANL   A,R0", "ANL   A,R1", "ANL   A,R2", "ANL   A,R3",
   "ANL   A,R4", "ANL   A,R5", "ANL   A,R6", "ANL   A,R7",
   "ADD   A,@R0","ADD   A,@R1","MOV   T,A",  "*??*",
   "JMP   ",     "STOP  TCNT", "*??*",       "RRC   A",
   "ADD   A,R0", "ADD   A,R1", "ADD   A,R2", "ADD   A,R3",
   "ADD   A,R4", "ADD   A,R5", "ADD   A,R6", "ADD   A,R7",
   "ADDC  A,@R0","ADDC  A,@R1","JB3   $",    "*??*",
   "CALL  ",     "EN    T0CLK","JF1   $",    "RR    A",
   "ADDC  A,R0", "ADDC  A,R1", "ADDC  A,R2", "ADDC  A,R3",
   "ADDC  A,R4", "ADDC  A,R5", "ADDC  A,R6", "ADDC  A,R7",
   "MOVX  A,@R0","MOVX  A,@R1","*??*",       "RET",
   "JMP   ",     "CLR   F0",   "JNI   $",    "*??*",
   "ORL   BUS,#","ORL   P1,#", "ORL   P2,#", "*??*",
   "ORL   P4,#", "ORL   P5,#", "ORL   P6,#", "ORL   P7,#",
   "MOVX  @R0,A","MOVX  @R1,A","JB4   $",    "RETR",
   "CALL  ",     "CPL   F0",   "JNZ   $",    "CLR   C",
   "ANL   BUS,#","ANL   P1,#", "ANL   P2,#", "*??*",
   "ANL   P4,#", "ANL   P5,#", "ANL   P6,#", "ANL   P7,#",
   "MOV   @R0,A","MOV   @R1,A","*??*",       "MOVP  A,@A",
   "JMP   ",     "CLR   F1",   "*??*",       "CPL   C",
   "MOV   R0,A", "MOV   R1,A", "MOV   R2,A", "MOV   R3,A",
   "MOV   R4,A", "MOV   R5,A", "MOV   R6,A", "MOV   R7,A",
   "MOV   @R0,#","MOV   @R1,#","JB5   $",    "JMPP  @A",
   "CALL  ",     "CPL   F1",   "JF0   $",    "*??*",
   "MOV   R0,#", "MOV   R1,#", "MOV   R2,#", "MOV   R3,#",
   "MOV   R4,#", "MOV   R5,#", "MOV   R6,#", "MOV   R7,#",
   "*??*",       "*??*",       "*??*",       "*??*",
   "JMP   ",     "SEL   RB0",  "JZ    $",    "MOV   A,PSW",
   "DEC   R0",   "DEC   R1",   "DEC   R2",   "DEC   R3",
   "DEC   R4",   "DEC   R5",   "DEC   R6",   "DEC   R7",
   "XRL   A,@R0","XRL   A,@R1","JB6   $",    "XRL   A,#",
   "CALL  ",     "SEL   RB1",  "*??*",       "MOV   PSW,A",
   "XRL   A,R0", "XRL   A,R1", "XRL   A,R2", "XRL   A,R3",
   "XRL   A,R4", "XRL   A,R5", "XRL   A,R6", "XRL   A,R7",
   "*??*",       "*??*",       "*??*",       "MOVP3  A,@A",
   "JMP   ",     "SEL   MB0",  "JNC   $",    "RL    A",
   "DJNZ  R0,$", "DJNZ  R1,$", "DJNZ  R2,$", "DJNZ  R3,$",
   "DJNZ  R4,$", "DJNZ  R5,$", "DJNZ  R6,$", "DJNZ  R7,$",
   "MOV   A,@R0","MOV   A,@R1","JB7   $",    "*??*",
   "CALL  ",     "SEL   MB1",  "JC    $",    "RLC   A",
   "MOV   A,R0", "MOV   A,R1", "MOV   A,R2", "MOV   A,R3",
   "MOV   A,R4", "MOV   A,R5", "MOV   A,R6", "MOV   A,R7"

%constinteger ret=131,retr=147,selrb0=197,selrb1=213,selmb0=229,selmb1=245

%routine initialise
%string(255)in,out=":t"
%record(f)%name prog
  %on 9 %start
    maxpc = maxpc-1
    %return
  %finish
  defineparam("Infile",in,pamnodefault)
  defineparam("Outfile",out,pamnewgroup)
  processparameters(cliparam)
  openinput(1,in)
  openoutput(1,out)
  %for maxpc = 0,1,4095 %cycle
    prog == program(maxpc)
    prog_value = 0; prog_flags = untouched
    prog_line = 0; prog_to = -1; prog_link = -1; prog_head = -1
  %repeat
  %for maxpc = 0,1,4095 %cycle
    readsymbol(program(maxpc)_value)
  %repeat
%end

%routine passone(%integer pc,flags,from)
%record(f)%name prog,prog2
%integer r1,r2,m1,m2,double,op,parm
%string(*)%name mnem
%bytename sym

  prog == program(pc)
  %unless prog_flags&beenmask=untouched %start
    r1 = prog_flags&rbmask; r2 = flags&rbmask
    %if r2=rbc %then r1 = rbc -
    %elseunless r1=rbc %start
      %if r2=rbu %then r1 = rbu -
      %elseunless r1=rbu %start
        r1 = rbc %unless r1=r2
      %finish
    %finish
    m1 = prog_flags&mbmask; m2 = flags&mbmask
    %if m2=mbc %then m1 = mbc -
    %elseunless m1=mbc %start
      %if m2=mbu %then m1 = mbu -
      %elseunless m1=mbu %start
        m1 = mbc %unless m1=m2
      %finish
    %finish
    flags = flags&labelmask!r1!m1
  %finish
  %if from>=0 %start
    prog2 == program(from)
    %signal 15 %unless prog2_link<0 %and prog2_to<0
    prog2_to = pc; prog2_link = prog_head; prog_head = from
  %finish
  %while pc<=maxpc %cycle
    prog == program(pc)
    %if prog_flags&beenmask=pass1 %start
      prog_flags = prog_flags&labelmask!pass1!flags; %return
    %finish
    prog_flags = prog_flags&labelmask!pass1!flags
    flags = flags&(rbmask!mbmask)
    op = prog_value
    mnem == mnemonic(op)
    sym == charno(mnem,length(mnem))
    parm = 0; double = 0
    %if op&15=4 %or sym='#' %or sym='$' %start
      double = 1
      prog2 == program(pc+1)
      parm = prog2_value
      prog2_flags = pass1
    %finish
    %if op&15=4 %start
      parm = op>>5<<8+parm
      parm = parm+1<<11 %if flags&mbmask=mb1
      %if op&16=0 %start
        passone(parm,flags!jump,pc)
        %return
      %finish
      passone(parm,flags!call,pc)
    %elseif sym='$'
      parm = (pc-1)&16_f00+parm
      passone(parm,flags!jump,pc)
    %else
      %returnif op=ret %or op=retr
      flags = flags&rbmask!mb0 %if op=selmb0
      flags = flags&rbmask!mb1 %if op=selmb1
      flags = flags&mbmask!rb0 %if op=selrb0
      flags = flags&mbmask!rb1 %if op=selrb1
    %finish
    pc = pc+double+1
  %repeat
%end

%routine passtwo
%integer line=0
%record(f)%name prog,prog2
%integer double,op,parm,breaks,pc
%string(*)%name mnem
%bytename sym
  %cycle
    breaks = 0; pc = 0
    %while pc<=maxpc %cycle
      prog == program(pc)
      %if prog_flags&beenmask=pass1 %start
        line = line+1; prog_line = line
        prog_flags = prog_flags!!pass1!!pass2
        op = prog_value
        mnem == mnemonic(op)
        sym == charno(mnem,length(mnem))
        parm = 0; double = 0
        %if op&15=4 %or sym='#' %or sym='$' %start
          double = 1
          prog2 == program(pc+1)
          parm = prog2_value
          prog2_flags = pass2
        %finish
        %if op&31=4 %start
          parm = prog_to
          prog2 == program(parm)
          %if prog2_flags&labelmask=jump %and prog2_flags&beenmask#pass2 -
          %and prog2_head=pc %and prog_link<0 %start
            pc = parm-2; breaks = breaks+1
          %finish
        %finish
        pc = pc+double+1
      %else
        pc = pc+1
      %finish
    %repeat
  %repeatuntil breaks=0
%end

%routine passthree
%record(f)%name prog,prog2
%integer double,op,parm,breaks,pc
%string(*)%name mnem
%bytename sym
  printstring("Non-Code Areas"); newline
  pc = 0
  %while pc<=maxpc %cycle
    prog == program(pc); pc = pc+1 %andcontinueunless prog_flags=untouched
    %unless pc&15=0 %start
      newline; phex3(pc); spaces((pc&15)*3+1)
    %finish
    %cycle
      prog_flags = pass3
      %if pc&15=0 %start
        newline; phex3(pc); space
      %finish
      space; phex2(prog_value); pc = pc+1; %exitif pc>=maxpc
      prog == program(pc)
    %repeatuntil prog_flags#untouched
    newline
  %repeat
  newline
  %cycle
    breaks = 0; pc = 0
    %while pc<=maxpc %cycle
      prog == program(pc)
      %if prog_flags&beenmask=pass2 %start
        %if prog_flags&call#0 %start
          newline; printstring("Called from ")
          parm = prog_head; op = 0
          %while parm>=0 %cycle
            prog2 == program(parm)
            %if prog2_value&31=20 %start
              %if op=4 %start
                op = 0
                newline; printstring("Called from ")
              %finish
              write(prog2_line,4); printsymbol('/')
              phex3(parm); op = op+1
            %finish
            parm = prog2_link
          %repeat
          newline
        %finish
        %if prog_flags&jump#0 %start
          newline; printstring("Jumped to from ")
          parm = prog_head; op = 0
          %while parm>=0 %cycle
            prog2 == program(parm)
            %unless prog2_value&31=20 %start
              %if op=4 %start
                op = 0
                newline; printstring("Jumped to from ")
              %finish
              write(prog2_line,4); printsymbol('/')
              phex3(parm); op = op+1
            %finish
            parm = prog2_link
          %repeat
          newline
        %finish
dummy:  newline %if prog_flags&labelmask#0
        write(prog_line,4); printsymbol('/'); phex3(pc); space
        parm = prog_flags&rbmask; printstring("RB")
        %if parm=rb0 %then printsymbol('0') %else-
        %if parm=rb1 %then printsymbol('1') %else-
        %if parm=rbc %then printsymbol('C') %else printsymbol('U')
        parm = prog_flags&mbmask; printstring("MB")
        %if parm=mb0 %then printsymbol('0') %else-
        %if parm=mb1 %then printsymbol('1') %else-
        %if parm=mbc %then printsymbol('C') %else printsymbol('U')
        prog_flags = prog_flags!!pass2!!pass3
        op = prog_value; space; phex2(op)
        mnem == mnemonic(op)
        sym == charno(mnem,length(mnem))
        parm = 0; double = 0
        %if op&15=4 %or sym='#' %or sym='$' %start
          double = 1
          prog2 == program(pc+1)
          parm = prog2_value; space; phex2(parm); space
          prog2_flags = pass3
        %finishelse spaces(4)
        %if op&15=4 %start
          prog2 == program(prog_to)
          printstring(mnem); write(prog2_line,0)
          printsymbol('/'); phex3(prog_to)
          %if op&16=0 %start
            %if prog2_flags&labelmask=jump %and prog2_flags&beenmask#pass3 -
            %and prog2_head=pc %and prog_link<0 %start
              newline; !newline; printstring("Dummy label"); newline
              breaks = breaks+1; pc = prog_to; prog == program(pc)
              ->dummy
            %finish
          %finish
        %else
          %if sym='$' %then printstring(substring(mnem,1,length(mnem)-1)) -
          %else printstring(mnem)
          %if prog_to>=0 %start
            prog2 == program(prog_to)
            write(prog2_line,0); printsymbol('/'); phex3(prog_to)
          %elseif double#0
            write(parm,0)
            %if ' '<=parm<='~' %start
              printstring("/'"); printsymbol(parm)
              printsymbol(parm) %if parm=''''; printsymbol('''')
            %elseif parm&128#0
              printstring("/-"); write(256-parm,0)
            %finish
          %finish
        %finish
        newline
        pc = pc+double+1
      %else
        pc = pc+1
      %finish
    %repeat
  %repeatuntil breaks=0
%end

initialise
passone(0,rb0!mb0!call,-1)
passone(3,rbu!mbu!call,-1)
passone(7,rbu!mbu!call,-1)
passtwo
passthree

%end
