; D1asm.asm -- Dorado resident interface procedures 28 June 1983

.get "MAsmCommon.d"
.get "D1Instrs.d"
.get "D1RegMem.d"
.get "D1Dmux.d"

; OS
.bext DoubleAdd

; MCMD
.bext ErrorAbort

; MDATA
.bext MDATAtab,MADDRtab,DWatch,CheckStoppedGlitches,MIRPE,VMBase

; MASM
.bextz OddParity,MSave2

; MGO
.bextz CantContinue

; D1I0
.bextz SaveMIR,DMuxTab,DHistTab
.bext BreakMIR,SaveBR36

; D1I1
.bextz LDRMEM	; Points at word 0 of LDR memory

; D1ACTIONS
.bext BadAText

; D1TABLES
.bextz NMEMS,MEMLEN

; D1MEM
.bext RdCACHEA,OldTPC,SaveTIOA,SaveSTKP
.bextz OldTask,SaveLINK,SaveTPC,SaveTask,SaveRBase,SaveMBase,SaveT
.bextz SaveSRN

; D1RES
.bext BR36Saved,BreakTask

; D1MICASM
.bextz MCXct

; D1CONFIG
.bext log2pgsize,AColumnShift,DColumnShift,HaveControl

; Defined here
.bext GFrameX
.bext stReadOnly,stPassive,stUndAdr,stNotIMA,stNotInVM,stRunning
.bextz D1In,D1Out
.bextz MADDRH,MADDRL	; Unpacked AVec
.bextz Xct,XctR16,XctR16C,XctR16Link,XctL16,XctL16C,XctL16T,XctL16Q
.bextz DoStrobe,XctLFF,SetALUF,SetRSTK
.bextz SelectTask,CheckStopped
.bext LoadMIR,LoadCPReg,CertifyAV,ConvertAV
.bext GetErrs,RBmux,ReadDMux,LoadDAddr,LoadDMD,LoadDWatch
.bext ContinueProgram,Start,Stop,MIRtoIM,IMtoMIR,ReadIMX,SelFltSrn


; Stuff in D1In readouts--**Note:  these are same names but different
; values from the ones in d1pe.d**
IMrhPE = 100000
IMlhPE = 40000
MdPE = 20000
IOBPE = 100000
RAMPE = 40000
MemPE = 20000
Stopped = 20000

.zrel

MADDRH:		0	; **Do not reorder (used in DoubleAdd)
MADDRL:		0
RDCnt:		0

D1In:		177030
D1Out:		177016

DoStrobe:	.DoStrobe
Xct:		.Xct
AXct:		.AXct	; For assembly code--returns non-skip
XctL16:		.XctL16
XctL16C:	.XctL16C
XctL16T:	.XctL16T
XctL16Q:	.XctL16Q
XctLFF:		.XctLFF
XctR16:		.XctR16
XctR16C:	.XctR16C
XctR16Link:	.XctR16Link
SetALUF:	.SetALUF
SetRSTK:	.SetRSTK
CheckStopped:	.CheckStopped
SelectTask:	.SelectTask

.srel

GFrameX:	.GFrameX
stReadOnly:	.stReadOnly
stPassive:	.stPassive
stUndAdr:	.stUndAdr
stNotIMA:	.stNotIMA
stNotInVM:	.stNotInVM
stRunning:	.stRunning

LoadMIR:	.LoadMIR
LoadCPReg:	.LoadCPReg
ReadDMux:	.ReadDMux
GetErrs:	.GetErrs
RBmux:		.RBmux
LoadDAddr:	.LoadDAddr
LoadDMD:	.LoadDMD
LoadDWatch:	.LoadDWatch

ContinueProgram:	.ContinueProgram
Start:		.Start
Stop:		.Stop

CertifyAV:	.CertifyAV
ConvertAV:	.ConvertAV
SelFltSrn:	.SelFltSrn

MIRtoIM:	.MIRtoIM
IMtoMIR:	.IMtoMIR
ReadIMX:	.ReadIMX

.nrel

.stReadOnly:	.txt "Read-only"
.stPassive:	.txt "Illegal to write while Passive"
.stUndAdr:	.txt "Undefined address"
.stNotIMA:	.txt "??Not IM address??"
.stNotInVM:	.txt "??Not in VM??"
.stRunning:	.txt "Illegal to write while running"

; Subroutine using new GetFrame instruction--replaces GetFrame procedure
; pointed to by 370
.GFrameX:
	GtFrame
	77400		; CallSwat() if stack overflow


; Arg1 is LDR address*4 of an instruction with 0 in RSTK; arg2 is a
; value for RSTK.  Modify the instruction fixing up parity and store
; it in MKINS.  Due to bit-scrambling in MIR the following:
.SetRSTK:
	sta 3 1 2
	sta 2 MSave2
	lda 3 LDRMEM
	add 0 3		; Pointer to instr being modified
	mov 1 2		; Preserve value for RSTK
	lda 0 XR113151	; Magic parity word
	cycle 0
	lda 1 XR200
	and 1 0		; 0/ 200 if modifying parity
	lda 1 1 3	; Mir1
	and# 1 0 szr
	sub 0 1 skp
	add 0 1
	mov 2 0
	lda 2 LDRMEM
	sta 1 MKINS+1 2	; Mir1 with modified parity
	cycle 14	; Left-justify value for RSTK
	lda 1 XR200
	movzl 0 0 szc
	add 1 0
	lda 1 0 3	; Mir0
Mir23Copy:
	add 1 0		; Add in RSTK or ALUF.0 bits
	sta 0 MKINS 2
	lda 0 2 3
	sta 0 MKINS+2 2
	lda 0 3 3
	sta 0 MKINS+3 2
	lda 2 MSave2
	lda 0 XMKINS
	lda 3 1 2
	jmp 1 3

XMKINS:		MKINS
XR200:		200
XR10000:	10000
XR113151:	113151

; Arg1 is LDR address*4 of instr with 0 in ALUF; arg2 is a value for
; ALUF.  Modify instr fixing up parity and store it in MKINS.  Due to
; bit-scrambling in MIR the following:
.SetALUF:
	sta 3 1 2
	sta 2 MSave2

	lda 3 LDRMEM
	add 0 3		; Pointer to instr.
	mov 1 2		; Preserve value for ALUF
	lda 0 XR113151	; Magic parity word
	cycle 0		; Position parity(ALUF) in bit 8
	lda 1 XR200
	and 0 1		; 200 if change parity
	mov 2 0		; 0/ ALUF
	lda 2 1 3	; 2/ Mir1
	and# 1 2 szr
	sub 1 2 skp
	add 1 2		; 2/ Mir1 with parity fixed
	cycle 14
	movzl 0 0 snc
	mkzero 1 1 skp
	lda 1 XR10000
	add 2 0		; 0/ Mir1 with parity and ALUF[1:3] fixed
	lda 2 LDRMEM
	sta 0 MKINS+1 2
	lda 0 0 3	; Mir0
	jmp Mir23Copy

; Return 16 bits of external BMux to caller
.RBmux:	sta 3 1 2
	jsr .RDin
	  Mir0+InB03
	  Mir0+InB47
	  Mir0+InB811
	  Mir0+InB1215
	lda 3 1 2
	jmp 1 3

; Return 16 bits of error status to caller
.GetErrs:
	sta 3 1 2
	jsr .RDin
	  Mir0+InErr0
	  Mir0+InErr1
	  Mir0+InErr2
	  Mir0+InErr3
	lda 3 1 2
	jmp 1 3

Mask03:		170000

.RDin:	sta 2 MSave2
	lda 0 0 3
	sta 0 @D1Out
	lda 2 @D1In
	lda 0 Mask03
	and 0 2		; 2 ← 1st 4-bit slice

	lda 1 2 3
	sta 1 @D1Out
	lda 1 @D1In
	ands 0 1
	add 1 2		; 2 ← 1st + 3rd 4-bit slices

	lda 1 1 3
	sta 1 @D1Out
	lda 1 @D1In
	and 1 0
	cycle 14
	add 0 2		; 2 ← 1st + 2nd + 3rd 4-bit slices

	lda 0 3 3
	sta 0 @D1Out
	lda 0 @D1In
	lda 1 Mask03
	and 1 0
	cycle 4
	add 2 0		; 0 ← all 4 4-bit slices

	lda 2 MSave2
	jmp 4 3

saveDVec:	0
save3rl:	0
cClock:		Clock
cClockAB:	Clock+UseCPReg

; Subroutine for turning off UseCPReg then doing XctR16, then turning
; UseCPReg back on again
.XctR16Link:
	sta 3 save3rl
	sta 0 1 2
	lda 0 cClock
	DStrobe		; Turn off UseCPReg
	lda 0 1 2
	jsr .XctR16
	 1
	lda 0 cClockAB
	DStrobe		; Turn UseCPReg back on again
	lda 0 @saveDVec
	lda 3 save3rl
	jmp 1 3

