// SwatInsAnal.bcpl - Routines for analyzing Alto instructions
// Copyright Xerox Corporation 1979, 1981, 1982
// Last modified March 21, 1982  2:10 PM by Boggs

// All you have to do is...07/25/73   (alb)

get "Swat.decl"

external
[
// outgoing procedures
SymbolicInst; EffAddr; BuildSI

// incoming procedures
VMFetch; ReportFail; AddrToSym
Ws; PutTemplate; Puts; Zero

// incoming statics
dsp; xmFlag
]

structure OP:	// instruction fields
[
   [
   alu bit 1
   acSrc bit 2
   acDest bit 2
   aluFn bit 3
   shift bit 2
   carry bit 2
   noLoad bit 1
   skip bit 3
   ] =
   [
   f1 bit 3
   f2 bit 2 = ac bit 2
   indir bit 1
   index bit 2
   disp bit 8
   ]
]

structure SI:		// Simulated Instruction
[
instr word		// simulating instruction
doItRtn word		// 0: default, 1: jmp, 2: bri
simRtn word		// simulation routine dispatch (small integer)
disp word		// sign extended displacement
eaReg word		// 0, or -> trapAdd, trapAC2, or AC3
indir word		// number of times to indirect (0-2)
]
compileif size SI/16 ne 6 then
   [ Error("Change lenSI declaration in Swat.decl") ]

manifest
[
// SI.sim values -- *** known to SwatResident.asm ***
simMRIALU = 0		// Memory Reference and Arithmetic Logical instrs
simJmp = 1
simJsr = 2
simDirs = 3
simBRI = 4

// SI.doIt values -- *** known to SwatResident.asm ***
doItDefault = 0
doItJmp = 1
doItBRI = 2
]

//----------------------------------------------------------------------------
let EffAddr(instr, addr, returnIfNoEA; numargs na) = valof
//----------------------------------------------------------------------------
[
let disp = Displacement(instr)
test (instr & 177400B) eq 64400B  //JSRII
   ifso resultis VMFetch(VMFetch(disp+addr))
   ifnot test (instr & 177400B) eq 65000B  //JSRIS
      ifso resultis VMFetch(VMFetch(disp+VMFetch(userAC2)))
      ifnot
         [
         if instr<<OP.f1 gr 2 test na ge 3 & returnIfNoEA
            ifso resultis -1
            ifnot ReportFail("Instruction has no effective address") 
         let ea = disp + selecton instr<<OP.index into
            [
            case 0: 0
            case 1: addr
            case 2: VMFetch(userAC2)
            case 3: VMFetch(userAC3)
            ]
         if instr<<OP.indir eq 1 then ea = VMFetch(ea)
         resultis ea
         ]
]

