;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;
;	D O R A D O   C o n t r o l   P r o g r a m
;
;		M i d a s   I n t e r f a c e
;
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

;	filed on DoradoMidasInt.masm
;	E. McCreight
;	last modified September 28, 1982  10:16 AM

	.EXPORT	MidasCall,MidasSetup,TrapEncountered
	.EXPORT	InhibitMidas,EnableMidas,MidasReturnPoint
	.EXPORT	MidasInhibitDepth

	.IMPORT	PacifyWatchdog,PacifyWatchdogIfJumper
	.IMPORT	ZPtr
	.IMPORT	ZPC,ZS,ZP,ZA,ZX,ZY
	.IMPORT	ZSubPC,ZSubS,ZSubP,ZSubA,ZSubX,ZSubY
	.IMPORT	ZSimBlk

	.SHORT	ZPtr
	.SHORT	ZPC,ZS,ZP,ZA,ZX,ZY
	.SHORT	ZSubPC,ZSubS,ZSubP,ZSubA,ZSubX,ZSubY
	.SHORT	ZSimBlk


	.PREDEFINE "MCS6502PREDEFS.SR"
	.GETNOLIST	"DoradoIO.mdefs"


;			V a r i a b l e s

	.LOC	MidasData
	.SHORT	MidasData

;	Midas need not know where this stuff is, because it's
;	only used by the microcomputer.

