// SwatCommand.bcpl - Main Loop
// Copyright Xerox Corporation 1980, 1982
// Last modified March 21, 1982  1:59 PM by Boggs

get "Swat.decl"

external
[
// outgoing procedures
SwatCommand; OpenCell

// incoming procedures from Swat
Exp
SysIn; SysOut; TeleSwatServer; PrintError
SetFailPt; ReportFail
EffAddr; SymbolicInst
StackSwapIn; MapStack; PrintFrame; Frame; GetRetPC
MeasureSpy; DisplaySpy; StartSpy; StopSpy
SetBreak; DelBreak; DelAllBreaks; PrintAllBreaks; BreakSwapOut; BreakSwapIn
ResidentSwapOut; ResidentSwapIn; UserScreen; Go; Call; DisplayState
SymSwapIn; AddrToSym; SymRead; SymPrint
VMFetch; VMStore; VMSwap; VMSpace; VMPrint; VMCache
ReadSwapOut; ReadSwapIn; ReadLine; ReadFromFile; ReadChar

// incoming procedures from OS
Ws; PutTemplate; Puts; Free; Gets; Resets

// outgoing statics
openCell

// results of Exp's sucessful parse are:
// char - the control character that ended the line
NARGS		// the number of arguments
ARGS		// a vector of arguments (ARG!1 is first)
ALTFLG		// true if an ESC immediately preceded char
ALTFLG2		// true if two ESCs immediately preceded char

// incoming statics
sysZone; dsp; state; keys; vm; debugFlag
] 

static
[
assignable = false	// true iff open cell is assignable
openCell		// address of current open cell
lastOpenCell		// cell open just before this one
openMode		// type out mode (↑O, ↑D, ↑I, ↑N, or ↑S)
char
lastSearch		// last arg to search command
]

manifest
[
CTRLA = 1B;  CTRLB = 2B;  CTRLC = 3B;  CTRLD = 4B;  CTRLE = 5B
CTRLF = 6B;  CTRLG = 7B;  CTRLH = 10B; CTRLI = 11B; LF = 12B
CTRLK = 13B; CTRLL = 14B; CR = 15B;    CTRLN = 16B; CTRLO = 17B
CTRLP = 20B; CTRLQ = 21B; CTRLR = 22B; CTRLS = 23B; CTRLT = 24B
CTRLU = 25B; CTRLV = 26B; CTRLW = 27B; CTRLX = 30B; CTRLY = 31B
CTRLZ = 32B; ESC = 33B
]