//----------------------------------------------------------------------------
and BuildSI(si, instr) be
//----------------------------------------------------------------------------
// Builds an SI structure at si to simulate the execution of instr
[
Zero(si, lenSI)
si>>SI.instr = 401b  //jmp .+1
si>>SI.doItRtn = doItDefault
si>>SI.disp = Displacement(instr)
si>>SI.eaReg = selecton instr<<OP.index into
   [
   case 0: 0
   case 1: userPC
   case 2: userAC2
   case 3: userAC3
   ]

switchon instr<<OP.f1 into
   [
   case 0:	// jmp, jsr, isz, dsz
      [
      switchon instr<<OP.f2 into
         [
         case 0:  // jmp
            [
            si>>SI.simRtn = simJmp
            endcase
            ]
         case 1:  // jsr
            [
            si>>SI.simRtn = simJsr
            endcase
            ]
         case 2:  // isz
         case 3:  // dsz
            [
            si>>SI.simRtn = simMRIALU
            si>>SI.instr = (instr & 74000b) + 2405b  //op @.+5
            endcase
            ]
         ]
      si>>SI.indir = instr<<OP.indir 
      endcase
      ]
   case 1:	// lda
   case 2:	// sta
      [
      si>>SI.simRtn = simMRIALU
      si>>SI.instr = (instr & 74000b) + 2405b  //op @.+5
      si>>SI.indir = instr<<OP.indir 
      endcase
      ]
   case 4 to 7:	// alu
      [
      si>>SI.simRtn = simMRIALU
      si>>SI.instr = instr
      endcase
      ]

// BuildSI (cont'd)

   case 3:	// special Alto instructions
      [
      let i = instr & 77400b
      test i eq 64400b % i eq 65000b  // jsrii, jsris
         ifso
            [
            si>>SI.simRtn = simJsr
            si>>SI.indir = 2
            ]
         ifnot switchon instr into
            [
            case 61000b:	// dir
               [
               si>>SI.doItRtn = doItJmp
               endcase
               ]
            case 61001b:	// eir
               [
               si>>SI.doItRtn = doItBRI
               endcase
               ]
            case 61002b:	// bri
               [
               si>>SI.simRtn = simBRI
               si>>SI.doItRtn = doItBRI
               endcase
               ]
            case 61013b:	// dirs
               [
               si>>SI.simRtn = simDirs
               si>>SI.doItRtn = doItJmp
               endcase
               ]
            default:		// simMRIALU works for the rest of them
               [
               si>>SI.simRtn = simMRIALU
               // don't re-execute traps
               unless i eq 77400b do si>>SI.instr = instr
               if xmFlag & ((instr & xJmpInstMask) eq xJmp0) then
                  ReportFail("I Can't simulate xJmp instructions")
               endcase
               ]
            ]
      endcase
      ]
   ]
]

