//D0brkp.bcpl	stuff associated with breakpoints
//	Last edited: 2 January 1980

//Normal bp's are indicated in the IM word by MicroD (DVec!3[0:1]);
//Midas will make an ordinary entry in BPtable for instructions assembled
//this way, and also indicate the bp in VM tables so that Dump will
//work correctly without having to scan BPtable before writing each m-i.
//These bp's can be removed by the programmer from Midas singly, but
//the ClrBP action only removes bp's added after the Load.

//When Midas is in control, IM contains the unbreakpointed instructions,
//and bp addresses are remembered in a table.  Just before the
//processor is started, m-i's at bp addresses are read and saved
//in the table, and breakpoint m-i's (BreakPoint, FreezeResult, Goto[.])
//are inserted in their places.

//SS is implemented by planting bp(s) at the successor(s) to the m-i
//being single-stepped.  BP indices are used for this.

//It is illegal to continue if the m-i which contained a bp, or through
//which a SS occurred, contains a LoadPage.


get "mcommon.d"
get "d0.d"
manifest [ get "d0regmem.d" ]

external [
// OS
	Puts

// MASM
	@WssCSS; Wns; PutsCSS

// MSYM
	SearchBlocks

// MMPRGN
	UpdateMPDValues

// MCMD
	ErrorAbort; WnsCSSD; CmdCommentStream; CmdCS1

// D0I0
	BPTable

// D0ASM
	stNotInVM; stNotIMA

// D0GO
	AddBp; PrCCV; BreakAddr

// D0VM
	LookUpAA; LookUpVA; ChangeVMBrkp; @VirtualP

// Defined here
	BreakIML; ClrBp; ShowBP
]

//AVec is 0 to default the break address (to BreakAddr).
//BPflag is true to insert a break, false to remove one
//Called from InsertBreak and RemoveBreak in MBRKP.BCPL.
let BreakIML(AVec,MemX,BPflag,String) be
[	let BPindex = nil
	let T = vec 2
	let AA,VA = nil,nil
	if AVec eq 0 do
	[ MemX,AVec = IMXx,T; AVec!0 = 0; AVec!1 = BreakAddr & #7777
	]
	switchon MemX into
	[
default:	ErrorAbort(stNotIMA)
case IMXx:	AA = AVec!1
		VA = LookUpVA(AA); endcase
case IMx:	VA = AVec!1
		AA = LookUpAA(VA)
		if AA < 0 then ErrorAbort(stNotInVM)
		endcase
	]
	BreakAddr = AA	//So that UnBrk will default address
			//to bp we just inserted (???)
	test BPflag
	ifso		//insert breakpoint
	switchon AddBp(AA) into
	[ case -1: ChangeVMBrkp(VA,true); endcase
	  case 0:  ErrorAbort("BP table full")
	  case 1:  ErrorAbort("Already breakpointed")
	]
	ifnot		//remove breakpoint
	[ //verify instruction is breakpoint and get index
	  BPindex = 0
	  for I = BPmin to BPlen-1 do
	  [ if (BPTable>>BP↑I.Addr eq AA) & (BPTable>>BP↑I.InUse) do
	    [ BPindex = I; BPTable>>BP↑BPindex.w3 = #7777
	      ChangeVMBrkp(VA,false); break
	    ]
	  ]
	  if BPindex eq 0 then ErrorAbort("Instruction not breakpointed")
	]
	WssCSS(String); WssCSS(" break at "); PrCCV((lv AA)-1,IMXx)
	UpdateMPDValues()
]

//Action to clear all the bp's or all added since the load
and ClrBp(All,nil,nil) be
[	let Count,BPVec,VA,AA = 0,vec 22,nil,nil
	for I = BPmin to BPlen-1 do
	[ if BPTable>>BP↑I.InUse & (BPTable>>BP↑I.Added % All) do
	  [ AA = BPTable>>BP↑I.Addr
	    VA = LookUpVA(AA)
	    ChangeVMBrkp(VA,false)
	    BPTable>>BP↑I.w3 = #7777
	    if Count < 11 do	//Report first 7 BP's cleared to user
	    [ BPVec!(Count+Count) = AA; BPVec!(Count+Count+1) = VA
	    ]
	    Count = Count+1
	  ]
	]
	WssCSS("Cleared "); WnsCSSD(Count)
	if Count ge 8 then PutsCSS($.)
	WssCSS(" BP's")
	if Count ne 0 do
	[ PutsCSS($:)
	  let S = CmdCommentStream
	  let AVec = vec 1; AVec!0 = 0
	  for I = 0 to Count-1 do
	  [ if I ge 11 then return
	    test I eq 5
	    ifso S = CmdCS1
	    ifnot Puts(S,$ )
	    AVec!1 = BPVec!(I+I+1)
	    test VirtualP & (AVec!1 ge 0)
	    ifso SearchBlocks(S,IMx,AVec)
	    ifnot
	    [ if VirtualP then Puts(S,$a)
	      Wns(S,BPVec!(I+I),0,8)
	    ]
	  ]
	]
]


//Action to show first 10 bp's added since the load
and ShowBP(nil,nil,nil) be
[	let Count,BPVec,VA,AA = 0,vec 24,nil,nil
	for I = BPmin to BPlen-1 do
	[ if BPTable>>BP↑I.InUse & BPTable>>BP↑I.Added do
	  [ AA = BPTable>>BP↑I.Addr
	    VA = LookUpVA(AA)
	    if Count < 12 do
	    [ BPVec!(Count+Count) = AA; BPVec!(Count+Count+1) = VA
	    ]
	    Count = Count+1
	  ]
	]
	test Count eq 0
	ifso WssCSS("No BP's added since last Load")
	ifnot
	[ WssCSS("BP's at:")
	  let S = CmdCommentStream
	  let AVec = vec 1; AVec!0 = 0
	  for I = 0 to Count-1 do
	  [ if I > 12 then return
	    test I eq 6
	    ifso S = CmdCS1
	    ifnot Puts(S,$*S)
	    AVec!1 = BPVec!(I+I+1)
	    test VirtualP & (AVec!1 ge 0)
	    ifso SearchBlocks(S,IMx,AVec)
	    ifnot
	    [ if VirtualP then Puts(S,$a)
	      Wns(S,BPVec!(I+I),0,8)
	    ]
	  ]
	]
]