//----------------------------------------------------------------------------
let SwatCommand() be
//----------------------------------------------------------------------------
[
let lineMem = 0

Cloop: SetFailPt(Cloop)  // errors go here

if lineMem then [ Free(sysZone, lineMem); lineMem = 0 ]
openMode = PrintO

   [SwapLoop
   // We'll be in this loop for months! (until he does another InstallSwat)
   let swapSignal = 0
   while swapSignal eq 0 do
      [CommandLoop
      VMCache(vmFlush)  // in case user boots out of Swat
      let TermChar(c) = (c ls 40b & c ne ESC) % (c eq $?)
      lineMem = ReadLine("#", TermChar)
      if lineMem!(lineMem!0) ne $*N then Puts(dsp, $*n)
      char = Exp(lineMem); Free(sysZone, lineMem); lineMem = 0
      unless char eq $*n % char eq LF % char eq CTRLB % char eq CTRLW do
	assignable = false

      manifest
         [	// for switchon into commands
         noArgs = 1000b
         oneArg = 2000b
         moreArgs = 3000b
         vmIsCore = 4000b
         oneAlt = 10000b
         twoAlts = 20000b
         ]

      let command = char + (ALTFLG2? twoAlts, ALTFLG? oneAlt, 0) +
       (NARGS eq 0? noArgs, NARGS eq 1? oneArg, moreArgs) +
       (vm>>VM.type eq vmTypeCore & not debugFlag? vmIsCore, 0)
      switchon command into
         [ // 'loop' is normal exit from switch, 'endcase' for errors.
         case CTRLA+noArgs+vmIsCore:		// ↑A
            [
            OpenCell(VMFetch(openCell))
            PrintOpenCell(0, 1)
            loop
            ]

         case CTRLB+noArgs:			// ↑B
            [
            if not assignable then
               ReportFail("Open cell not assignable")
            SetBreak(openCell)
            loop
            ]
         case CTRLB+noArgs+twoAlts:		// $$↑B
            [
            assignable = false
            PrintAllBreaks()
            loop
            ]
         case CTRLB+oneArg:			// addr↑B
            [
            assignable = false
            SetBreak(ARGS!1)
            loop
            ]
         case CTRLB+oneArg+oneAlt:		// index$↑B
            [
            assignable = false
            DelBreak(ARGS!1, true)
            loop
            ]
         case CTRLB+oneArg+twoAlts:		// 0$$↑B
            [
            assignable = false
            if ARGS!1 eq 0 then [ DelAllBreaks(); loop ]
            endcase
            ]
         case CTRLB+moreArgs:
            [
            unless NARGS eq 2 endcase
            test ARGS!1 eq 0
               ifso				// 0$addr↑B
                  [
                  assignable = false
                  DelBreak(ARGS!2, false)
                  ]
               ifnot SetBreak(ARGS!2, false, ARGS!1) // proceedCnt$addr↑B
            loop
            ]

         case CTRLC+oneArg:			// proc↑C
         case CTRLC+moreArgs:			// proc$n$...n$↑C
            [
            swapSignal = Call(NARGS, ARGS+1)
            loop
            ]

         case CTRLD+oneArg+oneAlt+vmIsCore:	// cnt$↑D
         case CTRLD+oneArg+vmIsCore:		// addr↑D
         case CTRLD+noArgs+vmIsCore:		// ↑D
            [
            PrintOpenCell(PrintD)
            loop
            ]

         case CTRLE+noArgs+vmIsCore:		// ↑E
            [
            OpenCell(EffAddr(VMFetch(openCell), openCell))
            PrintOpenCell(0, 1)
            loop
            ]
         case CTRLE+oneArg+vmIsCore:		// addr↑E
            [
            Search(ARGS!1, false)
            loop
            ]

         case CTRLF+oneArg+vmIsCore:		// index↑F
            [
            Frame(ARGS!1)
            loop
            ]

         case CTRLG+oneArg:			// addr↑G
            [
            swapSignal = Go(ARGS!1)
            loop
            ]

         case CTRLI+oneArg+oneAlt+vmIsCore:	// cnt$↑I
         case CTRLI+oneArg+vmIsCore:		// addr↑I
         case CTRLI+noArgs+vmIsCore:		// ↑I
            [
            PrintOpenCell(PrintI)
            loop
            ]

         case LF+oneArg+vmIsCore:		// val↑J
            [
            test assignable
               ifso VMStore(openCell, ARGS!1)
               ifnot ReportFail("No assignable cell")
            ]
         case LF+noArgs+vmIsCore:		// ↑J
            [
            OpenCell(openCell+1)
            PrintOpenCell(0, 1)
            loop
            ]
         case LF+noArgs+oneAlt+vmIsCore:	// $↑J
            [
            let t = openCell
            openCell = lastOpenCell+1
            lastOpenCell = t
            PrintOpenCell(0, 1)
            loop
            ]
         case LF+moreArgs+vmIsCore:		// byte$byte↑J
            [
            if NARGS eq 2 then
               [ ARGS!1 = ARGS!1 lshift 8 + ARGS!2; docase LF+oneArg ]
            loop
            ]

         case CTRLK+noArgs:			// ↑K
            [
            let topStatics = VMFetch(176777b)
            StopSpy()
            DelAllBreaks()
            VMStore(userAC0, 1)	// finish code = fcAbort
            swapSignal = Go(VMFetch(topStatics+21B)) // aka OsFinish
            loop
            ]

         case CTRLL+noArgs:			// ↑L
            [
            SysOut()
            loop
            ]

         case CR+oneArg+vmIsCore:		// val↑M
            [
            test assignable
               ifso VMStore(openCell, ARGS!1)
               ifnot ReportFail("No assignable cell")
            ]
         case CR+noArgs+vmIsCore:		// ↑M
            [
            assignable = false
            loop
            ]
         case CR+noArgs+oneAlt+vmIsCore:	// $↑M
            [
            let t = openCell
            openCell = lastOpenCell
            lastOpenCell = t
            PrintOpenCell(0, 1)
            loop
            ]
         case CR+moreArgs+vmIsCore:		// byte$byte↑M
            [
            if NARGS eq 2 then
               [ ARGS!1 = ARGS!1 lshift 8 + ARGS!2; docase CR+oneArg ]
            loop
            ]

         case CTRLN+oneArg+oneAlt+vmIsCore:	// cnt$↑N
         case CTRLN+oneArg+vmIsCore:		// addr↑N
         case CTRLN+noArgs+vmIsCore:		// ↑N
            [
            PrintOpenCell(PrintN)
            loop
            ]

         case CTRLO+oneArg+oneAlt+vmIsCore:	// cnt$↑O
         case CTRLO+oneArg+vmIsCore:		// addr↑O
         case CTRLO+noArgs+vmIsCore:		// ↑O
            [
            PrintOpenCell(PrintO)
            loop
            ]

         case CTRLP+oneArg+twoAlts:		// addr$$↑P
            [
            SetBreak(ARGS!1, true)
            swapSignal = Go(VMFetch(userPC))
            loop
            ]
         case CTRLP+oneAlt+noArgs:		// $↑P
	    [
            DelBreak(VMFetch(userPC), false)
            swapSignal = Go(VMFetch(userPC))
            loop
            ]
         case CTRLP+oneAlt+oneArg:		// index$↑P
            [
            if ARGS!1 eq 0 endcase
            SetBreak(GetRetPC(ARGS!1))
            ]
         case CTRLP+noArgs:			// ↑P
            [
            swapSignal = Go(VMFetch(userPC))
            loop
            ]
 
         case CTRLQ+noArgs:			// ↑Q
            [
            SysIn()
            openCell = 0
            lastOpenCell = 0
            openMode = PrintO
            assignable = false
            loop
            ]
 
         case CTRLR+noArgs+vmIsCore:		// ↑R
         case CTRLR+oneArg+vmIsCore:		// rregno↑R
            [
            PrintR()
            loop
            ]

         case CTRLS+oneArg+oneAlt+vmIsCore:	// cnt$↑S
         case CTRLS+oneArg+vmIsCore:		// addr↑S
         case CTRLS+noArgs+vmIsCore:		// ↑S
            [
            PrintOpenCell(PrintS)
            loop
            ]

         case CTRLT+noArgs+vmIsCore:		// ↑T
         case CTRLT+oneArg+vmIsCore:		// stackRoot↑T
            [
            MapStack(77777B, PrintFrame, dsp,
             (NARGS eq 0? VMFetch(userAC2), ARGS!1))
            loop
            ]
 
         case CTRLU+noArgs:			// ↑U
            [
            swapSignal = UserScreen()
            loop
            ]
 
         case CTRLV+noArgs+vmIsCore:		// ↑V
            [
            ARGS!1 = openCell
            ]
         case CTRLV+oneArg+vmIsCore:		// val↑V
            [
            PutTemplate(dsp, "$UOb = $D.*N", ARGS!1, ARGS!1)
            loop
            ]
 
         case CTRLW+oneArg+vmIsCore:		// val↑W
            [
            test assignable
               ifso VMStore(openCell, ARGS!1)
               ifnot ReportFail("No assignable cell")
            ]
         case CTRLW+noArgs+vmIsCore:		// ↑W
            [
            OpenCell(openCell-1)
            PrintOpenCell(0, 1)
            loop
            ]
         case CTRLW+noArgs+oneAlt+vmIsCore:	// $↑W
            [
            let t = openCell
            openCell = lastOpenCell-1
            lastOpenCell = t
            PrintOpenCell(0, 1)
            loop
            ]
         case CTRLW+moreArgs+vmIsCore:		// byte$byte↑W
            [
            if NARGS eq 2 then
               [ ARGS!1 = ARGS!1 lshift 8 + ARGS!2; docase CTRLW+oneArg ]
            loop
            ]

         case CTRLX+noArgs:			// ↑X
            [
            MeasureSpy()
            loop
            ]
         case CTRLX+oneArg:			// addr↑X
            [
            StartSpy(ARGS!1)
            loop
            ]
         case CTRLX+noArgs+oneAlt:		// $↑X
            [
            DisplaySpy(true)
            loop
            ]
         case CTRLX+noArgs+twoAlts:		// $$↑X
            [
            DisplaySpy(false)
            loop
            ]

         case CTRLY+noArgs+vmIsCore:		// ↑Y
            [
            SymRead()
            loop
            ]
         case CTRLY+noArgs+oneAlt+vmIsCore:	// $↑Y
            [
            ReadFromFile()
            loop
            ]
         case CTRLY+noArgs+twoAlts+vmIsCore:	// $$↑Y
            [
            TeleSwatServer()
            loop
            ]

         case CTRLZ+noArgs+vmIsCore:		// ↑Z
            [
            VMSpace()
            loop
            ]
         case CTRLZ+noArgs+oneAlt+vmIsCore:	// $↑Z
            [
            PutTemplate(dsp, "$P*N$P*N", VMPrint, true, SymPrint, true)
            loop
            ]
         case CTRLZ+noArgs+twoAlts+vmIsCore:	// $$↑Z
            [
            ResidentSwapIn()
            loop
            ]
         case $*035+noArgs+vmIsCore:		// ↑=
         case $*035+oneArg+vmIsCore:		// n↑=
         case $*035+noArgs+oneAlt+vmIsCore:	// $↑=
         case $*035+oneArg+oneAlt+vmIsCore:	// n$↑=
            [
            Search()
            loop
            ]

         case $?+noArgs+vmIsCore:		// ?
            [
            Ws("Help for command: ")
            char = ReadChar()
            Puts(dsp, char)
            Resets(state)
            PrintError(state, "Swat.help", HelpFetch)
            Gets(keys)
            DisplayState()
            loop
            ]

         default: test (command & vmIsCore) ne 0
            ifso [ Ws("???*n"); loop ]
            ifnot [ command = command + vmIsCore; docase command ]
         ]

      ]CommandLoop // end of while loop

   ReadSwapOut()
   ResidentSwapOut(swapSignal)
   BreakSwapOut()
   VMSwap()		// <------== This is it
   BreakSwapIn()
   SymSwapIn()
   StackSwapIn()
   ReadSwapIn(ResidentSwapIn())
   ]SwapLoop repeat
 ]

