// MDcheck.bcpl -- check the results of MicroD
// last edited November 29, 1979  5:12 PM

	get "mddecl.d"

external	// defined here
[	Check	// ()
]

external	// used
[		// OS
	Zero
	@oneBits
		// MDmain
	@IP
	@DMachine
	@IM; @NInstructions
		// MDerr
	Err
	PutAddrData
		// MDprescan
	@PageSize; @PageMask
	@globalZero
	@calledMask; @goedtoMask; @jbctMask
	@callerMask; @slowJump; @jbcSubpage
]


let Check() be
// Check all addressability constraints
[	Err(PassMessage, "Checking assignment...")
	let bt = vec IMsize/16
	Zero(bt, IMsize/16)
	let jbcSame = (jbcSubpage? IMsize-20B, PageMask)
	for i = 0 to NInstructions-1 do
	[ let ip = IP(i)
	  let a0 = ip>>IM.W0
	  let bitp, bitm = bt+(a0 rshift 4), oneBits!(a0&17B)
	  test (@bitp & bitm) ne 0
	   ifso	// Find the other location with the same assigned address
	  [ let j = i
	    [ j = j-1 ] repeatuntil IP(j)>>IM.W0 eq a0
	    Err(PassFatal, "******$P, $P....duplicate assignment", PutAddrData, j, PutAddrData, i)
	  ]
	   ifnot @bitp = @bitp + bitm
	  if (ip>>IM.global ne 0) & ((a0&globalZero) ne 0) then
	    Err(PassFatal, "******$P....bad assignment for global", PutAddrData, i)
	  let i1 = ip>>IM.W1
	  if i1 eq WExt loop
	  let ip1 = IP(i1)
	  let a1 = ip1>>IM.W0
	  let a1bit = oneBits!(a1&17B)
	  if (ip>>IM.iscond ne 0) & (ip>>IM.returns eq 0) then
	  [ let i2 = ip>>IM.W2
	    let a2 = IP(i2)>>IM.W0
	    if ((a1&1) ne 0) % (a2 ne a1+1) %
	     ((DMachine ne 0) & (ip>>IM.jbc ne 0) &
	      (((a1bit&jbctMask) eq 0) % ((a1&jbcSame) ne (a0&jbcSame)))) then
	      Err(PassFatal, "******$P -> $P, $P....bad assignment for conditional", PutAddrData, i, PutAddrData, i1, PutAddrData, i2)
	  ]
	  test DMachine eq 0
	  ifso
	  [ if ip>>IM.returns loop
	    if callerMask ne -1 then
	     test ip>>IM.calls
	      ifso if (a0&1) ne 0 then
	        Err(PassFatal, "******$P....does a CALL but at odd address", PutAddrData, i)
	      ifnot
	     if ip>>IM.oddcall then
	      if (a0&1) eq 0 then
	        Err(PassFatal, "******$P....does a RCALL but at even address", PutAddrData, i)
	    if ip1>>IM.returns loop
	    let i3 = (slowJump? ip1>>IM.W1, i1)
	    let ip3 = IP(i3)
	    if (ip3>>IM.W0/PageSize) ne (ip>>IM.swpage? ip>>IM.newpage, a1/PageSize) then
	      Err(PassFatal, (slowJump? "******$P....(-> $P) -> $P which is on wrong page", "******$P....-> $P which is on wrong page"), PutAddrData, i, PutAddrData, i1, PutAddrData, i3)
	  ]
	  ifnot
	  [ if ((ip>>IM.goes ne 0) & ((a1bit&goedtoMask) eq 0)) %
	     ((ip>>IM.calls ne 0) & (ip>>IM.returns eq 0) & ((a1bit&calledMask) eq 0)) then
	      Err(PassFatal, "******$P -> $P....bad assignment for GOTO or CALL", PutAddrData, i, PutAddrData, i1)
	    if (ip>>IM.usesFN eq 0) % (ip>>IM.returns ne 0) then
	      loop	// no constraint on successor
	    if ((a1&PageMask) ne (a0&PageMask)) & ((a1&globalZero) ne 0) then
	      Err(PassFatal, "******$P -> $P....bad assignment -- can't get there", PutAddrData, i, PutAddrData, i1)
	  ]
	]
]