MidasInhibitDepth:	.BLK	1	; =0 if Midas is enabled
MidasWantsYou:	.BLK	1	; =0 if Midas doesn't want service
MidasSubrDepth: .BLK	1	; >0 if within Midas subr call
; CPIBus[Trap'] = 0 if trap loop wants Midas' help

NumberOfTraps = 8
TrapPoints:	.BLK	3*NumberOfTraps	; 8 software breakpoints
RestartTrap:	.BLK	1	; index of restart point, if any. -1 if none.

;		M i d a s   I n t e r f a c e

	.LOC	0fffa	; Non-maskable interrupt location
	.ADR	MidasCall


	.LOC	MidasCode

;	Control gets here on a Midas-generated non-maskable interrupt

MidasCall:
	CLD
	PHA

	LDA	MidasInhibitDepth
	BEQ	OKForMidas
	LDAI	0ff
	STA	MidasWantsYou
	PLA
	RTI

OKForMidas:
	INC	MidasInhibitDepth
	CLI	; allow timer interrupts
MidasAlreadyInhibited:
	PLA
	STA	ZA	; Unload state to memory
	STX	ZX
	STY	ZY

StoreInterruptState:
	PLA
	STA	ZP
	PLA
	STA	ZPC	; low-order ZPC byte
	PLA
	STA	ZPC+1	; high-order ZPC byte
	TSX
	STX	ZS

	LDAI	WaitingForMidas,#LowAddrByte
	CMP	ZPC
	BNE	NoTrap
	LDAI	WaitingForMidas,#HighAddrByte
	CMP	ZPC+1
	BEQ	StoreInterruptState	; interrupted at trap jump, recover
				; original state

NoTrap:
	LDXI	AllOutput	; make sure Midas DDR's are right
	STX	DAC+DDR	; set data direction registers for output
	INX
	STX	CPRegH+DDR	; set data direction registers for input
	STX	CPRegL+DDR
	LDXI	CPIBusDDRValue
	STX	CPIBus+DDR	; mixed I/O register

	JSR	RemoveTraps

MidasWaitForSync:
	LDAI	0
	STA	MidasWantsYou

MidasNoSyncYet:
	LDA	CPRegH		; wait until AMSync ne MASync
	EOR	CPIBus
	BPL	MidasNoSyncYet

	LDA	CPRegH
	ANDI	MidasCommand
	TAX
	LDA	CPRegL

	DEX
	BMI	MidasCommandDone	; CPReg[5-7] = 0 (no-op)
	BEQ	MidasLdHiAd	; = 1
	DEX
	BEQ	MidasLdLoAd	; = 2
	DEX
	BEQ	MidasLdLoAdFetch	; = 3
	DEX
	BEQ	MidasFetchInc	; = 4
	DEX
	BEQ	MidasStoreInc	; = 5
	DEX
	BEQ	MidasMisc	; = 6

MidasCommandDone:
	LDA	CPRegH
	TAX
	LDAI	MASync	; invert MASync so MASync = AMSync
	EOR	CPIBus
	STA	CPIBus

	TXA
	ANDI	HoldMC	; See if Midas wants to hold us in the break
	BEQ	MidasNoHold

WaitForNextInterrupt:
	JSR	PacifyWatchdog
	LDA	MidasWantsYou
	BEQ	WaitForNextInterrupt
	BNE	MidasWaitForSync

MidasNoHold:
	JSR	InsertTraps
	LDX	ZS
	TXS
	LDA	ZPC+1	; high order ZPC byte
	PHA
	LDA	ZPC	; low-order ZPC byte
	PHA
	LDA	ZP
	PHA
	LDY	ZY
	LDX	ZX

	LDA	ZA
	PHA
	LDA	MidasWantsYou	; an interrupt between here &
;		RTI might be screwed up.

	BEQ	NoApparentCalls

MidasWantedUs:
	JMP	MidasAlreadyInhibited

NoApparentCalls:
	PLA
	DEC	MidasInhibitDepth
	RTI

;	Midas-Invoked Routines


MidasLdHiAd:
	STA	ZPtr+1
	JMP	MidasCommandDone


MidasLdLoAd:
	STA	ZPtr
	JMP	MidasCommandDone


MidasLdLoAdFetch:
	STA	ZPtr
	LDYI	0
	LDA@Y	ZPtr
	STA	MAByte
	JMP	MidasCommandDone


MidasFetchInc:
	LDYI	0
	LDA@Y	ZPtr
	STA	MAByte
	JMP	MidasIncAd


MidasStoreInc:
	LDYI	0
	STA@Y	ZPtr


MidasIncAd:
	INC	ZPtr
	BNE	MidasCommandDone
	INC	ZPtr+1

MidasNop:
	JMP	MidasCommandDone


MidasMisc:
	TAX
	BEQ	MidasCommandDone	; CPReg[8-15] = 0
	DEX
	BEQ	MidasCallSubroutine	; = 1
	DEX
	BEQ	MidasResumeSubroutine	; = 2
	BNE	MidasNop	; > 2

;	Code to call a subroutine from the Midas code. The
;	subroutine is assumed to start at location ZSubPC, and the
;	S, P, A, X, and Y registers are loaded from ZSubS, ZSubP, ZSubA,
;	ZSubX, and ZSubY before starting. The same storage locations are
;	re-loaded from their respective registers upon completion or
;	trap.

MidasCallSubroutine:
	TSX	; calculate a safe subroutine stack
	TXA
	SEC
	SBCI	40
	TAX
	TXS	; move to new stack
	JSR	MidasDoCall

BreakInsideMidas:
	BRK	; this traps a "proceed" after a RTS

MidasDoCall:
	JSR	MidasReallyDoCall

MidasReturnPoint:
	PHP

MidasTrapReturn:
	INC	MidasInhibitDepth
	DEC	MidasSubrDepth
	STA	ZSubA
	PLA
	STA	ZSubP

	CLD	; add 1 to recovered PC to fix JSR addresses
	CLC
	PLA
	ADCI	1
	STA	ZSubPC
	PLA
	ADCI	0
	STA	ZSubPC+1

	STX	ZSubX
	STY	ZSubY
	TSX
	STX	ZSubS	; save subroutine stack
	LDX	ZS
	TXS	; recover old stack
	JMP	MidasCommandDone


MidasResumeSubroutine:
	LDX	ZSubS	; resume old subroutine stack
	TXS

MidasReallyDoCall:
	LDA	ZSubPC+1
	PHA
	LDA	ZSubPC
	PHA
	LDA	ZSubP
	PHA
	LDY	ZSubY
	LDX	ZSubX
	LDA	ZSubA
	DEC	MidasInhibitDepth
	INC	MidasSubrDepth
	RTI


;	Code called from maskable interrupt when a trap due
;	to a BRK instruction (00x)
;	is discovered. Stack has 0: X, 1: A, 2: P, 3: PCLow, 4: PCHigh.

TrapEncountered:
	JSR	InhibitMidas

	LDAI	-2
	LDX	MidasSubrDepth
	BEQ	ExternalTrap
	LDAI	-3

ExternalTrap:
	CLD
	CLC
	TSX	; back the PC up to before the trap
	ADCX	StackTop+3
	STAX	StackTop+3
	LDAX	StackTop+4
	SBCI	0
	STAX	StackTop+4

	PLA
	TAX

	LDA	MidasSubrDepth
	BEQ	ExternalTrap2

	PLA
	JMP	MidasTrapReturn

ExternalTrap2:
	LDAI	0ff-Trap'	; notify Midas of trap
	AND	CPIBus
	STA	CPIBus

	PLA
	JSR	EnableMidas

WaitingForMidas:
	JSR	PacifyWatchdogIfJumper
		; only pacify watchdog timer if debugging jumper is installed
	JMP	WaitingForMidas	; wait until Midas notices

;	Midas Instruction Simulation

;		Conditional branches are of the form xxx1 0000
;		One-byte instructions are of the form xxxx 10x0
;		Three-byte instructions are of the form xxxx 11xx
;		Two-byte instructions are of the form xxxx 0xxx, except:
;			BRK (trap) is 00
;			JSR is 20
;			RTI is 40
;			RTS is 60

MidasBuildSimulation:
	LDX	RestartTrap
	BPL	SimulationNeeded

	LDXI	03a	; opcode for NOP
	LDYI	2
	STX	ZSimBlk	; NOP in first byte
	BNE	OneByter

SimulationNeeded:
	LDAX	TrapPoints+2
	STA	ZSimBlk
	LDYI	2

CopyMoreParameters:
	LDA@Y	ZSubPC
	STAY	ZSimBlk
	DEY
	BNE	CopyMoreParameters

	LDXI	0ea	; opcode for NOP
	LDYI	3	; instruction length
	LDA	ZSimBlk
	CMPI	20
	BEQ	ThreeByter	; JSR is 3 bytes long
	ANDI	8
	BEQ	TwoByter
	LDA	ZSimBlk
	ANDI	5
	BNE	ThreeByter

OneByter:
	DEY
	STX	ZSimBlk+1	; NOP in second byte

TwoByter:
	DEY
	STX	ZSimBlk+2	; NOP in third byte

ThreeByter:	; compute address of successor instruction
	TYA	; length of instruction
	CLC
	ADC	ZSubPC
	STA	ZSimBlk+4
	LDA	ZSubPC+1
	ADCI	0
	STA	ZSimBlk+5

	LDA	ZSimBlk+1	; compute PC-relative branch address
	CLC
	ADC	ZSimBlk+4
	STA	ZSimBlk+7
	LDA	ZSimBlk+1
	ANDI	80
	BPL	HOPCOffsetInA
	LDAI	-1

HOPCOffsetInA:
	ADC	ZSimBlk+5
	STA	ZSimBlk+8

	LDAI	04c	; opcode for absolute jump
	STA	ZSimBlk+3	; JMP to successor
	STA	ZSimBlk+6	; JMP if PC-relative branch taken

	LDA	ZSimBlk
	ANDI	1f
	CMPI	10
	BNE	NotConditionalBranch

	LDAI	3
	STA	ZSimBlk+1	; change conditional branch target to .+6

NotConditionalBranch:
	RTS



MidasStartSimulation:
	LDA	ZSimBlk
	CMPI	20	; JSR
	BNE	NoJSRSimulation

	LDA	ZSimBlk+5	; a JSR leaves NextPC-1 on the stack
	PHA
	LDA	ZSubPC+4
	PHA

	TSX
	LDAX	StackTop
	DECX	StackTop
	TAY
	BNE	SubPCDecremented
	DECX	StackTop+1

SubPCDecremented:
	LDAI	04c	; JMP
	STA	ZSimBlk

NoJSRSimulation:
	LDA	ZSubP
	PHA
	LDY	ZSubY
	LDX	ZSubX
	LDA	ZSubA
	DEC	MidasInhibitDepth
	INC	MidasSubrDepth
	PLP
	JMP	ZSimBlk

;	Instruction trap insertion/removal

RemoveTraps:
	LDAI	Trap'	; no longer trapped, trap state can be inferred
	ORA	CPIBus	;		from ZP
	STA	CPIBus

	LDXI	3*(NumberOfTraps-1)	; un-trap all the breakpoints

RemoveNextTrap:
	LDAI	0ff
	CMPX	TrapPoints
	BNE	RemoveFormerTrap
	CMPX	TrapPoints+1
	BEQ	TryRemovingNextTrap

RemoveFormerTrap:
	LDAX@	TrapPoints
	BEQ	RemoveRealTrap	; trap still there

	LDAI	0ff	; remove it from the trap list (should also complain)
	STAX	TrapPoints
	STAX	TrapPoints+1
	BNE	TryRemovingNextTrap

RemoveRealTrap:
	LDAX	TrapPoints+2	; opcode that should be there
	STAX@	TrapPoints

TryRemovingNextTrap:
	DEX
	DEX
	DEX
	BPL	RemoveNextTrap
	RTS


InsertTraps:
	LDAI	-1
	STA	RestartTrap

	LDXI	3*(NumberOfTraps-1)	; trap all the breakpoints

InsertNextTrap:
	LDAI	0ff
	CMPX	TrapPoints
	BNE	InsertRealTrap
	CMPX	TrapPoints+1
	BEQ	TryInsertingNextTrap

InsertRealTrap:
	LDA	ZSubPC
	CMPX	TrapPoints
	BNE	NotRestartAddr
	LDA	ZSubPC+1
	CMPX	TrapPoints+1
	BNE	NotRestartAddr
	STX	RestartTrap

NotRestartAddr:
	LDAX@	TrapPoints
	STAX	TrapPoints+2	; opcode that should be there
	LDAI	0	; BRK opcode
	STAX@	TrapPoints

TryInsertingNextTrap:
	DEX
	DEX
	DEX
	BPL	InsertNextTrap
	RTS



;	Midas User-Callable Utilities

MidasSetup:
	LDAI	Trap'	; we are running live code, not the trap loop
	ORA	CPIBus
	STA	CPIBus

	LDXI	17
	LDAI	0ff

InvalidateMoreTrapPoints:
	STAX	TrapPoints
	DEX
	BPL	InvalidateMoreTrapPoints

	LDAI	0
	STA	MidasWantsYou	; no Midas interrupts yet
	STA	MidasInhibitDepth	; but we'll accept them
	STA	MidasSubrDepth	; we're in the main code routine
	RTS


InhibitMidas:	; must save all processor state
	PHP
	INC	MidasInhibitDepth
	PLP
	RTS


EnableMidas:	; must save all processor state
	PHP
	PHA
	LDAI	1
	CMP	MidasInhibitDepth
	BNE	DropALevel	; not really enabling, just dropping a level

;	*** 	July 23, 1980  6:53 PM  When Midas takes/gives control
;	of the CPBus from/to the microcomputer by changing the value
;	of AHasCP, there is a race that clips the strobe and
;	simultaneously changes the CPBus data source. The following
;	code guarantees that if Midas obeys the standard "politeness"
;	convention, the clipped strobe will do no damage to the
;	control section because the MCP address and data are benign.
	LDAI	0
	STA	MCPBusH
	LDAI	Clock
	STA	MCPBusL

	DEC	MidasInhibitDepth
	LDA	MidasWantsYou
	BNE	SimulateMidasInterrupt
	BEQ	EnableExitP	; (unconditional)

DropALevel:
	DEC	MidasInhibitDepth

EnableExitP:
	PLA
	PLP
	RTS


SimulateMidasInterrupt:
	SEI
	TXA
	PHA
	TSX
	CLC
	CLD
	LDAX	StackTop+3	; add 1 to the stacked ZPC, so it looks
	ADCI	1	; like an interrupt
	STAX	StackTop+3
	LDAX	StackTop+4
	ADCI	0
	STAX	StackTop+4

	PLA
	TAX
	PLA
	JMP	MidasCall

	.END