--- /dev/null
+;Set FTKCN non-zero to include debugging count code
+
+TITLE TOPS-20 MIM INTERPRETER (MIMI)
+
+.SYMTAB 8001.,5000.
+
+IF1,[ .TNXDF
+ .DECSAV
+ XJRST==JRST 5, ; DOESN'T SEEM TO EXIST??
+ SS%EPN==10000 ; MAGIC BIT
+IFNDEF SWTRP%,SWTRP%==JSYS 573
+IFNDEF XSIR%,XSIR%==JSYS 602
+IFNDEF SMAP%,SMAP%==JSYS 767
+ XGVEC==JSYS 606
+ XSVEC==JSYS 607
+ IOX34==602462
+]
+
+FLIP==1 ; FLAG TO DO SECTION FLIPPING
+MON==0
+SBRFY==1 ; ENABLE "SUBRIFY" STUFF
+
+XBLT==123000,,[020000,,]
+
+A=1
+B=2
+C=3
+D=4
+E=5
+
+OP=6
+PC=7
+
+O1=10
+O2=11
+O3=12
+
+R=12
+M=13
+SP=14
+F=15
+
+TP=16
+P=17
+
+PV%OFF==3 ; OFFSET FOR CODE IN PURVEC
+TOPGC==777000-1
+TOPMGC==777000-1
+
+
+ENTMAX==0
+
+ZZZ==.
+
+LOC 136 ; POINTERS TO INTERESTING THING
+ MIMSEC,,TTBIND
+ MIMSEC,,BINDID ; VARIABLE BINDING ID
+ MIMSEC,,MPATM ; ATOM TO CALL FOR MAPPING
+ MIMSEC,,PURVEC ; PURE VECTOR
+ MIMSEC,,DBVEC ; OTHER PURE INFO
+ MIMSEC,,MINFO ; POINTER TO INFO VEC
+ MIMSEC,,TOPOBL ; OBLIST TABLE
+ MIMSEC,,PAGPTR ; POINTER TO PAGE TABLE
+ MIMSEC,,UWATM ; UNWIND ATOM
+ MIMSEC,,ICATM ; INTERRUPT ATOM
+ MIMSEC,,ECATM ; ERROR ATOM
+ MIMSEC,,NCATM ; UNDEFINED CALL ATOM
+
+DEFINE PR NM
+ PRILOC NM,\NM
+ TERMIN
+
+DEFINE PRILOC M,N
+PRINTC /M = N
+/
+TERMIN
+
+COMPERR:
+ JRST @[MIMSEC,,CMPERR]
+PR COMPERR
+FROBBS: SETZ CIEMP
+ SETZ CINTH
+ SETZ CIRST
+ SETZ CIMON
+ SETZ CIGAS
+ SETZ CIGVL
+FROBL==.-FROBBS
+
+PR FROBBS
+
+INGCPT: MIMSEC,,INGC
+
+PR INGCPT
+
+NOZONE: MIMSEC,,RCL ; POINTER TO NON-ZONE GC-PARAMS
+
+BLOCK 21 ; SPACE USED FOR IRDBLK BEFORE?
+
+DOSOUT: SOUT
+ POPJ P,
+CZONE: 0 ; current fs zone
+FRAMID: 0
+NARGS: 0
+UWATM: 0
+;DOCMPR: 0
+;DIDCMP: 0
+PNTRET: MIMSEC,,RET2
+PNTSTK: MIMSEC,,STKERR
+;TRACE: 0
+DOJSYS: XCT O1
+; JUMP 16,.+2 ;errors on sin/sout go to EXEC
+ AOS (P)
+ POPJ P,
+ 0
+\f
+SUBTTL MACROS
+
+;Feature test switches:
+ FTKCN==0 ;ne 0 to include kernel testing code
+
+LOWOP==1000
+
+CUROP==0
+
+DEFINE ENTRY ENTLOC,JSPQ
+ %!ENTLOC==CUROP
+IFE FTKCN,{SETZ ENTLOC }
+IFN FTKCN,{
+IFSE JSPQ,,1,,kercal ;;all dispatches through this address
+IFSN JSPQ,,1,,kerjsp
+IF2,{ ZZZ==.
+ loc kcltab+curop ;;hide real address in
+ xwd 1,entloc ;;other table (fake multi-sectioning)
+ LOC ZZZ
+}
+}
+ IFG <%!ENTLOC+ENTVEC-ENTMAX>,ENTMAX==%!ENTLOC+1+ENTVEC
+ IFL <CUROP-LOWOP>,LOWOP==CUROP
+ CUROP==CUROP+1
+TERMIN
+
+IFN FTKCN,{
+
+;;Some routines are JRST'd to, so we can't account them...
+DEFINE OENTRY ENTLOC,JSPQ
+ %!ENTLOC==CUROP
+ SETZ ENTLOC
+ IFG <%!ENTLOC-ENTMAX+ENTVEC>,ENTMAX==%!ENTLOC+1+ENTVEC
+ IFL <CUROP-LOWOP>,LOWOP==CUROP
+ CUROP==CUROP+1
+TERMIN
+};End FTKCN
+
+IFE FTKCN,{
+ DEFINE OENTRY ENTLOC,JSPQ
+ ENTRY ENTLOC,JSPQ
+TERMIN
+};End NFTKCN
+
+DEFINE TYPREC TBL,NAM\
+ $W!NAM=[$TYPCNT_6+$PRECORD,,0]
+ $T!NAM=$TYPCNT_6+$PRECORD
+ZZZ==.
+ LOC RECTBL+<$TYPCNT*2>
+ $TFIX,,0
+ SETZ TBL
+ LOC ZZZ
+$TYPCNT==$TYPCNT+1
+TERMIN
+
+DEFINE TYPMAK PT,NAM\
+ $W!NAM=[$TYPCNT_6+PT,,0]
+ $T!NAM=$TYPCNT_6+PT
+$TYPCNT==$TYPCNT+1
+TERMIN
+
+\f
+ENTVEC:
+PR ENTVEC
+SUBTTL OPCODE DEFINITIONS
+
+ ENTRY FRAME,T
+ oENTRY MCALL,T
+ oENTRY ACTIVATION,T
+ oENTRY AGAIN
+ oENTRY RETURN
+RETOFF==.-ENTVEC
+ oENTRY RTUPLE
+ oENTRY INCALL,T
+ ENTRY ARGS,T
+ ENTRY TUPLE,T
+ ENTRY NEXTS,T
+ ENTRY MAKTUP,T
+ ENTRY RETRY
+ ENTRY CONTENTS,T
+ ENTRY PFRAME,T
+ ENTRY LEGAL,T
+ ENTRY NEWTYPE,T
+ ENTRY LIST
+ ENTRY UBLOCK
+ ENTRY RECORD
+ ENTRY NTHU
+ ENTRY NTHR
+ ENTRY PUTU
+ ENTRY PUTR
+ ENTRY RESTU,T
+ ENTRY BACKU,T
+ ENTRY TOPU,T
+ ENTRY CONS,T
+ ENTRY BIND,T
+ ENTRY FIXBIND,T
+ ENTRY UNBIND,T
+ ENTRY OPENX
+ ENTRY CLOSEX
+ ENTRY READX
+ ENTRY PRINTZ
+ ENTRY RESETX
+ ENTRY SAVEX
+ ENTRY RESTORE
+ ENTRY ATIC
+ ENTRY INTGO
+ ENTRY QUIT
+ ENTRY RANDOM,T
+ ENTRY MARKL,T
+ ENTRY MARKU,T
+ ENTRY MARKR,T
+ ENTRY MKL,T
+ ENTRY MKU,T
+ ENTRY MKR,T
+ ENTRY SWNEXT,T
+ ENTRY TMPTBL,T
+ ENTRY XRECOR
+ ENTRY RELL,T
+ ENTRY RELU,T
+ ENTRY RELR,T
+ oENTRY UNWCNT
+ ENTRY SETZON,T
+ ENTRY SINX
+ ENTRY SOUTX
+ ENTRY GTJFNX
+ ENTRY JFNSX
+ ENTRY ERSTRX
+ ENTRY GTJFNL
+ ENTRY IOERR
+ oENTRY ACALL
+ ENTRY SFRAME,T
+ oENTRY MRETUR
+ ENTRY RNTIME
+ ENTRY SUNWAT,T
+ ENTRY TYPEW,T
+ ENTRY DFATAL,T
+ ENTRY IENABLE
+ ENTRY UUBLOCK
+ ENTRY SBLOCK
+ ENTRY USBLOCK
+ ENTRY ILVAL,T
+ ENTRY IASS,T
+ ENTRY ISET,T
+ ENTRY MOVSTR,T
+ ENTRY SETSIZ
+IFN SBRFY,[
+ ENTRY SBFPMP,T
+ ENTRY SBFRAM,T
+]
+ ENTRY RFTADX
+ENDENT==.
+PR ENDENT
+\f
+SUBTTL Kernel stuff left in section 0 for max winnage
+
+IFN SBRFY,[
+SBRFLN==7
+SBRMYT==-6
+SBRMYM==-5
+SBRCLL=-4
+SBRFRM==-2
+SBRPC==-1
+SBRPRV==0
+
+SBFRAM: MOVE O1,@3(M) ; get atom of current MSUBR
+ PUSH TP,(O1)
+ ADDI TP,SBRFLN-1
+ MOVEM M,SBRMYM(TP)
+ SETZM SBRCLL(TP)
+ MOVEM 0,SBRPC(TP)
+ SKIPL O1,-1(F)
+ HRROI O1,(F)
+ HRRZ 0,O1
+ SUBI 0,SBRCLL-SBRFRM(TP)
+ HRL O1,0
+ MOVEM O1,SBRFRM(TP)
+ MOVEM F,SBRPRV(TP)
+ JRST (PC)
+]
+
+SFRAME: PUSH TP,[$TSFRAM+$FRMDOPE,,0]
+ JRST .+2
+FRAME: PUSH TP,[$TFRAME+$FRMDOPE,,0]
+ ADDI TP,FR.LN
+ SETZM -FR.LN+1(TP)
+ JRST (PC)
+
+BIND: PUSH TP,[$TBIND+$FRMDOPE,,0]
+ ADDI TP,8
+ SETZM -7(TP)
+ MOVEI A,-6(TP)
+ HRLI A,-7(TP)
+ BLT A,(TP)
+ MOVEM SP,-2(TP)
+ XMOVEI B,-7(TP)
+ MOVE SP,B
+ MOVE A,[$TBIND,,16.] ; LENGTH CHANGED (WAS 6)
+ JRST (PC)
+
+FIXBIN: MOVE A,SP
+ MOVEI 0,(F)
+
+FIXBLP: MOVE B,2(A) ; THE ATOM FOR THIS BINDING
+ CAMLE A,1(B) ; Survivored frob, we've already fixed this
+ JRST FIXBL1 ; guy
+ MOVE O1,1(B) ; get section
+ CAMLE O1,TP ; skip if not top level binding
+FIXBL1: CAILE 0,(A) ; ARE WE BEHIND THE CURRENT FRAME?
+ JRST (PC)
+FIXBL2: MOVEM A,1(B) ; MAKE ATOM POINT TO THIS BINDING
+ SKIPE A,5(A) ; GET PREVIOUS BINDING AND LOOP
+ JRST FIXBLP
+ JRST (PC)
+
+MCALL:
+IFN FTKCN,< AOS @[MIMSEC,,KCNTAB+%CALL]> ;Count calls
+ SUB PC,R
+ HRLI PC,(SETZ (R))
+CALLZ:
+CALLR:
+; SKIPE TRACE
+; PUSHJ P,@[MIMSEC,,TRACIN]
+CALLRX: MOVE C,O2 ; SAVE # OF ARGUMENTS
+ SKIPN B,(O1) ; GET GLOBAL BINDING
+ JRST @[MIMSEC,,CALNGS] ; BARF, NOT GASSIGNED!
+ HLRZ A,(B) ; LOAD GVAL
+ CAIE A,$TMSUBR ; IS IT AN MSUBR?
+ JRST @[MIMSEC,,CALNGS] ; OH, FOO!
+ MOVE D,1(B) ; GET MSUBR
+ICRET:
+IFN FTKCN,{ SKIPE @[MIMSEC,,TRACNT] ;Trace count?
+ PUSHJ P,@[MIMSEC,,TRINCT] ; Yup
+};End FTKCN
+ SKIPE B,@1(D) ; POINT TO GVAL OF ATOM OF IMSUBR
+ SKIPN M,1(B)
+ JRST COMPER ; If IMSUBR is not assigned...
+ SKIPL A,-1(F) ; GET PREVIOUS GLUED FRAME
+ SKIPA A,F ; OR ELSE CURRENT FRAME
+ HLL A,F
+ HRRM SP,FR.SP(A) ; SAVE BINDING POINTER
+ MOVEM PC,FR.PC(A) ; SAVE PC (THIS IS WRONG)
+ LSH C,1
+ SUBM TP,C ; POINT ABOVE FIRST ARG
+ MOVEM D,FR.MSA-1(C) ; STORE MSUBR IN FRAME
+ SKIPL (F)
+ SUBI F,FR.OFF
+ MOVEM F,FR.FRA-1(C) ; STORE PTR TO PREV FRAME
+ AOS F,FRAMID ; GET A UNIQUE ID
+ HRL F,O2 ; SAVE # ARGS IN LH
+ MOVEM F,FR.ARG-1(C) ; STORE ARGS,,ID
+ XMOVEI F,-1(C) ; POINT AT FRAME
+ SETZM (F) ; FOR WINNAGE
+ MOVE D,7(D) ; OFFSET
+ HLRZ A,(M) ; CHECK FOR FBIN TYPE KLUDGE
+ MOVE R,1(M)
+ CAIE A,$TPCODE
+ JRST .+3
+ SKIPN R,PV%OFF(R)
+ PUSHJ P,@[MIMSEC,,DMAPIN]
+ HRLI D,400000+R
+ SKIPE INTFLG
+ PUSHJ P,@[MIMSEC,,INTGOC]
+; SKIPE DOCMPR
+; JRST @[MIMSEC,,STKERR]
+STKMNG:
+IFE FLIP&0,[ JRST @D ]
+IFN FLIP&0,[
+ TLNN M,1 ; ODD/EVEN CHECK
+ JRST EVNSEC
+ HRLI TP,EVSEC
+ HRLI F,EVSEC
+ HRLI P,EVSEC
+ JRST @D
+
+EVNSEC: HRLI TP,ODDSEC
+ HRLI F,ODDSEC
+ HRLI P,ODDSEC
+ JRST @D ]
+
+
+UNBIND: SUBI PC,(R)
+ HRLI PC,(SETZ (R))
+IUNBIN: MOVEI C,0 ; IN CASE NO BINDINGS FLUSHED
+ SETZB A,B ; IN CASE UNWINDER FOUND
+ HRRZS O1
+IUNBNL: CAIL O1,(SP) ; IS BINDING POINTER ACCURATE?
+ JRST IUNBNQ ; YES, RETURN
+ SKIPN D,2(SP) ; THE ATOM BOUND
+ JRST NXTBND
+ CAMN D,UWATM ; REALLY AN UNWIND?
+ JRST @[MIMSEC,,DOUNWI] ; AND LOOP UNTIL ALL DONE
+UNJOIN: MOVE C,6(SP) ; THE OLD BINDING FOR THIS ATOM
+ MOVEM C,1(D) ; STUFF OLD BINDING INTO ATOM
+NXTBND: MOVE C,SP ; SAVE LAST BINDING FLUSHED
+ MOVE SP,5(SP) ; POINT TO PREVIOUS BINDING
+ JRST IUNBNL ; YES, GO HANDLE IT
+
+IUNBNQ: JRST @PC
+; JUMPE C,@PC
+; HLL C,TP
+; CAMGE C,TP ; NEED STACK TO FLUSH?
+; XMOVEI TP,-2(C) ; FLUSH BINDING DW AS WELL
+; JRST @PC
+
+RETURN:
+IFN FTKCN,< AOS @[MIMSEC,,KCNTAB+%RETUR]>
+; SKIPE DIDCMP ; SEE IF MUST CHECK FOR OVFL PAGE HACK
+; JRST @[MIMSEC,,RET2]
+RET3: SKIPL C,(F) ;NOTE THIS INSTRUCTION CAN BE MUNGED!!!
+ JRST IRET1
+ XMOVEI TP,-2(F)
+ HRR F,1(F)
+IFE SBRFY,[ JRST @C]
+IFN SBRFY,[ TLZN C,SBRCAL ; SKIP IF SUBRIFY
+ JRST @C
+ MOVE M,-2(TP) ; CALLER'S M
+ SUBI TP,4
+ HLRZ 0,(M) ; CHECK FOR PMAPPED
+ MOVE R,1(M)
+ CAIN 0,$TPCODE
+ SKIPE R,PV%OFF(R)
+ JRST @C
+ PUSHJ P,@[MIMSEC,,DMAPI1]
+ JRST @C]
+
+IRET1:
+; SKIPE TRACE
+; PUSHJ P,@[MIMSEC,,TRACOUT]
+ JSP E,FRMFIX
+ JRST @PC
+
+FRMFIX: MOVEI O1,-FR.LN(F)
+ CAIGE O1,(SP) ; DO WE NEED SOME UNBINDING?
+ JSP PC,IUNBNL ; YES. DO THEM
+ XMOVEI TP,-FR.LN(F)
+ HRR F,FR.FRA(F) ; GET PREVIOUS FRAME
+ SKIPL (F)
+ JRST [ADDI F,FR.OFF
+ MOVE C,F
+ MOVEI O2,0
+ JRST CHPCO]
+ MOVE C,FR.FRA(F)
+ SETCM O2,C
+ HLL C,F
+CHPCO: MOVE PC,FR.PC(C) ; RESTORE PC FROM FRAME
+ SKIPN M,FR.MSA(C) ; RESTORE MSUBR PTR FROM FRAME
+ JRST RESTPC
+ MOVE M,@1(M) ; POINT TO GBIND THROUGH ATOM
+ MOVE M,1(M) ; GET IMSBUR INTO M
+RESTPC: JUMPE M,(E)
+ HLRZ O1,(M) ; CHECK FOR FBIN TYPE KLUDGE
+ MOVE R,1(M)
+ CAIE O1,$TPCODE
+ JRST .+3
+ SKIPN R,PV%OFF(R)
+ PUSHJ P,@[MIMSEC,,DMAPI1]
+IFN SBRFY,[
+ TLNN O2,-1
+IFE FLIP&0,[ JRST (E)]
+IFN FLIP&0,[ JRST NOSBR]
+ HLRZS O2 ; FIND FRAME OF SUBRIFIED THING
+ ADD C,O2 ; THROUGH GROSS HAIR
+ DMOVE R,@(C) ; ONLY WORKS CAUSE R=M-1
+ JRST RESTPC
+NOSBR: ]
+IFE FLIP&0,[ JRST (E) ]
+IFN FLIP&0,[
+ TLNN M,1 ; ODD/EVEN CHECK
+ JRST EVNSE3
+ HRLI TP,EVSEC
+ HRLI F,EVSEC
+ HRLI P,EVSEC
+ JRST (E)
+
+EVNSE3: HRLI TP,ODDSEC
+ HRLI F,ODDSEC
+ HRLI P,ODDSEC
+ JRST (E) ]
+
+; MAKTUP -- 0/ TOTAL ARGS PASSED, O1/ REQUIRED+OPT ARGS, O2/ #TEMPS
+
+MAKTUP:
+ SUB 0,O1 ; SUBTRACT REQUIRED ARGUMENTS
+ LSH O2,1 ; O2 IS NUMBER OF TEMPS
+ ADJSP TP,(O2) ; BUMP TP TO REFLECT THIS
+ SKIPG A,0 ; A NOW HAS LENGTH OF TUPLE IN RH
+ JRST IMAKET ; ZERO LENGTH TUPLE
+ LSH O1,1 ; WORDS WORTH OF REQUIRED ARGS
+ MOVN C,0 ; # ARGS TO MOVE (NEG FOR XBLT)
+ ASH C,1 ; TO NUMBER OF WORDS
+ MOVEI D,2(O1) ; D/ # OF REQ ARGS+2
+ ADD D,F ; D POINT TO FIRST TUPLE WORD
+ SUB D,C ; NOW LAST TUPLE WORD+1
+ MOVE E,D ; COMPUTE DEST
+ ADD E,O2 ; ADD IN DELTA
+ XBLT C,
+ HRLI A,$TTUPLE
+ MOVE B,E
+ JRST PUSHDW
+
+IMAKET:
+ MOVSI A,$TTUPLE
+ XMOVEI B,1(TP) ; POINT AT DOPE WORD FOR EMPTY TUPLE
+PUSHDW: LSH 0,1 ; MAKE IT BE # OF WORDS INSTEAD OF ELTS
+ HRLI 0,$TTUPLE+$FRMDOPE ; GENERATE A DOPE WORD
+ PUSH TP,0
+ PUSH TP,[0] ; MUST PUT IN OTHER DOPE WORD
+ SKIPGE FR.TP(F) ; SKIP IF MUST MUNG FRAME
+ JRST (PC)
+ MOVEI 0,(F)
+ SUBI 0,(TP)
+ HRLM 0,FR.ARG(F) ; INDICATE IN FRAME
+ JRST (PC)
+
+CONS: JSP OP,ICELL1 ; GET LIST CELL
+ JRST @[MIMSEC,,CONS1] ; REQS A GC
+
+ MOVEM E,(A)
+ DMOVEM C,1(A)
+ MOVE B,A
+ MOVSI A,$TLIST
+ JRST (PC)
+
+
+ICELL1: SKIPN B,CZONE
+ XMOVEI B,NOZONE-GCPOFF
+ MOVE B,GCPOFF(B) ; GC params
+ SKIPE A,RCLOFF(B) ; Recycled list cells?
+ JRST [MOVE 0,(A) ; Yes, use one
+ MOVEM 0,RCLOFF(B)
+ JRST 1(OP)]
+; MOVE 0,GCFLGO(B)
+; TLNE 0,$GC%PB ; ONLY PAGES FROM ZONE?
+; JRST CMPERR
+ICELL2: MOVE A,GCSBOF(B) ; Get GCSBOT
+ MOVEI 0,3 ; # words to allocate
+ ADDB 0,GCSBOF(B) ; Update GCSBOT?
+ CAMG 0,GCSMXO(B) ; Need GC?
+ JRST 1(OP) ; No, skip return
+ MOVNI 0,3
+ ADDM 0,GCSBOF(B) ; Fix up GCSBOT
+ JRST (OP) ; Lose, lose
+
+TUPLE: MOVE B,TP ; POINT TO STACK
+ MOVE A,O1 ; SAVE LENGTH
+ LSH O1,1
+ SUBI B,-1(O1)
+ HRLI O1,$TTUPLE+$FRMDOP
+ PUSH TP,O1
+ PUSH TP,[0]
+ HRLI A,$TTUPLE ; TYPE/LENGTH IN A
+ JRST (PC)
+
+SUBTTL OPEN COMPILER UTILITIES
+
+CIEMP:
+IFN FTKCN,<AOS @[MIMSEC,,KCNTAB+CUROP]>
+ MOVE 0,A ; POSSIBLE COUNT
+ LDB A,[220300,,A] ; ISOLATE PRIMTYPE
+ JUMPE A,COMPER
+ JRST CIMON1
+CIMON:
+IFN FTKCN,<AOS @[MIMSEC,,KCNTAB+CUROP+1]>
+ MOVE 0,A ; POSSIBLE COUNT
+ LDB A,[220300,,A] ; GET PRIMTYPE
+CIMON1: CAIN A,$PLIST
+ JUMPN B,CIMON3
+ CAIL A,$PBYTES
+ TRNN 0,-1
+ ADDI PC,1
+CIMON3: MOVE A,0
+ JRST (PC)
+
+;CIMTBL: SKIPA
+; SKIPE B
+; SKIPA ; THIS IS REALLY WRONG!!!
+; SKIPA
+; TRNE 0,-1
+; TRNE 0,-1
+; TRNE 0,-1
+; TRNE 0,-1
+
+CINTH:
+IFN FTKCN,<AOS @[MIMSEC,,KCNTAB+CUROP+2]>
+ LDB A,[220300,,A]
+ XCT CINTBL(A)
+ JRST (PC)
+
+CINTBL: JRST COMPER
+ DMOVE A,1(B)
+ JRST COMPER
+ JRST COMPER
+ JRST DOILD1
+ JRST [MOVSI A,$TCHARACTER
+ JRST DOILDB ]
+ JRST [MOVE B,(B)
+ MOVSI A,$TFIX
+ JRST (PC)]
+ DMOVE A,(B)
+
+DOILD1: MOVSI A,$TFIX
+DOILDB: ILDB B,B
+ JRST (PC)
+
+CIRST:
+IFN FTKCN,<AOS @[MIMSEC,,KCNTAB+CUROP+3]>
+ LDB 0,[220300,,A]
+ ADDI 0,CIRTBL
+ TLO 0,(SETZ)
+ JRST @0
+
+CIRTBL: JRST COMPER
+ JRST [MOVE B,(B)
+ MOVSI A,$TLIST
+ JRST (PC)]
+ JRST COMPER
+ JRST COMPER
+ JRST [HRLI A,$TBYTES
+ JRST DOIBP]
+ JRST DOIBP1
+ AOJA B,[HRLI A,$TUVECTOR
+ SOJA A,(PC)]
+ ADDI B,2
+ HRLI A,$TVECTOR
+; CAMG B,[TPSEC+2,,] ; Win with tuples???
+; HRLI A,$TTUPLE
+ SOJA A,(PC)
+
+DOIBP1: HRLI A,$TSTRING
+DOIBP: IBP B
+ SOJA A,(PC)
+
+CONSTANTS
+
+IFN MON,[
+INSDIS: .+1
+INSDO: 0
+ JRST @INSRE1
+ JRST @INSRE2
+INSRE1: MIMSEC,,INSRET
+INSRE2: MIMSEC,,INSRET+1
+]
+INTFLG: 0
+ENDP1==.
+PR ENDP1
+\f
+
+RH==2200
+LH==222200
+
+STACKL==20000.
+PDLLEN==1000.
+
+LENWRD==2200 ; LENGTH WORD
+TYPWRD==222200 ; TYPE WORD
+
+UPTBYT==220200 ; UBLOCK-PRIMTYPE PART OF TYPE WORD
+PTPBYT==220300 ; PRIMTYPE PART OF TYPE WORD
+TYPBYT==301200 ; TYPE PART OF TYPE WORD
+RTYBYT==061200 ; FOR A TYPE IN THE RH
+MONBYT==250200 ; MONITOR PART OF TYPE WORD
+$FRMDOPE==40 ; LH BIT FOR DOPE WORD
+$DOPEBIT==400000
+$QSFRB==100000 ; BIT IN GLUED FRM PC IF SEG CALL
+ ; **** CAUTION SUSPECT IN FUTURE
+ ; VERSIONS OF THE 20 ****
+SBRCAL==200000 ; BIT IF "SUBRIFY CALL"
+; Flags associated with gc spaces (see GCSFLGs) (LEFT HALF WORD)
+
+$GC%DW==400000 ; don't create dope words
+$GC%PB==200000 ; only on page boundaries
+
+LOC 1000
+
+SPCSET: BLOCK 20.
+SPCGET: BLOCK 20.
+
+STPG==._<-9.>
+
+RECTBL: BLOCK 256.*2 ; Each entry is a type/val pair
+FNBLK: BLOCK 40.
+GTJFBK: BLOCK 20
+GTJFB2=GTJFBK+1
+GTJFOS=GTJFB2+.GJCPP
+
+; UVECTOR of machine dependent information
+
+MINF: 100 ; jfn for tty input
+ 101 ; jfn for tty output
+ 36. ; bits per word
+ 7. ; bits per character
+ 512. ; words per page
+ 5 ; characters per word
+ 0 ; shift for address in word terms
+ 4 ; bytes per word
+ 377777777777 ; largest possible number (float)
+ 400000000001 ; smallest possible number (float)
+
+BOOTYP: 0
+
+; WHAT FOLLOWS IS THE INITIAL SET OF GC-PARAMS, USED UNTIL THE
+; FS SYSTEM IS STARTED.
+
+RCL: 0
+
+; RCLV IS A POINTER STRUCTURE OF FREE NON-LIST STORAGE.
+; IT IS CHAINED TOGETHER SUCH THAT MOVE AC,(AC) WILL GET THE
+; NEXT FREE BLOCK OF STORAGE. THE LENGTH OF A GIVEN BLOCK
+; POINTED AT BY AC IS TWO PLUS THE RIGHT HALF OF -1(AC).
+; THIS WORD, I.E. -1(AC) IS THE FIRST DOPE WORD OF THE BLOCK
+; WHICH WAS RECYCLED.
+; BELOW IS A SCHEMATIC REPRESENTATION OF RCLV
+
+; BITS,,LENGTH-2 BITS,,LENGTH-2
+; RCLV -> NEXT FREE BLOCK -> NEXT FREE BLOCK -> ... -> 0
+
+; 0 ; 'TYPE WORD' FOR RCLV (ALWAYS 0)
+RCLVOF==.-RCL
+RCLV: 0 ; RECYCLE VECTOR
+; 0
+0
+RCLV2O==.-RCL
+RCLV2: 0
+; 0
+RCLV3O==.-RCL
+RCLV3: 0
+; 0
+RCLV4O==.-RCL
+RCLV4: 0
+; 0
+0
+0
+RCLV7O==.-RCL
+RCLV7: 0
+; 0
+RCLV8O==.-RCL
+RCLV8: 0
+; 0
+0
+RCL10O==.-RCL
+RCLV10: 0
+GCSBOF==.-RCL
+GCSBOT: 0 ; CURRENT GC POINTER
+GCSMIO==.-RCL
+GCSMIN: GCSTRT
+GCSMXO==.-RCL
+GCSMAX: 0
+GCFLGO==.-RCL
+GCFLGS: 0
+GCPL==.-RCL
+
+SAVAC: BLOCK 20
+SAVPC: 0
+
+;TRACE: 0
+TRACL: 10
+TRACTM: 0
+
+
+ICMPER: 0
+ JRST CMPERR
+
+UUOH: 0
+ XJRST .+1
+ 0
+ MIMSEC,,UUOH1
+PAGTLN==512.
+PAGTBL: REPEAT PAGTLN,0
+INGC: 0
+ 0
+PCLEV1: 0 ; two words per int pc for multi-sec
+ 0
+PCLEV2: 0
+DUALPC: 0
+ 0
+RUNINT: 0 ; IF NON-ZERO, RUN INTS IMMEDIATELY
+MLTUUP: 0 ; HOLDS UUO (SWAPPED SORT OF)
+MLTPC: 0 ; 23 BIT PC
+UUOE:
+MLTEA: 0 ; EFF ADDR OF UUO INSTRUCTION
+MLTUUH: MIMSEC,,MLTUOP ; RUN IN MIMSEC
+
+INITZN==1 ; for now...
+
+$TANY==0
+$TBOOLEAN==0
+
+$PFIX==0
+$PLIST==1
+$PRECORD==2
+$PSTRING==5
+$PUVECTOR==6
+$PVECTOR==7
+$PBYTES==4
+$PBITS==7
+
+$TYPCNT==0
+
+; Offsets associated with FRAMEs
+
+FR.LN==6 ; Length of full frame
+FR.OFF==4 ; Offset from F to real frame ptr
+FR.ACT==1 ; Offset for PC for activation
+FR.SP==0 ; Offset for saved binding (rh)
+FR.TP==0 ; Offset for saved TP (lh)
+FR.FRA==-1 ; Offset for previous frame
+FR.ARG==-2 ; Offset for # of args to this guy (lh)
+FR.ID==-2 ; Offset for frame id (rh)
+FR.PC==-3 ; Offset for saved PC
+FR.MSA==-4 ; Offset for save MSUBR pointer
+FR.HDR==-5 ; Offset for FRAME header
+\f
+SUBTTL MULTIS
+
+; In multi-section/extended addressing mode, MIMI20 lives in section 1.
+; it is mapped there at startup time. MIMI should be able to run in either
+; single or multi section mode. The TP stack lives in a section of its own
+; and everything else is GC space (for now).
+
+MIMSEC==1 ; MIMI sections
+TPSEC==1 ; STACK sections
+IFE FLIP,[ INIGC==TPSEC+2 ; First GC section
+ ]
+IFN FLIP,[ INIGC==TPSEC+2
+ IFE TPSEC&1,[ ODDSEC==TPSEC+1
+ EVSEC==TPSEC ]
+ IFN TPSEC&1,[ ODDSEC==TPSEC
+ EVSEC==TPSEC+1 ] ]
+
+COMPAG==0 ; page mapped into all sections except
+ ; stack
+NUMSEC==12 ; total # of initial sections
+ ; (initial value of CURSIZ...)
+STRTTP==200000 ; begin control stack to avoid paging
+ ; problems
+STPDL==777000 ; put P stack in a strange place also
+PGPDL==<<TPSEC_9>\<<STPDL>_<-9>>> ; P STACK PAGE
+TPENDP==PGPDL-1 ; illegal page to end TP
+TPWARN==TPENDP-5 ; page to warn of end
+\f
+
+
+SUBTTL TYPE DEFINITIONS
+
+ TYPMAK $PFIX,UNBOUND
+ TYPMAK $PFIX,FIX
+ TYPMAK $PFIX,CHARACTER
+ TYPMAK $PFIX,FLOAT
+
+ TYPMAK $PLIST,LIST
+ TYPMAK $PLIST,FALSE
+ TYPMAK $PLIST,DECL
+
+ TYPMAK $PSTRING,STRING
+ TYPMAK $PUVECTOR,MCODE
+
+ TYPMAK $PVECTOR,VECTOR
+ TYPMAK $PVECTOR,MSUBR
+
+ TYPREC FRMTBL,FRAME
+ TYPREC BNDTBL,BINDING
+ TYPREC ATMTBL,ATOM
+ TYPREC ATMTBL,OBLIST
+ TYPREC GBNTBL,GBIND
+
+ TYPMAK $PLIST,FORM
+
+; TYPES STARTING HERE SHOULD BE HANDLED DIFFERENTLY AT SOME
+; FUTURE DATE.
+
+ TYPMAK $PFIX,TYPC
+ TYPMAK $PFIX,TERMIN
+
+ TYPMAK $PLIST,SEGMENT
+ TYPMAK $PLIST,DEFER
+ TYPMAK $PLIST,FUNCTION
+ TYPMAK $PLIST,MACRO
+
+ TYPMAK $PVECTOR,CHANNEL
+ TYPMAK $PVECTOR,ENTRY
+ TYPMAK $PVECTOR,ADECL
+ TYPMAK $PVECTOR,OFFSET
+
+ TYPREC ATMTBL,LVAL
+ TYPREC ATMTBL,GVAL
+ TYPREC ATMTBL,LINK
+
+ TYPMAK $PVECTOR,TUPLE
+ TYPMAK $PUVECTOR,UVECTOR
+ TYPMAK $PVECTOR,IMSUBR
+ TYPREC QFTBL,QFRAME
+ TYPMAK $PVECTOR,TAT
+ TYPMAK $PVECTOR,I$SDTABLE
+ TYPMAK $PVECTOR,I$DISKCHANNEL
+ TYPMAK $PVECTOR,MUDCHAN
+ TYPMAK $PFIX,WORD
+ TYPMAK $PUVECTOR,PCODE
+ TYPMAK $PVECTOR,ZONE
+ TYPMAK $PUVECTOR,GCPARAMS
+ TYPMAK $PUVECTOR,AREA
+ TYPREC FRMTBL,SFRAME
+ TYPMAK $PBYTES,BYTES
+ TYPMAK $PFIX,TYPW
+ TYPREC QFTBL,QSFRAM
+ TYPMAK $PFIX,BITS
+ TYPMAK $PVECTOR,KENTRY
+ TYPMAK $PLIST,SPLICE
+\f
+
+MPATM: 0
+PURVEC: 0
+DBVEC: 0 ; LOCATIONS WHERE PURE VEC STUFF IS STORED
+MINFO: MINF
+TOPOBL: 0
+ 0
+PAGPTR: $TUVEC,,PAGTLN
+ 0
+ICATM: 0
+ECATM: 0
+NCATM: 0
+BINDID: 0 ; USED IN BININING
+TTBIND: 0 ; TOP LEV BIND
+
+CURSIZ: NUMSEC ; Number of sections we have
+
+PURZON: 0
+ATMZON: 0
+
+RETPUR: MOVE A,PURVEC
+ MOVE B,DBVEC
+ HALTF
+ MOVE A,[SAVAC+B,,B] ; Restore ACs
+ BLT A,P
+ MOVE B,PURZON ; Pick up pure zone
+ MOVE C,ATMZON ; and atom zone
+ MOVEM A,INTSAV ; Make sure flag set
+ PUSHJ P,SAV1 ; Go do the save
+ HALTF
+
+IFN FTKCN,{
+;storage for metering
+ksava: block 1 ;save ac a
+kcntab: block 400 ;count of calls
+kcltab: block 400 ;addresses of routines to call
+;storage for trace counting
+tracnt: block 1 ;0 means don't count calls
+ tranum==4000 ;number of different atoms we may see:
+tratab: block tranum+1 ;tbluk table for atom names
+trascr: block tranum*3 ;scratch space for atom names
+traptr: block 1 ;pointer to first free word in scratch space
+tranam: block 10 ;temp space for atom name before lookup
+trsava: block 2 ;save a,b
+trsavc: block 2 ;save c,d
+trsav5: block 2 ;save 5,6
+initra: push p,a
+ movei a,trascr ;address of scratch space
+ movem a,traptr ;is first free at startup
+ hrrzi a,tranum ;0,,num
+ movem a,tratab ;tbluk table header
+ pop p,a ;restore ac
+ popj p, ;and return init'd
+;print out the table (and zero it)
+pritab: dmovem a,trsava
+ dmovem c,trsavc
+ dmovem 5,trsav5
+priget: hrroi a,[asciz/Output file for trace: /]
+ PSOUT
+ move a,[gj%sht+gj%fns]
+ move b,[.priin,,.priout]
+ GTJFN
+ jrst priget
+ move b,[070000,,300000] ;7-bit read/write
+ OPENF
+ jrst priget ;clever error handling
+prilup: hlrz 5,tratab ;number of entries in table
+ movn 5,5 ;negate
+ jumpe 5,pridun ;done?
+ hrlz 5,5 ;in left half
+ setz 3, ;largest count so far....
+
+plup: hrrz 4,tratab+1(5) ;get a canditate count
+ caml 4,3 ;bigger or equal?
+ jrst [ hrrz 6,5 ;yes, store new index
+ hrrz 3,tratab+1(6) ;and new count
+ jrst .+1]
+ aobjn 5,plup ;iterate
+;index of largest entry in ac 6 now
+ setzb 3,4
+ hrroi b,[asciz/
+/]
+ SOUT
+ hlro b,tratab+1(6) ;name
+ SOUT
+ hrrz b,tratab+1(6) ;count
+ move c,[100010,,12] ;8 columns, leading filler, decimal
+ NOUT
+ jfcl
+ hlrz 4,tratab ;table size
+ move 3,tratab+1(4) ;top entry
+ exch 3,tratab+1(6) ;flush out biggest entry
+ sos 4 ;decrement used size
+ hrlm 4,tratab ;save nwe count
+ jrst prilup ;and iterate
+pridun: CLOSF ;close the file
+ jfcl ;clever error handling
+ dmove a,trsava
+ dmove c,trsavc
+ dmove 5,trsav5
+ popj p, ;and return to caller
+;here to count a call
+trinct: dmovem a,trsava
+ dmovem c,trsavc
+ move b,3(d) ;get name of msubr
+ move a,3(b) ;get string (count,,address)
+ hrrz b,2(b) ;count into b
+ move c,[440700,,tranam] ;temp space for name
+ ildb d,a ;get bytes
+ idpb d,c ;and put them
+ sojg b,.-2 ;until there ain't no more (assumes 1 or more)
+ setz d, ;null terminator
+ idpb d,c
+ movei a,tratab ;table address
+ move b,[440700,,tranam] ;point to string
+ TBLUK ;is it there?
+ tlne b,40000 ;set if exact match
+ jrst [aos (a) ;bump count
+ jrst trret] ;and return this call
+;not in table, must add it
+ move c,traptr ;get address of first free
+ hrli c,440700 ;byte pointer
+ move a,[440700,,tranam] ;
+ ildb d,a ;get bytes
+ idpb d,c ;and put them
+ jumpn d,.-2 ;do til null
+ movei a,tratab ;table address
+ hrlz b,traptr ;address,,0
+ aos b ;,,1 initial count
+ TBADD ;add to table
+ aos c ;bump pointer to next word boundary
+ hrrzm c,traptr ;and store it
+trret: dmove a,trsava
+ dmove c,trsavc
+ popj p,
+
+;Dispatch routine to use for metering calls into the kernel
+kerjsp: movem a,ksava ;called with JSP PC,
+ hrrz a,-1(pc) ;get table offset
+ aos kcntab-entvec(a) ;bump counter
+ move a,kcltab-entvec(a) ;get real addr
+ exch a,ksava ;restore a and setup to call
+ jrst @ksava
+kercal: movem a,ksava ;save a
+ move a,(p) ;return address
+ sos a ;caller's address
+ hrrz a,(a) ;table offset used in call
+ subi a,entvec ;table index relative to table start
+ aos kcntab(a) ;count calls to this routine
+ move a,kcltab(a) ;get address of routine being called
+ exch a,ksava ;restore a and save routine address
+ jrst @ksava ;do the real kernel call
+
+};End FTKCN
+
+LOC <<.+777>&777000>
+
+SUBTTL STACK OPERATIONS & FLOW OF CONTROL
+
+; LEGAL? TAKES ARGUMENT IN A & B
+
+LEGAL: HLRZ C,A ; GET TYPE OF FROBBIE
+ CAIN C,$TFRAME
+ JRST LGLFRM
+ CAIN C,$TBIND
+ JRST LGLBND
+ MOVE C,B
+ TLZ C,770000 ; CLEAR OUT BYTE POINTER BITS
+ CAML C,[INIGC,,0] ; SKIP IF IN STACK AREA
+ JRST LGLTRU
+ HRRZ C,TP
+ HRRZ D,B
+ CAMLE D,C ; SKIP IF ON STACK
+ JRST LGLFLS ; NO, A LOSER
+ LDB D,[220300,,A] ; GET SAT
+ JRST @LGLTAB(D) ; DISPATCH
+LGLTRU: MOVSI A,$TFIX
+ JRST (PC)
+LGLTAB: SETZ LGLTRU
+ SETZ LGLTRU
+ SETZ LGLTRU
+ SETZ LGLTRU
+ SETZ LGLBYT
+ SETZ LGLSTR
+ SETZ LGLUVC
+ SETZ LGLTUP
+LGLBYT:
+LGLSTR: TLZ A,-1
+ IBP A,B ; REST TO END OF STRING
+ ADDI A,1 ; TO NEXT WORD
+LGLCOM: HLRZ B,(A)
+ TRNN B,$FRMDOPE ; DOPE WORD?
+ JRST LGLFLS ; NO, LOSER
+ HRRZ B,(A)
+ MOVE D,(A)
+ SUB A,B
+ CAME D,-1(A)
+ JRST LGLFLS
+ JRST LGLTRU
+LGLUVC: TLZ A,-1
+ MOVE C,B
+ ADD A,C
+ JRST LGLCOM
+
+LGLFRM: MOVSI D,<$TFRAME+$FRMDOPE>
+ MOVSI E,<$TSFRAM+$FRMDOPE>
+LGLFR1: HRRZ C,B
+ CAILE C,(TP)
+ JRST LGLFLS
+ HLL C,TP
+ MOVE C,-1(B)
+ MOVSI A,$TFIX
+ CAME C,E
+ CAMN C,D
+ JRST (PC)
+LGLFLS: SETZ B,
+ MOVSI A,$TFALSE
+ JRST (PC)
+
+LGLBND: CAML B,[INIGC,,0]
+ JRST LGLTRU
+ MOVSI D,<$TBIND+$FRMDOPE>
+ MOVE E,D
+ JRST LGLFR1
+
+LGLTUP: HRRZ C,B
+ CAILE C,(TP)
+ JRST LGLFLS
+ HRRZS A
+ LSH A,1
+ HLL B,TP
+ ADD A,B
+ HLRZ D,(A)
+ CAIE D,$TVECTOR+$FRMDOPE
+ CAIN D,$TTUPLE+$FRMDOPE
+ JRST LGLTRU
+ HLRZ D,-FR.LN-1(B) ; SEE IF ARGS OF A FRAME
+ CAIE D,$TFRAME+$FRMDOPE
+ CAIN D,$TSFRAM+$FRMDOPE
+ JRST LGLTRU
+
+;here to check for rested args of a frame
+
+ MOVE D,F ; start at current frame
+LGLTU3: SKIPL (D) ; glued frame
+ JRST LGLTU2
+ HRRZ D,-1(D) ; get real frame
+ HLL D,F
+LGLTU2: CAMG D,B ; skip if frame above tuple
+ JRST LGLTU1
+ MOVE D,-1(D)
+ SKIPL (D)
+ ADDI D,FR.OFF
+ JRST LGLTU3
+LGLTU1: HLRE C,FR.ARG(D) ; get arg count
+ JUMPL C,LGLFLS
+ LSH C,1
+ ADDI D,2(C) ; should be tuple end
+ CAME D,A
+ JRST LGLFLS
+ JRST LGLTRU
+
+PFRAME: HLL O1,TP
+ MOVE B,3(O1)
+ SKIPL (B)
+ JRST IPFRM1
+ HRRZ B,-1(B)
+ SUBI B,FR.OFF
+ HLL B,F
+IPFRM1: MOVE A,$WFRAME
+ JRST (PC)
+
+IENABLE:
+ SUBM R,(P)
+ PUSH P,O1
+ PUSHJ P,RINTGO
+ POP P,RUNINT
+ SUBM R,(P)
+ POPJ P,
+
+SUNWAT:
+IFN FLIP,[
+ MOVEM O1,@[MIMSEC,,UWATM]
+ MOVEM O1,@[MIMSEC+1,,UWATM]
+]
+IFE FLIP MOVEM O1,UWATM
+ JRST (PC)
+
+ARGS: HLRE A,FR.OFF+FR.ARG(O1) ; COUNT OF ARGUMENTS
+ JUMPL A,IARG1 ; FUNNY, CASE
+ HRLI A,$TTUPLE ; SET TYPE WORD
+ MOVEI B,6(O1) ; POINT AT ARGUMENT BLOCK
+ HLL B,F
+ JRST (PC)
+
+IARG1: SUBM O1,A ; POINT TO DW OF TUPLE
+ HRRZ B,FR.OFF-1(A) ; GET LENGTH
+ SUBM A,B
+ HRRZ A,FR.OFF-1(A)
+ LSH A,-1
+ HRLI A,$TTUPLE
+ ADDI B,FR.OFF-1
+ HLL B,F
+ JRST (PC)
+
+INCALL:
+IFN FTKCN,< AOS KCNTAB+%INCAL> ;Count calls
+ MOVE B,PC
+ JSP PC,FRAME
+ SUB B,R
+ HRLI B,(SETZ (R))
+ SKIPL A,-1(F) ; GET PREVIOUS GLUED FRAME
+ MOVE A,F ; OR ELSE CURRENT FRAME
+ XHLLI A,(F)
+ HRRM SP,FR.SP(A)
+ MOVEM B,FR.PC(A)
+ MOVE 0,FR.MSA(A) ; SO RETURN WINS
+ XMOVEI A,(F)
+ SKIPL (A)
+ SUBI A,FR.OFF
+ MOVEM A,-2(TP)
+IFN FLIP,[
+ AOS F,@[MIMSEC,,FRAMID]
+ MOVEM F,@[MIMSEC+1,,FRAMID]
+]
+IFE FLIP AOS F,FRAMID
+ HRRZM F,-3(TP)
+ XMOVEI F,-1(TP)
+ MOVEM 0,FR.MSA(F) ; SO RETURN WINS
+ SETZM (F)
+ ADDI B,1 ; NOTE: DONT CHANGE TO AOJA!!!
+ JRST @B
+
+ACALL:
+IFN FTKCN,< AOS KCNTAB+%ACALL> ;Count calls
+ LDB 0,[222000,,A]
+ CAIN 0,$TMSUBR
+ JRST [ MOVE D,B ; GET ATOM
+ SUB PC,R
+ HRLI PC,(SETZ (R))
+ MOVE C,O2
+ JRST ICRET ]
+ MOVEI O1,0
+ SUB PC,R
+ HRLI PC,(SETZ (R))
+ JRST CALNGS
+
+CALNGS: SKIPN NCATM ; CALL'ED ATOM IS NOT GASSIGNED
+ PUSHJ P,HALTX
+ ADJSP TP,2 ; ROOM FOR EXTRA ARG
+ XMOVEI OP,(TP)
+ SKIPN E,O2 ; # OF ARGS TO B
+ JRST CALNG5
+ DMOVE C,-3(OP)
+ DMOVEM C,-1(OP)
+ SUBI OP,2
+ SOJG E,.-3 ; MAKE ROOM
+
+CALNG5: JUMPE O1,CALNG2 ; JUMP IF NOT A CALL TO AN ATOM
+
+CALNG1: MOVE B,[$TATOM,,$LATOM]
+ MOVEM B,-1(OP)
+ MOVEM O1,(OP)
+CALNG3: MOVE O1,NCATM
+ SKIPN B,(O1) ; See if global binding for this guy
+ PUSHJ P,HALTX
+ HLRZ A,(B)
+ CAIE A,$TMSUBR ; Better be an msubr, or
+ PUSHJ P,HALTX ; we'd go into an infinite loop
+ AOJA O2,CALLR
+
+CALNG2: DMOVEM A,-1(OP) ; MUNG IN WHATEVER IT IS
+ JRST CALNG3
+
+
+CALNMS: PUSHJ P,HALTX ; VALUE OF CALL'ED ATOM ISN'T MSUBR
+
+ACTIVA:
+IFN FTKCN,< AOS KCNTAB+%ACTIVA> ;Count calls
+ MOVEI A,(PC)
+ SUBI A,(R)
+ HRRM A,FR.ACT(F)
+ HRRZ A,TP
+ SUBI A,(F) ; REL TP TO FRAME
+ HRLM A,FR.TP(F)
+ JRST (PC)
+
+RETRY: XMOVEI F,FR.OFF(O1)
+ HLRE B,FR.ARG(F) ; SEE IF TUPLE CASE
+ JUMPGE B,BLTDON
+ SUBM F,B ; B POINTS TO DW
+ HRRZ A,-1(B) ; A IS REAL # ARG
+ LSH A,-1
+ HRLM A,FR.ARG(F) ; FIX UP # ARGS
+ LSH A,1 ; TO # WORDS
+ SUBI B,1(A) ; B IS SOURCE (I.E. 1ST ARG WORD)
+ XMOVEI C,2(F) ; FIRS DEST
+ XBLT A,
+BLTDON: PUSH P,FR.ARG(F) ; SAVE FOR NEW FRAME
+ PUSH P,FR.MSA(F)
+ JSP E,FRMFIX
+ PUSH P,PC
+ JSP PC,FRAME
+ POP P,PC
+ POP P,D
+ POP P,O2
+ HLRZS C,O2
+ ADJSP TP,(O2)
+ ADJSP TP,(O2)
+ JRST ICRET
+
+AGAIN:
+IFN FTKCN,< AOS KCNTAB+%AGAIN> ;Count
+ ADDI O1,FR.OFF
+ SKIPGE (F) ; CHECK FOR GLUEDNESS
+ HRR F,-1(F) ; GET THE REAL FRAME
+ CAMN F,O1
+ JRST IAGN1
+ MOVE F,O1
+ HLRZ O1,FR.TP(F)
+ ADD O1,F
+ JSP PC,IUNBIN
+ MOVE M,FR.MSA(F)
+ MOVE M,@1(M) ; GET ATOM OF IMSUBR
+ MOVE M,1(M) ; AND FINALLY IMSUBR
+ HLRZ A,(M) ; CHECK FOR FBIN TYPE KLUDGE
+ MOVE R,1(M)
+ CAIN A,$TPCODE
+ JRST [ SKIPN R,PV%OFF(R) ; GET POINTER
+ ; NOT THERE, MAP IT IN
+ PUSHJ P,MAPIN
+ JRST .+1 ]
+IAGN1: HRRZ PC,FR.ACT(F)
+ JUMPE PC,CMPERR
+ ADD PC,R
+ HLRZ TP,FR.TP(F)
+IFE FLIP&0,[ ADD TP,F
+ JRST (PC) ]
+IFN FLIP&0,[
+ TLNN M,1 ; ODD/EVEN CHECK
+ JRST EVNSE1
+ HRLI F,EVSEC
+ HRLI P,EVSEC
+ ADD TP,F
+ JRST (PC)
+
+EVNSE1: HRLI F,ODDSEC
+ HRLI P,ODDSEC
+ ADD TP,F
+ JRST (PC) ]
+
+; HERE TO HANDLE AN UNWINDER
+
+DOUNWI: SKIPN O2,1(SP) ; GET UNWIND FRAME
+ JRST UNJOIN
+ SKIPN M,FR.MSA+FR.OFF(O2) ; RESTORE MSUBR PTR FROM FRAME
+ JRST CMPERR
+ MOVE M,1(M) ; POINT TO ATOM
+ MOVE M,(M) ; POINT TO GBIND
+ MOVE M,1(M) ; GET IMSBUR INTO M
+ HLRZ C,(M) ; CHECK FOR FBIN TYPE KLUDGE
+ MOVE R,1(M)
+ CAIN C,$TPCODE
+ JRST [ SKIPE R,PV%OFF(R) ; GET POINTER
+ JRST .+1
+ PUSH TP,A ; NOT THERE, MAP IT IN
+ PUSH TP,B
+ PUSH P,O1
+ PUSH P,O2
+ PUSHJ P,MAPIN
+ POP P,O2
+ POP P,O1
+ POP TP,B
+ POP TP,A
+ JRST .+1 ]
+ HRRZ C,4(SP) ; GET PC OFFSET
+ MOVEI D,(SP)
+ SUBI D,(TP)
+ ADJSP TP,6(D) ; MUNG IT
+ ADD C,R
+ PUSH TP,A
+ PUSH TP,B
+ PUSH TP,$WFRAM
+ PUSH TP,F
+ PUSH TP,$WBIND
+ PUSH TP,O1
+ PUSH TP,$WFIX
+ PUSH TP,PC
+ PUSH TP,$WFIX
+ PUSH TP,E
+ XMOVEI F,FR.OFF(O2)
+IFE FLIP&0,[ JRST (C) ]
+IFN FLIP&0,[
+ TLNN M,1 ; ODD/EVEN CHECK
+ JRST EVNSE2
+ HRLI TP,EVSEC
+ HRLI F,EVSEC
+ HRLI P,EVSEC
+ JRST (C)
+
+EVNSE2: HRLI TP,ODDSEC
+ HRLI F,ODDSEC
+ HRLI P,ODDSEC
+ JRST (C) ]
+
+UNWCNT:
+IFN FTKCN,< AOS KCNTAB+%UNWCN> ;Count calls
+ MOVE E,(TP)
+ MOVE PC,-2(TP)
+ MOVE O1,-4(TP)
+ MOVE F,-6(TP)
+ ADJSP TP,-10
+ POP TP,B
+ POP TP,A
+ MOVE D,2(SP) ; REALLY UNBIND IT IF SUCCESSFUL
+ JRST UNJOIN
+
+; HERE TO HANDLE FIXUP AFTER STACK LOSSAGE FROM RETURN
+RET2: MOVEI C,(TP)
+ CAIL C,<<TPWARN>_9.> ; ARE WE BELOW
+ JRST [ SKIPL C,(F)
+ JRST RET3+1
+ JRST RET3+2 ]; NO
+ PUSH P,A
+ PUSH P,B
+ MOVSI A,(SETZ)
+ HRRI A,TPWARN
+ MOVSI B,0
+ SPACS
+ HRRI A,TPWARN+1000
+ SPACS
+ POP P,B
+ MOVSI A,(SKIPL C,(F))
+ MOVEM A,RET3 ; MUNG THAT INS!!!
+ MOVEM A,@[MIMSEC+1,,RET3]
+ POP P,A
+ JRST RET3
+
+; RTUPLE WILL NOT RUN IN MIM MODE
+
+MRETUR: TDZA D,D
+
+RTUPLE: MOVEI D,1
+
+IFN FTKCN,[ SKIPN D
+ AOSA KCNTAB+%RTUPL
+ AOS KCNTAB+%MRETU
+]
+ SKIPN O2 ; 0 ==> MRET FROM CURRENT FRAME
+ XMOVEI O2,-FR.OFF(F) ; UPDATE FRAME
+MRET2: SKIPGE C,FR.OFF(O2) ; GLUED FRAME?
+ JRST GRTUPL
+ JUMPN D,MRET3 ; JUMP IF RTUPLE
+ HLRZ C,FR.HDR+FR.OFF(O2) ; SEE IF SEG FRAME
+ CAIN C,$TSFRAM+$FRMDOP
+ JRST MRET3
+ MOVE A,FR.FRA+FR.OFF(O2) ; Previous frame
+ SKIPGE C,FR.OFF(A) ; Glued?
+ JRST [HRR A,-1(A) ; Point to real frame
+ JRST MRETFO]
+ MOVE C,FR.OFF+FR.PC(A) ; Get return PC if not glued
+MRETFO: MOVE M,FR.MSA+FR.OFF(A) ; MSUBR
+ MOVE M,@1(M)
+ MOVE M,1(M) ; IMSUBR
+ HLRZ 0,(M)
+ MOVE R,1(M)
+ CAIE 0,$TPCODE ; skip if fbin
+ JRST .+3
+ SKIPN R,PV%OFF(R) ; skip if already mapped in
+ PUSHJ P,@[MIMSEC,,DMAPI1] ; Map the guy in
+ MOVE B,@C ; THIS KLUDGE SEES IF WE CAN STEP TO
+ ; NEXT FRAME FOR THIS MRETURN
+ CAMN B,[JRST @<RETOFF+ENTVEC>] ; IS IT A RETURN
+ JRST [ MOVE O2,FR.OFF+FR.FRA(O2) ; YES, MRETURN FROM IT
+ SKIPGE (O2) ; skip if not glued frame
+ SUBI O2,FR.OFF ; fix up pointer
+ JRST MRET2 ] ; try this all again
+ MOVE C,TP
+ SUB C,O1
+ SUB C,O1
+ JSP PC,FRAME
+ PUSH TP,[$TFRAME,,$LFRAME]
+ PUSH TP,O2
+ MOVEI O2,1(O1)
+
+ JUMPE O1,MRET4
+MRET5: PUSH TP,1(C)
+ PUSH TP,2(C)
+ ADDI C,2
+ SOJG O1,MRET5
+MRET4:
+ MOVE O1,ECATM
+ JSP PC,CALLZ
+ JRST COMPER
+
+MRET3: XMOVEI F,FR.OFF(O2)
+ PUSH P,O1 ; SAVE NUMBER OF ITEMS
+ PUSH P,TP ; SAVE POINTER TO STACK
+ PUSH P,C
+ PUSH P,D
+ JSP E,FRMFIX ; UNBIND, DO RETURN
+ POP P,E
+ POP P,D
+ POP P,A ; GET BACK STACK
+ MOVE C,(P) ; GET BACK TUPLE LENGTH
+ LSH C,1 ; TWICE THAT FOR # OF WORDS
+ SUB A,C ; POINT TO FIRST ELEMENT
+ XMOVEI B,1(TP) ; SAVE POINTER TO TUPLE
+ JUMPN E,IRTPL2
+ ADDI PC,1
+IRTPL2: JUMPE C,IRTPLE ; AN EMPTY TUPLE
+IRTPLP: PUSH TP,1(A) ; PUSH AN ELEMENT OF THE TUPLE
+ PUSH TP,2(A)
+ ADDI A,2 ; MOVE THROUGH TUPLE
+ SUBI C,2 ; DECREMENT COUNT
+ JUMPN C,IRTPLP ; LOOP UNTIL DONE
+IRTPLE: JUMPE E,IRTPL3
+ POP P,A ; RESTORE LENGTH
+ HRLI A,$TTUPLE
+ JRST @PC ; WIN AWAY
+
+IRTPL3: POP P,B
+ MOVSI A,$TFIX
+ JRST @PC
+
+
+GRTUPL: XMOVEI E,FR.OFF-2(O2) ; SAVE A COPY OF GLUED FRAME
+ ; POP OF GLUED FRAME
+ MOVE F,FR.OFF+1(O2) ; GET RESTORED
+ MOVE A,O1 ; COPY # OF ELEMENTS
+ LSH O1,1 ; TO NUMBER OF WORDS
+ MOVE O2,TP
+ SUB O2,O1 ; POINT TO FIRST
+ XMOVEI B,1(E)
+ MOVE O1,A
+ JUMPN D,IGRTP3 ; JUMP IF RTUPLE NOT MRETURN
+ TLZE C,$QSFRB ; SEG CALL
+ AOJA C,IGRTP3 ; YES, SKIP RETURN WITH STUFF ON STACK
+ MOVE B,@C ; THIS KLUDGE SEES IF WE CAN STEP TO
+ ; NEXT FRAME FOR THIS MRETURN
+ CAMN B,[JRST @<RETOFF+ENTVEC>] ; IS IT A RETURN
+ JRST MRET2
+ JUMPE O1,COMPER ; MUST HAVE AT LEAST ONE ARG
+ DMOVE A,1(O2) ; RET 1ST ELEMENT
+ MOVE TP,E
+ JRST @C
+
+IGRTP3: JUMPE O1,IGRTP1
+IGRTP2: PUSH E,1(O2)
+ PUSH E,2(O2)
+ ADDI O2,2
+ SOJG O1,IGRTP2
+
+IGRTP1: MOVE TP,E
+ JUMPE D,IGRTP4 ; IF MRET, RET # OF ARGS
+ HRLI A,$TTUPLE
+ JRST @C
+
+IGRTP4: MOVEI B,(A)
+ MOVSI A,$TFIX
+ JRST @C
+\f
+SUBTTL CODE TO TRY TO MAP IN A FROB
+
+IFN SBRFY,[
+SBFPMP: MOVE R,1(M) ;pointer to pcode
+ SKIPE R,PV%OFF(R)
+ JRST (PC)
+
+SBFPM1: PUSH TP,$TFIX
+ PUSH TP,5(B)
+ PUSH TP,$TFIX
+ PUSH TP,O2
+ PUSHJ P,MAPIN
+ MOVE O2,(TP)
+ MOVE 0,-2(TP)
+ SUBI TP,4
+ JRST @0
+]
+DMAPIN: PUSH P,D ; NOT THERE, MAP IT IN
+ PUSH P,O2
+IFE FLIP, PUSH P,NARGS
+IFN FLIP,[
+ PUSH P,@[MIMSEC,,NARGS]
+ PUSH P,@[MIMSEC+1,,NARGS]
+]
+ PUSHJ P,MAPIN
+IFE FLIP, POP P,NARGS
+IFN FLIP,[
+ POP P,@[MIMSEC+1,,NARGS]
+ POP P,@[MIMSEC,,NARGS]
+]
+ POP P,O2
+ POP P,D
+ POPJ P,
+
+DMAPI1: PUSH P,PC ; NOT THERE, MAP IT IN
+ PUSH P,E
+ PUSH TP,A ; SAVE RET VAL
+ PUSH TP,B
+ PUSHJ P,MAPIN
+ DMOVE A,-1(TP)
+ ADJSP TP,-2
+ POP P,E
+ POP P,PC
+ POPJ P,
+
+MAPIN: SKIPN O1,MPATM ; HAVE WE BEEN SUPPLIED WITH ATOM?
+ JRST COMPERR
+ JSP PC,FRAME ; CREATE A FRAME
+ PUSH TP,(M) ; CALL WITH THE PURVE PNTR OF INTEREST
+ PUSH TP,1(M)
+ MOVEI O2,1 ; ONE ARG
+ JSP PC,CALLZ ; GO FOR IT
+ MOVE R,1(M) ; SET UP R NOW
+ SKIPN R,PV%OFF(R) ; FROM THE VECTOR
+ JRST COMPER ; OOPS?
+ POPJ P,
+\f
+
+CIGAS:
+ MOVSI A,$TFIX
+ SKIPE B,@(TP)
+ SKIPN B,(B)
+ MOVSI A,$TFALSE
+ JRST FOOADJ
+
+CIGVL: SKIPN B,@(TP)
+ JRST COMPER
+ DMOVE A,(B)
+FOOADJ: ADJSP TP,-8.
+ POPJ P,
+
+\f
+SUBTTL UTILITY
+
+HALTX: PUSH P,A
+ HRROI A,[ASCIZ /MIMI20 Not Running
+/]
+ PSOUT
+ POP P,A
+ HALTF
+ JRST .-1
+
+; GET THE NEXT ELEMENT ON THE STACK. POINTER INTO THE STACK
+; IS THE ARGUMENT (LOCAL). RETURNS AN OBJECT, OR A #UNBOUND -1
+; IF THERE IS NOTHING ELSE ON THE STACK
+
+NEXTS: SKIPN O1
+ JRST [MOVE B,CZONE
+ MOVE B,GCPOFF(B)
+ IRP %A,,[RCLOFF,RCLVOF,RCLV2O,RCLV3O,RCLV4O,RCLV7O,RCLV8O
+ RCL10O]
+ SETZM %A(B) ; THIS IS THE START OF A GC
+ TERMIN ; SO RELEASE EVERYTHING
+ MOVEI O1,STRTTP
+ HLL O1,TP
+; SETOM INGC ; DONT PERMIT INTERRUPTS
+ JRST INEXT4]
+INEXT2: HLRE B,(O1)
+ TRNE B,$FRMDOPE ; IS THIS A RECORD DOPE WORD?
+ JRST [CAIN B,$TTUPLE+$FRMDOPE
+ JRST INEXT3
+ LDB A,[000300,,B] ; GET SAT
+ CAIE A,$PRECORD ; RECORD?
+ JRST INEXT6 ; NO, SKIP IT (STACK STRUCTURE)
+ LDB B,[RTYBYT,,B] ; YES. GET RECORD TYPE
+ ASH B,1
+ MOVE B,@RECTBL+1(B) ; GET LENGTH FROM TABLE
+ LSH B,-1 ; DIVIDE BY TWO FOR 36-BIT WORDS
+ ADDI O1,1(B) ; ADD ONE FOR HEADER WORD
+ JRST INEXT5] ; REENTER CODE
+INEXT3: ADDI O1,2 ; POINT TO NEXT ELEMENT
+INEXT5: XMOVEI B,(TP) ; ARE WE DONE YET?
+ CAML O1,B
+ JRST [MOVEI B,0 ; YUP
+ JRST INEXT1 ]
+INEXT4: HLRE B,(O1)
+ JUMPL B,[ADDI O1,3 ; SKIP PSEUDO-FRAME
+ JRST INEXT5] ; TRY THAT
+
+ TRNE B,$FRMDOPE
+ JRST [ LDB A,[000300,,B]
+ CAIE A,$PRECORD
+ CAIN A,$PVECTOR
+ JRST INEXT7
+ JRST INEXT6 ]
+
+INEXT7: SKIPN 1(O1) ; DONT RETURN 0 POINTER
+ JRST [ CAIE B,$TBIND+$FRMDOPE
+ JRST INEXT2
+ JRST .+1 ]
+ MOVE B,O1
+INEXT1: MOVE A,$WFIX
+ JRST (PC)
+INEXT6: HRRZ B,(O1)
+ ADDI O1,2(B)
+ JRST INEXT5 ; SKIP STRUCTURE, TRY AGAIN
+
+CONTEN: DMOVE A,(O1) ; GET THE PAIR FROM THE STACK
+ TLZE A,$FRMDOPE ; IS THE TYPE-WORD A DOPE WORD?
+ XMOVEI B,1(O1) ; POINT PAST THE DOPE WORD
+ JRST (PC) ; RETURN RECORD POINTER
+
+\f
+SUBTTL TYPE MANIPULATION
+
+NEWTYP: LDB B,[300,,O1] ; GET PRIMTYPE BITS
+ MOVE A,$WTCNT ; GET TYPE COUNT
+ AOS $WTCNT
+ CAIL A,1024. ; MAX NUMBER
+ PUSHJ P,COMPER ; DIE
+ DPB A,[61300,,B] ; STUFF NEW TYPE CODE
+ MOVE A,$WFIX ; AND RETURN IT
+ JRST (PC)
+
+; TYPEW - build a type word O1/ type-code O2/ type-code of prim
+
+TYPEW: LDB B,[600,,O2]
+ MOVSI A,$TTYPW
+ CAIE B,$PRECORD
+ JRST [ HRLZ B,O1
+ JRST (PC) ]
+ LDB O2,[061200,,O2]
+ ASH O2,1
+ MOVE O2,RECTBL+1(O2) ; GET POINTER TO RECORD TABLE
+ HRRZ B,(O2) ; GET LENGTH FROM TABLE
+ HRL B,O1
+ JRST (PC)
+
+; Add user template information to internal record table"
+
+TMPTBL: LSH O1,1
+ DMOVEM A,RECTBL(O1)
+ JRST (PC)
+
+XRECOR: SUBM R,(P) ; RELATIVIZE PC IN CASE OF GC
+ MOVEI A,2(O2)
+ PUSH P,E
+ PUSH P,O1
+ PUSH P,O2
+ JSP PC,IBLOCK
+ POP P,C
+ MOVE D,C ; CHANGED BY MARC (BAD DOPE WORD)
+ ADD C,A ; POINT TO DW
+ POP P,O1
+ HRL D,O1
+ TLO D,$DOPEBIT
+ TLNN 0,$GC%DW ; SKIP IF NO DW
+ MOVEM D,(C)
+ MOVE B,A
+ POP P,A
+ HRL A,O1
+ ANDI O1,$PBITS
+ CAIN O1,$PSTRING
+ ADD B,[657777,,-1] ; MAKE GLOBAL BP
+ CAIN O1,$PBYTES
+ ADD B,[577777,,-1]
+RPOPJ: SUBM R,(P)
+ POPJ P,
+\f
+SUBTTL STRUCTURE CREATION
+
+LIST: SUBM R,(P)
+ SETZ B, ; INITIALIZE CDR
+LISTL: SOJL O1,LISTE ; LOOP UNTIL DONE
+ PUSH TP,$WLIST
+ PUSH TP,B
+ PUSH P,O1
+ PUSHJ P,ICELL ; GET A CELL IN 'A'
+ POP TP,(A)
+ ADJSP TP,-1
+ POP TP,2(A) ; POP VALUE
+ POP TP,1(A) ; AND TYPE/LENGTH INTO CELL
+ POP P,O1
+ MOVE B,A ; UPDATE CDR POINTER
+ JRST LISTL ; AND LOOP
+
+LISTE: MOVE A,$WLIST ; TYPE-WORD LIST
+ SUBM R,(P)
+ POPJ P,
+
+UBLOCK: TLNE O2,-1
+ JRST COMPER ; either negative of too big
+ SUBM R,(P)
+ HRLZS O1
+ PUSHJ P,UBLOKR
+ SUBM R,(P)
+ POPJ P,
+
+UBLOKR: MOVE A,O1
+ HRR O1,O2 ; MAKE TYPE WORD (WRONG FOR STRING, BYTES)
+ MOVE D,O2
+ LSH D,1
+ PUSH P,D
+ SUBM TP,D ; POINT D AT FIRST ELEMENT
+ LDB A,[220200,,A]
+ JRST @UBLTBL(A)
+
+UBLTBL: SETZ UBLB
+ SETZ UBLS
+ SETZ UBLU
+ SETZ UBLV
+
+UBLB: MOVEI A,4
+ MOVSI B,441000
+ HRLOI C,577777
+ PUSHJ P,DOSTR
+ PUSH P,A ; PUT # WORDS WHERE EXPECTED
+ JRST UBLR1
+
+UBLS: MOVEI A,5
+ MOVSI B,440700
+ HRLOI C,657777
+ PUSHJ P,DOSTR
+ PUSH P,A
+ JRST UBLR1
+
+; COUNT IS IN O2; POINTER IN D. RETURN COUNT IN A; CAN CLOBBER D.
+STRCNT: MOVEI A,0
+ PUSH P,B
+ PUSH P,C
+ MOVE B,O2
+ JUMPE B,STRCDN
+STRCLP: LDB C,[220304,,1]
+ JUMPN C,STRCST ; A CHARACTER
+ AOJA A,STRELP
+STRCST: HRRZ C,1(D)
+ ADD A,C ; LENGTH OF STRING/BYTES
+STRELP: ADDI D,2
+ SOJG B,STRCLP
+STRCDN: POP P,C
+ POP P,B
+ POPJ P,
+
+; BYTE POINTER IN B, ARG POINTER IN D, ARG COUNT IN O2, A IS SACRED
+; (BYTE POINTER IS (A)).
+STRMOV: LDB C,[220304,,1] ; SAT OF THING IN 1(D)
+ JUMPN C,STRMVB
+ MOVE C,2(D)
+ IDPB C,B ; STUFF OUT A BYTE
+STRMEL: ADDI D,2
+ SOJG O2,STRMOV
+ POPJ P,
+STRMVB: HRRZ E,1(D)
+ JUMPE E,STRMEL
+ MOVE 0,2(D)
+STRMVL: ILDB C,0
+ IDPB C,B
+ SOJG E,STRMVL
+ JRST STRMEL
+
+DOSTR: ADJSP P,3 ; SPACE FOR EXTRA STUFF
+ PUSH P,A ; BYTES/WORD
+ PUSH P,B ; FROB TO MAKE LOCAL BYTE POINTER
+ PUSH P,C ; FROB TO MAKE GLOBAL BP WHEN DONE
+ PUSH P,D
+ PUSHJ P,STRCNT
+ HRR O1,A ; FIX UP SAVED TYPE WORD
+ ADD A,-3(P)
+ SUBI A,1 ; ROUND UP TO NEXT FULL WORD
+ IDIV A,-3(P)
+ MOVEM A,-6(P) ; # OF WORDS FOR FROB
+ ADDI A,2
+ PUSH P,O1
+ PUSH P,O2
+ JSP PC,IBLOCK ; GET STORAGE
+ POP P,O2
+ POP P,O1
+ POP P,D
+ MOVEM A,-4(P)
+ MOVEM 0,-3(P) ; SAVE ADDRESS AND FLAGS
+ MOVE B,-1(P) ; ARGUMENT FROM B
+ TLO B,1 ; MAKE BP (A)
+ JUMPE O2,STRMDN ; OBVIOUSLY EMPTY?
+ PUSH P,D
+ PUSHJ P,STRMOV
+ POP P,D
+STRMDN: MOVE 0,-3(P) ; FLAGS
+ MOVE B,-4(P) ; ADDRESS
+ MOVE C,-5(P) ; # WORDS
+ ADD C,B ; POINT TO DOPE WORDS
+ ADD B,(P) ; GLOBAL BP
+ ADJSP P,-5 ; FLUSH ALL BUT # OF WORDS
+ POP P,A ; VALUES IN A,B,C
+ POPJ P,
+
+UBLR: POP P,B ; TP BECOMES PLACE OF FIRST ARG.
+ MOVE C,(P) ; # OF WORDS IN THE UBLOCK
+ ADD C,B
+UBLR1: POP P,D ; # OF WORDS
+ TLNN 0,$GC%DW ; MAYBE STUFF INTO DOPE WORDS
+ HRRM D,(C)
+ MOVE D,O1 ; OTHER HALF OF DOPE WORD
+ TLO D,$DOPEBIT
+ TLNN 0,$GC%DW
+ JRST [HLLM D,(C)
+ SETZM 1(C)
+ JRST .+1]
+ POP P,D
+ MOVNS D
+ ADJSP TP,(D)
+ MOVE A,O1
+ POPJ P,
+
+UBLU: MOVE A,O2 ; GET # ARGUMENTS
+ PUSH P,A
+ ADDI A,2 ; ADD DOPE WORDS
+ PUSH P,O1
+ PUSH P,D
+ PUSH P,O2
+ JSP PC,IBLOCK ; GET CORE
+ POP P,O2
+ POP P,D
+ POP P,O1
+ PUSH P,A ; SAVE LOCATION
+ JUMPE O2,UBLR
+UBLUL: MOVE B,2(D)
+ MOVEM B,(A)
+ ADDI D,2
+ ADDI A,1
+ SOJN O2,UBLUL ; AND LOOP
+ JRST UBLR
+
+UBLV: MOVE A,O2 ; GET # ARGUMENTS
+ LSH A,1 ; 2 36-BIT WORDS FOR EACH
+ PUSH P,A
+ ADDI A,2 ; ADD DOPE WORDS
+ PUSH P,O1
+ PUSH P,D
+ PUSH P,O2
+ JSP PC,IBLOCK ; GET CORE
+ POP P,O2
+ POP P,D
+ POP P,O1
+ PUSH P,A ; SAVE LOCATION
+ JUMPE O2,UBLR ; CHOMPING EMPTY VECTOR
+UBLVL: MOVE B,1(D)
+ MOVEM B,(A)
+ MOVE B,2(D)
+ MOVEM B,1(A) ; STUFF
+ ADDI D,2
+ ADDI A,2
+ SOJN O2,UBLVL ; AND LOOP
+ JRST UBLR
+
+; RETURN UNINITIALIZED STORAGE. ARGS JUST LIKE UBLOCK (O1 TYPE, O2 # ELEMENTS),
+; BUT NOTHING ON STACK.
+UUBLOCK:
+ TLNE O2,-1
+ JRST COMPER ; either negative or too big!
+ HRLZS O1
+ SUBM R,(P) ; IN CASE OF GC
+ LDB A,[220200,,O1] ; GET TYPE
+ JRST @UUBLTB(A) ; TYPE DISPATCH
+UUBLTB: SETZ UUBLB
+ SETZ UUBLS
+ SETZ UUBLU
+ SETZ UUBLV
+
+UUBLB: MOVEI A,4
+ JRST UUBLS1 ; LIKE STRING, WITH 4 BYTES/WORD
+UUBLS: MOVEI A,5
+UUBLS1: MOVE B,O2 ; # OF ELEMENTS
+ ADDI B,-1(A) ; ROUND UP
+ IDIV B,A ; # OF WORDS NEEDED
+ PUSHJ P,UIB ; BUILD THE STORAGE
+ HRLOI C,657777
+ CAME O1,[$TSTRING,,0]
+ HRLOI C,577777
+ ADD B,C ; MAKE A BYTE POINTER
+UUBLR: SUBM R,(P)
+ POPJ P,
+UUBLU: MOVE B,O2
+ PUSHJ P,UIB
+ JRST UUBLR
+UUBLV: MOVE B,O2
+ LSH B,1
+ PUSHJ P,UIB
+ PUSHJ P,CLRVEC ; THIS HAS TO BE ZEROED
+ JRST UUBLR
+; TYPE IN O1, LENGTH IN O2, # WORDS (EXCLUSIVE OF DW) IN B. RETURN
+; POINTER IN A, B (SOMEBODY ELSE MAKES BYTE POINTER FOR STRINGS, BYTES
+UIB: CAILE B,777000-2 ;length better be less than a section
+ JRST COMPER
+ PUSH P,B
+ PUSH P,O1
+ PUSH P,O2
+ MOVEI A,2(B) ; # WORDS, WITH DW
+ JSP PC,IBLOCK ; GET THE STORAGE
+ POP P,O2
+ POP P,O1
+ TLNN 0,$GC%DW
+ JRST [MOVE B,A
+ ADD B,(P) ; POINT AT DOPE WORDS
+ MOVE D,O1
+ TLO D,$DOPEBIT
+ HLLM D,(B)
+ MOVE D,(P)
+ HRRM D,(B)
+ JRST .+1]
+ ADJSP P,-1
+ MOVE B,A
+ MOVE A,O1
+ HRR A,O2
+ POPJ P,
+
+; BUILD STACK STRUCTURES. O1 IS TYPE WORD, O2 IS # ELTS.
+SBLOCK: TLNE O2,-1 ; skip if not negative or too big
+ PUSHJ P,COMPER
+ HRLZS O1
+ MOVE D,O2
+ LSH D,1
+ SUBM TP,D ; POINT AT FIRST ARGUMENT (-1)
+ LDB A,[220200,,O1] ; GET LOW BITS OF SAT
+ JRST @SBTBL(A)
+SBTBL: SETZ SBBYT
+ SETZ SBSTR
+ SETZ SBUVC
+ SETZ SBVEC
+
+SBVEC: EXCH O1,O2 ; THIS IS ALMOST LIKE TUPLE
+ JSP PC,TUPLE
+ HLL A,O2
+ POPJ P,
+SBUVC: HRR O1,O2
+ MOVE A,O1 ; TYPE WORD
+ TLO O1,$FRMDOPE ; DOPE WORD
+ MOVEM O1,1(D) ; STUFF OUT FIRST DOPE WORD
+ XMOVEI C,2(D)
+ MOVE B,C ; SAVE POINTER
+ JUMPE O2,SBUVCD
+SBUVCL: MOVE E,2(D) ; PICK UP A FROB
+ MOVEM E,(C) ; STUFF IT OUT
+ ADDI D,2 ; UPDATE POINTER TO SOURCE
+ ADDI C,1 ; AND TO DEST
+ SOJG O2,SBUVCL ; JUMP IF NOT DONE
+SBUVCD: MOVEM O1,(C) ; OTHER DOPE WORD
+ MOVE TP,C ; UPDATE STACK
+ POPJ P, ; DONE
+
+; STACK BYTES AND STRINGS. D STILL HAS POINTER TO FIRST ARGUMENT
+SBBYT: MOVEI A,4
+ MOVSI B,441000
+ HRLOI C,577777
+ PUSHJ P,STKSTR
+ POPJ P,
+
+SBSTR: MOVEI A,5
+ MOVSI B,440700
+ HRLOI C,657777
+ PUSHJ P,STKSTR
+ POPJ P,
+
+STKSTR: PUSH P,O1
+ PUSH P,O2
+ PUSH P,A
+ PUSH P,B
+ PUSH P,C
+ PUSH P,D
+ PUSHJ P,STRCNT ; GET LENGTH OF NEW STRING INTO A
+ PUSH P,A ; SAVE IT
+ ADD A,-4(P)
+ SUBI A,1
+ IDIV A,-4(P) ; # WORDS FOR STRING
+ HRR O1,A ; SAVE FOR DOPE WORDS
+ ADDI A,2 ; PLUS DOPE
+ TLO O1,$FRMDOPE ; MAKE IT A DOPE WORD
+ MOVE B,O2
+ LSH B,1 ; WORDS OF ARGUMENT
+ MOVE C,-1(P) ; BEGINNING OF BLOCK, ALMOST
+ ADDI C,1 ; REAL BEGINNING OF BLOCK
+ PUSH P,C ; WHICH WILL BE LOC OF 1ST DOPE WORD
+ MOVE D,C
+ CAML A,B ; ENSURE NO BACKWARDS BLT PROBLEMS
+ JRST [ADD D,A
+ JRST SSBCNT]
+ ADD D,B
+SSBCNT: MOVEM D,-2(P) ; SAVE IT
+ XBLT B, ; BLT THE ARGS DOWN THE STACK
+ POP P,A ; GET POINTER TO STACK AREA WE'RE USING
+ MOVEM O1,(A) ; DUMP OUT FIRST DW
+ ADDI A,1
+ PUSH P,A ; SAVE ADDRESS OF RESULT
+ MOVE B,-4(P) ; LOCAL BYTE POINTER
+ TLO B,1 ; MAKE IT BE (A)
+ MOVE O2,-6(P)
+ JUMPE O2,SSBNOM
+ MOVE D,-2(P)
+ SUBI D,1 ; SHOULD POINT BEFORE ARG BLOCK
+ PUSHJ P,STRMOV ; COPY THE STUFF IN
+SSBNOM: MOVE B,(P) ; RESULT POINTER
+ HRRI C,(O1)
+ ADDI B,(C) ; POINT TO LAST DOPE WORD
+ MOVEM O1,(B) ; STUFF OUT DOPE WORD
+ MOVE TP,B
+ POP P,B ; POINTER
+ POP P,A
+ HLL A,O1
+ TLZ A,$FRMDOPE
+ ADD B,-1(P)
+ ADJSP P,-6
+ POPJ P,
+
+; RETURN UNINITIALIZED STORAGE ON STACK. O1 IS TYPE WORD, O2 IS # ELTS.
+; SAVE ACS EXCEPT A AND B.
+USBLOCK:
+ TLNE O2,-1
+ JRST COMPER ; either negative or too big
+ HRLZS O1
+ PUSH P,C
+ LDB A,[220200,,O1]
+ JRST @USTBL(A)
+USTBL: SETZ USBYT
+ SETZ USSTR
+ SETZ USUVC
+ SETZ USVEC
+USBYT: MOVEI A,3(O2)
+ IDIVI A,4 ; # WORDS, EXCLUDING DOPE WORDS
+ MOVE C,O1
+ TLO C,$FRMDOPE
+ HRRI C,(A)
+ PUSH TP,C
+ XMOVEI B,1(TP)
+ ADJSP TP,(A)
+ PUSH TP,C
+ ADD B,[577777,,-1]
+USRET: MOVE A,O1
+ HRR A,O2
+ POP P,C
+ POPJ P,
+USSTR: MOVEI A,4(O2)
+ IDIVI A,5
+ MOVE C,O1
+ TLO C,$FRMDOPE
+ HRRI C,(A)
+ PUSH TP,C
+ XMOVEI B,1(TP)
+ ADJSP TP,(A)
+ PUSH TP,C
+ ADD B,[657777,,-1]
+ JRST USRET
+
+USUVC: MOVE C,O1 ; MAKE A DOPE WORD
+ TLO C,$FRMDOPE
+ HRRI C,(O2) ; # ELTS + 2 FOR DOPE WORD
+ PUSH TP,C ; PUSH HEADER DOPE WORD
+ XMOVEI B,1(TP) ; SAVE POINTER
+ ADJSP TP,(O2) ; CREATE SPACE
+ PUSH TP,C ; PUSH TRAILER DOPE WORD
+ JRST USRET ; RETURN
+
+USVEC: MOVE A,O2
+ LSH A,1
+ HRLI C,$FRMDOPE+$TTUPLE
+ HRRI C,(A)
+ XMOVEI B,1(TP)
+ ADJSP TP,(A)
+ PUSH TP,C
+ PUSH TP,[0]
+ MOVE A,O1
+ HRR A,O2
+ PUSHJ P,CLRVEC
+ POP P,C
+ POPJ P,
+
+; ZERO A VECTOR
+CLRVEC: TRNN A,-1
+ POPJ P, ; EMPTY
+ PUSH P,C ; SAVE ACS
+ PUSH P,D
+ PUSH P,E
+ HRRZ C,A ; GET LENGTH IN WORDS
+ LSH C,1
+ SUBI C,1 ; LESS FIRST WORD
+ SETZM (B) ; CLEAR FIRST WORD
+ MOVE D,B ; SOURCE BLOCK
+ XMOVEI E,1(B) ; DEST BLOCK
+ XBLT C, ; DO IT
+ POP P,E
+ POP P,D
+ POP P,C
+ POPJ P,
+
+RECORD: SUBM R,(P)
+ HRLZS O1
+ PUSHJ P,RECORR
+ SUBM R,(P)
+ POPJ P,
+
+RECORR: LDB A,[301200,,O1]
+ ASH A,1
+ MOVE A,RECTBL+1(A) ; GET POINTER TO RECORD TABLE
+ ADDI A,1 ; POINT TO FIRST ENTRY
+ PUSH P,O1 ; SAVE TYPE WORD FOR RETURN
+ PUSH P,A ; SAVE POINTER TO TABLE
+
+; HLRZ C,-1(A)
+; HRRM C,-1(P)
+; HRRZ A,-1(A) ; GET # 1/2 WORDS NEEDED FOR RECORD
+
+; THE SEMI'ED LINES ABOVE ARE CHANGED TO THE TWO FOLLOWING
+; SHOULD CHANGE THE LENGTH FIELD OF RECORDS TO BE 'RIGHT'
+; I.E. THE NUMBER OF 1/2 WORDS IN THE RECORD
+
+ HRRZ A,-1(A)
+ HRRM A,-1(P)
+
+ ASH A,-1
+ PUSH P,A ; SAVE THIS FOR A MOMENT
+ ADDI A,2 ; ADD FOR DOPE WORDS
+ PUSH P,O1
+ PUSH P,O2
+ JSP PC,IBLOCK ; HERE THEY ARE
+ POP P,O2
+ POP P,O1
+ MOVE C,A ; HOLD ON TO RECORD POINTER
+ ADD A,(P) ; POINT TO THE DOPE WORD
+ POP P,B ; HERE'S THE # WORDS AGAIN
+ TLNN 0,$GC%DW
+ JRST [TLO O1,$DOPEBIT ; SET THE DOPEWORD BIT
+ HLLM O1,(A) ; PUT TYPE WORD IN DOPES
+ HRRM B,(A) ; STORE IT IN DOPE WORD
+ SETZM 1(A)
+ JRST .+1]
+ POP P,A ; RESTORE TABLE POINTER
+ PUSH P,C ; SAVE POINTER TO RECORD FOR RETURN
+ MOVE D,C
+ MOVSI C,222200+D ; MAKE BP TO RECORD
+ MOVE E,O2 ; GET COUNT OF ELEMENTS
+ LSH E,1 ; 2 WORDS PER ELEMENT
+ PUSH P,E
+ SUBM TP,E ; E POINTS TO FIRST ARG
+ ADDI E,1
+RECORL: HLRZ C,1(A) ; BYTE OFFSET
+ ADJBP C,[222200+D,,0]
+ HRRZ B,1(A) ; SIZE OF THIS ELEMENT IN RECORD
+ PUSHJ P,@PUTRTB-1(B) ; DO A 'PUTR'
+ ADDI A,2 ; ADVANCE POINTER IN TABLE
+ ADDI E,2 ; ADVANCE POINTER TO ELEMENT
+ SOJN O2,RECORL ; LOOP UNTIL DONE
+ POP P,D
+ MOVNS D
+ ADJSP TP,(D) ; RESTORE TP
+ POP P,B ; RESTORE VALUE WORD (POINTER)
+ POP P,A ; RESTORE TYPE/LENGTH WORD
+ POPJ P,
+
+\f
+SUBTTL STRUCTURE MANIPULATION
+
+NTHU: LDB A,[UPTBYT,,A] ; TYPE IN A, PTR IN O1, NUM IN O2
+ JRST @NTHUTB(A)
+
+NTHUTB: SETZ NTHUS
+ SETZ NTHUS
+ SETZ NTHUU
+ SETZ NTHUV
+
+NTHUB: ADJBP O2,O1
+ LDB B,O2
+ MOVE A,$WFIX
+ POPJ P,
+
+NTHUS: ADJBP O2,O1
+ LDB B,O2
+ MOVE A,$WCHARACTER
+ POPJ P,
+
+NTHUU: SUBI O2,1
+ ADD O2,O1
+ MOVE A,$WFIX
+ MOVE B,(O2)
+ POPJ P,
+
+NTHUV: SUBI O2,1
+ LSH O2,1
+ ADD O2,O1
+ DMOVE A,(O2)
+ POPJ P,
+
+;; NTHR CODE
+
+NTHR:
+NTHRR: ASH A,1
+ SKIPN A,RECTBL+1(A) ; AND POINTER TO TABLE
+ PUSHJ P,HALTX
+ LSH O2,1 ; 4 16-BIT WORDS / ENTRY
+ ADDI A,-1(O2) ; POINT TO CORRECT ENTRY
+ HRRZ B,1(A) ; GET SIZE OF ITEM TO EXTRACT
+ HLRZ C,1(A) ; WORD OFFSET TO START FROM
+ MOVE O2,O1 ; COPY IN CASE MULTI SECT
+; HRLI O1,222240 ; MAKE WORK IN MULTI SECT
+ MOVSI O1,222200+O2
+ ADJBP C,O1 ; MAKE BYTE POINTER TO ITEM
+ ; IN MULTI SECT, C & D ARE BPTR
+ JRST @NTHRTB-1(B) ; DISPATCH
+
+NTHRTB: SETZ NTHRBB ; BOOLEAN
+ SETZ NTHRE ; ERROR - SHOULDN'T HAPPEN
+ SETZ NTHRBB ; ENUMERATION
+ SETZ NTHRBB ; SUB-RANGE
+ SETZ NTHRBB ; SUB-RANGE (SBOOL)
+ SETZ NTHRLF ; LIST OR FIX
+ SETZ NTHRLF ; LIST OR FIX (SBOOL)
+ SETZ NTHRS3 ; STRUC IN 3 HALF WORDS
+ SETZ NTHRS3 ; SAME WITH SBOOL
+ SETZ NTHRS2 ; STRUC WITH DEFINED LENGTH
+ SETZ NTHRS2 ; SAME SBOOL
+ SETZ NTHRA ; ANY
+ SETZ NTHRHW ; SPECIAL TYPE-C CASE
+
+; HERE TO EXTRACT A BOOLEAN
+
+NTHRBB: LDB B,C ; GET WORD OF BOOLEANS
+ LSH B,18. ; SHIFT OVER
+ ILDB C,C ; GET NEXT 16 BITS
+ IOR B,C ; THEN OR THEM TOGETHER
+ LDB C,[111100,,(A)] ; GET LEFT SHIFT
+ LSH B,(C) ; SHIFT IT
+ LDB C,[001100,,(A)] ; GET RIGHT SHIFT
+ MOVNS C
+ LSH B,(C) ; SHIFT RIGHT
+ HLLZ A,(A)
+ POPJ P,
+
+; HERE FOR LOSER
+
+NTHRE: PUSHJ P,COMPER
+
+; HERE TO EXTRACT LIST OR FIX
+
+NTHRLF: HLLZ A,(A) ; GET TYPE/LENGTH FROM TABLE
+ LDB B,C ; GET VALUE BYTE
+ LSH B,18. ; SHIFT OVER
+ ILDB C,C ; GET NEXT 16 BITS
+ IOR B,C ; THEN OR THEM TOGETHER
+ POPJ P,
+
+; HERE TO EXTRACT 2-WORD ITEM
+
+NTHRS3: HLLZ A,(A) ; GET TYPE/LENGTH FROM TABLE
+ LDB 0,C ; LOAD FIRST 16 BITS
+ ILDB B,C ; GET NEXT 16 BITS
+ LSH B,18. ; SHIFT OVER
+ ILDB C,C ; GET NEXT 16 BITS
+ IOR B,C ; THEN OR THEM TOGETHER
+ HRR A,0
+NTHRX: JUMPN B,CPOPJ
+ MOVE A,$WFALSE
+CPOPJ: POPJ P,
+
+; HERE TO EXTRACT STRUC WITH KNOWN LENGTH ITEM
+
+NTHRS2: LDB B,C ; GET LENGTH WORD
+ LSH B,18. ; SHIFT OVER
+ ILDB C,C ; GET NEXT 16 BITS
+ IOR B,C ; THEN OR THEM TOGETHER
+ MOVE A,(A) ; GET TYPE WORD FROM TABLE
+ ILDB C ; FIX POINTER (SHOULD BE IBP)
+ JRST NTHRX
+
+; HERE TO EXTRACT 4-WORD ITEM (ANY)
+
+NTHRA: LDB B,C ; GET TYPE WORD
+ HRLZS B
+ ILDB A,C ; GET LENGTH WORD
+ IOR A,B ; PUT EM TOGETHER
+ ILDB B,C ; LOAD FIRST 16 BITS
+ LSH B,18. ; SHIFT OVER
+ ILDB C,C ; GET NEXT 16 BITS
+ IOR B,C ; THEN OR THEM TOGETHER
+ POPJ P,
+
+NTHRHW: LDB B,C ; GET POSSIBLE TYPE CODE
+ CAIN B,-1
+ JRST [ MOVEI B,0
+ MOVSI A,$TFALSE
+ POPJ P, ]
+ HLLZ A,(A) ; TYPE FROM TABLE
+ POPJ P,
+
+PUTU: LDB A,[UPTBYT,,A]
+ JRST @PUTUTB(A)
+
+PUTUTB: SETZ PUTUS
+ SETZ PUTUS
+ SETZ PUTUU
+ SETZ PUTUV
+
+PUTUS: ADJBP O2,B
+ DPB D,O2
+ POPJ P,
+
+PUTUU: ADDI B,-1(O2)
+ MOVEM D,(B)
+ POPJ P,
+
+PUTUV: SUBI O2,1
+ LSH O2,1
+ ADD B,O2
+ DMOVEM C,(B)
+ POPJ P,
+
+PUTR: ASH A,1
+ SKIPN A,RECTBL+1(A) ; AND POINTER TO TABLE
+ PUSHJ P,HALTX
+ PUSH TP,(D) ; SAVE VALUE
+ PUSH TP,1(D)
+ LSH O2,1 ; 4 16-BIT WORDS / ENTRY
+ ADDI A,-1(O2) ; POINT TO CORRECT ENTRY (REMEMBER TOP)
+ HRRZ B,1(A) ; GET SIZE OF ITEM TO EXTRACT
+ HLRZ C,1(A) ; WORD OFFSET TO START FROM
+ MOVE O2,O1
+ XMOVEI E,-1(TP) ; SEND VALUE IN E
+; HRLI O1,LH+40
+ MOVSI O1,LH+O2
+ ADJBP C,O1 ; MAKE BYTE POINTER TO ITEM
+ PUSHJ P,@PUTRTB-1(B) ; DISPATCH
+ ADJSP TP,-2
+ POPJ P,
+
+PUTRTB: SETZ PUTRBB ; BOOLEAN
+ SETZ PUTRE ; ERROR - SHOULDN'T HAPPEN
+ SETZ PUTRBB ; ENUMERATION
+ SETZ PUTRBB ; SUB-RANGE
+ SETZ PUTRBB ; SUB-RANGE (SBOOL)
+ SETZ PUTRLF ; LIST OR FIX
+ SETZ PUTRLF ; LIST OR FIX (SBOOL)
+ SETZ PUTRS3 ; STRUC IN 3 HALF WORDS
+ SETZ PUTRS3 ; SAME WITH SBOOL
+ SETZ PUTRS2 ; STRUC WITH DEFINED LENGTH
+ SETZ PUTRS2 ; SAME SBOOL
+ SETZ PUTRA ; ANY
+ SETZ PUTRHW ; SPECIAL CASE FOR TYPE-C
+
+; HERE TO SET A BOOLEAN
+
+PUTRBB: LDB 0,[111100,,(A)] ; GET LSHIFT
+ LDB A,[001100,,(A)] ; GET RSHIFT
+ MOVE B,A
+ SUB B,0
+ LSH B,30. ; BUILD BYTE POINTER
+ MOVEI 0,36.
+ SUBI 0,(A)
+ LSH 0,24.
+ IOR 0,B ; HAVE LH OF BYTE POINTER
+ LDB B,C
+ LSH B,18.
+ ILDB A,C
+ IOR A,B
+ HRRI 0,A ; POINT TO AC
+ MOVE B,1(E) ; NEW VAL
+ DPB B,0 ; SMASH REGISTER
+ DPB A,C ; PUT IT BACK
+ MOVNI B,1
+ ADJBP B,C ; SMASH OTHER BYTE
+ HLRZS A
+ DPB A,B ; OTHER HALF BACK IN
+ POPJ P,
+
+
+PUTRE: PUSHJ P,COMPER
+
+PUTRLF: LDB B,[LH,,1(E)] ; GET LH OF VALUE OF 3RD ARG
+ DPB B,C ; AND STUFF
+ LDB B,[RH,,1(E)] ; GET RH OF VALUE OF 3RD ARG
+ IDPB B,C ; AND STUFF
+ POPJ P,
+
+PUTRS2: HLRZ B,(E) ; TYPE OF ARG
+ CAIN B,$WFALSE
+ SETZM 1(E) ; MAKE SURE 0
+ JRST PUTRLF
+
+; HERE FOR 3 WORD ITEM (IE LENGTH AND POINTER)
+
+PUTRS3: LDB B,[LENWRD,,(E)] ; GET LENGTH
+ DPB B,C ; STUFF IT
+ ILDB C ; FIX POINTER (SHOULD BE IBP)
+ JRST PUTRS2
+
+; HERE TO SET 4-WORD ITEM (ANY)
+
+PUTRA: LDB B,[TYPWRD,,(E)] ; GET TYPE
+ DPB B,C ; AND STUFF IT
+ LDB B,[LENWRD,,(E)]
+ IDPB B,C
+ ILDB B,C
+ JRST PUTRLF
+
+PUTRHW: LDB B,[TYPWRD,,(E)] ; TYPE OF ARG
+ CAIE B,$TFALSE ; FALSE ==> ZERO SLOT
+ SKIPA B,1(E) ; NOT FALSE USE TYPEC
+ MOVEI B,-1
+ DPB B,C ; STORE IT
+ POPJ P,
+
+BACKU: MOVNS O2
+RESTU: LDB C,[UPTBYT,,A]
+ JRST @RESUTB(C)
+
+RESUTB: SETZ RESUB
+ SETZ RESUS
+ SETZ RESUU
+ SETZ RESUV
+
+RESUU: SUB A,O2
+ ADD B,O2
+ HRLI A,$TUVECTOR
+ JRST (PC)
+
+RESUB: SUB A,O2
+ EXCH B,O2
+ ADJBP B,O2
+ HRLI A,$TBYTES
+ JRST (PC)
+
+RESUS: SUB A,O2
+ EXCH B,O2
+ ADJBP B,O2
+ HRLI A,$TSTRING
+ JRST (PC)
+
+RESUV: SUB A,O2
+ LSH O2,1
+ ADD B,O2
+ HRLI A,$TVECTOR
+; CAMG B,TP
+; HRLI A,$TTUPLE ; Win with tuples???
+ JRST (PC)
+
+TOPU: HRRZ C,A
+ LDB D,[UPTBYT,,A]
+ JRST @TOPUTB(D)
+
+TOPUTB: SETZ TOPUB
+ SETZ TOPUS
+ SETZ TOPUU
+ SETZ TOPUV
+
+TOPUB: MOVEI D,60
+ MOVEI E,4
+ HRLI 0,$TBYTES
+ JRST TOPUS1
+
+TOPUS: MOVEI D,66
+ MOVEI E,5
+ HRLI 0,$TSTRING
+TOPUS1: ADJBP C,B ; ADJUST TO THE END
+ MOVE B,C
+ LDB C,[360600,,B]
+ SUBI C,(D) ; # BYTES UNUSED IN LAST WORD
+ TLZ B,770000 ; MAKE WORD POINTER
+ HRRZ A,1(B) ; THIS IS TOTAL LENGTH (FROM DOPE)
+ SUB B,A ; TO WORD ADDRESS OF STRING START
+ IMUL A,E
+ LSH D,12.
+ TLO B,(D) ; MAKE CORRECT GLOBAL BP
+ ADD A,C ; ADJUST LENGTH
+ HLL A,0 ; MAKE A TYPE WORD
+ JRST (PC)
+
+TOPUU: ADD B,C ; POINT TO DOPE WORD
+ HRRZ A,(B) ; GET TOTAL LENGTH
+ SUB B,A ; BACK IT UP
+ HRLI A,$TUVECTOR ; HERE'S THE TYPE WORD
+ JRST (PC)
+
+TOPUV: LSH C,1
+ ADD B,C ; POINT TO DOPE WORD
+ HRRZ A,(B) ; HERE IS TOTAL LENGTH
+ SUB B,A ; POINTS TO TOP OF VECTOR
+ LSH A,-1 ; GET LENGTH
+ HRLI A,$TVECTOR ; AND FINISH TYPE WORD
+ JRST (PC)
+
+; HERE FOR CONS NEEDING GC
+
+CONS1: PUSH P,PC
+ SUBM R,(P)
+ PUSH TP,C
+ PUSH TP,D
+ PUSH TP,$WLIST
+ PUSH TP,E ; IN CASE A GC OCCURS
+ PUSHJ P,ICELL
+ POP TP,(A)
+ ADJSP TP,-1
+ POP TP,2(A)
+ POP TP,1(A)
+ MOVE B,A
+ MOVE A,$WLIST
+ JRST RPOPJ
+
+
+\f
+SUBTTL INPUT / OUTPUT
+
+BPS: 440700,,(D)
+ 350700,,(D)
+ 260700,,(D)
+ 170700,,(D)
+ 100700,,(D)
+
+OPENX: MOVE E,D
+ PUSHJ P,OPNAM ; MAKE FILE NAME STRING
+ HRROI B,FNBLK
+ XCT GTJMOD(O1) ; PERFORM GTJFN BITS MAGIC
+ GTJFN
+ JUMP 16,JFSERR
+ MOVE B,O2
+ LSH B,30.
+ XCT OPNMOD(O1) ; PERFORM OPENF BITS MAGIC
+ OPENF
+ JUMP 16,JFSERR
+ MOVE B,$WFIX ; RETURN JFN NUMBER
+ EXCH A,B
+ POPJ P,
+
+OPNAM: MOVE B,[440700,,FNBLK] ; BP TO FILE NAME BLOCK
+ HRRZS C
+OPNAML: ILDB 0,E ; GET CHARACTER
+ IDPB 0,B ; AND STUFF IT
+ SOJN C,OPNAML ; LOOP UNTIL DONE
+ SETZ 0,
+ IDPB 0,B ; MAKE IT ASCIZ
+ POPJ P,
+
+GTJMOD: MOVSI A,(GJ%SHT+GJ%OLD)
+ MOVSI A,(GJ%SHT+GJ%FOU)
+ JRST COMPER
+ JRST COMPER
+
+OPNMOD: HRRI B,OF%RD
+ HRRI B,OF%WR
+ JRST COMPER
+ JRST COMPER
+
+CLOSEX: CLOSF ; ATTEMPT TO CLOSE JFN
+ JRST RETERR ; CHOMP
+ MOVE A,$WFIX ; RETURNS 1 IF WINNING
+ MOVEI B,1
+ POPJ P,
+
+RESETX: POPJ P,
+
+ATIC: AOS A,ATICNM'
+ MOVEI C,35.
+ SUB C,A
+ MOVEI B,1
+ LSH B,(C)
+ TDNN B,[770000,,003777]
+ JRST ATIC ; TRY different char
+ MOVEI A,.FHSLF
+ AIC
+ JUMPL O1,ATICDN ; If not a char, don't do ATI
+ MOVE A,ATICNM
+ HRL A,O1
+ CAIN O1,7 ; store channel for ^G and ^A
+ MOVEM B,CTLGCH
+ CAIN O1,1
+ MOVEM B,CTLACH
+ ATI
+ATICDN: MOVE A,$WFIX
+ MOVE B,ATICNM
+ POPJ P,
+
+RETERR: PUSH P,A ; SAVE ERROR CODE
+ PUSHJ P,ICELL ; GET A LIST CELL
+ MOVE B,$WFIX ; STUFF THE CELL WITH ERROR CODE
+ SETZM (A)
+ MOVEM B,1(A)
+ POP P,2(A)
+ MOVE B,A
+ MOVE A,$WFALSE ; AND RETURN AS FALSE
+ POPJ P,
+
+IOERR: SUBM R,(P)
+ MOVEI A,400000 ; GET ERROR
+ GETER
+ HRRZ A,B
+ PUSHJ P,RETERR ; CONS IT UP
+ MOVEI O2,1
+ JRST CMPER2 ; GO GIVE IT TO USER
+
+; Return run time of process, in seconds, as float
+RNTIME: PUSH P,C
+ MOVEI A,.FHSLF
+ RUNTM
+ FLTR B,A
+ FDVR B,[1000.0]
+ MOVE A,$WFLOAT
+ POP P,C
+ POPJ P,
+
+PRINTZ: MOVNS C
+ SOUT
+ POPJ P,
+
+READX: PUSH P,C
+ PUSH P,D
+ MOVEM OP,.RDRTY+IRDBLK ; SET UP PROMPT
+ JUMPN OP,READX1
+ PUSH TP,$WFALSE ; SAVE IF NO PROMPT
+ PUSH TP,OP
+ JRST READX4
+READX1: MOVEI D,1 ; OTHERWISE, GET LENGTH, SAVE STRING
+READX3: ILDB C,OP
+ JUMPE C,READX2
+ AOJA D,READX3
+READX2: HRLI D,$TSTRING
+ PUSH TP,D
+ PUSH TP,.RDRTY+IRDBLK
+READX4: MOVEI C,IRDBRK
+ MOVEM C,.RDBRK+IRDBLK ; SETUP BREAK MASK
+ PUSH TP,$WFIX
+ PUSH TP,[0]
+ JUMPE E,READNM
+ SETOM (TP)
+ SETZM ARDBRK
+ MOVE C,[ARDBRK,,ARDBRK+1]
+ BLT C,ARDBRK+3
+ MOVEI C,ARDBRK
+ MOVEM C,.RDBRK+IRDBLK
+ SKIPA C,[4] ; Turn on ctrl-D
+READLP: ILDB C,E
+ JUMPE C,READNM
+ IDIVI C,32.
+ MOVSI OP,400000
+ MOVNS D
+ LSH OP,(D)
+ IORM OP,ARDBRK(C)
+ JRST READLP
+READNM: MOVE C,-1(P)
+ MOVE D,(P)
+ HRLM A,.RDIOJ+IRDBLK ; INPUT JFN
+ MOVEM B,.RDBFP+IRDBLK ; DESTINATION BUFFER POINTER
+ MOVEM B,.RDBKL+IRDBLK ; BACKUP LIMIT
+ SUB C,D ; GET LENGTH OF STRING
+ MOVEM C,.RDDBC+IRDBLK ; AND SUBTRACT CHRS ALREADY READ
+ ADJBP D,B ; ADJUST STRING FOR CHRS ALREADY READ
+ MOVEM D,.RDDBP+IRDBLK ; DESTINATION STRING
+ MOVEI C,.NULIO
+ CAIN A,.PRIIN
+ MOVEI C,.PRIOU
+ HRRM C,.RDIOJ+IRDBLK
+ PUSH TP,$WFIX
+ PUSH TP,IRDBLK+.RDIOJ
+ MOVE C,-1(P) ; STRING LENGTH
+ HRLI C,$TSTRING
+ PUSH TP,C
+ PUSH TP,IRDBLK+.RDBFP
+ MOVE C,IRDBLK+.RDBRK
+ PUSH TP,$WFIX
+ PUSH TP,(C)
+ PUSH TP,$WFIX
+ PUSH TP,1(C)
+ PUSH TP,$WFIX
+ PUSH TP,2(C)
+ PUSH TP,$WFIX
+ PUSH TP,3(C)
+ ADJSP P,-2 ; NOW NOTHING ON P STACK
+BRESTA: MOVEI A,IRDBLK
+ TEXTI ; DO IT
+RRESTA: JFCL
+; This now has a giant kludge to make ctrl-D redisplay the buffer without
+; clearing the screen.
+ LDB B,.RDDBP+IRDBLK ; Look at last character read
+ CAIE B,^D ; ctrl-D?
+ JRST DTEXTI
+ HRRZ A,.RDIOJ+IRDBLK ; Yes, pick up output jfn to use
+ MOVEI B,^M ; do crlf
+ BOUT
+ MOVEI B,^J
+ BOUT
+ SKIPN B,.RDRTY+IRDBLK
+ JRST NOPRMP
+ MOVEI C,0
+ SOUT ; Output prompt
+NOPRMP: MOVE B,.RDBFP+IRDBLK ; pick up pointer to buffer beginning
+ HRRZ C,-11(TP) ; ORIGINAL LENGTH OF BUFFER
+ AOS .RDDBC+IRDBLK ; ADD 1 TO CHARS AVAILABLE
+ SUB C,.RDDBC+IRDBLK ; REAL NUMBER CHARS IN BUFFER
+ MOVNS C ; - # CHARS IN BUFFER
+ SKIPE C ; don't print if none there
+ SOUT ; print buffer
+ MOVEM B,.RDDBP+IRDBLK ; update dest string pointer
+ MOVEI A,IRDBLK
+ JRST BRESTA ; try again
+
+DTEXTI: CAIE B,^M ; FUNNINESS IF ^M AS TERMINAL
+ JRST DTEXT2
+ HLRZ A,.RDIOJ+IRDBLK ; PICK UP INPUT JFN
+ SIBE
+ JRST DTEXT1
+ JRST DTEXT2
+DTEXT1: BIN ; READ & DUMP THE CHARACTER
+DTEXT2: HRRZ B,-11(TP) ; GET ORIGINAL LENGTH
+ SUB B,.RDDBC+IRDBLK ; FIXUP COUNT
+ MOVE A,$WFIX
+ ADJSP TP,-20 ; EIGHT THINGS PUSHED ON STACK
+ POPJ P,
+
+; JFN IN A, TABLE IN B, LENGTH IN C
+RFTADX: PUSH TP,$WFIX
+ PUSH TP,B
+ PUSH TP,$WFIX
+ PUSH TP,P
+ HLRZ D,P ; Make sure it's really the same
+ HRLI B,1 ; section
+ CAIE D,2
+ HRLI B,2
+ HRRI B,1(P)
+ ADJSP P,(C)
+ RFTAD
+ ERJMP RFTADF ; Return false
+ MOVE A,-2(TP)
+RFTADL: MOVE D,(B)
+ MOVEM D,(A)
+ ADDI A,1
+ ADDI B,1
+ SOJG C,RFTADL
+ MOVSI A,$TFIX
+ SKIPA
+RFTADF: MOVSI A,$TFALSE
+ MOVEI B,0
+ POP TP,P
+ ADJSP TP,-3
+ POPJ P,
+
+SOUTX: SKIPA O1,[SOUT]
+
+SINX: MOVE O1,[SIN]
+RSINX: MOVEI O2,1
+ PUSH P,C
+ PUSH P,D ; Save these guys in case of retry
+ PUSH P,B ; Byte pointer
+ PUSH P,0 ; Type
+ LDB 0,[220300,,0]
+ CAIN 0,$PUVECT
+ JRST [HLL 0,B
+ HRLI B,444400
+ HRRI 0,DOJSYS
+ PUSHJ P,@0
+ MOVEI O2,0 ; INDICATE FAILURE (never happens)
+ POP P,A
+ POP P,C
+ SKIPLE B
+ ADDI B,1
+ SUBM B,C
+ SUBI A,(C)
+ JRST SINXXX]
+ PUSH P,0 ; SAVE TYPE OF FROB
+ CAIE 0,$PSTRIN
+ CAIN 0,$PBYTES
+ CAIA
+ JRST COMPER
+ XCT O1
+ JUMP 16,[ MOVEI O2,0 ; Error case
+ JRST .+1 ]
+ HRL O1,A ; SAVE JFN
+ POP P,0
+ LDB E,[360600,,B] ; GET BYTE PART
+ LDB A,[360600,,-1(P)] ; OF BOTH
+ SUB E,A ; ODD BYTES
+ MOVE C,B ; COPY POINTER
+ TLZ C,770000 ; JUST WORD POINTER
+ POP P,A ; GET ORIGINAL COUNT WORD
+ POP P,D ; AND ORIG PNTR
+ TLZ D,770000
+ SUB C,D
+ CAIE 0,$PBYTES
+ JRST [IMULI C,5
+ JRST SINXX1]
+ IMULI C,4
+SINXX1: ADD C,E ; C has actual # of characters xfered
+ SUBI A,(C) ; AND FIX IT
+SINXXX: SKIPN O2 ; skip if not error
+ JRST SINLSR ; go handle error
+ ADJSP P,-2 ; flush saved c and d
+ POPJ P,
+
+SINLSR: PUSH TP,A ; save rested string
+ PUSH TP,B
+ MOVEI A,400000 ; GET ERROR
+ GETER
+ MOVEI A,(B) ; ERROR TO A
+ CAIN A,IOX4 ; IS THIS EOF
+ JRST [ POP TP,B ; yes just return rested string
+ POP TP,A
+ ADJSP P,-2 ; flush saved args
+ POPJ P,]
+ CAIE A,IOX11 ; Quota exceeded
+ CAIN A,IOX34 ; Disk full
+ JRST SINFUL ; Handle this case
+ PUSH TP,$WFIX ; save SIN/SOUT and JFN
+ PUSH TP,O1
+ PUSH TP,$WFIX
+ POP P,0 ;return PC
+ SUB 0,R
+ PUSH TP,0 ;relativized ret PC
+ PUSH TP,-5(TP)
+ PUSH TP,-5(TP)
+ PUSHJ P,RETERR ; cons up error code
+ PUSH TP,A
+ PUSH TP,B
+ PUSHJ P,ICELL ; include buffer in false
+ MOVE B,(TP)
+ MOVEM A,(B)
+ ADJSP TP,-2
+ POP TP,2(A)
+ POP TP,1(A)
+ SKIPN O1,ECATM ; call error-in compiled code handler
+ JRST CMPERX
+ JSP PC,FRAME
+ PUSH TP,$WFALS
+ PUSH TP,B
+ MOVEI O2,1
+ JSP PC,CALLZ
+ MOVE PC,(TP) ; returned from error, try i/o again
+ ADD PC,R
+ PUSH P,PC
+ MOVE O1,-2(TP) ; unrelativized PC to stack
+ DMOVE A,-5(TP) ; buffer back
+ MOVEI C,(A)
+ MOVNS C
+ MOVE 0,A
+ HLRZ A,O1
+ HRLI O1,(JSYS)
+ ADJSP TP,-6
+ JRST RSINX
+
+SINFUL: MOVEI A,.FHSLF
+ MOVE B,[<SETZ_<0-.ICQTA>>]
+ IIC ; Cause fatal interrupt
+ POP P,D ; Restore terminating char
+ MOVE B,C
+ POP P,C ; # chars to transfer
+ SKIPL C ; Set up for update
+ MOVNS B
+ ADD C,B ; Actual # to transfer
+ POP TP,B ; String
+ POP TP,0 ; Count word
+ HLRZ A,O1 ; restore JFN
+ JRST SOUTX ; Try again
+
+GTJFNX: TLNN A,(GJ%FNS) ; STRING ARG?
+ JRST [MOVE E,B
+ PUSHJ P,OPNAM ; FORCE ASCIZ IN THIS SECTION
+ HRROI B,FNBLK
+ JRST GTJFN1 ]
+GTJFN1: GTJFN
+ JUMP 16,JFSERR
+ MOVE B,A
+ MOVSI A,$TFIX
+ POPJ P,
+
+JFNSX: CAIGE A,177 ; SKIP IF JFNSing to a string
+ JUMPGE A,[ JFNS ; DO IT
+ JUMP 16,JFSERR
+ MOVSI A,$TFIX
+ POPJ P,]
+
+ MOVE O1,A
+ HRROI A,FNBLK
+ JFNS
+ JUMP 16,JFSERR ; LOSE...
+
+ EXCH E,O1
+ MOVE C,[440700,,FNBLK]
+ MOVEI B,0
+JFNSL: ILDB 0,C
+ JUMPE 0,JFNSM
+ ADDI B,1
+ IDPB 0,E ; MOVE CHARS
+ CAMN C,A ; ARE WE DONE
+ JRST JFNSM
+ SOJG O1,JFNSL
+
+ MOVNS B ; RETURN NEGATIVE LENGTH
+JFNSM: MOVSI A,$TFIX
+ POPJ P,
+
+JFSERR: MOVEI A,400000 ; GET ERROR
+ GETER
+ MOVEI A,(B) ; ERROR TO A
+ JRST RETERR
+
+ERSTRX: CAIG A,177 ; SKIP IF TO STRING
+ JUMPGE A,[ ERSTR
+ JUMP 16,RETF1
+ JRST RETF2
+ MOVSI A,$TFIX
+ POPJ P,]
+
+ MOVE O2,A ; SAVE ORG STR PNTR
+ ERSTR
+ JUMP 16,RETF1
+ JRST RETF2
+
+ LDB B,[360600,,A] ; GET BYTE PART
+ LDB 0,[360600,,O2]
+ SUB B,0
+ TLZ A,770000
+ TLZ O2,770000
+ SUB A,O2
+ IMULI A,5
+ ADD B,A
+ MOVSI A,$TFIX
+ POPJ P,
+
+RETF1: TDZA A,A
+RETF2: MOVEI A,1
+ AOJA A,RETERR
+
+; do long form GTJFN
+
+GTJFNL: MOVNI A,(O1) ; FIND BASE OF ARGS
+ ADD A,A
+ MOVE O2,TP ; COPY STACK POINTER
+ ADJSP O2,(A) ; POINT TO FIRS ARG
+ MOVE B,[440700,,FNBLK] ; FOR COPIED STRINGS
+ MOVEI A,GTJFBK ; POINT TO ARG BLOCK
+ PUSH P,O2
+ PUSH P,O1
+
+GTJFLP: HLRZ 0,1(O2)
+ CAIE 0,$TSTRING ; STRING
+ JRST [ MOVE 0,2(O2) ; NO GET FIX
+ MOVEM 0,(A) ; INTO BLOCK
+ JRST GTJFNA]
+
+ HRRZ C,1(O2) ; STRING LENGTH
+ JUMPE C,[ SETZM (A)
+ JRST GTJFNA]
+ MOVEM B,(A) ; STORE BYTE POINTER
+ MOVE E,2(O2) ; STR PNTR
+ PUSHJ P,OPNAML ; FORCE ASCIZ IN THIS SECTION
+GTJFNA: ADJSP O2,2 ; NEXT ARG
+ ADDI A,1
+ SOJG O1,GTJFLP
+
+ MOVE B,GTJFBK
+ MOVEI A,GTJFB2
+ MOVE O2,GTJFOS
+ GTJFN ; DO THE GTJFN
+ JUMP 16,GTERR ; ERROR
+
+ POP P,O1
+ POP P,TP
+ MOVE B,A
+ MOVSI A,$TFIX
+ SKIPN GTJFOS
+ POPJ P,
+
+ MOVE D,.GJCPP+.GJCPP+4(TP)
+ HRRZ C,.GJCPP+.GJCPP+3(TP)
+
+ ILDB 0,O2
+ IDPB 0,D
+ SOJG C,.-2
+ POPJ P,
+
+GTERR: POP P,O1
+ POP P,TP
+ JRST JFSERR
+
+IRDBLK: 10
+ RD%JFN ; JFNS COMING
+ .PRIOU ; FOR EDITING
+ 0 ; DESTINATION STRING
+ 0
+ 0
+ 0
+ IRDBRK ; FOR FUTURE EXPANSION
+ 0
+
+IRDBRK: 20000,,400 ; BREAK ON CONTROL-D
+ 0
+ 0
+ 0
+ARDBRK: BLOCK 4 ; ALTERNATE BREAK MASK FOR READ
+
+\f
+SUBTTL ARITHMETIC
+
+RANDOM: GTAD
+ IDIV A,O1
+ ADDI B,1
+ MOVE A,$WFIX
+ JRST (PC)
+
+SUBTTL LVAL MANIPULATION
+
+;ILVAL RECEIVES ATOM IN IN O1
+
+ILVAL: SKIPN O2,1(O1) ;SEE IF BINDING
+ JRST ILVAL1
+ MOVE 0,7(O2) ; GET BINDID
+ CAME 0,BINDID ; SKIP IF OK
+ JRST ILVAL1
+ DMOVE A,(O2) ; GET VALUE
+ JUMPN A,(PC) ; RETURN IF BOUND
+ILVAL2: PUSH P,PC
+ JSP PC,FRAME ; Have binding with no value
+ PUSH TP,[$TATOM,,$LATOM] ; So strictly error case of EICC
+ PUSH TP,O1
+ MOVEI O2,1
+ MOVE O1,ECATM ; ERROR IN COMPILED CRUFT...
+ POP P,PC
+ JRST MCALL
+
+ILVAL1: MOVE A,PC ; SAVE PC
+ JSP PC,IASS ; SEE IF ASSIGNED AT ALL
+ MOVEI O2,0 ; IF NOT , SO INDICATE
+ MOVE PC,A
+ JUMPE O2,ILVAL2 ; GENERATE ERROR
+ DMOVE A,(O2)
+ JRST (PC)
+
+;IASS -- ASSIGNED? O1 IS ATOM, SKIP IF ASSIGNED?
+
+IASS: SKIPN O2,1(O1) ; BINDING PNTR?
+ JRST (PC) ; NO, NO SKIP
+ MOVE 0,7(O2) ; BIND ID?
+ CAME 0,BINDID ; SKIP IF NO SEARCH
+ JRST IASS1
+IASS4: SKIPE (O2) ; BOUND?
+ ADDI PC,1
+ JRST (PC)
+
+IASS1: MOVE O2,SP ; SEARCH
+IASS2: CAMN O1,2(O2) ; SKIP IF NOT IT
+ JRST IASS4 ; CHECK VALUE OK
+ SKIPE O2,5(O2) ; NEXT BINDING
+ JRST IASS2
+ MOVE O2,TTBIND ; SAME THING FOR TOP BINDING
+IASS3: CAMN O1,2(O2)
+ JRST IASS4
+ SKIPE O2,5(O2)
+ JRST IASS3
+ JRST (PC)
+
+;ISET -- RECEIVES ATOM IN O1 , NEW VAL IN A,B
+
+ISET: SKIPN O2,1(O1) ;SEE IF BINDING
+ JRST ISET1
+ MOVE 0,7(O2) ; GET BINDID
+ CAME 0,BINDID ; SKIP IF OK
+ JRST ISET1
+ DMOVEM A,(O2) ; SET VALUE
+ JRST (PC) ; RETURN
+
+ISET1: PUSH P,PC
+ JSP PC,FRAME
+ PUSH TP,[$TATOM,,$LATOM]
+ PUSH TP,O1
+ PUSH TP,A
+ PUSH TP,B
+ MOVEI O2,2
+ MOVE O1,ECATM ; ERROR IN COMPILED CRUFT...
+ POP P,PC
+ JRST MCALL
+
+;MOVSTR - O1 FROM, O2 TO, O #CHARS
+
+MOVSTR: SKIPG C,0 ; make sure something to move
+ JRST (PC) ; ret immediately
+ MOVE A,O1 ; compute word addrs of strs
+ MOVE D,O2
+ MOVE E,0
+ ADJBP C,A ;C is end of from
+ ADJBP E,D ;E is end of to
+ TLZ O1,770000 ; clear byte pntr part, O1 start of from
+ TLZ O2,770000 ; O2 start of to
+ TLZ C,770000
+ TLZ E,770000
+ CAMG O1,E ; skip if start from is grtr than end to
+ CAMLE O2,C ; dont skip if start of to is grt end from
+ JRST NOOVER ; jump to use movestr instruction
+
+ CAMN O1,O2 ; same word, check bp
+ JRST [ CAMG A,D
+ JRST MOVBAK
+ JRST MOVFWD ]
+ CAMG O1,O2
+ JRST MOVBAK ; must go backwards
+MOVFWD: ILDB O1,A
+ IDPB O1,D
+ SOJG 0,MOVFWD
+ JRST (PC)
+
+;hairy back move
+
+MOVBAK: MOVE O1,0
+ MOVE O2,0
+ ADJBP O1,A ; point to last byte in both
+ ADJBP O2,D
+
+MOVBK1: LDB C,O1 ; move a byte
+ DPB C,O2
+ADJBP1: MOVNI A,1 ; now tediously backup the 2 bps
+ ADJBP A,O1
+ TLNE A,770000 ; check for micro code bug
+ JRST .+3
+ AOS BUGS
+ JRST ADJBP1
+ MOVE O1,A
+ADJBP2: MOVNI A,1
+ ADJBP A,O2
+ TLNE A,770000 ; check for micro code bug
+ JRST .+3
+ AOS BUGS
+ JRST ADJBP2
+ MOVE O2,A
+ SOJG 0,MOVBK1
+ JRST (PC)
+
+; here if strings dont overlap 0 & A & C are setup ok
+
+MOVSLJ==123000,,[016000,,]
+
+NOOVER: MOVE C,0
+ SETZB B,E ; superstition
+ MOVSLJ 0,
+ JRST COMPER
+ JRST (PC)
+
+\f
+SUBTTL GARBAGE COLLECTION UTILITIES
+
+MARKR: CAMG B,[INIGC,,] ; DON'T MARK STACK OBJECTS
+ JRST (PC)
+ HRRZ D,A
+ LSH D,-1
+ ADD B,D ; MOVE TO DOPE WORD
+ JRST MRKUX
+
+MARKU: LDB D,[UPTBYT,,A]
+ JRST @MRKTBL(D)
+
+MRKTBL: SETZ MRKUS
+ SETZ MRKUS
+ SETZ MRKUU
+ SETZ MRKUV
+
+MRKUS: ANDI A,-1
+ ADJBP A,B
+ TLZ A,770000
+ XMOVEI B,1(A)
+ JRST MRKUX
+
+MRKUU: HRRZ D,A
+ JRST MRKUUV
+
+MRKUV: HRRZ D,A
+ LSH D,1
+MRKUUV: ADD B,D
+MRKUX: MOVSI D,200000
+ JUMPE C,[ANDCAM D,(B)
+ JRST (PC)]
+ CAME C,[200000,,]
+ MOVEM C,1(B) ; STORE RELOCATION
+ IORM D,(B)
+ JRST (PC)
+
+MARKL: JUMPE B,(PC)
+ ADDI B,1
+ JUMPE C,MRKUX
+ MOVSI C,200000
+ JRST MRKUX
+
+; HERE FOR MARK PREDICATE
+
+MKL: JUMPE B,[MOVEI B,1
+ JRST IMKL1]
+ LDB B,[MARKBIT,,1(B)]
+ JUMPE B,IMKL1 ; JUMP IF NOT MARKED
+ MOVE B,(B) ; RETURN RELOCATION
+ MOVSI A,$WLIST
+ JRST (PC)
+
+IMKL1: MOVE A,$WFIX
+ JRST (PC)
+
+MKR: CAMG B,[INIGC,,] ; SAY IT'S MARKED IF ITS ON THE STACK
+ JRST MKRT
+ HRRZ D,A
+ LSH D,-1
+ ADD B,D ; MOVE TO DOPE WORD
+ LDB B,[MARKBIT,,(B)] ; MUNG IT
+ JUMPE B,MKRT
+ MOVE B,1(B) ; RELOCATED WITH OLD TYPE
+ SUBI D,1(D) ; BACK TO TOP
+ JRST (PC)
+
+MKRT: MOVE A,$WFIX
+ JRST (PC)
+
+MKU: LDB C,[UPTBYT,,A]
+ JRST @MKTB(C)
+
+MKTB: SETZ MKUS
+ SETZ MKUS
+ SETZ MKUU
+ SETZ MKUV
+
+MKUS: ANDI A,-1 ; GET TO DW
+ MOVE 0,A
+ ADJBP A,B
+ LDB B,[MARKBIT,,1(A)]
+ JUMPE B,MKRT
+ SKIPN B,2(A)
+ AOJA B,MKRT
+ HRRZ A,1(A)
+ SUB B,A
+ JRST (PC)
+
+MKUU: HRRZ C,A
+ JRST MKUUV
+
+MKUV: HRRZ C,A
+ LSH C,1
+MKUUV: ADD B,C
+ LDB B,[MARKBIT,,(B)]
+ JUMPE B,MKRT
+ MOVE B,1(B)
+ SUBI B,1(C)
+ JRST (PC)
+
+MARKBIT==420100
+
+; SWEEP PHASE INSTRUCTIONS
+
+; SWEEPNEXT - GIVEN IN O1 A POINTER TO GC SPACE, IN A A POINTER TO
+; GC PARAMS
+; RETURNS A POINTER TO THE NEXT FROB IN GC SPACE
+
+SWNEXT: SKIPN B,O2
+ MOVE B,GCSBOF(A)
+ LDB E,[PTPBYT,,O1]
+ CAIE E,$PSTRING
+ CAIN E,$PBYTES
+ TLZ B,770000
+ CAMG B,GCSMIO(A)
+ JRST [SETZ B,
+ MOVE A,$WFIX
+ JRST (PC)]
+ MOVE A,-2(B) ; GET THE DOPE WORD
+ TLZE A,$DOPEBIT ; IS THE DOPE BIT SET?
+ JRST ISWVR ; YES. EITHER A UBLOCK OR RECORD
+ SUBI B,3 ; NEXT FROB IS THREE BACK
+ MOVE A,$WLIST
+ JRST (PC)
+
+ISWVR: HRRZ D,A ; GET LENGTH
+ SUBI B,2(D) ; FIND THE NEXT ONE
+ LDB E,[PTPBYT,,A] ; GET THE TYPE WORD
+ CAIN E,$PRECORD
+ JRST [ADDI A,(A) ; RECORD DOPE WORD IS FULL WORDS (SIGH)
+ JRST (PC)]
+ CAIN E,$PVECTOR ; VECTOR DOPE WORD HAS TWICE LENGTH (SIGH)
+ JRST [LSH D,-1
+ HRR A,D
+ JRST (PC)]
+ CAIN E,$PSTRING
+ JRST ISWVRS
+ CAIN E,$PBYTES
+ JRST ISWVRB
+ JRST (PC)
+; The byte pointers returned here are NOT standard--they are
+; 440700,,x rather than 010700,,x-1. This works because everyone
+; deals with them the adjbp and such; it avoids confusion in the
+; sweep phase due to the x-1.
+ISWVRS: TLO B,610000 ; FIXUP STRING POINTER
+ IMULI D,5 ; AND TYPE WORD
+ HRR A,D ; SIGH. THIS SEEMS KLUDGY...
+ JRST (PC)
+ISWVRB: TLO B,540000
+ IMULI D,4
+ HRR A,D
+ JRST (PC)
+
+RELL: SKIPN C,CZONE
+ XMOVEI C,-GCPOFF+IGCPR
+ MOVE C,GCPOFF(C)
+ MOVE 0,RCLOFF(C) ; GET FREE LIST POINTER
+ MOVEM 0,(B) ; CHAIN FREE LIST
+ MOVEM B,RCLOFF(C) ; UPDATE FREE LIST POINTER
+ SETZM 1(B)
+ SETZM 2(B)
+ JRST (PC)
+
+RELR: HRRZ D,A
+ LSH D,-1
+ ADD D,B
+ ADDI D,1
+ JSP OP,RELB
+ JRST (PC)
+
+RELU: LDB C,[UPTBYT,,A] ; GET THE PRIMTYPE
+ JSP E,@RELUTB(C) ; POINT D AT THE DOPE WORDS
+ JSP OP,RELB ; RECYCLE THE BLOCK OF STORAGE
+ JRST (PC) ; DON'T WORK EITHER
+
+RELUTB: SETZ RELUB
+ SETZ RELUS
+ SETZ RELUU
+ SETZ RELUV
+
+RELUB:
+
+RELUS: HRRZ C,A ; GETLENGTH
+RELUSX: ADJBP C,B ; ADJUST TO THE END
+ MOVE D,C ; ROUND UP
+ TLZ D,770000
+ ADDI D,2 ; POINT TO SECOND DOPE WORD
+ JRST (E)
+
+RELUU: HRRZ C,A ; GET LENGTH
+RELUX: MOVE D,B ; POINT TO UVECTOR
+ ADDI D,1(C) ; POINT TO SECOND DOPE WORD
+ JRST (E)
+
+RELUV: HRRZ C,A ; GET LENGTH
+ LSH C,1 ; TIMES TWO FOR GOOD LUCK
+ JRST RELUX ; REJOIN CODE
+
+
+; set the current free storage zone (arg in A and B)
+; if passed 0, return current, if current is zero, return gc params
+
+SETZON: JUMPN B,SETZN1 ; set it
+ SKIPE B,CZONE ; get current if any
+ JRST [MOVE A,[$TZONE,,7]
+ JRST (PC)]
+ HRRZ B,IGCPR
+ HRLI B,MIMSEC
+ MOVE A,[$TUVEC,,GCPL]
+ JRST (PC)
+
+SETZN1:
+; SETZM INGC ; THIS TENDS TO HAPPEN AFTER A GC
+ SKIPE ONOISY
+ JRST [ HRROI A,[ASCIZ /OK int soon/]
+ PSOUT
+ SETZM ONOISY
+ JRST .+1 ]
+IFN FLIP,[
+ MOVEM B,@[MIMSEC,,CZONE]
+ MOVEM B,@[MIMSEC+1,,CZONE]
+ MOVE B,SECL(B) ; FIRST AREA
+ MOVE B,@2(B) ; BOUND OF AREA
+ TLNN B,1 ; ODD/EVEN CHECK
+ JRST STZSE2
+ HRLI TP,EVSEC
+ HRLI F,EVSEC
+ HRLI P,EVSEC
+ JRST (PC)
+
+STZSE2: HRLI TP,ODDSEC
+ HRLI F,ODDSEC
+ HRLI P,ODDSEC
+ JRST (PC) ]
+IFE FLIP,[
+ MOVEM B,CZONE
+ JRST (PC)
+]
+
+IGCPR: -GCPL,,RCL
+
+; HERE IS THE BLOCK STORAGE RECYCLER
+; D POINTS TO THE SECOND DOPE WORD OF THE FROB BEING RECYCLED
+
+; RCL IS A LIST OF FREE CELLS
+
+GCPOFF==1
+GCFCN==3
+SECL==11.
+RCLOFF==0
+
+RCLTB: PUSHJ P,COMPER ; ZERO LENGTH?
+ PUSHJ P,COMPER ; ONE LENGTH?
+ XMOVEI B,RCLV2O(A)
+ XMOVEI B,RCLV3O(A)
+ XMOVEI B,RCLV4O(A)
+ XMOVEI B,RCLVOF(A)
+ XMOVEI B,RCLVOF(A)
+ XMOVEI B,RCLV7O(A)
+ XMOVEI B,RCLV8O(A)
+ XMOVEI B,RCLVOF(A)
+ XMOVEI B,RCL10O(A)
+
+RELB: HRRZ E,-1(D) ; FIRST GET BLOCK LENGTH
+ ADDI E,2
+ CAIG E,2
+ JRST RELB1 ; JUST DOPE WORDS
+ MOVE B,D
+ SUBI B,-2(E) ; ZERO EVERYTHING EXCEPT DOPE WORDS
+ SETZM -1(B)
+ HRLI B,-1(B)
+ CAILE E,3
+ BLT B,-2(D)
+RELB1: SKIPN B,CZONE
+ XMOVEI B,-GCPOFF+IGCPR
+ MOVE A,GCPOFF(B)
+ CAILE E,10.
+ XMOVEI B,RCLVOF(A)
+ CAIG E,10.
+ XCT RCLTB(E)
+ TLZ OP,400000
+ MOVEI 0,(B)
+ CAIE 0,RCLVOF(A)
+ TLO OP,400000
+ SKIPN A,(B) ; GET THE POINTER TO THE CHAIN
+ JRST [MOVEM D,(B)
+ SETZM (D)
+ TLZ OP,400000
+ JRST (OP) ]
+ MOVE A,B ; START FROM RCLV
+
+RECBL: MOVE B,(A) ; GET POINTER TO NEXT FREE BLOCK
+ CAML B,D ; DOES IT GO HERE?
+ JRST RECIN ; YES. INSERT IT
+ JUMPE B,RECIN
+ MOVE A,B ; GO ON TO NEXT FREE BLOCK
+ JRST RECBL
+
+RECIN: CAMN B,D ; Don't skip if block already there
+ JRST [PUSH P,A
+ HRROI A,[ASCIZ /Recycled block already on chain
+/]
+ ESOUT
+ POP P,A
+ HALTF
+ JRST (OP)] ; Can be continued...
+ TLZE OP,400000
+ JRST RECIN1
+ MOVE C,D ; GET POINTER TO OUR BLOCK
+ SUB C,E ; BACK OFF TO THE TOP
+ CAMN C,A ; DOES IT TOUCH PREVIOUS BLOCK?
+ JFCL ; THIS GETS HAIRY. MORE CODE TO FOLLOW
+ SKIPN C,B ; GET CDR FOR THIS BLOCK
+ JRST RECIN1
+ HRRZ 0,-1(B) ; GET ITS LENGTH+2
+ ADDI 0,2
+ SUB C,0 ; SUBTRACT OFF THE BLOCK
+ CAMN C,D ; DO WE TOUCH ON THE BOTTOM?
+ JRST [ADDM E,-1(B) ; YES. SIMPLY UPDATE LENGTH
+ JRST (OP)]
+RECIN1: MOVEM B,(D) ; CHAIN THE NEW BLOCK IN
+ MOVEM D,(A)
+ MOVEI B,$TUVECTOR+$DOPEBIT
+ HRLM B,-1(D) ; MAKE SURE THIS IS A UV
+ JRST (OP)
+
+\f
+SUBTTL CORE ALLOCATION
+
+ICELL: JSP OP,ICELL1 ; Get a cell
+ CAIA ; Failed
+ POPJ P,
+ MOVEI A,3 ; Need 3 words
+ JSP PC,IBLOCK ; IBLOCK looks at other chains, then GCs
+ POPJ P,
+
+; HERE TO THE GARBAGE COLLECTOR FOR THE CURRENT ZONE
+
+RUNGC: JSP PC,FRAME
+ PUSH TP,$WFIX
+ PUSH TP,A
+ SKIPN A,CZONE ; MUST HAVE A ZONE
+ HALTF
+ MOVE O1,GCFCN(A)
+ MOVEI O2,1
+ JSP PC,CALLZ
+ POPJ P,
+
+
+IBLOCK: MOVE E,A
+ SKIPN B,CZONE
+ XMOVEI B,-GCPOFF+IGCPR
+ MOVE A,GCPOFF(B)
+ XMOVEI B,RCLVOF(A) ; DEFAULT RCL CHAIN
+ MOVE 0,GCFLGO(A) ; IF NO DWS, FUDGE HERE
+ TLNE 0,$GC%DW
+ SUBI E,2
+; TLNE 0,$GC%PB ; ONLY EVEN # OF PAGES?
+; TRNN E,777
+; CAIA
+; JRST COMPERR
+ CAIG E,10.
+ XCT RCLTB(E) ; GET POINTER TO CORRECT RCL CHAIN
+ SKIPE (B) ; DON'T BOTHER IF NOTHING'S ON THE CHAIN
+ JRST IBLOLD ; Got something there
+ XMOVEI B,RCLVOF(A) ; Check general chain
+ SKIPN (B) ; Skip if something there
+ JRST IBLNEW ; OLD STYLE BLOCK ALLOCATOR
+IBLOLD: MOVEI 0,(B)
+ CAIE 0,RCLVOF(A) ; Skip if allocating from general chain
+ JRST IBLFIX ; FIXED SIZE OBJECT
+ MOVE D,B ; SETUP BACK POINTER
+ MOVE B,(B) ; GET THE RECYCLE CHAIN ITSELF
+IBLCL: HRRZ C,-1(B) ; HOW MUCH STUFF HERE
+ ADDI C,2 ; PLUS DOPE WORDS
+ CAMN C,E ; IS THIS AN EXACT MATCH?
+ JRST IBLC1 ; YES. DO THE RIGHT THING
+
+ CAIL E,-2(C) ; CAN IT BE BROKEN UP
+ JRST IBLC2 ; NO, KEEP LOOKING
+
+ SUBI C,2(E) ; C ==> LENGTH OF REMAINDER
+ HRRM C,-1(B) ; STORE IT
+ CAILE C,10. ; SKIP IF MUST PUT IT ON OTHER CHAIN
+ JRST IBLC3
+ MOVE 0,(B) ; SPLICE IT OUT
+ MOVEM 0,(D)
+ SETZM (B) ; FLUSH OLD POINTER
+ PUSH P,A
+ PUSH P,B
+ PUSH P,C
+ PUSH P,E
+ PUSH P,OP
+ MOVE D,B
+ JSP OP,RELB ; CALL BLOCK RECYCLER
+ POP P,OP
+ POP P,E
+ POP P,C
+ POP P,B
+ POP P,A
+
+IBLC3: SUBI B,2(C) ; NEW DW
+ SUBI E,2
+ HRRZM E,-1(B) ; DW LENGTH
+ SETZM (B)
+ MOVE 0,GCFLGO(A) ; GET FLAGS
+ MOVE A,B ; PNTR TO A
+ SUBI A,1(E) ; POINT TO TOP
+IBLRET: TLNE 0,$GC%PB ; REQUIRE PAGE BOUNDARY?
+ TRNN A,777
+ JRST (PC) ; NO RETURN
+ JRST CMPERR
+
+IBLC2: MOVE D,B ; GET NEW BACK POINTER
+ SKIPN B,(B) ; GET NEXT ENTRY
+ JRST IBLNEW ; END OF CHAIN
+ JRST IBLCL ; LOOP WITH NEW BLOCK
+
+IBLC1: MOVE (B) ; FOUND AN EXACT MATCH
+ MOVEM (D) ; UPDATE CHAIN POINTER
+ SETZM (B) ; CLEAR CHAIN POINTER
+ MOVE 0,GCFLGO(A) ; FLAGS
+ MOVE A,B
+ SUBI A,-1(C) ; SUBTRACT OFF TO GET TO TOP
+
+IBLPOP:
+ JRST (PC)
+
+IBLNEW: MOVE 0,GCSBOF(A)
+ ADDB E,GCSBOF(A)
+ SUBI E,1
+ CAMLE E,GCSMXO(A)
+ JRST [ADDI E,1
+ SUB E,0
+ PUSH P,E
+ PUSH P,PC
+ MOVEM 0,GCSBOF(A)
+ MOVE A,E ; # WORDS NEEDED
+ PUSHJ P,RUNGC
+ POP P,PC
+ POP P,A
+ JRST IBLOCK ] ; WILL GC
+ MOVE A,GCFLGO(A) ; RET FLAGS IN 0
+ EXCH A,0
+ JRST (PC)
+
+IBLFIX: MOVE 0,GCFLGO(A)
+ MOVE A,(B)
+ MOVE E,(A)
+ SETZM (A)
+ MOVEM E,(B)
+ HRRZ C,-1(A)
+ SUBI A,1(C)
+ JRST (PC)
+
+$WTCNT: $TYPCNT
+
+\f
+SUBTTL KNOWN RECORD TYPE TABLES
+
+ATMTBL: 5,,$LATOM
+ $TGBIND,,$LGBIND
+ 0,,11.
+ $TBIND,,$LBIND
+ 2,,11.
+ $TSTRING,,$LANY
+ 5,,8.
+ $TOBLIST,,$LATOM
+ 8,,11.
+ $TTYPC,,0
+ 4.,,13.
+
+FRMTBL: 8.,,$LFRAME
+ $TMSUBR,,4
+ 0,,10.
+ $TFIX,,0
+ 2,,6
+ $TFIX,,<<0._9.>\18.>
+ 4,,3
+ $TFIX,,<<18._9.>\18.>
+ 4,,3
+ $TFRAME,,8.
+ 6,,10.
+ $TFIX,,<<0._9.>\18.>
+ 8.,,3
+ $TBIND,,<<18._9.>\18.>
+ 8.,,3
+ $TFIX,,0
+ 10.,,6
+
+BNDTBL: 6,,$LBIND
+ $TANY,,$LANY
+ 0,,12.
+ $TATOM,,$LATOM
+ 4,,11.
+ $TANY,,$LANY
+ 6,,12.
+ $TBIND,,$LBIND
+ 10.,,11.
+ $TBIND,,$LBIND
+ 12.,,11.
+ $TFIX,,0
+ 14.,,6
+
+GBNTBL: 3,,$LGBIND
+ $TANY,,$LANY
+ 0,,12.
+ $TATOM,,$LATOM
+ 4,,11.
+ $TANY,,$LANY
+ 6,,12.
+
+QFTBL==. ; will build tabel later
+
+$LANY==0
+$LATOM==10.
+$LFRAME==12.
+$LGBIND==10.
+$LBIND==16.
+\f
+SUBTTL ERROR ROUTINES & UTILITIES
+
+CMPERR: MOVEI O2,0
+CMPER2: SKIPE O1,ECATM
+ JRST CMPER1
+CMPERX: HRROI A,[ASCIZ /Error in Compiled Code
+/]
+ PSOUT
+ PUSHJ P,HALTX
+
+CMPER1: PUSH P,02
+ JSP PC,FRAME
+ JUMPE O2,CMPER3
+ PUSH TP,A
+ PUSH TP,B
+CMPER3: JSP PC,CALLZ
+ POP P,O2
+ JUMPE O2,CMPERR
+ JRST RPOPJ
+
+\f
+SUBTTL DEBUGGING UTILITIES
+
+; CALL TO SAVE FROM THE INTERPRETER
+; PASSED: A/ JFN
+; B/ 0 or pointer-to-pure-zone
+; C/ 0 or pointer-to-frozen-atom-zone
+
+SAVEX: MOVEM A,INTSAV'
+ MOVEM B,PURZON
+ MOVEM C,ATMZON ; SAVE ZONES IN CASE NEED TO RE-SAVE
+ TLO A,400000
+ CLOSF ; LIKE RESTORE, FILE SHOULDN'T BE OPEN...
+ HALTF
+ MOVE E,(P) ; GET RETURN PC
+ CAIA
+
+SAV: SETZM INTSAV
+
+SAV1: MOVEI SAVAC
+ BLT SAVAC+17
+ MOVEI A,400000
+ MOVEI B,4
+ MOVEI C,[JRST RST
+ JRST [XJRST [0
+ MIMSEC,,CMPERR] ]
+ -1
+ JRST RETPUR ]
+ SKIPE INTSAV ; DIFFERENT STARTING ADDRESS FOR .SAVE
+ MOVEI C,[JRST RST1
+ JRST [XJRST [0
+ MIMSEC,,CMPERR] ]
+ -1
+ JRST RETPUR ]
+ XSVEC
+ SKIPE A,INTSAV
+ JRST SAV2
+ HRROI A,[ASCIZ /Output name: /]
+ PSOUT
+ MOVE A,[GJ%FOU+GJ%SHT+GJ%NEW+GJ%FNS]
+ MOVE B,[100,,101]
+ GTJFN
+ HALTF
+SAV2: ; Special save for multi sect
+; Here to write out multi-sect file
+;
+MSSAVE:
+; FORMAT of extended page map for file
+;
+; even words: -count,,flags
+; odd words: starting job page number
+;
+ MOVEI 0,SVMAP+6 ; SET UP MAP
+ MOVEM 0,SVMAPP
+ SKIPE O1,CZONE ; zones set up?
+ JRST ZND1 ; yes, do it for them
+
+ MOVE O1,GCSBOT ; get bounds
+ MOVE O2,GCSMIN
+
+ PUSHJ P,PMSEC
+ JRST ZND3A
+
+ZND1: MOVE B,SAVAC+2 ; restore possible pure zone
+ MOVE C,SAVAC+3 ; and atom zone
+ SKIPN INTSAV ; skip if from user
+ SETZB B,C ; otherwise, no pure or atom zones
+ PUSH P,B
+ PUSH P,C
+ZND6: PUSH P,SECL(O1) ; list of section bounds
+ MOVE O1,GCPOFF(O1)
+ PUSH P,GCSBOF(O1)
+ PUSH P,GCSMIO(O1)
+
+ZND2: SKIPE E,-2(P) ; any more bounds
+ JRST ZND4
+
+ SKIPN O1,-3(P) ; atom zone?
+ JRST ZND5
+ SETZM -3(P) ; dont look again
+ ADJSP P,-3 ; remove old zone
+ JRST ZND6
+
+ZND5: SKIPN O1,-4(P)
+ JRST ZND3
+ SETZM -4(P)
+ ADJSP P,-3
+ JRST ZND6
+
+ZND4: MOVE O1,2(E) ; pointer to UVEC
+ MOVE 0,3(O1) ; areas flags
+ MOVE O2,1(O1) ; bounds of gcspace
+ CAMN O2,(P) ; current zone?
+ JRST [ MOVE O2,-1(P)
+ MOVEM O2,(O1)
+ JRST .+1 ]
+ DMOVE O1,(O1)
+ MOVE E,(E)
+ MOVEM E,-2(P)
+ PUSHJ P,PMSEC ; write it out
+ JRST ZND2
+
+PMSEC: MOVE B,O2
+ SUB B,O1
+ JUMPE B,CPOPJ
+; SUBI B,777 ; dividing neg number by shift, so
+ ; dont' round
+ ASH B,9.
+ HRRI B,SS%RD+SS%CPY+SS%EXE+SS%EPN
+ TRNE 0,2 ; skip if not read-only
+ HRRI B,SS%RD+SS%EXE+SS%EPN
+ MOVE D,SVMAPP
+ MOVEM B,(D)
+ MOVE B,O2
+ LSH B,-9.
+ MOVEM B,1(D)
+ ADDI D,2
+ MOVEM D,SVMAPP
+ POPJ P,
+
+ZND3: ADJSP P,-5
+ZND3A: MOVEI B,STRTTP-777 ; compute pages of stack
+ SUBI B,(TP)
+ ASH B,9.
+ HRRI B,SS%RD+SS%CPY+SS%EXE+SS%EPN
+ MOVE D,SVMAPP
+ MOVEM B,(D)
+ MOVEI B,<TPSEC_9.>+<STRTTP_-9.> ; add in core page for stack
+ MOVEM B,1(D)
+ SETZM 2(D)
+
+; now write out the actual cruft
+
+ HRLI A,400000
+ MOVEI B,SVMAP
+ MOVEI C,0
+ SSAVE
+ ERJMP SAVLOS
+ SKIPN INTSAV
+ JRST [ HALTF ; give chance to save symbols
+ JRST RST2 ]
+ MOVE A,$WFIX
+ MOVEI B,0
+ POPJ P,
+SAVLOS: SKIPN INTSAV
+ JRST [HRROI A,[ASCIZ /?/]
+ ESOUT
+ MOVEI A,.PRIOU
+ MOVE B,[.FHSLF,,-1]
+ MOVEI C,0
+ ERSTR
+ JFCL
+ JFCL
+ HALTF]
+ MOVEI A,.FHSLF
+ GETER
+ HRRZ A,B
+ PUSHJ P,RETERR ; return a false with error code
+ POPJ P,
+
+RST: SETZM INTSAV
+RST1:
+IFN <MIMSEC-TPSEC>,[
+ MOVEI A,0
+ MOVE B,[.FHSLF,,MIMSEC] ; create brand new section
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1] ; bits for mapping
+ SMAP%
+]
+ MOVE D,[.FHSLF,,1]
+RMAPLP: MOVE A,D
+ RMAP
+ TLZN B,(RM%PEX)
+ JRST RNXTMP
+ MOVSI C,(PM%RD+PM%WR+PM%EX)
+ MOVE A,D
+ MOVE B,D
+ ADDI B,<MIMSEC_9.>
+ PMAP
+IFN FLIP,[
+ MOVSI C,(PM%RD+PM%WR+PM%EX)
+ MOVE A,D
+ MOVE B,D
+ ADDI B,<<MIMSEC+1>_9.>
+ PMAP
+]
+RNXTMP: ADDI D,1
+ CAME D,[.FHSLF,,1000]
+ JRST RMAPLP
+IFN FLIP,[
+ MOVE A,[.FHSLF,,<<TPSEC_9>+<STRTTP_<-9>>>]
+ MOVE B,A
+ ADDI B,1000
+ MOVSI C,(PM%RD+PM%WR+PM%EX+PM%CNT)
+ HRRI C,1000-<STRTTP_<-9>>
+ PMAP
+]
+RSTTPD: MOVE 0,CURSIZ
+ LSH 0,-1
+; MOVEI 0,<<NUMSEC+INIGC>_<-1>>
+ MOVE A,[.FHSLF,,1000]
+IFN FLIP,MOVE B,[.FHSLF,,3000]
+IFE FLIP,MOVE B,[.FHSLF,,2000]
+ MOVSI C,(PM%RD+PM%WR+PM%EX)
+
+RSTX: HRRI A,1000
+ PMAP
+IFN FLIP,[
+ ADDI B,1000
+ HRRI A,2000
+ PMAP
+]
+ ADDI B,1000
+ SOJG 0,RSTX
+
+RST2: MOVSI SAVAC
+ BLT 17
+ PUSHJ P,INTON
+ MOVSI SAVAC
+ BLT 17
+ MOVE O1,B
+ XJRST [0
+ MIMSEC,,.+1]
+ ADJSP P,-1
+
+ MOVEI A,.FHSLF
+ MOVEI B,2 ; CODE FOR SETUP OF UUO TABLE
+ MOVE C,[MIMSEC,,MLTUUP]
+ SWTRP%
+
+ MOVE A,[TPWARN_9]
+ MOVES (A)
+ MOVES <<TPENDP-TPWARN>_9>(A)
+ ADD A,[1,,]
+ MOVES (A)
+ MOVES <<TPENDP-TPWARN>_9>(A)
+ MOVSI A,(SETZ)
+ HRRI A,TPENDP
+ MOVSI B,0
+ SPACS
+ MOVSI A,(SETZ)
+ HRRI A,TPWARN
+ MOVSI B,0
+ SPACS
+IFN FLIP,[
+ MOVSI A,(SETZ)
+ HRRI A,TPENDP+1000
+ MOVSI B,0
+ SPACS
+ MOVSI A,(SETZ)
+ HRRI A,TPWARN+1000
+ MOVSI B,0
+ SPACS
+]
+ SKIPE INTSAV
+ JRST [MOVE A,$WFIX
+ MOVEI B,1
+ JRST (E)]
+ PUSH P,PC
+ JSP PC,FRAME
+ POP P,PC
+ MOVEI O2,0
+ JRST CALLR
+
+; RESTORE CALLED FROM MUM
+; TAKES JFN IN ACCUMULATOR A
+
+RESTOR: MOVE D,A
+ MOVNI A,1
+ MOVE B,[.FHSLF,,TPWARN]
+ MOVE C,[PM%CNT\<<TPENDP-TPWARN>+1>] ; unmap end-of-stack warning
+ PMAP
+IFN FLIP,[
+ MOVE B,[.FHSLF,,<TPWARN+1000>]
+ MOVE C,[PM%CNT\<<TPENDP-TPWARN>+1>]
+ PMAP
+]
+ MOVNI A,1
+ MOVE B,[SETZ INIGC] ; FLUSH MANY SECTIONS
+ MOVE C,CURSIZ
+ SMAP% ; FLUSH LOTS OF STUFF
+ MOVE A,D ; RESTORE CHANNEL
+ SETOM INTSAV ; CALLED FROM MUM
+ TLO A,400000 ; KEEP THE JFN
+ CLOSF ; FOR REASONS KNOWN ONLY TO GOD, AND
+ HALTF ; I EVEN DOUBT THAT, THE FILE CAN'T
+ HRLI A,.FHSLF ; BE OPEN WHEN A GET IS DONE. SIGH.
+ MOVE C,[GET]
+ MOVE D,[MOVEI A,.FHSLF]
+ MOVE E,[XGVEC]
+ MOVE OP,[JRST @C]
+ JRST C
+
+; Take fix or false in A/B. If false, return first GC sec,,# GC secs;
+; otherwise, set.
+SETSIZ: PUSH P,C
+ LDB C,[TYPWRD,,A]
+ CAIE C,$TFALSE
+ JRST SETSZ1
+SETSZD: MOVSI A,$TFIX
+ MOVE B,CURSIZ
+ HRLI B,INIGC
+SETSZ0: POP P,C
+ POPJ P,
+SETSZ1: MOVEM B,CURSIZ
+ JRST SETSZ0
+
+DFATAL: PUSH TP,A
+ PUSH TP,B
+ PUSH P,C
+ HRROI A,[ASCIZ /Fatal error--/]
+ ESOUT
+ MOVEI A,.PRIOU
+ POP TP,B
+ POP TP,C
+ TLZ C,-1
+ MOVNS C
+ SOUT
+ POP P,C
+ HALTF
+ JRST (PC)
+
+QUIT: HALTF
+ POPJ P,
+
+TRACIN: PUSH P,A
+ PUSH P,B
+ PUSH P,C
+ PUSH P,D
+ PUSHJ P,TRACSP
+ MOVEI A,">
+ PBOUT
+ DC
+ HRROI A,[ASCIZ / (/]
+ PSOUT
+ MOVE A,(O1)
+ MOVE A,1(A)
+ MOVE B,1(A)
+ MOVE B,(B)
+ MOVE B,1(B)
+ MOVE B,1(B)
+ ADD B,7(A)
+ MOVE A,$WFIX
+ PUSHJ P,UPDISP
+ HRROI A,[ASCIZ /.) [/]
+ PSOUT
+ MOVE C,O2 ; # OF ARGUMENTS
+ MOVE D,C
+ LSH C,1
+ SUBM TP,C ; POINT THERE
+TRACA: SOJL D,TRACB
+ DMOVE A,1(C)
+ PUSH P,C
+ PUSH P,D
+ PUSHJ P,UPDISP
+ POP P,D
+ POP P,C
+ ADDI C,2
+ MOVEI A,40
+ PBOUT
+ JRST TRACA
+
+TRACB: AOS TRACL
+ AOS TRACL
+ MOVEI A,"]
+ PBOUT
+ SKIPE A,TRACTM
+ DISMS
+TRACEX: MOVEI A,^M
+ PBOUT
+ MOVEI A,^J
+ PBOUT
+ POP P,D
+ POP P,C
+ POP P,B
+ POP P,A
+ POPJ P,
+
+TRACOU: SOS TRACL
+ SOS TRACL
+ PUSH P,A
+ PUSH P,B
+ PUSH P,C
+ PUSH P,D
+ PUSHJ P,TRACSP
+ MOVEI A,"<
+ PBOUT
+ MOVEI A,40
+ PBOUT
+ DMOVE A,-3(P)
+ PUSHJ P,UPDISP
+ JRST TRACEX
+
+TRACSP: MOVEI A,40
+ MOVE B,TRACL
+ SOJL B,CPOPJ
+ PBOUT
+ JRST .-2
+
+\f
+
+SVMAPP: SVMAP
+SVMAP: -ENDPG,,SS%CPY+SS%RD+SS%EXE+SS%EPN
+ 0
+ -1,,SS%CPY+SS%RD+SS%EXE+SS%EPN
+ <MIMSEC_9>
+ -1,,SS%CPY+SS%RD+SS%EXE+SS%EPN
+ <<MIMSEC+1>_9>
+ BLOCK 30.
+
+
+\f
+SUBTTL INTERRUPT HANDLER
+
+LEVTAB: 0,,PCLEV1
+ 0,,PCLEV2
+ 0
+
+CHNTAB: REPEAT 36.,[ 2,,CHNS+<.RPCNT*2>
+ ]
+
+CHNS: REPEAT 36.,[ PUSH P,[.RPCNT]
+ JRST CHNSRV
+ ]
+
+CHNSRV: EXCH A,(P)
+ PUSH P,B
+ PUSH P,C
+ CAIN A,PWRIT ; have we touched "magic" page
+ JRST STKCHK
+ MOVEI B,1
+ MOVEI C,35.
+ SUB C,A
+ LSH B,(C)
+ MOVE C,@[MIMSEC,,INTFLG]
+IFN FLIP,[
+ IORM B,@[MIMSEC,,INTFLG]
+ IORM B,@[MIMSEC+1,,INTFLG]
+]
+IFE FLIP, IORM B,INTFLG
+ AND C,B
+ HRRZ A,PCLEV2
+ CAIN A,RRESTA
+ JRST CHNS1
+ CAME B,CTLGCH
+ CAMN B,CTLACH
+ CAIA
+ JRST CHNS3
+ SKIPE INGC
+ JRST [ SKIPN NOISY
+ JRST CHNS3
+ HRROI A,[ASCIZ /GCing--please wait../]
+ PSOUT
+ SETOM ONOISY
+ JRST CHNS3 ]
+ AOS C,CTLGS ; how many successive ^G or ^As
+ CAIGE C,3 ; if more than 5, int anyway
+ JRST CHNS3
+
+ HRROI A,[ASCIZ /Forced interrupt, here's hoping...
+/]
+ PSOUT
+
+ SETZM CTLGS
+ POP P,C
+ POP P,B
+ POP P,A
+ JRST CHNS41
+
+CHNS3: POP P,C
+ POP P,B
+ POP P,A
+ SKIPN RUNINT
+ DEBRK
+; Come here when interrupts enabled
+ EXCH A,@LEVTAB+1
+ TLNN A,10000 ; Test for user mode
+ JRST CHNS4
+ EXCH A,@LEVTAB+1
+ DEBRK
+CHNS4: EXCH A,@LEVTAB+1
+CHNS41: PUSH TP,[$TUVEC+$FRMDO,,13.]
+ PUSH TP,CZONE
+ PUSH TP,RUNINT
+ SETZM RUNINT
+ PUSH TP,0
+ PUSH TP,A
+ PUSH TP,B
+ PUSH TP,C
+ PUSH TP,D ; Save ACs for system call
+ PUSH TP,E
+ PUSH TP,OP
+ PUSH TP,PC
+ PUSH TP,O1
+ PUSH TP,O2
+ DMOVE A,@LEVTAB+1
+ PUSH TP,B
+ PUSH TP,[$TUVEC+$FRMDO,,13.]
+ SUBM R,-1(TP) ; Save rel PC
+ XMOVEI B,CHNS5
+ DMOVEM A,@LEVTAB+1
+ DEBRK ; Leave int level, go to rest of handler
+CHNS5: PUSHJ P,RINTGO ; Process interrupts
+ SUBM R,-1(TP) ; Get real PC back
+ SOS A,-1(TP) ; Back it up
+ HRRZ C,(A)
+ LDB B,[331100,,(A)] ; Get opcode
+ SKIPN -12.(TP) ; skip if from JSYS
+ AOJA A,CHNS51
+ CAIE B,104 ; Not JSYS; assume XCT 0
+ HRRZ C,-11.(TP)
+ ADDI A,1
+ CAIE C,BIN
+ JRST CHNS51
+ PUSH P,A
+ MOVEI A,.FHSLF
+ MOVEI B,IOX4 ; Return with error code
+ SETER
+ POP P,A
+ MOVE A,(A) ; Get ERJMP instruction
+ TLZ A,777760
+ TLO A,400000
+ XMOVEI A,@A ; Get address of error routine
+CHNS51: PUSH P,A
+ MOVE 0,-15(TP) ; saved CZONE
+ CAME 0,CZONE ; no, change -- no GC
+ SKIPE -14(TP)
+ CAIA ; here if either no GC, or doesn't matter
+ JRST [ HRROI A,[ASCIZ /GC has occurred, you may lose..
+/]
+ PSOUT
+ JRST .+1
+]
+ MOVE O2,-2(TP)
+ MOVE O1,-3(TP)
+ MOVE PC,-4(TP)
+ MOVE OP,-5(TP)
+ MOVE E,-6(TP)
+ MOVE D,-7(TP)
+ MOVE C,-10(TP)
+ MOVE B,-11(TP)
+ MOVE A,-12(TP)
+ MOVE 0,-13(TP)
+ SKIPE -14(TP)
+ SETOM RUNINT ; Re-enable interrupts
+ ADJSP TP,-15.
+ POPJ P, ; Back into code
+
+CHNS1: MOVEI B,CHNS2
+ HRRM B,PCLEV2 ; Go back to section originally in
+ JRST CHNS3
+
+; come here when interrupt out of TEXTI. Everything needed for TEXTI
+; except .rddbp and .rddbc is on tp; those two can be computed.
+CHNS2: PUSH TP,$WFIX
+ PUSH TP,IRDBLK+.RDDBC ; SAVE BYTE COUNT
+ PUSHJ P,RINTGO ; HACK INTERRUPTS
+ MOVE A,-20(TP) ; PROMPT
+ MOVEM A,IRDBLK+.RDRTY
+ MOVEI A,IRDBRK
+ SKIPE -16(TP)
+ MOVEI A,ARDBRK
+ MOVE B,-10(TP)
+ MOVEM B,(A)
+ MOVE B,-6(TP)
+ MOVEM B,1(A)
+ MOVE B,-4(TP)
+ MOVEM B,2(A)
+ MOVE B,-2(TP)
+ MOVEM B,3(A) ; GET BREAKS SET UP
+ MOVEM A,IRDBLK+.RDBRK ; Restore right word
+ MOVE A,-14(TP) ; JFN WORD
+ MOVEM A,IRDBLK+.RDIOJ
+ MOVE A,-12(TP) ; ORIGINAL STRING
+ MOVEM A,IRDBLK+.RDBFP
+ MOVEM A,IRDBLK+.RDBKL
+ HRRZ B,-13(TP)
+ SUB B,(TP) ; # CHARS USED
+ ADJBP B,A ; POINT TO EMPTY PAART
+ MOVEM B,IRDBLK+.RDDBP
+ MOVE B,(TP)
+ MOVEM B,IRDBLK+.RDDBC ; SPACE REMAINING
+ ADJSP TP,-2
+ JRST BRESTA ; FALL BACKK INTO TEXTI
+
+INTGO: HALTF
+
+INTGOC: SKIPE INGC ; DONT INTERRUPT POOR GC
+ POPJ P,
+ SETZM CTLGS
+ PUSH TP,$WFIX
+ PUSH TP,(P)
+ PUSH TP,$WFIX
+ PUSH TP,D
+ PUSH TP,$WFIX
+ PUSH TP,O2
+IFN FLIP,[
+ PUSH TP,$WFIX
+ PUSH TP,@[MIMSEC,,NARGS]
+ PUSH TP,$WFIX
+ PUSH TP,@[MIMSEC+1,,NARGS]
+]
+IFE FLIP,[
+ PUSH TP,$WFIX
+ PUSH TP,NARGS
+]
+ PUSHJ P,RINTGO
+IFN FLIP,[
+ POP TP,@[MIMSEC+1,,NARGS]
+ ADJSP TP,-1
+ POP TP,@[MIMSEC,,NARGS]
+ ADJSP TP,-1
+]
+IFE FLIP,[
+ POP TP,NARGS
+ ADJSP TP,-1
+]
+ POP TP,O2
+ ADJSP TP,-1
+ POP TP,D
+ ADJSP TP,-1
+ POP TP,(P)
+ ADJSP TP,-1
+ POPJ P,
+
+RINTGO: PUSH TP,$WFIX
+ PUSH TP,(P)
+INTLP: SETZM CTLGS
+ MOVE A,INTFLG
+ JFFO A,INTL1
+ POP TP,(P)
+ ADJSP TP,-1
+ POPJ P,
+
+INTL1: MOVEI A,36.
+ SUB A,B
+ MOVEI C,1
+ LSH C,-1(A)
+IFN FLIP,[
+ ANDCAM C,@[MIMSEC,,INTFLG]
+ ANDCAM C,@[MIMSEC+1,,INTFLG]
+]
+IFE FLIP, ANDCAM C,INTFLG ; AND CLEAR IT
+ JSP PC,FRAME
+ PUSH TP,$WFIX
+ PUSH TP,B
+ MOVE O1,ICATM
+ MOVEI O2,1
+ JSP PC,CALLZ
+ JRST INTLP
+
+INTINI: MOVE A,[-36.,,CHNTAB]
+ HLRZ 0,(A)
+ LSH 0,12. ; move level over
+ IORI 0,MIMSEC ; cause it to run int MIM
+ HRLM 0,(A)
+ AOBJN A,.-4
+
+ MOVEI 0,MIMSEC
+ HRLM 0,LEVTAB ; also mung LEVTAB
+ SOS LEVTAB
+ HRLM 0,LEVTAB+1
+ SOS LEVTAB+1
+ HRLM 0,LEVTAB+2
+
+INTON: SETZM ATICNM
+ MOVEI A,.FHSLF
+ MOVEI B,[ 3
+ LEVTAB
+ CHNTAB ]
+ XSIR% ; enable ints
+ EIR
+PWRIT==17. ; Bit for page write int
+INFINT==19. ; bit for inferior interrupt
+ MOVEI A,.FHSLF
+ MOVSI B,(<SETZ>_<-PWRIT>)
+ TRO B,<SETZ>_<-INFINT>
+ AIC ; Activate the int
+ POPJ P,
+\f
+;Here to see if illegal page access is really stack overflow
+
+STKCHK: XMOVEI B,1(TP) ; lets see which page
+ LSH B,-9 ; to page number
+ CAIE B,TPWARN+1000
+ CAIN B,TPWARN ; warning page?
+ JRST [MOVSI A,(SETZ)
+ HRRI A,TPWARN
+ MOVSI B,(PA%RD+PA%EX+PA%WT)
+ SPACS
+ HRRI A,TPWARN+1000
+ SPACS
+ MOVE A,[JRST @PNTSTK]
+ MOVEM A,STKMNG
+ MOVEM A,@[MIMSEC+1,,STKMNG]
+ JRST CHNS3 ]
+
+ HRROI A,[ASCIZ /Fatal error: stack overflow
+/]
+ CAIE B,TPENDP+1000
+ CAIN B,TPENDP
+ CAIA
+STKLOS: HRROI A,[ASCIZ /Fatal error: illegal memory access
+/]
+ PSOUT
+ POP P,C
+ XMOVEI B,HALTX ; Fall into HALTX when leave handler
+ MOVE A,PCLEV2 ; PC where lossage happened
+ MOVEM B,PCLEV2 ; Store new return PC
+ EXCH A,-1(P) ; Leave losing PC on stack
+ POP P,B
+ DEBRK ; Return from interrupt, so loser who
+ ; reenters has interrupts
+
+STKERR:
+IFE FLIP&0,[ MOVE 0,[JRST @D]]
+IFN FLIP&0,[ MOVE 0,[TLNN M,1]]
+ MOVEM 0,STKMNG
+ MOVEM 0,@[MIMSEC+1,,STKMNG]
+ MOVE 0,[JRST @PNTRET] ; CHANGE INS IN RETURN
+ MOVEM 0,RET3
+ MOVEM 0,@[MIMSEC+1,,RET3]
+ MOVEI O2,1
+ MOVE A,$WFIX
+ MOVEI B,0
+ JRST CMPER2
+\f
+SUBTTL DEBUGGING UUOS
+
+ZZZ==.
+LOC 40
+ 0
+ JSR UUOH
+LOC ZZZ
+
+UUOCT==0
+UUOTAB: SETZ ILUUO
+ IRPS X,,[FRM DP DC TON TOFF EX GVERR MADJBP]
+ UUOCT==UUOCT+1
+ X==UUOCT_33
+ SETZ U!X
+ TERMIN
+
+UUOMAX==.-UUOTAB
+MLTUOP: PUSH P,MLTUUP
+ PUSH P,MLTPC
+ JRST UUOSAV
+
+UUOH1: PUSH P,UUOH
+
+; Here if in multi-section mode but running a section 0 uuo
+
+ EXCH 0,(P) ;GET PC AND SAVE 0
+ HRRZM 0,MLTPC
+ HLLZM 0,MLTUUP
+ MOVE 0,40
+ HRRZM 0,MLTEA
+ HLRM 0,MLTUUP
+ POP P,0
+ XJRST .+1
+ 0
+ MIMSEC,,MLTUOP
+
+UUOSAV: PUSH P,
+ PUSH P,A
+ PUSH P,B
+ PUSH P,C
+ PUSH P,D
+ MOVE @UUOE
+ MOVEM UUOD' ; CONTENTS OF EFF ADR
+ MOVE B,UUOE ; EFF ADR
+ LDB A,[050400,,MLTUUP] ; GET UUO AC,
+ LDB C,[110400,,MLTUUP] ; AND OPCODE
+ JRST UUODSP
+
+UUODS1: LDB A,[270400,,40] ; GET UUO AC,
+ LDB C,[330600,,40] ; OP CODE
+UUODSP: CAIL C,UUOMAX
+ MOVEI C,0 ; GRT=>ILLEGAL
+ JRST @UUOTAB(C) ; GO TO PROPER ROUT
+
+UUORET: POP P,D
+ POP P,C
+ POP P,B
+ POP P,A ; RESTORE AC'S
+UUORT1: POP P,
+ POP P,MLTPC
+ POP P,MLTUUP
+ XJRST MLTUUP
+
+ILUUO: HALTF
+
+; KLUDGE TO DO ADJBP GIVEN MICROCODE BUG
+UMADJBP:
+ CAILE A,D ; CHECK AC ARG
+ JRST ADJB2 ; Not pushed, so continue
+ SUBI A,D ; Make A point to stack slot
+ ADD A,P
+ADJB2: MOVE C,(A) ; PICK UP AC
+ IBP C,UUOD ; Do the IBP
+ TLNE C,770000 ; Skip if lost
+ JRST ADJBO
+ AOS BUGS ; Count it
+ JRST ADJB2 ; And try again
+ADJBO: MOVEM C,(A) ; Won, stuff bp out
+ JRST UUORET ; And return
+
+UGVERR: SUBM R,-5(P) ; RELATIVE RETURN PC
+ SKIPN O1,ECATM
+ JRST CMPER2
+ JSP PC,FRAME
+ PUSH P,O2
+ CAIGE B,20 ; IF EA IS REGISTER, HACK IT
+ JRST [ PUSH TP,[$TGVAL,,$LATOM]
+ CAIG B,D
+ JRST [ ADDI B,-4(P)
+ HLL B,P
+ JRST UGVER1 ]
+ HRLI B,1
+ JRST UGVER1 ]
+ MOVE 0,-1(B) ; CHANGE ATOM TO GVAL
+ CAME 0,[$TGBIND,,$LGBIND]
+ MOVE 0,[$TGVAL,,$LATOM]
+ PUSH TP,0 ; PUSH GBIND POINTER OR ATOM POINTER
+UGVER1: PUSH TP,(B)
+ MOVEI O2,1
+ JSP PC,CALLZ ; CALL EICC
+ POP P,O2
+ ADJSP P,-4 ; PRESERVE NEW CONT. OF A AND B
+ SUBM R,-1(P)
+ AOS -1(P) ; SKIP RETURN
+ JRST UUORT1
+
+UFRM: SKIPGE (F)
+ JRST [HRRZ C,-1(F)
+ SUBI C,FR.OFF
+ XHLLI C,(F)
+ JRST .+2]
+ XMOVEI C,-FR.OFF(F)
+ SETO D,
+UFRML: AOJ D,
+ MOVE B,(C)
+ DP 2(B)
+ HRROI A,[ASCIZ / /]
+ PSOUT
+ MOVSI A,$TVECT
+ SKIPGE 2(C)
+ JRST [HRROI A,[ASCIZ /< TUPLE >/]
+ PSOUT
+ JRST UFRMLX]
+ HLR A,2(C)
+ XMOVEI B,6(C)
+ PUSH TP,A
+ PUSH TP,B
+ DP -1(TP)
+ ADJSP TP,-2 ; SUB TP,[2,,2]
+UFRMLX: HRROI A,[ASCIZ /
+/]
+ PSOUT
+ SKIPGE C,3(C) ; GET NEXT FRAME
+ JRST [HRROI A,[ASCIZ / <GLUED FRAME(S)>
+/]
+ PSOUT
+ HRRZ C,-1(C) ; GET REAL FRAME
+ XHLLI C,(F)
+ SUBI C,FR.OFF
+ JRST .+1]
+ SKIPGE (C)
+ JRST [HRROI A,[ASCIZ / <GLUED FRAME(S)>
+/]
+ PSOUT
+ HRRZ C,-1(C)
+ SUBI C,FR.OFF
+ XHLLI C,(F)
+ JRST .+1]
+ JUMPG C,UFRML
+ JRST UUORET
+
+UDC: MOVE B,3(O1)
+ PUSHJ P,UDPSTR
+ JRST UUORET
+
+UDP: MOVE A,(B) ; TYPE WORD
+ MOVE B,1(B)
+ PUSHJ P,UPDISP
+ JRST UUORET
+
+UPDISP: HLRZ C,A
+ TLZE C,200000 ; IS IT MARKED?
+ JRST [PUSH P,A
+ MOVEI A,"@
+ PBOUT
+ POP P,A
+ JRST .+1]
+ JUMPE C,UDPUNB
+ CAIN C,$TFORM
+ JRST UDPFRM
+ CAIN C,$TTUPLE
+ JRST UDPTUP
+ CAIN C,$TOBLI
+ JRST UDPOBL
+ CAIN C,$TATOM
+ JRST UDPATM
+ CAIN C,$TSTRING
+ JRST UDPSTR
+ CAIN C,$TFIX
+ JRST UDPFIX
+ CAIN C,$TFALS
+ JRST UDPFLS
+ CAIN C,$TCHAR
+ JRST UDPCHR
+ CAIN C,$TFLOAT
+ JRST UDPFLT
+ CAIN C,$TLIST
+ JRST UDPLST
+ CAIN C,$TMSUBR
+ JRST UDPMSB
+ CAIN C,$TMCODE
+ JRST UDPMCD
+ CAIN C,$TVECTOR
+ JRST UDPVCT
+ CAIN C,$TCHANNEL
+ JRST UDPSTM
+ HRROI A,[ASCIZ /??/]
+UPOUT: PSOUT
+ POPJ P,
+
+UDPUNB: HRROI A,[ASCIZ /#UNBOUND /]
+ PSOUT
+ JRST UDPFIX
+
+UDPMCD: HRROI A,[ASCIZ /#MCODE |??|/]
+ JRST UPOUT
+
+UDPFLS: HRROI A,[ASCIZ /#FALSE ()/]
+ PSOUT
+ POPJ P,
+
+UDPMSB: HRROI A,[ASCIZ /#MSUBR ??/]
+ PSOUT
+ POPJ P,
+
+UDPCHR: HRROI A,[ASCIZ /!\/]
+ PSOUT
+ MOVE A,B
+ PBOUT
+ POPJ P,
+
+UDPFIX: MOVEI A,.PRIOU
+ MOVEI C,10.
+ NOUT
+ JFCL
+ POPJ P,
+
+UDPFLT: MOVEI A,.PRIOU
+ FLOUT
+ JFCL
+ POPJ P,
+
+UDPSTR: PUSH P,A
+ HRROI A,[ASCIZ /"/]
+ PSOUT
+ POP P,A
+ HRRZ C,A
+ MOVEI A,.PRIOU
+ SOUT
+ HRROI A,[ASCIZ /"/]
+ PSOUT
+ POPJ P,
+
+UDPOBL: HRROI A,[ASCIZ /#OBLIST /]
+ PSOUT
+UDPATM: HRRZ C,2(B)
+ MOVE B,3(B)
+ PUSH P,C
+ POP P,C
+ MOVEI A,.PRIOU
+ SOUT
+ POPJ P,
+
+UDPTUP: PUSH P,A
+ HRROI A,[ASCIZ /#TUPLE /]
+ PSOUT
+ POP P,A
+UDPVCT: PUSH P,B
+ HRRZ C,A
+ PUSH P,C
+ HRROI A,[ASCIZ /[/]
+ PSOUT
+ JUMPE C,UDPVCE
+UDPVCL: MOVE A,(B)
+ MOVE B,1(B)
+ PUSHJ P,UPDISP
+ SOSG (P)
+ JRST UDPVCE
+ AOS -1(P)
+ AOS B,-1(P)
+ HRROI A,[ASCIZ / /]
+ PSOUT
+ JRST UDPVCL
+
+UDPVCE: HRROI A,[ASCIZ /]/]
+ PSOUT
+ ADJSP P,-2 ; SUB P,[2,,2]
+ POPJ P,
+
+UDPFRM: HRROI A,[ASCIZ /</]
+ PSOUT
+ PUSH P,[ASCIZ />/]
+ JUMPE B,UPLSTE
+ JRST UPLSTL
+UDPLST: HRROI A,[ASCIZ /(/]
+ PSOUT
+ PUSH P,[ASCIZ /)/]
+ JUMPE B,UPLSTE
+UPLSTL: PUSH P,B
+ DMOVE A,1(B)
+ PUSHJ P,UPDISP
+ POP P,B
+ MOVE B,(B)
+ JUMPE B,UPLSTE
+ HRROI A,[ASCIZ / /]
+ PSOUT
+ JRST UPLSTL
+
+UPLSTE: HRROI A,(P)
+ PSOUT
+ ADJSP P,-1
+ POPJ P,
+
+UDPSTM: PUSH P,A
+ HRROI A,[ASCIZ /#CHANNEL [/]
+ PSOUT
+ POP P,A
+ PUSH P,B
+ PUSH P,C
+ MOVE A,(B)
+ MOVE B,1(B)
+ PUSHJ P,UPDISP
+ MOVEI A,40
+ PBOUT
+ MOVE B,-1(P)
+ MOVE A,4(B)
+ MOVE B,5(B)
+ PUSHJ P,UPDISP
+ MOVEI A,"]
+ PBOUT
+ ADJSP P,-2
+ POPJ P,
+
+UTON:; SETOM TRACE
+ JRST UUORET
+
+UTOFF:; SETZM TRACE
+ JRST UUORET
+
+UEX: MOVE D,(P)
+ MOVE C,-1(P)
+ MOVE B,-2(P)
+ MOVE A,-3(P)
+ MOVE 0,-4(P)
+ XCT @MLTEA ; get ins to execute
+ JRST UUORET
+\f
+SUBTTL END OF THE ROAD
+
+CONSTANTS
+NOISY: 1 ; non-zero, say if int in GC
+ONOISY: 0 ; non-zero, say ok after GC
+BUGS: 0 ; count bad ADJBP
+CTLGS: 0 ; count ^Gs and ^As
+CTLGCH: 0 ; int channel for ^G
+CTLACH: 0 ; int channel for ^A
+PAT:
+PATCH: BLOCK 100
+PATEND: 0
+VARIABLES
+
+IFN MON,.INSRT M20:INSINT.MID
+
+;MUMBLE: BLOCK 1000
+LOC <<.+777>&777000> ; GO TO PAGE BOUNDARY
+ENDPG==<.+777>_<-9.>
+
+STACK: BLOCK STACKL
+PDL: BLOCK 256.
+
+LOC <<.+777>&777000>
+
+GCSTRT==.
+GCSPST==._<-9.>
+\f
+SUBTTL BOOTSTRAP MSUBR READER
+
+ZZZ==.
+BOOTGC==15000.
+LOC STACK+BOOTGC
+
+BSATBL: BLOCK 256.
+BSAPTR: -256.,,BSATBL-1
+
+BOOTER: MOVE A,GCSMIN
+ MOVEM A,GCSBOT
+ SETZM (A)
+ MOVEI B,1(A)
+ HRLI B,(A)
+ MOVE A,[MIMSEC,,PAGTBL]
+ MOVEM A,PAGPTR+1
+ MOVE A,[MIMSEC,,MINF]
+ MOVEM A,MINFO
+ MOVEI A,TOPGC
+ MOVEM A,GCSMAX
+ HRROI A,[ASCIZ /MIMI20 Initialization
+/]
+ PSOUT
+ SKIPN A,BOOTYP
+ JRST BNIN
+ HRRO A,[[ASCIZ /Using msubrs
+/]
+ [ASCIZ /Using mbins
+/]
+ [ASCIZ /Using big mbins
+/]]+1(A)
+ PSOUT
+ JRST BNIN1
+BNIN: HRROI A,[ASCIZ /Enter type (1 big mbins, 0 mbins, -1 msubrs): /]
+ PSOUT
+ MOVEI A,.PRIOUT
+ MOVEI C,10.
+ NIN
+ JRST BNIN
+ MOVEM B,BOOTYP
+
+BNIN1: MOVE P,[-PDLLEN,,PDL-1]
+ MOVE TP,[-STACKLEN,,STACK-1]
+
+ PUSHJ P,SMAPIT ; setup multi sections
+
+ PUSHJ P,INTINI
+ MOVEI A,<238.*2>
+ JSP PC,IBLOCK
+ MOVE B,[$TVECTOR,,237.]
+ MOVEM B,TOPOBL
+ MOVEM A,TOPOBL+1
+ MOVEI B,237.
+ MOVE C,$WLIST
+ MOVEM C,(A)
+ SETZM 1(A)
+ ADDI A,2
+ SOJN B,.-3
+ MOVE B,[$DOPEBIT+$TVECT,,<237.*2>]
+ MOVEM B,(A)
+ SETZM 1(A)
+
+ MOVSI A,(GJ%SHT+GJ%OLD)
+ HRROI B,[ASCIZ /<MIM.BOOT>BOOT.MSUBR/]
+ GTJFN
+ JRST BSNOF
+ MOVE B,[070000,,OF%RD]
+ OPENF
+ JRST BSNOF
+ MOVEM A,BSJFN'
+ SETZM BSCHR'
+ PUSHJ P,BSREAD
+ SKIPN BSENDF'
+ JRST .-2
+ MOVE A,BSJFN
+ CLOSF
+ JFCL
+ HRROI D,BSATBL
+ MOVE C,[.BYTE 7 ? "B ? "O ? "O ? "T]
+ PUSHJ P,BSLKPL ; GET ATOM BOOT IN A/B
+ CAIA
+ JRST BSNOB
+ MOVE O1,B
+ SETZB O2,F
+ SETZM STACK
+ MOVE A,[STACK,,STACK+1]
+ BLT A,STACK+300
+ JSP PC,FRAME ; MAKE A FRAME
+ XMOVEI F,-1(TP)
+ JSP PC,FRAME
+ HRROI A,[ASCIZ /Bootstrap Loaded
+/]
+ PSOUT
+ PUSH TP,$WFIX
+ PUSH TP,BOOTYP
+ MOVEI O2,1 ; Actually call with 1 arg
+ MOVEI SP,0 ; START SP IN RIGHT SECT
+ JSP PC,CALLZ ; CALL BOOTSTRAP WITH NO ARGS
+ JRST SAV ; AND ATTEMPT TO SAVE OURSELVES
+
+BSSEP: CAIE B,"
+ CAIN B,^J
+ POPJ P,
+ CAIE B,^L
+ CAIN B,^M
+ POPJ P,
+ CAIE B,"]
+ CAIN B,^J
+ POPJ P,
+ CAIE B,""
+ CAIN B,")
+ POPJ P,
+ CAIE B,^Z
+ CAIN B,0
+ JRST BSEND
+POPJ1: AOS (P)
+ POPJ P,
+
+BSEND: SETOM BSENDF
+ POPJ P,
+
+BSREAD: SKIPE BSENDF
+ POPJ P,
+ MOVE A,BSJFN
+ SKIPN B,BSBRK
+ BIN
+BSRD1: SETZM BSBRK
+ CAIN B,"|
+ JRST BSCOD
+ CAIN B,"#
+ JRST BSTYP
+ CAIN B,"[
+ JRST BSVEC
+ CAIN B,"(
+ JRST BSLST
+ CAIN B,"%
+ JRST BSIMM
+ CAIN B,""
+ JRST BSSTR
+ CAIE B,")
+ CAIN B,"]
+ JRST [MOVE A,$WUNBOUND
+ POPJ P,]
+ CAIN B,"!
+ JRST BSCHAR
+ PUSHJ P,BSSEP
+ JRST BSREAD
+ CAIL B,"0
+ CAILE B,"9
+ JRST BSATM
+ JRST BSFIX
+
+; HERE TO READ # FORMAT
+
+BSTYP: PUSHJ P,BSREAD ; GET TYPE NAME
+ MOVE B,3(B) ; GET PNAME
+ TLZ B,770000
+ MOVE C,1(B)
+ TRZ C,377
+ CAMN C,[.BYTE 7 ? "M ? "S ? "U ? "B]
+ PUSH P,$WMSUBR
+ CAMN C,[.BYTE 7 ? "I ? "M ? "S ? "U]
+ PUSH P,$WIMSUB
+ CAMN C,[.BYTE 7 ? "D ? "E ? "C ? "L]
+ PUSH P,$WDECL
+ CAMN C,[.BYTE 7 ? "U ? "N ? "B ? "O]
+ PUSH P,$WUNBOUND
+ CAMN C,[.BYTE 7 ? "F ? "A ? "L ? "S]
+ PUSH P,$WFALSE
+ PUSHJ P,BSREAD ; GET PRIMITIVE STRUCTURE
+ HLL A,(P) ; GET NEW TYPE WORD
+ ADJSP P,-1
+ HLLZ C,A
+ CAME C,$WIMSUB
+ CAMN C,$WMSUBR
+ CAIA
+ POPJ P,
+ PUSH TP,A
+ PUSH TP,B
+ PUSH TP,A
+ PUSH TP,B
+ REPEAT 4,PUSH TP,[0]
+ MOVE O1,$WGBIND
+ MOVEI O2,3
+ PUSHJ P,RECORR ; MAKE A BINDING
+ PUSH P,B
+ POP TP,B
+ POP TP,A ; RESTORE THE MSUBR
+ MOVE C,3(B) ; THE ATOM
+ CAMN C,$WMSUBR
+ MOVE C,1(B)
+ POP P,A
+ MOVEM A,(C) ; STUFF BINDING IN ATOM
+ MOVEM C,2(A) ; STUFF ATOM IN BINDING
+ POPJ P,
+
+
+; HERE TO READ A FIX
+
+BSFRC: 0
+
+BSFIX: SETZM BSFRC
+ MOVEI C,-"0(B) ; C WILL HOLD FIX
+ SETZ D, ; D IS FRACTION / E IS # OF DIGITS
+ MOVEI E,1
+BSFIXL: BIN ; GET NEXT CHARACTER
+ PUSHJ P,BSSEP ; IS IT A SEPARATOR
+ JRST BSFIXE ; YES, FINISH
+ SKIPE BSFRC
+ JRST [IMULI D,10. ; UPDATE INFO
+ ADDI D,-"0(B)
+ IMULI E,10.
+ JRST BSFIXL]
+ CAIN B,". ; DECIMAL?
+ JRST [SETOM BSFRC
+ JRST BSFIXL]
+ IMULI C,10. ; SHIFT OVER SOME
+ ADDI C,-"0(B) ; ADD IN THE NEXT DIGIT
+ JRST BSFIXL ; AND LOOP
+
+BSFIXE: MOVEM B,BSBRK'
+ MOVE A,$WFIX
+ SKIPE BSFRC
+ JRST [FLTR C,C
+ FLTR D,D
+ FLTR E,E
+ FDVR D,E
+ FADR C,D
+ MOVE A,$WFLOAT
+ JRST .+1]
+ MOVE B,C
+ POPJ P,
+
+; HERE TO READ A CHARACTER
+
+BSCHAR: BIN
+ CAIE B,"\
+ HALTF
+ BIN
+ MOVE A,$WCHARACTER
+ POPJ P,
+
+; HERE TO READ A STRING
+
+BSSTR: PUSH P,[0] ; CLEAR COUNT (PREPARE TO MAKE STRING)
+BSSTRL: BIN
+ SKIPE BSQUOT
+ JRST [SETZM BSQUOT
+ JRST BSSTR1]
+ CAIN B,"\
+ SETOM BSQUOT'
+ CAIN B,""
+ JRST BSSTR2
+BSSTR1: PUSH TP,$WCHARACTER ; PUT CHARACTER ON STACK
+ PUSH TP,B
+ AOS (P)
+ JRST BSSTRL ; AND LOOP
+BSSTR2: MOVE O1,$WSTRING
+ POP P,O2
+ PUSHJ P,UBLOKR ; MAKE THE STRING
+ POPJ P,
+
+; HERE TO READ AN ATOM
+
+BSATM: PUSH P,[0] ; CLEAR COUNT (PREPARE TO MAKE STRING)
+ JRST BSATM1
+BSATML: BIN
+ PUSHJ P,BSSEP
+ JRST BSATM2
+BSATM1: PUSH TP,$WCHARACTER ; PUT CHARACTER ON STACK
+ PUSH TP,B
+ AOS (P)
+ JRST BSATML ; AND LOOP
+BSATM2: MOVEM B,BSBRK
+ MOVE O1,$WSTRING
+ POP P,O2
+ PUSHJ P,UBLOKR ; MAKE THE STRING
+ TLZ B,770000
+ PUSHJ P,BSLKP
+ POPJ P,
+BSGBND: TLO B,660000
+ PUSH TP,A
+ PUSH TP,B
+ PUSH TP,$WUNBOUND
+ PUSH TP,[0]
+ PUSH TP,[0]
+ PUSH TP,[0]
+ PUSH TP,[0]
+ PUSH TP,[0]
+ MOVE O1,$WGBIND
+ MOVEI O2,3
+ PUSHJ P,RECORR
+ POP TP,D
+ POP TP,C
+ PUSH TP,A ; PUSH GLOBAL BINDING
+ PUSH TP,B
+ PUSH TP,$WFIX ; PUSH LOCAL BINDING
+ PUSH TP,[0]
+ PUSH TP,C ; PUSH PNAME
+ PUSH TP,D
+ TLZ D,770000
+ PUSH P,1(D)
+ MOVE O1,$WATOM
+ MOVEI O2,3
+ PUSHJ P,RECORR ; MAKE AN ATOM (ISN'T THIS FUN?)
+ MOVE D,(B) ; GET GLOBAL BINDING
+ MOVEM B,2(D) ; STUFF IT IN ATOM
+ MOVE D,BSAPTR
+ PUSH D,(P)
+ PUSH D,B
+ MOVEM D,BSAPTR
+ ADJSP P,-1
+ POPJ P,
+
+BSLKP: HRROI D,BSATBL
+ MOVE C,1(B) ; POINT TO START OF PNAME
+BSLKPL: SKIPN E,(D)
+ JRST POPJ1
+ CAMN E,C
+ JRST BSLKP1
+ ADDI D,2
+ JRST BSLKPL
+BSLKP1: MOVE B,1(D)
+ MOVE A,[$TATOM,,10.] ; CHANGED (WAS 4)
+ POPJ P,
+
+; HERE TO READ SOME MCODE
+
+BSCOD: PUSH P,[0] ; CLEAR THE COUNTER
+BSCODL: MOVEI D,0
+ MOVEI E,4
+BSCDL: BIN
+ CAIG B,"A-1
+ JRST .-2
+ CAIN B,"|
+ JRST BSCODE
+ MOVEI C,-"A(B)
+ LSH C,5
+ BIN
+ CAIG B,"A-1
+ JRST .-2
+ SUBI B,"A
+ IOR C,B
+ LSH D,9.
+ IOR D,C
+ SOJG E,BSCDL
+
+ PUSH TP,$WFIX ; PUT IT ON THE STACK
+ PUSH TP,D ; P.S. - IT HAD BETTER BE A FIX
+ AOS (P)
+ JRST BSCODL ; AND LOOP
+BSCODE: CAIN E,4
+ JRST [IMULI E,9
+ LSH D,(E)
+ PUSH TP,$WFIX
+ PUSH TP,D
+ AOS (P)
+ JRST .+1]
+ MOVE O1,$WMCODE ; TYPE WORD SET
+ POP P,O2
+ PUSHJ P,UBLOKR ; MAKE THE UBLOCK (STRING)
+ POPJ P,
+
+; HERE TO READ A VECTOR
+
+BSVEC: PUSH P,[0]
+BSVECL: PUSHJ P,BSREAD
+ CAMN A,$WUNBOUND
+ CAIE B,"]
+ CAIA
+ JRST BSVECE
+ PUSH TP,A
+ PUSH TP,B
+ AOS (P)
+ JRST BSVECL
+BSVECE: MOVE O1,$WVECTOR
+ POP P,O2
+ PUSHJ P,UBLOKR
+ POPJ P,
+
+BSIMM: MOVE A,BSJFN
+ BIN
+ CAIE B,"< ; This is the only % frob we know how to read
+ HALTF
+ BIN
+ CAIE B,">
+ HALTF
+ MOVEI B,0
+ MOVE A,$WFALSE
+ POPJ P,
+
+; HERE TO READ A LIST
+
+BSLST: PUSH P,[0]
+BSLSTL: PUSHJ P,BSREAD
+ CAMN A,$WUNBOUND
+ CAIE B,")
+ CAIA
+ JRST BSLSTE
+ PUSH TP,A
+ PUSH TP,B
+ AOS (P)
+ JRST BSLSTL
+BSLSTE: POP P,O1
+ PUSHJ P,LIST
+ POPJ P,
+
+; HERE FOR BOOTSTRAP ERRORS
+
+BSNOB: HRROI A,[ASCIZ /No MSUBR named BOOT
+/]
+ PSOUT
+ PUSHJ P,HALTX
+
+BSNOF: HRROI A,[ASCIZ /Can't open BOOT.MSUBR
+/]
+ PSOUT
+ PUSHJ P,HALTX
+SUBTTL SMAP% CODE FOR MULTI SECTION HACKING
+
+SMAPIT: PUSH P,A
+ PUSH P,B
+ PUSH P,C
+; Create 1 or 2 stack sections, depending on FLIP
+ MOVEI A,0
+ MOVE B,[.FHSLF,,MIMSEC] ; create brand new section
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1] ; bits for mapping
+ SMAP%
+IFN FLIP,[
+ MOVEI A,0
+ MOVE B,[.FHSLF,,MIMSEC+1] ; create brand new section
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1] ; bits for mapping
+ SMAP%
+]
+ MOVSI C,(PM%RD+PM%EX+PM%CPY)
+ MOVSI A,.FHSLF
+ MOVE B,[.FHSLF,,<MIMSEC_9>]
+ PMAP
+IFN FLIP,[
+ MOVSI C,(PM%RD+PM%EX+PM%CPY)
+ MOVSI A,.FHSLF
+ MOVE B,[.FHSLF,,<<MIMSEC+1>_9>]
+ PMAP
+]
+ MOVE D,[.FHSLF,,1]
+MAPLP: MOVE A,D
+ MOVSI C,(PM%RD+PM%WR+PM%EX)
+ MOVE B,D
+ ADDI B,<MIMSEC_9.>
+ PMAP
+IFN FLIP,[
+ MOVSI C,(PM%RD+PM%WR+PM%EX)
+ MOVE A,D
+ MOVE B,D
+ ADDI B,<<MIMSEC+1>_9.>
+ PMAP
+]
+NXTMAP: ADDI D,1
+ CAME D,[.FHSLF,,1000]
+ JRST MAPLP
+
+; create stack section
+IFN <MIMSEC-TPSEC>,[
+ MOVEI A,0
+ MOVE B,[.FHSLF,,TPSEC]
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1] ; bits for mapping
+ SMAP%
+]
+; create initial GC space section and section following (for MAPPUR)
+
+ MOVEI A,0
+ MOVE B,[.FHSLF,,INIGC]
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+2] ; bits for mapping
+ SMAP%
+
+; and map special page in from 0
+
+ MOVE A,[.FHSLF,,COMPAG+<MIMSEC_9>]
+ MOVE B,[.FHSLF,,<<INIGC_9.>+COMPAG>]
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1] ; bits for mapping
+ PMAP
+IFN FLIP,MOVE A,[.FHSLF,,COMPAG+<<MIMSEC+1>_9>]
+IFE FLIP,MOVE A,[.FHSLF,,COMPAG+<MIMSEC_9>]
+ MOVE B,[.FHSLF,,<<<INIGC+1>_9.>+COMPAG>]
+ MOVE C,[PM%CNT+PM%RD+PM%EX+PM%WR+1]
+ PMAP
+
+; now all that is left to do is set up UUOs, fix ENTRY table and make stacks
+; happy
+
+ XJRST .+1
+ 0
+ MIMSEC,,.+1
+ MOVE A,[<ENTVEC+LOWOP-ENTMAX-1>,,ENTVEC+LOWOP]
+IFN FLIP, MOVEI B,MIMSEC+1
+IFE FLIP, MOVEI B,MIMSEC
+
+ HRRZ C,(A)
+ CAILE C,777
+ HRLM B,(A) ; MAKE POINT TO CORRECT SECTION
+ AOBJN A,.-3
+
+ MOVE A,[-FROBL,,FROBBS]
+ HRRZ C,(A)
+ CAILE C,777
+ HRLM B,(A)
+ AOBJN A,.-3
+
+IFN FLIP,[
+ XJRST .+1
+ 0
+ MIMSEC+1,,.+1
+ MOVE A,[<ENTVEC+LOWOP-ENTMAX-1>,,ENTVEC+LOWOP]
+ MOVEI B,MIMSEC
+
+ HRRZ C,(A)
+ CAILE C,777
+ HRLM B,(A) ; MAKE POINT TO CORRECT SECTION
+ AOBJN A,.-3
+]
+ MOVE A,[-FROBL,,FROBBS]
+ HRRZ C,(A)
+ CAILE C,777
+ HRLM B,(A)
+ AOBJN A,.-3
+
+ JRST @.+1
+ .+1
+ MOVEI A,.FHSLF
+ MOVEI B,2 ; CODE FOR SETUP OF UUO TABLE
+ MOVE C,[MIMSEC,,MLTUUP]
+ SWTRP%
+
+ MOVE TP,[TPSEC,,STRTTP] ; now have good TP
+ MOVE A,[INIGC,,1000] ; MAKE THIS START GC
+ MOVEM A,GCSMIN
+ MOVEM A,GCSBOT
+ MOVE A,[INIGC,,TOPMGC]
+ MOVEM A,GCSMAX
+ MOVE B,[MPAGM,,PAGTBL]
+ BLT B,PAGTBL+MPAGME-MPAGM
+ POP P,C
+ POP P,B
+ POP P,A
+ POP P,DUALPC+1
+ MOVEI 0,MIMSEC
+ HRLM DUALPC+1
+ MOVE P,[TPSEC,,STPDL] ; p-stack in MIM section
+ SETZM DUALPC
+ XJRST DUALPC ; poof we are outta here!
+
+MPAGM: ENDPG
+ 0
+ SETZ
+ 1000-ENDPG
+ ENDPG
+ -1
+ ENDPG
+ <MIMSEC_9.>
+ SETZ
+IFN <TPSEC-MIMSEC>,[
+ 1000-ENDPG
+ <MIMSEC_9.>+ENDPG
+ -1
+]
+ 1000-<STRTTP_<-9.>>
+ <STRTTP_<-9.>>+<TPSEC_9>
+ SETZ
+ ENDPG
+ <<MIMSEC+1>_9.>
+ SETZ
+IFN <TPSEC-MIMSEC>,[
+ 1000-ENDPG
+ <<MIMSEC+1>_9.>+ENDPG
+ -1
+]
+ 1000-<STRTTP_<-9.>>
+ <STRTTP_<-9.>>+<<TPSEC+1>_9>
+ SETZ
+ 1
+ <INIGC_9>
+ SETZ
+ <TOPMGC_<-9.>>+1
+ <INIGC_9>+1
+ INITZN
+ REPEAT <NUMSEC-1>,[1
+ <<INIGC+.RPCNT+1>_9.>
+ SETZ
+ 1000-1
+ <<INIGC+.RPCNT+1>_9.>+1
+ 0
+ ]
+
+MPAGME: 0
+
+
+CONSTANTS
+VARIABLES
+LOC ZZZ
+
+ END BOOTER
\ No newline at end of file