//----------------------------------------------------------------------------
and SymbolicInst(instr, addr) be
//----------------------------------------------------------------------------
// Print instr as an Alto instruction assuming it resides at addr.
[
PutTemplate(dsp, "$6UO ", instr)
test instr<<OP.alu eq 1
   ifso
      [
      Ws(selecton instr<<OP.aluFn into
         [
         case 0:"com"
         case 1:"neg"
         case 2:"mov"
         case 3:"inc"
         case 4:"adc"
         case 5:"sub"
         case 6:"add"
         case 7:"and"
         ])
      Ws(selecton instr<<OP.carry into
         [
         case 0:""
         case 1:"z"
         case 2:"o"
         case 3:"c"
         ])
      Ws(selecton instr<<OP.shift into
         [
         case 0:""
         case 1:"l"
         case 2:"r"
         case 3:"s"
         ])
      if instr<<OP.noLoad ne 0 then Puts(dsp, $#)
      PutTemplate(dsp, " $O $O ", instr<<OP.acSrc, instr<<OP.acDest)
      Ws(selecton instr<<OP.skip into
         [
         case 0:""
         case 1:"skp"
         case 2:"szc"
         case 3:"snc"
         case 4:"szr"
         case 5:"snr"
         case 6:"sez"
         case 7:"sbn"
         ])

// SymbolicInst (Cont'd)

      test instr<<OP.skip eq 0
         ifso if instr<<OP.acSrc eq instr<<OP.acDest then
            PutTemplate(dsp, selecton instr & 103777b into //ignore ACs
               [
               case 102520b: "; AC$O ← 1"
               case 102000b: "; AC$O ← -1"
               case 102400b: "; AC$O ← 0"
               default: ""
               ], instr<<OP.acSrc)
         ifnot PutTemplate(dsp, selecton instr & 103767b into //ignore ACs,nl
            [
            case 102023b: "$S$O uls AC$O"
            case 102423b: "$S$O ule AC$O"
            case 102422b: "$S$O ugr AC$O"
            case 102022b: "$S$O uge AC$O"
            case 102102b: case 102122b: "$S$O ls AC$O"
            case 102502b: case 102522b: "$S$O le AC$O"
            case 102503b: case 102523b: "$S$O gr AC$O"
            case 102103b: case 102123b: "$S$O ge AC$O"
            case 102405b: "$S$O ne AC$O"
            case 102404b: "$S$O eq AC$O"
            case 101103b: "$S$O ls 0"
            case 100502b: "$S$O le 0"
            case 100503b: "$S$O gr 0"
            case 101102b: "$S$O ge 0"
            case 101005b: "$S$O ne 0"
            case 101004b: "$S$O eq 0"
            case 100005b: "$S$O ne -1"
            case 100004b: "$S$O eq -1"
            case 101202b: "$S$O even"
            case 101203b: "$S$O odd"
            default: ""
            ], "; Skip if AC", instr<<OP.acSrc, instr<<OP.acDest)
      ]

// SymbolicInst (Cont'd)

   ifnot switchon instr<<OP.f1 into
      [
      case 0:
         [
         Ws(selecton instr<<OP.f2 into
            [
            case 0:"jmp "
            case 1:"jsr "
            case 2:"isz "
            case 3:"dsz "
            ])
         PrintAddress(instr, addr)
         endcase
         ]
      case 1:
         [
         PutTemplate(dsp, "lda $O ", instr<<OP.ac)
         PrintAddress(instr, addr)
         endcase
         ]
      case 2:
         [
         PutTemplate(dsp, "sta $O ", instr<<OP.ac)
         PrintAddress(instr, addr)
         endcase
         ]
      case 3:
         [
         Ws(selecton instr into
            [
            case 61000b: "dir"
            case 61001b: "eir"
            case 61002b: "bri"
            case 61003b: "rclk"
            case 61004b: "sio"
            case 61005b: "blt"
            case 61006b: "blks"
            case 61007b: "sit"
            case 61010b: "jmpram"
            case 61011b: "rdram"
            case 61012b: "wrtram"
            case 61013b: "dirs"
            case 61014b: "vers"
            case 61015b: "dread"
            case 61016b: "dwrite"
            case 61017b: "dexch"
            case 61020b: "mul"
            case 61021b: "div"
            case 61022b: "diagnose1"
            case 61023b: "diagnose2"
            case 61024b: "bitblt"
            case 61025b: "xmlda"
            case 61026b: "xmsta"

            case 61037b: "setdefaultdisk"
            case 61040b: "doradoin"
            case 61041b: "doradoout"
            case 61042b: "doradohalt"
            case 61043b: "setpchist"

            case 64034b: "xjmp0"
            case 64035b: "xjmp1"
            case 64036b: "xjmp2"
            case 64037b: "xjmp3"
            default: ""
            ])
         switchon instr & 77400b into
            [
            case 60000b: [ PutTemplate(dsp, "cycle $O", instr&17B); endcase ]
            case 64400b: [ Ws("jsrii"); PrintAddress(instr, addr); endcase ]
            case 65000b: [ Ws("jsris"); PrintAddress(instr, addr); endcase ]
            case 67000b: [ PutTemplate(dsp, "convert $P", SignedDisp, instr) ]
            ]
         endcase
         ]
      ]
]

//----------------------------------------------------------------------------
and PrintAddress(instr, addr) be
//----------------------------------------------------------------------------
// Prints jump and memory reference addresses
[
if instr<<OP.indir eq 1 then Puts(dsp, $@)
switchon instr<<OP.index into
   [
   case 0:  // page zero
      [
      PutTemplate(dsp, "$O", instr<<OP.disp)
      endcase
      ]
   case 1:  // pc relative
      [
      PutTemplate(dsp, ".$P", SignedDisp, instr)
      endcase
      ]
   case 2:  // ac2 relative
   case 3:  // ac3 relative
      [
      PutTemplate(dsp, "$O,$O", Displacement(instr), instr<<OP.index)
      endcase
      ]
   ]
let effAdd = EffAddr(instr, addr)
PutTemplate(dsp, " -> $P: $UO", AddrToSym, effAdd, VMFetch(effAdd))
]

//----------------------------------------------------------------------------
and Displacement(instr) = (instr<<OP.index eq 0? instr<<OP.disp,
    (instr<<OP.disp + (instr<<OP.disp ge 200b? 177400b, 0))) 
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and SignedDisp(stream, instr) be
//----------------------------------------------------------------------------
[
let disp = Displacement(instr)
PutTemplate(stream, "$S$O", (disp ge 0? "+", ""), disp)
]