//----------------------------------------------------------------------------
and HelpFetch(nil) = char
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and PrintOpenCell(routine, num; numargs na) be
//----------------------------------------------------------------------------
[
if na ls 2 then num = 1

test routine eq 0
   ifso routine = openMode
   ifnot if NARGS eq 1 test ALTFLG ne 0 & ALTFLG2 eq 0
      ifso num = ARGS!1
      ifnot OpenCell(ARGS!1)

let done = 0
   [
   PutTemplate(dsp, "$P: ", AddrToSym, openCell+done)
   let todo = routine eq PrintN? 1, num-done
   for i = 1 to (todo gr 8? 8, todo) do
      [
      routine(openCell+done)
      done = done +1
      ]
   if done eq num break
   Puts(dsp, $*N)
   ] repeat

if num ne 1 then OpenCell(openCell+num-1)
openMode = routine
assignable = true
]

//----------------------------------------------------------------------------
and PrintN(cell) be SymbolicInst(VMFetch(cell), cell)
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and PrintO(cell) be PutTemplate(dsp, "$UO ", VMFetch(cell))
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and PrintD(cell) be PutTemplate(dsp, "$D. ", VMFetch(cell))
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
and PrintI(cell) be
//----------------------------------------------------------------------------
   PutTemplate(dsp, "$O $O ", VMFetch(cell) rshift 8, VMFetch(cell) & 377B)