; Arg1 is LDR address*2, arg2 is DVec
; Execute instruction and store 16 bits of data in DVec
; Also return value in 0
.XctR16:
	sta 1 saveDVec
	sta 3 2 2
	jsr .AXct
	jsr .RDin
	  Mir0+InB03
	  Mir0+InB47
	  Mir0+InB811
	  Mir0+InB1215
	jmp XRC1

.XctR16C:
	sta 1 saveDVec
	sta 3 2 2
	jsr .AXct
	jsr .RDin
	  Mir0+InB03
	  Mir0+InB47
	  Mir0+InB811
	  Mir0+InB1215
	com 0 0
XRC1:	sta 0 @saveDVec
	lda 3 2 2
	jmp 1 3

; Arg1 is a displacement into LDRMEM (LDRaddr*4) of an instruction
; to execute with Arg2 added to the FF field.  Because of bit-scrambling
; in LDRMEM, the following:
.XctLFF:
	inc 3 3
	sta 3 1 2
	sta 2 MSave2

	movzr 1 3	; Compute parity of 5 bits in Arg2
	movzr 3 2
	add 2 3		; (Arg2 rshift 2)+(Arg2 rshift 1)
	movzr 2 2
	add 2 3		; (Arg2 rshift 3)+(Arg2 rshift 2)+(Arg2 rshift 1)
	movzr 2 2
	add 2 3
	addr 1 3 snc	; Carry←sum of bits = xor of bits and skip if 1
	sub 2 2 skp	; Parity is even--no change
	lda 2 X200	; Parity is odd--will complement

	lda 3 LDRMEM
	addz 0 3	; 3 = pointer to instruction, 0 into carry
	lda 0 0 3
	sta 0 XLIns0	; Copy byte 0 of instr. (no change)

	lda 0 3 3
	and# 0 2 szr	; Xor P1631
	sub 2 0 skp
	add 2 0
	sta 0 XLIns3	; Copy byte 3 with Xor'ed parity

	lda 2 1 3
	lda 3 2 3
	movzr 1 0 snc	; Skip if Arg2 is odd, 0 = FF rshift 1
	jmp .+3
	lda 1 X4000
	add 1 3		; Add 1 to FF.7
	movs 0 0
	add 0 2		; Add (FF rshift 1) to FF[3:6]
	sta 2 XLIns1
	sta 3 XLIns2

	lda 2 MSave2	; Restore stack pointer
	jsr XLFF	; 3 = pointer to instruction, continue inside Xct
XLIns0:	 0		; 0th instr byte saved here
XLIns1:	 0		; 1st
XLIns2:	 0		; 2nd
XLIns3:	 0		; 3rd
XLFF:	mov 3 1
	jmp XLFF1

X200:	200
X4000:	4000

; Subroutine to execute a microinstruction in the LDR memory.  Arg is
; an address in LDR*4.
.Xct:	inc 3 3
.AXct:	sta 3 1 2
Xct1:	lda 1 LDRMEM
	add 0 1		; Compute address of MIRvec in LDR

XLFF1:	lda 0 cNormal
	MIRLoad		; Special Alto microinstruction

; Check for PE's
	lda 0 xErr2
	sta 0 @D1Out
	lda 0 @D1In
	movl 0 0 szc	; Know CIMPErh = 100000
	jmp XctE2141
XctER0:	movl 0 0 szc	; Know CIMPElh = 40000
	jmp XctE020
XctX:	lda 0 cXct	; Single-step
	DStrobe
	jmp @1 2

XctE2141:
	lda 3 @lvMIRPE
	isz 1 3
	jmp XctER0
	jmp XctER0

XctE020:
	lda 3 @lvMIRPE
	isz 0 3
	jmp XctX
	jmp XctX

cXct:		Control+Freeze+SetRun+SetSS
cNormal:	Control+Freeze
xErr2:		Mir0+InErr2
Masklh:		177400
lvMIRPE:	MIRPE

; For XctL16 and XctL16C, arg1 is LDR address*4, arg2 is 16 bits of data.
; Load CPReg with data, execute the instruction with UseCPReg true,
; then turn off UseCPReg.  XctL16T and XctL16Q accept data as arg1 and
; do either LDT or LDQ as the instruction.
.XctL16Q:
	mov 0 1
	lda 0 xLDQ
	jmp .XctL16

.XctL16T:
	mov 0 1 skp
.XctL16C:
	com 1 1 skp	; Complement the data first
	lda 0 xLDT
.XctL16:
	inc 3 3
	sta 3 1 2
	sta 0 2 2
	movs 1 0	; l.h. 0←value for CPReg1, l.h. 1←value for CPReg0
	lda 3 Masklh
	and 3 0		; 0←Value for CPReg1
	and 3 1		; 1←Value for CPReg0
	lda 3 cCPReg1
	add 3 0
	lda 3 cCPReg0
	add 1 3
	DStrobe		; Strobe CPReg1
	mov 3 0
	DStrobe		; Strobe CPReg0
	lda 0 2 2
	jmp Xct1

xLDT:		LT
xLDQ:		LQ
cCPReg1:	CPReg1
cCPReg0:	CPReg0

RCcnt:		Clock+ShiftDMux
RControl:	Control

; Subroutine to read all machine state that can be read passively:
; 2048 DMux addresses, saved in DMuxTab; 16 BMUX bits via D1In,
; stored in DMuxTab!128; and 16 error status bits, stored in DMuxTab!129.
; The readout is then rearranged for convenient usage by the rest of Midas.
.ReadDMux:
	sta 3 1 2
	jsr @GetFrame
	 12
	jsr @StArgs
; 0←Value, 1←Last, 3←-Count
	lda 3 R177600	; 3/ -200
	lda 1 DMuxTab
	adc 3 1		; 1/ DMuxTab+177
	mkzero 0 0
	blks		; Zero(DMuxTab,200B)
	lda 0 RControl
	DStrobe		; Must clear SetRun to enable Alto muffler control
	lda 0 RCcnt	; Clock+ShiftDMux
	mkzero 1 1
	lda 3 DMuxTab
	RDMux		; New read-DMux instruction in special microcode
			; reads all addresses except 2047
	jmp RDMo

R177600:	177600
RB100000:	100000
R4:		4
RMir0:		Mir0
RMir0x:		Mir0+200
RMir1:		Mir1
RMir1x:		Mir1+200
R100200:	100200
R20000:		20000
R40:		40

; Finished reading DMux--rearrange bits for registers that must be
; displayed independently
RDMo:	sta 2 MSave2
	lda 3 DMuxTab

; Temperature sensors and BaseBoard
	lda 0 dCTASK 3
	lda 2 RB100000
	and 0 2		; 2 ← CBTempSense in sign bit
	lda 1 dCLKRUN 3
	lda 0 R4
	and 1 0
	sub 0 1
	sta 1 dCLKRUN 3	; CLKRUN with TBaseTempSense removed
	cycle 14
	add 0 2
	lda 0 dSCCON 3
	lda 1 R100200
	and 0 1
	sub 1 0
	sta 0 dSCCON 3	; SCCON with TempSense stuff removed
	movzr 1 1
	movzr 1 1
	lda 0 R20000
	and 1 0		; ProcH TempSense in bit 2
	add 0 2
	lda 0 R40
	ands 1 0
	movzr 0 0	; ProcL TempSense in bit 3
	add 0 2
	lda 1 dFFK 3
	lda 0 R40
	and 1 0
	sub 0 1

	sta 1 dFFK 3
	cycle 6		; IFUTemp in bit 4
	add 0 2
	lda 1 dKSTATE 3
	lda 0 R100000
	and 1 0
	sub 0 1
	sta 1 dKSTATE 3
	cycle 13	; DiskEthTemp in bit 5
	add 0 2
	sta 2 dTEMP 3

; Control section rearrangements
; Get bdIM signals in MIR-loading format and put in 4-word IMOUT vector
	lda 0 dCTASK 3
	cycle 4
	mov 0 2		; bdRSTK.0, bdIMLH, bdIMRH, bdJCN.7 left-justified

	lda 0 R170000
	lda 1 dNEXT 3	; bdIM[1:20]
	and 0 1
	lda 3 dCTD 3	; bdIM[21:40]
	and 3 0
	lda 3 RMir0	; Mir0 in address field, RSTK.0 false
	movl 2 2 szc
	lda 3 RMir0x	; RSTK.0 true
	add 1 3
	cycle 14
	add 3 0
	lda 3 DMuxTab
	sta 0 dIMOUT+0 3

	lda 0 R7400
	lda 1 dCTD 3
	and 0 1
	lda 3 dNEXT 3
	and 3 0
	lda 3 RMir1	; Mir1 in address field, P020 false
	movl 2 2 szc
	lda 3 RMir1x	; P020 true
	add 1 3
	cycle 4
	add 3 0
	lda 3 DMuxTab
	sta 0 dIMOUT+1 3

	lda 1 dCTD 3
	lda 0 R17
	ands 0 1
	lda 3 dNEXT 3
	ands 3 0
	lda 3 RMir3
	movl 2 2 szc
	lda 3 RMir3x
	add 1 3
	cycle 4
	add 3 0
	lda 3 DMuxTab
	sta 0 dIMOUT+3 3

	lda 0 R360
	lda 1 dNEXT 3
	ands 0 1
	lda 3 dCTD 3
	and 3 0
	lda 3 RMir2	; Mir2 in address field, JCN.7 false
	movl 2 2 szc
	lda 3 RMir2x	; JCN.7 true
	add 1 3
	cycle 4
	add 3 0
	lda 3 DMuxTab
	sta 0 dIMOUT+2 3

; Get MIR into MIR-loading format and put in the 4-word vector SaveMIR
	lda 0 dCTASK 3
	lda 1 R17
	and 0 1
	sta 1 dCTD 3	; CTD[0:3]
	cycle 4
	lda 2 R3
	and 0 2		; bRSTK.0, IMLH right-justified

	lda 0 dBNT 3	; MIR[21:40]
	lda 1 R170000
	and 1 0
	lda 3 dPENC 3	; MIR[1:20]
	and 3 1
	lda 3 RMir0
	movr 2 2 szc	; IMLH tested
	lda 3 RMir0x
	add 1 3
	cycle 14
	add 3 0
	lda 3 DMuxTab
	sta 0 dSaveMIR+0 3

	lda 0 dPENC 3
	lda 1 R7400
	and 1 0
	lda 3 dBNT 3
	and 3 1
	lda 3 RMir1
	movr 2 2 szc	; bRSTK.0 tested
	lda 3 RMir1x
	add 1 3
	cycle 4
	add 3 0
	lda 3 DMuxTab
	sta 0 dSaveMIR+1 3

	lda 1 R360
	lda 0 dBNT 3
	and 1 0
	lda 2 dCJNK1 3	; bJCN.7, IMRH left-justified
	lda 3 dPENC 3
	ands 3 1
	lda 3 RMir2
	movl 2 2 szc	; bJCN.7 tested
	lda 3 RMir2x
	add 1 3
	cycle 4
	add 3 0
	lda 3 DMuxTab
	sta 0 dSaveMIR+2 3

	lda 0 dPENC 3
	lda 1 R17
	and 1 0
	lda 3 dBNT 3
	ands 3 1
	lda 3 RMir3
	movl 2 2 szc	; IMRH tested
	lda 3 RMir3x
	add 1 3
	cycle 14
	add 3 0
	lda 3 DMuxTab
	sta 0 dSaveMIR+3 3
	jmp RConZ

R100000:	100000
RMir2:		Mir2
RMir2x:		Mir2+200
RMir3:		Mir3
RMir3x:		Mir3+200
R170000:	170000
R7400:		7400

R360:		360
R17:		17
R40000:		40000
R3:		3
R177400:	177400
R140:		140
R37777:		37777
R377:		377
R14:		14
R10400:		10400