//----------------------------------------------------------------------------
and PrintS(cell) be
//----------------------------------------------------------------------------
   PutTemplate(dsp, "$C $C ", VMFetch(cell) rshift 8, VMFetch(cell) & 377B)

//----------------------------------------------------------------------------
and Search() be
//----------------------------------------------------------------------------
// search from openCell+1 to end of memory (176777b).
[
if NARGS ne 0 then lastSearch = ARGS!1
let loc = openCell +1
while loc ne 177000b do
   [
   test ALTFLG
      ifnot if VMFetch(loc) eq lastSearch then
         [ openMode = PrintO; break ]
      ifso if EffAddr(VMFetch(loc), loc, true) eq lastSearch then
         [ openMode = PrintN; break ]
   loc = loc +1
   ]
test loc eq 177000b
   ifso Ws("Not found*N")
   ifnot
      [
      OpenCell(loc)
      PrintOpenCell(0, 1)
      ]
]

//----------------------------------------------------------------------------
and OpenCell(cell) be
//----------------------------------------------------------------------------
[
if openCell+1 ne cell & openCell-1 ne cell then lastOpenCell = openCell
openCell = cell
]

//----------------------------------------------------------------------------
and PrintR() be
//----------------------------------------------------------------------------
[
//Microcode routine should be:
//1000	L← register, SWMODE;
//	  [ BS=0(3 for S reg), RSELECT=reg, ALUF=0, LoadL, F1=10, NEXT=1001 ]
//1001	AC0← L, :START;
//	  [ BS=1, RSELECT=3, NEXT=20(start) ]
structure MI:
   [
   rselect bit 5
   blank bit 4
   bs bit 3
   blank bit 4
   ]

manifest [ read = true; write = false ]

//see if a ram is present by reading and writing in util area
let save = vec 4; RWRam(read, save)
let saveBar = vec 3; for i = 0 to 3 do saveBar!i = not save!i
RWRam(write, saveBar)
RWRam(read, saveBar)
for i = 0 to 3 do if saveBar!i ne (not save!i) then
   ReportFail("You have no RAM.")

let num = NARGS eq 1? 1, 100B
let reg = NARGS eq 1? ARGS!1, 0
let JumpRam = table [ 61010B; 1401B ]
let done = 0
   [  // read and print loop
   PutTemplate(dsp, "*NR$2F0O: ", reg)
   for i = 1 to num-done gr 8? 8, num-done do
      [
      if reg gr 77B then [ done = num; break ]
      let microInsts = table [ 0; 101001B; 14030B; 102020B ]
      microInsts>>MI.rselect = reg
      microInsts>>MI.bs = reg ge 40B? 3, 0
      RWRam(write, microInsts)	//Plop it down
      PutTemplate(dsp, "$U6O ", JumpRam(nil, 1000B))
      done = done +1
      reg = reg +1
      ]
   ] repeatuntil done eq num
RWRam(write, save)
]

//----------------------------------------------------------------------------
and RWRam(read, tab) be
//----------------------------------------------------------------------------
[
let ReadRam = table [ 61011B; 1401B ]
let WriteRam = table [ 55001B; 35003B; 61012B; 35001B; 1401B ]
for i = 0 to 1 do
   [
   let j = i+i; let j1 = j+1
   test read
      ifso
         [
         tab!j = ReadRam(nil, 3000B+i)	//High order
         tab!j1 = ReadRam(nil, 1000B+i)	//Low order
         ] 
      ifnot WriteRam(tab!j, 1000B+i, tab!j1)
   ]
]