RConZ:	lda 2 dCTASK 3
	lda 0 R360
	and 2 0
	cycle 14
	sta 0 dCTASK 3	; CTASK complete (bSWd' remaining in ac2)
	sta 0 SaveTask

	lda 0 dCJNK1 3
	lda 1 R37777
	and 1 0		; Flush bJCN.7 and IMRH (was put into MIR)
	lda 1 R40000
	and 2 1		; bSWd'
	add 1 0		; 0/ CJNK1 with bSWd' added

	lda 1 dTOPE 3
	lda 2 R100000
	and 1 2		; Call
	sub 2 1
	sta 1 dTOPE 3	; ToPE[1:15] (Call removed)

	add 0 2		; 2/ CJNK1 with bJCN.7, IMRH removed,
			; bSWd', Call added
	lda 0 R14
	and 2 0
	sub 0 2		; 2/ FF=UseDMD and FF=TOffIsOk removed
	sta 2 dCJNK1 3
	movzl 0 1
	movzl 1 1
	lda 2 dFFEQ 3
	lda 0 R377
	and 2 0		; 0/ Bnt and bPEnc
	sub 0 2		; 2/ BNT and bPEnc removed
	add 1 2		; 2/ FF=UseDMD, FF=TOffIsOk added
	lda 1 R17
	and 0 1
	sub 1 0
	sta 1 dPENC 3	; bPEnc[0:3] complete

	cycle 14
	sta 0 dBNT 3

	lda 0 dCJNK0 3
	lda 1 R17
	and 0 1
	sub 1 0
	sta 0 dCJNK0 3	; FF= bits removed
	add 1 2		; FF= bits added

	lda 0 R10400
	and 2 0
	sub 0 2		; FF= with Link←BMuxa, B←Link' removed
	sta 2 dFFEQ 3
	cycle 7
	lda 1 RA10
	and 0 1
	lda 2 dCJNK1 3
	add 1 2		; Link←BMuxa added
	cycle 4
	lda 1 RA10
	andzr 1 0
	add 0 2		; B←Link' added
	sta 2 dCJNK1 3

	lda 2 dCJNK3 3
	lda 0 R170000
	and 2 0
	sub 0 2
	sta 2 dCJNK3 3	; CJNK3 complete
	cycle 4
	sta 0 dNEXT 3	; NEXT complete

; MemC rearrangements
	lda 0 dMAPAD 3
	lda 2 RA377
	and 0 2
	sub 2 0
	cycle 14
	sta 0 dAAD 3	; Aad with 4 zeroes to the right

	lda 0 dPAIR 3
	lda 1 RA200
	and 0 1
	sub 1 0
	sta 0 dPAIR 3
	movzl 1 1
	add 2 1
	sta 1 dMAPAD 3	; MapAd[0:8] right-justified

	lda 1 dPVAL 3
	lda 0 RA100000
	and 1 0		; MemB.0
	sub 0 1
	lda 2 RA10000
	and 1 2		; MemB.1
	sub 2 1
	movzl 2 2
	movzl 2 2
	add 2 0		; MemB[0:1] in bits 0:1
	sta 1 dPVAL 3	; PVAL with MemB[0:1] removed
	cycle 5
	lda 2 dHIT 3
	lda 1 RA7
	and 2 1
	sub 1 2		; 2/ HIT with MemB[2:4] removed
	add 1 0
	sta 0 dMEMB 3	; MemB[0:4] right-justified
	lda 0 RA777
	and 2 0
	sub 0 2		; 2/ Mcr stuff from MemC
	sta 0 dHIT 3	; HIT with Mcr and MemB stuff removed
	lda 0 RA17000
	and 2 0
	sub 0 2
	cycle 14
	add 0 2		; 2/ Mcr stuff from MemC in position
	lda 1 dHOLD 3
	lda 0 RA170000
	and 1 0
	sub 0 1
	sta 1 dHOLD 3	; Victim' and NextV' removed
	com 0 0
	lda 1 RA170000
	and 1 0
	cycle 15
	add 0 2		; 2/ Mcr stuff with Victim & NextV added (high-true)
	lda 1 dFLTMEM 3
	lda 0 RA160000
	and 1 0		; 1/ other Mcr bits from MemX
	sub 0 1
	sta 1 dFLTMEM 3
	cycle 3
	add 0 2
	sta 2 dMCR 3	; Complete Mcr

	lda 0 dPVAH 3
	lda 1 RA60000
	and 0 1		; true, WantCHDly'
	sub 1 0
	movzr 1 1
	lda 2 dHOLD 3
	add 1 2
	sta 2 dHOLD 3	; HOLD complete
	lda 2 dPVAL 3
	lda 1 RA60000
	and 2 1
	sub 1 2		; 2/ ProcVA[20:31] right-justified
	add 1 0		; 0/ ProcVA[4:19]
	cycle 14
	lda 1 RA170000
	and 0 1
	sub 1 0
	add 1 2
	sta 0 dPVAH 3	; ProcVA[4:15] right-justified
	sta 2 dPVAL 3	; ProcVA[16:31]
	jmp RCMemD

RA377:		377
RA200:		200
RA100000:	100000
RA10000:	10000
RA7:		7
RA777:		777
RA17000:	17000
RA170000:	170000
RA160000:	160000
RA60000:	60000
RA177767:	177767
RA10:		10
RA100003:	100003
RA60:		60
RA40:		40
RA2:		2
RA1:		1
RA1000:		1000
RA2000:		2000
RA177377:	177377

; MemD rearrangements
RCMemD:	lda 1 dEC 3
	lda 0 RA170000
	and 1 0
	sub 0 1
	sta 1 dEC 3	; EC with MDMad[0:3] removed
	cycle 4
	sta 0 dMDMAD 3	; MDMad[0:3] right-justified

	lda 0 dFD 3
	lda 1 RA177767
	and 1 0		; Clear possible garbage bit
	lda 1 dMEMD0 3
	lda 2 RA10
	and 1 2
	sub 2 1		; 1/ MEMD0 with DontWriteMDM removed
	add 2 0
	sta 0 dFD 3	; Move DontWriteMDM bit into FD
	lda 0 dDAD 3
	lda 2 RA100003
	and 0 2
	sub 2 0
	movzl 0 0
	sta 2 dDADE 3	; D0BCE'c, D0ACE'c, and WriteD0'e scrambled
	lda 2 RA7
	and 1 2
	sub 2 1		; 1/ MEMD0 with DAD1.10b-12b removed
	add 2 0
	sta 0 dDAD 3	; DAD complete
	lda 2 RA60
	and 1 2		; 2/ D1BCE'c and WriteD1'd
	sub 2 1
	sta 1 dMEMD0 3
	lda 0 RA40
	and 2 0
	add 2 0		; Move the D1BCE'c bit left 1
	cycle 6		; 0/ D1BCE'c and WriteD1'd in position
	lda 2 RA100000
	lda 1 dDADE 3
	andzr 1 2
	add 0 2		; D0BCE'c, D1BCE'c, & WriteD1'd in position
	lda 0 RA2
	and 1 0
	cycle 16
	add 0 2		; D0ACE'c also in position
	lda 0 dDADE 3
	lda 1 RA1
	ands 1 0
	cycle 3
	add 0 2		; WriteD0'e also in position
	lda 1 dEC 3
	lda 0 RA1000
	and 1 0
	sub 0 1
	sta 1 dEC 3	; EC with D1ACE'c removed
	cycle 4		; D1ACE'c in pos.
	add 0 2
	sta 2 dDADE 3	; DADE complete

	lda 1 dFD 3
	lda 0 RA200
	and 1 0		; 0/ Fout.00
	sub 0 1		; 1/ FD with Fout.00 removed
	lda 2 dMEMD0 3
	lda 3 RA1000
	and 2 3		; 3/ Dbuf←'
	sub 3 2		; 2/ MEMD0 with Dbuf←' removed
	movzr 3 3
	movzr 3 3
	add 3 1		; 1/ FD with Dbuf←' added
	movzr 0 0
	movzr 0 0
	add 0 2		; 2/ MEMD0 with Dbuf←' added
	lda 3 DMuxTab
	sta 1 dFD 3
	lda 0 RA2000
	and 2 0
	sub 0 2		; 2/ MEMD0 with EcInD.0 removed
	sta 2 dMEMD0 3	; MEMD0 complete
	cycle 16
	lda 1 dEC 3
	lda 2 RA177377
	and 2 1		; Clear garbage bit
	add 1 0
	sta 0 dEC 3	; EC complete

; To this point, ReadDMux has used ~461 instructions + RDmux opcode.
	lda 2 MSave2
	jsrii lvRBmux
	 0
	lda 3 DMuxTab
	sta 0 dBMUX 3	; BMUX in extended DMuxTab

	jsrii lvGetErrs
	 0
	lda 3 DMuxTab
	sta 0 dESTAT 3	; ESTAT in extended DMuxTab

; left-shift DHIST bits into 32-bit accumulators (~645 instructions)
	sta 2 MSave2
	lda 3 MEMLEN
	lda 0 DHISTx+DHISTx+1 3
	sta 0 RDCnt	; Iteration count
	lda 3 DHistTab
HisLp:	lda 0 2 3	; Selected DMux address in left 12 bits of 3rd wrd
	lda 2 RA177400
	ands 0 2	; Right-justify word number
	lda 1 DMuxTab
	add 1 2
	cycle 14	; Right-justify bit number
	mov 0 1
	lda 0 0 2	; Word from DMuxTab
	cycle 0		; Left-justify selected bit
	movl 0 0	; DMux bit into CRY
	lda 0 1 3	; Left-shift two-word history
	movl 0 0
	sta 0 1 3
	lda 0 0 3
	movl 0 0
	sta 0 0 3
	lda 0 RA3
	add 0 3
	dsz RDCnt
	  jmp HisLp
	lda 2 MSave2

	jsr .LoadDWatch
	 0
	jsr @Return

RA3:		3
RA177400:	177400
lvRBmux:	RBmux
lvGetErrs:	GetErrs

; Load 12-bit DMux address in AC0 and then execute it with UseDMD.
; **Doesn't restore DMux address to DWatch
.LoadDMD:
	sta 3 2 2
	jsr .LoadDAddr
	 1
	lda 0 LDMx
	DStrobe
	lda 3 2 2
	jmp LDMDf	; Turn off UseDMD and return

; Subroutine to load the DMux address with DWatch[20:37] in MDATA for
; scope observation.
.LoadDWatch:
	sta 3 1 2
	lda 3 @lvDWatch
	lda 0 1 3
	mov# 0 0 skp
; Procedure to load the DMux address selected by arg 0
.LoadDAddr:
	sta 3 1 2
	cycle 4		; Left-justify 12-bit number
	mov 0 1
	lda 0 LDControl
	DStrobe		; Clear SetRun to enable CP muffler control
	lda 3 LDMDc1
; Maximum speed desirable here
	movl 1 1 szc	; Skip if next bit is 0
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe		; Strobe next bit into DMux address
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe
	movl 1 1 szc
	mov 3 0 skp
	lda 0 LDMDc0
	DStrobe

	lda 3 1 2
LDMDf:	lda 0 ClockN
	DStrobe
	jmp 1 3

LDMx:		Clock+UseCPReg+UseDMD
LDMDc0:		Clock+ShiftDMux+UseCPReg
LDMDc1:		Clock+ShiftDMux+UseCPReg+DAddrBit
lvDWatch:	DWatch
LDControl:	Control
ClockN:		Clock+UseCPReg

; IMtoMIR(MIRvec,IMvec) transforms IMvec into MIRvec where MIRvec is the
; four-word vector such that four DStrobe's load MIR with the IM data
.IMtoMIR:
	sta 3 1 2
	jsr @GetFrame
	 12
	jsr @StArgs

	lda 3 5 2	; 3/ IMvec
	lda 1 2 3
	movzl 1 1
	movzl 1 1	; IMLH bad parity bit into sign
	lda 0 1 3
	movl 0 0	; ASEL.2 into carry
	lda 0 0 3
	movl 0 0 snc	; 0/ IM[1:20], skip if RSTK.0 true
	jmp IMtoMIRa
	movl 1 1 snc	; Skip if bad parity into IMLH
	mkzero 1 1 skp
	mkone 1 1
	lda 3 mMir0x
	jmp IMtoMIRb
IMtoMIRa:
	movl 1 1 snc
	mkone 1 1 skp
	mkzero 1 1
	lda 3 mMir0
IMtoMIRb:
	sta 3 6 2	; Mir0 control with RSTK.0 fixed
	sta 0 7 2	; IM[1:20]
	jsr @OddParity	; Returns -1 if P020 is odd, 0 if even
	 2
	lda 3 m200
	and 0 3		; P020 in pos for Mir1
	lda 0 7 2
	cycle 4
	lda 1 m170000
	and 0 1
	add 3 1		; 1/ partial Mir1 control
	lda 3 4 2	; 3/ MIRvec
	sta 1 1 3	; Partial Mir1 control
	cycle 14
	lda 1 m170000
	and 0 1
	lda 0 6 2
	add 0 1
	sta 1 0 3	; Partial Mir0 control
	lda 0 7 2	; IM[1:20] again
	cycle 10
	lda 1 m170000
	and 0 1
	sta 1 2 3	; Partial Mir2 control
	cycle 4
	lda 1 m170000
	and 0 1
	lda 0 mMir3
	add 0 1
	sta 1 3 3	; Partial Mir3 control

	lda 3 5 2	; 3/ IMvec
	lda 1 2 3	; JCN[6:7], IMLHbad, IMRHbad
	lda 0 1 3
	movzl 1 1
	movl 0 0	; 0/ IM[21:40]
	sta 0 7 2
	movl 1 1 snc	; Skip if JCN.7 true
	jmp IMtoMIRc
	movl 1 1
	movl 1 1 snc	; Skip if bad parity into IMRH
	mkzero 1 1 skp
	mkone 1 1
	lda 3 mMir2x
	jmp IMtoMIRd
IMtoMIRc:
	movl 1 1
	movl 1 1 snc
	mkone 1 1 skp
	mkzero 1 1
	lda 3 mMir2
IMtoMIRd:
	sta 3 6 2	; 6,2/ Mir2 controls with JCN.7 fixed
	jsr @OddParity
	 2
	lda 1 m200
	and 0 1
	lda 3 4 2	; MIRvec
	lda 0 3 3
	add 0 1
	sta 1 3 3	; Mir3 control barring JCN[3:6]
	lda 0 7 2	; IM[21:40]
	lda 1 m7400
	and 0 1
	lda 0 1 3
	add 0 1
	lda 0 mMir1
	add 0 1
	sta 1 1 3	; Mir1 controls complete
	lda 0 7 2
	cycle 4
	lda 1 m7400
	and 0 1
	lda 0 6 2
	add 0 1
	lda 0 2 3
	add 0 1
	sta 1 2 3	; Mir2 controls complete
	lda 0 7 2
	cycle 14
	lda 1 m7400
	and 0 1
	lda 0 0 3
	add 0 1
	sta 1 0 3	; Mir0 controls complete
	lda 0 7 2
	cycle 10
	lda 1 m7400
	and 0 1
	lda 0 3 3
	add 0 1
	sta 1 3 3	; Mir3 controls complete
	mov 3 0		; resultis MIRvec
	jsr @Return

mMir0:		Mir0
mMir0x:		Mir0+200
mMir1:		Mir1
mMir2:		Mir2
mMir2x:		Mir2+200
mMir3:		Mir3
m200:		200
m170000:	170000
m7400:		7400

m20000:		20000

; MIRtoIM(IMvec,MIRvec) transforms MIRvec into IM format and leaves result
; in IMvec
.MIRtoIM:
	sta 3 1 2
	jsr @GetFrame
	 12
	jsr @StArgs

	lda 3 5 2	; 3/ MIRvec
	sta 2 MSave2
	lda 2 0 3	; MIR[0:3], MIR[16:19] in l.h.
	lda 0 m170000
	and 0 2
	lda 1 2 3	; MIR[8:11], MIR[24:27] in l.h.
	ands 0 1
	add 1 2
	lda 1 1 3	; MIR[4:7], MIR[20:23] in l.h.
	and 1 0
	cycle 14
	add 0 2
	lda 0 3 3	; MIR[12:15], MIR[28:31] in l.h.
	lda 1 m170000
	and 1 0
	cycle 4
	add 2 0
	lda 2 MSave2
	sta 0 6 2	; IM[1:20]

	lda 2 1 3
	lda 0 m7400
	and 0 2
	lda 1 3 3
	ands 0 1
	add 1 2
	lda 1 0 3
	and 1 0
	cycle 4
	add 0 2
	lda 0 2 3
	lda 1 m7400
	and 1 0
	cycle 14
	add 2 0
	lda 2 MSave2
	sta 0 7 2	; IM[21:40]

	lda 0 2 3
	lda 1 m200
	ands 0 1	; Sign of 1 ← JCN.7
	lda 0 0 3
	movs 0 0	; Sign of 0 ← RSTK.0
	movzl 0 0
	lda 0 6 2
	movr 0 0	; 0 ← IM[0:17], carry ← IM[20]
	lda 3 4 2	; 3 ← IMvec
	sta 0 0 3
	lda 0 7 2
	movr 0 0	; 0 ← IM[20:37], carry ← IM[40]
	sta 0 1 3
	movr 1 1	; 1 ← JCN[6:7] with trailing 0's
	sta 1 2 3

	lda 3 5 2	; 3 ← MIRvec
	lda 0 1 3
	movs 0 0	; Sign of 0 ← P020
	lda 1 0 3
	movs 1 1	; Sign of 1 ← RSTK.0
; Strobe bit to the right of P020 and RSTK.0 is 0 so no carry-in to bit 0
	addzl 1 0 szc	; Skip if RSTK.0 xor P020 is 0
	mkzero 0 0 skp
	mkone 0 0
	lda 1 6 2
	jsr @OddParity	; -1 if IM[1:20], RSTK.0, P020 is odd parity
	 2
	lda 1 m20000
	and 1 0		; 20000 if parity wrong else 0
	lda 3 5 2
	sta 0 5 2

	lda 0 3 3
	movs 0 0	; Sign of 0 ← P2141
	lda 1 2 3
	movs 1 1	; Sign of 1 ← JCN.7
	addzl 1 0 szc	; Skip if JCN.7 xor P2141 is 0
	mkzero 0 0 skp
	mkone 0 0
	lda 1 7 2
	jsr @OddParity	; 0 if IM[21:40], JCN.7, P2141 is even parity
	 2
	lda 1 m20000	; 100000 if parity wrong else 0
	andzr 1 0
	lda 1 5 2
	add 1 0
	lda 3 4 2	; 3 ← IMvec
	lda 1 2 3	; JCN[6:7]
	add 1 0		; JCN[6:7], PE[0:20], PE[21:41]
	sta 0 2 3	; Save PE bits in IMvec!2
	mov 3 0		; resultis IMvec
	jsr @Return

riLLINK:	LLINK
riRLINK:	RLINK
riRIM0:		RIM0
riRIM1:		RIM1
riRIM2:		RIM2
riRIM3:		RIM3

; ReadIMX(DVec,DVX) reads the IMX location in MADDRL into DVec using
; the vector DVX as temp storage
.ReadIMX:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs

	lda 0 riLLINK
	lda 1 MADDRL
	jsr @XctL16C	; XctL16C(LLINK,MADDRL)
	 2
	lda 0 riRIM0
	jsr @AXct	; Xct(RIM0)
	lda 0 riRLINK
	lda 1 5 2
	jsr @XctR16Link	; DVX!0 = RIM0 readout
	 2

	isz 5 2
	lda 0 riLLINK
	lda 1 MADDRL
	jsr @XctL16C	; XctL16C(LLINK,MADDRL)
	 2
	lda 0 riRIM1
	jsr @AXct	; Xct(RIM1)
	lda 0 riRLINK
	lda 1 5 2
	jsr @XctR16Link	; DVX!1 = RIM1 readout
	 2

	isz 5 2
	lda 0 riLLINK
	lda 1 MADDRL
	jsr @XctL16C	; XctL16C(LLINK,MADDRL)
	 2
	lda 0 riRIM2
	jsr @AXct	; Xct(RIM2)
	lda 0 riRLINK
	lda 1 5 2
	jsr @XctR16Link	; DVX!2 = RIM2 readout
	 2

	isz 5 2
	lda 0 riLLINK
	lda 1 MADDRL
	jsr @XctL16C	; XctL16C(LLINK,MADDRL)
	 2
	lda 0 riRIM3
	jsr @AXct	; Xct(RIM3)
	lda 0 riRLINK
	lda 1 5 2
	jsr @XctR16Link	; DVX!3 = RIM3 readout
	 2

	lda 3 5 2
	lda 1 -1 3
	lda 3 ri777
	and 3 0
	and 3 1
	jsr @OddParity
	 2
	com 0 0
	lda 1 ri100000
	andzr 1 0	; PrhOK
	lda 3 4 2
	sta 0 2 3

	lda 3 5 2
	lda 0 -3 3
	lda 1 -2 3
	lda 3 ri777
	and 3 0
	and 3 1
	jsr @OddParity
	 2
	com 0 0
	lda 1 ri100000
	and 1 0		; PlhOK
	lda 3 5 2
	lda 1 0 3
	lda 3 ri3
	and 3 1		; JCN[6:7]
	add 1 0
	lda 3 4 2
	lda 1 2 3
	add 1 0
	cycle 16
	sta 0 2 3	; DVec!2 complete

	lda 3 5 2
	lda 0 -3 3
	lda 1 ri777
	and 1 0
	cycle 7
	lda 1 -2 3
	lda 3 ri377
	andzr 3 1
	add 1 0
	lda 3 4 2
	sta 0 0 3	; DVec!0 complete

	lda 3 5 2
	lda 0 -1 3
	lda 1 ri777
	and 1 0
	cycle 7		; 9 bits left-cycled 1
	lda 1 -2 3
	mkone 3 3
	and 3 1
	add 1 0		; 10 bits left-cycled 1
	lda 3 5 2
	lda 1 0 3
	lda 3 ri374
	andzr 3 1
	add 1 0
	cycle 17
	lda 3 4 2
	sta 0 1 3	; DVec!1 complete
	jsr @Return

ri777:		777
ri100000:	100000
ri377:		377
ri374:		374
ri3:		3

; Special kludge to allow address eq length to default the address to
; some reasonable value: SaveTask for task-specific registers or
; MemBase[SaveTask] for BR.
; Have 1/ Length and 0/ AddrVec!1.
CertX:	sub# 1 0 szr
	jmp CertBad	; Error if address # memory length
	jsr CertX1
	 jmp CertBad	; $ABSOLUTE
	 jmp CUseST	; TPC
	 jmp CUseST	; TLINK
	 jmp CUseST	; OLINK
	 jmp CertBad	; IMBD
	 jmp CertBad	; IM
	 jmp CertBad	; IMX
	 jmp CertBad	; ALUFM
	 jmp CUseST	; T
	 jmp CUseST	; RBASE
	 jmp CUseST	; TIOA
	 jmp CUseST	; MEMBASE
	 jmp CertBad	; RM
	 jmp CertBad	; STK
	 jmp CertBad	; PIPE
	 jmp CUseMB	; BR
	 jmp CertBad	; CACHEA
	 jmp CertBad	; CACHED
	 jmp CertBad	; MAP
	 jmp CertBad	; VM
	 jmp CertBad	; IFUM
	 jmp CertBad	; LDR
	 jmp CertBad	; MDATA
	 jmp CertBad	; MADDR
	 jmp CertBad	; DMUX
	 jmp CertBad	; DHIST
	 jmp CertBad	; VH
	 jmp CUseST	; MD
	 jmp CertBad	; TASKN
	 jmp CertBad	; DEVICE
	 jmp CertBad	; STKX
	 jmp CertBad	; MSTAT
	 jmp CertBad	; $ABS
	 jmp CertBad	; ROW
	 jmp CertBad	; BRX
CertX1:	lda 0 5 2
	add 0 3
	jmp 0 3

CUseST:	lda 1 SaveTask
	sta 1 MADDRL	; MADDRL = SaveTask
	jmp CertOK	; Return MemX

CUseMB:	lda 1 SaveMBase
	sta 1 MADDRL
	jmp CertOK

; CertifyAV(AVec,MemX) returns true if AVec is a legal address in MemX
; else false.
.CertifyAV:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs
	lda 1 5 2	; MemX
	lda 3 NMEMS
	subl# 1 3 szc	; Skip if legal MemX
	 77400		; else CallSwat
	lda 3 4 2	; AVec
	lda 0 1 3
	sta 0 MADDRL	; MADDRL = AVec!1
	lda 0 0 3
	sta 0 MADDRH	; MADDRH = AVec!0
	lda 3 cVMx
	sub# 1 3 snr
	 jmp CertVM	; Offset by VMBase if VM
Cert2:	lda 3 MEMLEN
	add 1 3
	add 1 3
	lda 1 0 3	; MEMLEN!(MemX+MemX)
	sub# 1 0 szr	; Skip if high parts equal
	jmp Cert1
	lda 1 1 3	; MEMLEN!(MemX+MemX+1)
	lda 0 MADDRL
Cert1:	adcz# 0 1 snc	; Skip if Usc(Addr,Length) < 0
	jmp CertX	; Check address eq length kludges
CertOK:	mkminusone 0 0 skp
CertBad:
	mkzero 0 0
	jsr @Return

lvVMBase:	VMBase
pMADDRH:	MADDRH
lvDoubleAdd:	DoubleAdd
cVMx:		VMx

CertVM:	lda 0 pMADDRH
	lda 1 @lvVMBase
	jsrii lvDoubleAdd
	 2
	lda 0 MADDRH
	lda 1 5 2	; MemX
	jmp Cert2

; ConvertAV(AVec,MemX) used by PutMemData and GetMemData to error-check
; AVec and perform setup common to both Put and Get
.ConvertAV:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs
	lda 0 4 2	; AVec
	lda 1 5 2	; MemX
	lda 3 MEMLEN
	add 1 3
	add 1 3
	lda 3 1 3
	sta 3 6 2	; Save length for CACHEA/D
	jsr .CertifyAV	; Check for legal address and leave high part in
	 2		; MADDRH, low part in MADDRL
	mov# 0 0 snr
	jmp ConM1
	lda 1 5 2	; MemX
	jsr CAV1
	 ConABSOL-.	; $ABSOLUTE
	 ConXit-.	; TPC
	 ConST-.	; TLINK
	 ConST-.	; OLINK
	 ConIMBD-.
	 ConXit-.	; IM
	 ConXit-.	; IMX
	 ConXit-.	; ALUFM
	 ConST-.	; T
	 ConST-.	; RBASE
	 ConST-.	; TIOA
	 ConST-.	; MEMBASE
	 ConRM-.
	 ConSTK-.
	 ConSRN-.	; PIPE
	 ConBR-.
	 ConCACHEA-.
	 ConCACHED-.
	 ConMAP-.
	 ConVM-.
	 ConIFUM-.
	 ConLDR-.
	 ConMDATA-.
	 ConMADDR-.
	 ConXit-.	; DMUX
	 ConDH-.	; DHIST
	 ConVH-.
	 ConST-.	; MD
	 ConUnImp-.	; TASKN
	 ConUnImp-.	; DEVICE
	 ConSTKX-.
	 ConMSTAT-.
	 ConABS-.
	 ConUnImp-.	; ROW
	 ConBRX-.
CAV1:	add 1 3
	lda 1 0 3	; Self-relative pointer
	add 1 3
	lda 0 MADDRL
	mov 0 1
	jmp 0 3		; Dispatch to setup routine

lvErrorAbort:	ErrorAbort
lvBadAText:	BadAText

; Should never get here
ConUnImp:
;	jsr ConUI1
;	.txt "Ill. memory"
ConM1:	lda 3 @lvBadAText
ConUI1:	mov 3 0
	jsrii lvErrorAbort
	 1
	77400

ConMSTAT:
	add 0 0
	inczl 0 0 skp	; Address*4+2
ConABS:	add 0 0		; Address*2
	sta 0 MADDRL
ConABSOL:
	lda 3 cav177400
	ands 3 0
	lda 1 cvMCLdHi
	add 1 0
	jsr @MCXct
	 1
	lda 0 MADDRL
	lda 1 cav377
	and 1 0
	lda 1 cvMCLdLo
	add 1 0
	jsr @MCXct
	 1
	jmp ConXtX

cav177400:	177400
cav377:		377
cvMCLdHi:	BCLdHi+BHoldInt+BInt
cvMCLdLo:	BCLdLo+BHoldInt+BInt
lvMDATAtab:	MDATAtab
lvMADDRtab:	MADDRtab

ConMDATA:
	lda 3 @lvMDATAtab
ConXt3:	add 3 0		; AVec!1 * 3 + disp
	add 1 1
	jmp ConXt0

ConMADDR:
	lda 3 @lvMADDRtab
	add 3 0		; MADDRtab+(2*AVec!1)
	jmp ConXt0

ConDH:	lda 3 DHistTab
	jmp ConXt3

ConLDR:	addzl 1 1	; AVec!1 * 4
	lda 0 LDRMEM
ConXt0:	add 1 0
	sta 0 MADDRL
	jmp ConXtX

ConVH:	lda 3 cv17
	and 1 3
	sta 3 MADDRL	; Shift count so that DMuxTab!I rshift MADDRL
	cycle 13	; right-justifies the bit
	movl 0 0 snc	; Skip if in word 1
	mkone 0 0 skp
	mkzero 0 0
	sta 0 MADDRH	; 0 for addresses 16 to 31, 1 for 0 to 15
ConXtX:	lda 0 5 2
	jsr @Return

ConRM:	lda 3 cv17
	and 1 3
	sta 3 MADDRL	; MADDRL ← RSTK value
	lda 3 cv360
	and 3 0
	cycle 14
	mov 0 1
	lda 0 cLRB0
	jsr @XctLFF	; XctLFF(LRB0,(orig. MADDRL rshift 4) & 17B)
	 2
	jmp ConXtX

ConM1R:	mkminusone 0 0
	jsr @Return

ConSTKX:
	lda 0 @lvSaveSTKP
	lda 3 cav77
	and 0 3		; Only 100 words of STK accessible at-a-time
	sub 1 0		; 0/ address if ok
	sub 1 3		; negative if off end of stack
	movl# 3 3 szc
	jmp ConM1R	; return -1 (an illegal MemX) if off end
ConSTK:	jsr @XctL16Q
	 1
	lda 0 cSTKPFQ
	jsr @AXct
	mkzero 0 0
ConST:	jsr @SelectTask
	 1
	sta 0 OldTask
	jmp ConXtX

cSTKPFQ:	STKPFQ
cLRB0:		LRB0
cv360:		360
lvSaveSTKP:	SaveSTKP
cav77:		77
cv17:		17
cLMBSX0:	LMBSX0

; Midas uses task 17 for everything because ASRN changes, so only
; tasks 0 and 17 are feasible, and smashing the pipe state of task 17
; is less frequently harmful.
ConBRX:	jsr SelT17SRN1
	lda 0 cLMBSX0
	jmp ConBX1	; XctLFF(LMBSX0,MADDRL)

ConBR:	jsr SelT17SRN1
	lda 0 cLMB0
ConBX1:	lda 1 MADDRL
	jsr @XctLFF	; XctLFF(LMB0,MADDRL)
	 2
	lda 0 McrBR
	jsr @XctL16T	; XctL16T(DisHold+DisCF+NoWake)
	 1
	lda 0 cMCRFT	; Xct(MCRFT)
	jmp ConXX

ConCACHEA:	; 0,1/ 2-bit column..n-bit row, n = 6 (4k) or 10 (16k)
	lda 1 6 2	; CACHEA length
	neg 1 1
	com 1 1		; CACHEA length-1
	movzr 1 3
	movzr 3 3	; 3/ word mask
	sub 3 1		; 1/ column mask
	and 0 3		; 3/ word (row) bits
	and 1 0
	lda 1 @lvAColumnShift	; 5 (4k) or 3 (16k)
	cycle 0
	sta 0 MADDRL	; MADDRL/ 2-bit col in pos for UseMcrV
	mov 3 0
	cycle 4		; Position address bits to address a munch (= row)
	sta 0 MADDRH
	jsr SelT17SRN1
	jmp ConXit

ConCACHED:	; 0,1/ 2-bit column..n-bit row..4-bit word
	lda 1 6 2	; CACHED length
	neg 1 1
	com 1 1		; length-1
	movzr 1 3
	movzr 3 3	; 3/ word mask
	sub 3 1		; 1/ column mask
	and 0 3
	sta 3 MADDRH	; MADDRH/ word bits = row..word-in-munch
	and 1 0		; for Fetch/Store
	lda 1 @lvDColumnShift	; 1 (4k) or 17 (16k)
	cycle 0
	sta 0 MADDRL
	jsr SelT17SRN1
	lda 0 lvMADDRH	; DVec of MADDRH and MADDRL
	jsrii lvRdCACHEA
	 1
	lda 3 McrCD0	; NoWake+DisHold
; **Used to use just Vacant for CACHED reads, Vacant+WP for writes
	lda 1 FlagsCD0	; Vacant+WP
	and# 1 0 szr
	lda 3 McrCD1	; NoWake+DisCF+DisHold
	mov 3 0
	jmp ConCD0	; Rest of setup same as VM

; Left-shift the Map address by log2pgsize; then rest of setup is
; identical to VM references.
ConMAP:	lda 3 @lvlog2pgsize
	neg 3 3
	lda 1 MADDRH
	movzl 0 0	; left-shift low part of address
	movl 1 1	; left-shift high part
	inc 3 3 szr
	jmp .-3
	sta 1 MADDRH
	sta 0 MADDRL
ConVM:	jsr SelT17SRN1	; OldTask = SelectTask(17)
			; ProcSRN←1, MemBase←36, Save BR 36 if necessary
	lda 0 McrVM
ConCD0:	jsr @XctL16T	; T←NoWake
	 1
	lda 0 cMCRFT
	jsr @AXct
	lda 0 MADDRH
	jsr @XctL16T	; T←MADDRH
	 1
	lda 0 cvBRHIFT
	jsr @AXct	; BRHI←T
	lda 0 MADDRL
	jsr @XctL16T	; T←MADDRL
	 1
	lda 0 cvBRLOFT	; BRLO←T
	jsr @AXct
	mkzero 0 0
	jsr @XctL16T	; T←0
	 1
	mkzero 0 0	; Noop
ConXX:	jsr @AXct
ConXit:	lda 0 5 2	; resultis MemX
	jsr @Return

ConSRN:	jsr @XctL16T
	 1
	lda 0 cSRNFT
	jmp ConXX	; Xct(SRNFT)

cvBRLOFT:	BRLOFT
cvBRHIFT:	BRHIFT
cBRKINSFQ:	BRKINSFQ
cMCRFT:		MCRFT
cSRNFT:		SRNFT
cLMB0:		LMB0
cISEVFQ:	ISEVFQ
cIFRES:		IFRES
cv40000:	40000
cv36:		36
cv177400:	177400
cv100000:	100000
McrCD1:
McrBR:		DisHold+DisCF+NoWake
McrVM:		NoWake
lvAColumnShift:	AColumnShift
lvDColumnShift:	DColumnShift
lvlog2pgsize:	log2pgsize
lvMADDRH:	MADDRH
lvRdCACHEA:	RdCACHEA
McrCD0:		NoWake+DisHold
FlagsCD0:	Cvacant+Cwp
cav17:		17

SelT17SRN1:
	sta 3 6 2
	lda 0 cav17
	jsr @SelectTask
	 1
	sta 0 OldTask
	mkone 0 0
	jsr @XctL16T	; T←1
	 1
	lda 0 cSRNFT
	jsr @AXct	; ProcSRN←T
; BR 36, used for memory system access, is saved the first time a memory
; system word is accessed rather than by ReadAllRegs because a consequence
; of saving BR 36 is that pipe entry 1 is smashed.  This means that
; fault task breakpoints are ok provided that none of CACHEA, VNV, CACHED,
; MAP, or VM is displayed, and other task breakpoints are always ok unless
; they use SRN 1 (which would violate the programming convention).
	lda 1 cv36
	lda 0 cLMB0
	jsr @XctLFF	; MemBase←36S
	 2
	lda 0 @lvBR36Saved
	mov# 0 0 szr	; Skip if haven't saved BR 36 since b.p.
	jmp @6 2	; Done if already saved
	lda 0 @lvBreakTask
	lda 1 cav17
	sub 0 1 szr	; Skip if breakpoint for task 17
	jmp srn1a
	lda 0 CantContinue
	lda 1 cMemDisplayed
	and# 0 1 snr
	add 1 0
	sta 0 CantContinue	; Indicate that "Continue" is illegal
srn1a:	lda 0 McrBR
	jsr @XctL16T	; T←DisHold+DisCF+NoWake
	 1
	lda 0 cMCRFT
	jsr @AXct	; Mcr←T
	mkzero 0 0
	jsr @XctL16T	; T←0
	 1
	lda 0 cDUMMYFT
	jsr @AXct	; DummyRef←T
	mkzero 0 0
	jsr @AXct	; Noop
	lda 1 @lvSaveBR36
	lda 0 cRVAHI
	jsr @XctR16C	; XctR16C(RVAHI,SaveBR36)
	 2
	lda 1 @lvSaveBR36
	inc 1 1
	lda 0 cRVALO
	jsr @XctR16C	; XctR16C(RVALO,SaveBR36+1)
	 2
	mkminusone 0 0
	sta 0 @lvBR36Saved	; Indicate BR 36 saved
	jmp @6 2

cDUMMYFT:	DUMMYFT
cRVAHI:		RVAHI
cRVALO:		RVALO
lvBR36Saved:	BR36Saved
lvSaveBR36:	SaveBR36
lvBreakTask:	BreakTask
cMemDisplayed:	100	; **Should be symbolic but def in mcommon.d
cIFUMdisplayed:	400	; **Should be symbolic but in mcommon.d

; Needed by MGetMemData for ROW to setup for victim/next-victim read.
.SelFltSrn:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs
	jsr SelT17SRN1
	jsr @Return

ConIFUM:
	lda 0 cIFRES
	jsr @AXct	; Xct(IFRES)
	lda 1 MADDRL
	lda 0 cv177400
	and 1 0		; 0/ insset in bits 6:7
	lda 1 cv100000
	add 1 0		; 100000+(insset lshift 8)
	jsr @XctL16Q	; XctL16Q((MADDRL & 1400B)+100000B)
	 2
	lda 0 cISEVFQ
	jsr @AXct	; Xct(ISEVFQ)
	lda 0 CantContinue
	lda 1 cIFUMdisplayed
	and# 0 1 snr
	add 1 0
	sta 0 CantContinue
	lda 0 MADDRL
	movs 0 0
	jsr @XctL16Q	; XctL16Q(MADDRL lshift 8)
	 1
	lda 0 cBRKINSFQ
	jsr @AXct	; Xct(BRKINSFQ)
	mkzero 0 0
	jmp ConXX	; Xct(NOOP) and return

; Have to make BNPC have 0 during the test.  To do this, arrange for
; PEnc eq #17 and TPC[#17] eq 0.  Do Notify[#17] with Freeze off to get
; Ready.15 true.  For restore, must reload task 17's TPC and do ClrReady.
ConIMBD:
	mkzero 0 0
	jsr @SelectTask
	 1
	sta 0 OldTask	; OldTask = SelectTask(0)
	lda 1 cav17
	lda 0 cvRTPC
	jsr @XctL16C	; ReadTPC←17
	 2
	lda 1 lvOldTPC
	lda 0 cvRLINK
	jsr @XctR16Link	; Save old TPC[17] for restore
	 2
	mkzero 1 1
	lda 0 cvLLINK
	jsr @XctL16C	; Link←0 (value for TPC[17])
	 2
	lda 1 cav17
	lda 0 cvLTPC
	jsr @XctL16C	; LoadTPC←17 (loads 0 into TPC 17)
	 2
	mkzero 0 0
	jsr @AXct	; Noop
	lda 0 cWAKE17
	lda 1 LDRMEM
	add 1 0
	jsr .LoadMIR	; LoadMIR(WAKE17)
	 1
	lda 0 sControlSS
	DStrobe		; Single-step with Freeze off
	lda 0 cvRLINK
	mkminusone 1 1
	jsr @XctL16	; XctL16(RLINK,-1) puts 0 on BMux for write
	 2
	lda 0 MADDRL
	lda 1 cv77
	and 1 0
	lda 1 cvIMAddr1
	add 1 0
	jsrii lvLoadDMD	; LoadDMD(IMAddr1+(MADDRL & #77))
	 1
	lda 0 MADDRL
	cycle 12
	lda 1 cv77
	and 1 0
	lda 1 cvIMAddr0
	add 1 0
	jsrii lvLoadDMD	; LoadDMD(IMAddr0+((MADDRL rshift 6) & #77))
	 1
	lda 0 MADDRL
	cycle 4
	lda 1 cv3
	and 1 0
	lda 1 cvIMAddr2
	add 1 0
	jsrii lvLoadDMD	; LoadDMD(IMAddr2+((MADDRL rshift 12) & 3))
	 1		; (needed after expansions to 16K microstore)
	lda 0 5 2
	jsr @Return	; resultis MemX

cvRTPC:		RTPC
lvOldTPC:	OldTPC
cvRLINK:	RLINK
cvLLINK:	LLINK
cvLTPC:		LTPC
cWAKE17:	WAKE17
cvControl:	Control
lvLoadDMD:	LoadDMD
cv77:		77
cvIMAddr0:	IMAddr0
cvIMAddr1:	IMAddr1
cvIMAddr2:	IMAddr2
cv3:		3

; Subroutine to load MIR, pointer to 4-word MIR vec in 0
.LoadMIR:
	sta 3 1 2
	mov 0 1
	lda 0 sControl
	MIRLoad
; **Check for MIR parity disagreeing with load
;	lda 0 SStopped
;	sta 0 @D1Out
	lda 3 1 2
	jmp 1 3


; Subroutine to load CPReg
.LoadCPReg:
	sta 3 1 2
	movs 0 1
	lda 3 z177400
	and 3 0		; 0←value for CPReg0
	and 3 1		; 1←value for CPReg1
	lda 3 zCPReg1
	add 3 1
	lda 3 sCPReg0
	add 3 0
	DStrobe
	mov 1 0
FStrobe:
	lda 3 1 2
; DoStrobe(Value) does a three step strobing sequence using value
.DoStrobe:
	DStrobe
	jmp 1 3

zCPReg1:	CPReg1
z177400:	177400


; Stop() halts the D1 which must be or have been running
.Stop:	lda 0 sStop
	jmp .DoStrobe

sStop:	Control+SetRun+SetSS

; Procedure returning true if D1 has stopped, else false
.CheckStopped:
	lda 0 SStopped
	sta 0 @D1Out	; Point D1In at ESTAT word containing "Stopped"
	lda 1 CStopped
	lda 0 @D1In
	and 1 0 snr
	 jmp CSret0
; Check again to make sure (suspected flakiness here at one time)
CSyes:	lda 0 SStopped
	sta 0 @D1Out
	lda 0 @D1In
	and 1 0 szr
	 jmp CSret1
	sta 3 1 2
	lda 3 @lvCheckStoppedGlitches
	isz 0 3
	 jmp .+1
	lda 3 1 2
CSret0:	mkzero 0 0 skp	; return 0 if not stopped
CSret1:	mkminusone 0 0	; -1 if stopped
	jmp 1 3

SStopped:	Mir0+InErr2
CStopped:	Stopped
lvCheckStoppedGlitches:	CheckStoppedGlitches

; ContinueProgram(GoVec)
.ContinueProgram:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs
	lda 0 @lvBreakMIR
	jsr .LoadMIR	; Load MIR with break inst, clearing Freeze
	 1
	jmp CGo1

lvBreakMIR:	BreakMIR
sClock:		Clock
sControlSS:	Control+SetRun+SetSS
sControl:	Control
sControlC:	Control+ClrStop
sClockUC:	Clock+UseCPReg+ClrReady
sClockU:	Clock+UseCPReg
cSTARTX:	STARTX

; Start(GoV) sets up to start the microprocessor at a new address.
; GoV!1 is the address
.Start:	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs

	lda 0 sClockUC
	DStrobe		; Turn on UseCPReg (needed for Rep-Go and Rep-SS)
			; Clear Ready flipflops
	lda 0 sClockU
	DStrobe		; Turn off ClrReady
; *Cannot do a SelectTask here for Rep-Go or Rep-SS because finding
; *out the current task by ReadDMux takes too long
	lda 3 4 2
	lda 1 1 3	; GoV!1 = address for start
	lda 0 STLLINK
	jsr @XctL16C	; XctL16C(LLINK,GoV>>Go.Addr)
	 2
; Following code = XctL16C(STARTX,SaveLINK) except that Freeze is
; turned off
	lda 0 cSTARTX
	lda 3 LDRMEM
	add 3 0
	jsr .LoadMIR	; MIR←STARTX instruction, clear Stop and Freeze
	 1
; Note that LINK is loaded with GoV>>Go.Addr while TLINK is not, but don't
; care about TLINK since the branch computation is from LINK.
	lda 0 SaveLINK
	com 0 0
	jsr .LoadCPReg	; CPReg←SaveLINK
	 1
	lda 0 sControlSS
	DStrobe		; SingleStep RETURN, B←RWCPREG with Freeze off
	lda 0 sControl
	DStrobe		; DoStrobe(Control), clearing SetRun first
	lda 0 sControlC
	DStrobe		; DoStrobe(Control+ClrStop), clearing Stop
	lda 0 sControl
	DStrobe		; DoStrobe(Control), clearing ClrStop
CGo1:	lda 0 sClock
	DStrobe		; Turn off UseCPReg
	jsr @Return

sNorm:		Control+Freeze
sCPReg0:	CPReg0
cRTPC:		RTPC
cRLINK:		RLINK
cRT:		RT
cTFPTRS:	TFPTRS
STLLINK:	LLINK
cLTPC:		LTPC
cTFTIOA:	TFTIOA
ST17400:	17400
ST17:		17
STClear:	Control+ClrCT
STJam:		Control+Jam
STGetTLINK:	Clock+UseCPReg+GetTLINK

; SelectTask(Task)
.SelectTask:
	sta 3 1 2
	jsr @GetFrame
	 10
	jsr @StArgs
	lda 0 4 2
	lda 1 SaveTask
	sub# 0 1 snr
	jsr @Return	; if (Task eq SaveTask) then resultis Task
	sta 1 6 2
	sta 0 SaveTask
	lda 1 SaveTPC
	sta 1 5 2
	mkzero 0 0
	jsr @AXct	; Xct(NOOP) to finish t3 and t4 of last instr
	lda 1 SaveTask
	lda 0 cRTPC
	jsr @XctL16C	; XctL16C(RTPC,Task)
	 2
	lda 0 cRLINK
	lda 1 lvSaveTPC
	jsr @XctR16Link	; SaveTPC = XctR16Link(RLINK,lv SaveTPC)
	 2
	lda 0 STLLINK
	lda 1 SaveLINK
	jsr @XctL16C	; XctL16C(LLINK,SaveLINK)
	 2
	mkzero 0 0
	jsr @AXct	; Xct(NOOP)
	lda 0 4 2
	movs 0 3
	cycle 14
	add 3 0
	lda 1 sCPReg0
	add 1 0
	DStrobe		; DoStrobe(CPReg0+(Task lshift 8)+(Task lshift 12))
	lda 0 STClear
	DStrobe		; DoStrobe(Control+ClrCT)
	lda 0 STJam
	DStrobe		; DoStrobe(Control+Jam)
	lda 0 sNorm
	DStrobe		; DoStrobe(Control+Freeze)
	lda 0 STGetTLINK
	DStrobe		; DoStrobe(Clock+UseCPReg+GetTLINK)
	mkzero 0 0
	jsr @AXct	; Xct(NOOP)
	lda 0 cRLINK
	lda 1 lvSaveLINK
	jsr @XctR16Link
	 2
	com 0 0
	sta 0 SaveLINK	; SaveLINK = not XctR16Link(RLINK,lv SaveLINK)
	lda 0 cRT
	lda 1 lvSaveT
; PE here goes undetected and the machinations with reading and writing
; T cause bad parity to be rewritten correctly so that ScanForPE won't
; work.
	jsr @XctR16	; XctR16(RT,lv SaveT)
	 2
	lda 0 cTFPTRS
	jsr @AXct
	lda 0 cRT
	lda 1 lvSaveRBase
	jsr @XctR16
	 2
	lda 1 ST17
	and 0 1
	sta 1 SaveRBase	; SaveRBase = SaveRBase<<Pointers.RBase
	lda 1 ST17400
	ands 0 1
	sta 1 SaveMBase	; SaveMBase = XctR16(RT,lv SaveRBase)<<Pointers.MemBase
	lda 0 cTFTIOA
	jsr @AXct
	lda 0 cRT
	lda 1 lvSaveTIOA
	jsr @XctR16	; SaveTIOA = XctR16(RT,lv SaveTIOA)
	 2
	lda 0 SaveT
	jsr @XctL16T	; XctL16T(SaveT)
	 1
	mkzero 0 0
	jsr @AXct	; Xct(NOOP)
	lda 0 STLLINK
	lda 1 5 2
	jsr @XctL16C	; XctL16C(LLINK,OldTPC)
	 2
; Since we don't need TLINK valid, ok to not do NOOP here
	lda 0 cLTPC
	lda 1 6 2
	jsr @XctL16C	; XctL16C(LTPC,OldTask)
	 2
; **This NOOP may be unnecessary
	mkzero 0 0
	jsr @AXct	; Xct(NOOP)
	lda 0 STLLINK
	lda 1 SaveLINK
	jsr @XctL16C	; XctL16C(LLINK,SaveLINK)
	 2
	mkzero 0 0
	jsr @AXct	; Xct(NOOP)
	lda 0 6 2
	jsr @Return	; resultis OldTask

lvSaveTPC:	SaveTPC
lvSaveLINK:	SaveLINK
lvSaveT:	SaveT
lvSaveRBase:	SaveRBase
lvSaveTIOA:	SaveTIOA

.end