[comp.sys.mac.programmer] Surviving a Bus Error

louis@asterix.drev.dnd.ca (Louis Demers) (03/14/90)

Hi,

Background:
	We are developing a piece of lab equipment which is controlled by
	a Macintosh  II.  We developed our own controllers which will be
	interfaced to the mac using GreenSpring IO card and some custom
	Industry Pack.  The control registers can be configured at
	different addresses.

Problems:
	When we access one of the registers and the controllers is not
	turned on, we crash with a bus errors.  We suffer the same faith
	when we access the registers at the wrong address.

Wish:
	I wish I could try to access an address and if the controller
	were turned off or not at this particular address, I would like to
	tell the user to check the power to the card or the address
	configuration.  This could take the form of a subroutine with
	could be declared like this:
			int TryIT(Ptr memoryAddress,long *value)
	the return value could indicate if the access was successful and
	the parameter value could returned the actual value read.

Question:
	Anybody has suggestions or better yet, code to do this ?
	Can it be done only in C ? I work with MPW 3.0 C and C++.
	( I hate assembler but I feel like this time I won't be able to
	avoid it &-)
	
	Thanks in advance,
		Louis

-- 
| Louis Demers              | DREV, Defence Research Establishment,Valcartier |
| louis@asterix.drev.dnd.ca | POBox 8800, Courcelette,Quebec, CANADA, G0A 1R0 |
|            (131.132.48.2) | Office: (418) 844-4424       fax (418) 844-4511 |
+---------------------------+-------------------------------------------------+

ts@cup.portal.com (Tim W Smith) (03/18/90)

Try something like this:

	long saveBusErrorVector;

	if ( setjmp( something ) )
	{
		*(long *)8 = saveBusErrorVector;
		return GOT_A_BUS_ERROR;
	}
	saveBusErrorVector = *(long *)8;
	*(long *)8 = MyBusErrorHandler();

	/* access your board */

	*(long *)8 = saveBusErrorVector;
	return DID_NOT_GET_A_BUS_ERROR;

The function MyBusErrorHandler would look something like this:

	SetupA5();		/* or whatever your development
				 * system uses */
	longjmp( something );

Check the Motorola manual to see what bus error does to the interrupt
level.  I would guess that it is treated like a level 7 interrupt, and
thus sets the interupt level to 7.  If so, you will have to do something
about this.  This will require assembly language.

					Tim Smith

ps: when I say "this will require assembly language", I am assuming
we are all gentle people who would not even think of casting a string
pointer to a function pointer and calling it, or any other such things
best not mentioned in polite company...

ting@mergsun.UUCP (Steve Ting) (03/20/90)

From article <1990Mar13.192544.1617@asterix.drev.dnd.ca>, by louis@asterix.drev.dnd.ca (Louis Demers):
> Hi,
> 
> Background:
> 	We are developing a piece of lab equipment which is controlled by
> 	a Macintosh  II.  We developed our own controllers which will be
> 	interfaced to the mac using GreenSpring IO card and some custom
> 	Industry Pack.  The control registers can be configured at
> 	different addresses.
> 
> Problems:
> 	When we access one of the registers and the controllers is not
> 	turned on, we crash with a bus errors.  We suffer the same faith
> 	when we access the registers at the wrong address.
> 
> Wish:
> 	I wish I could try to access an address and if the controller
> 	were turned off or not at this particular address, I would like to
> 	tell the user to check the power to the card or the address
> 	configuration.  This could take the form of a subroutine with
> 	could be declared like this:
> 			int TryIT(Ptr memoryAddress,long *value)
> 	the return value could indicate if the access was successful and
> 	the parameter value could returned the actual value read.
> 
> Question:
> 	Anybody has suggestions or better yet, code to do this ?
> 	Can it be done only in C ? I work with MPW 3.0 C and C++.
> 	( I hate assembler but I feel like this time I won't be able to
> 	avoid it &-)
> 	
> 	Thanks in advance,
> 		Louis
>;
Louis,
You need to find your controller's base address first, before you can
access it's registers.  Normally, you have a configuration rom on your
board with a ID number to identify it. Using the following, if
GetSlotBase returns 0, then your software should not try to access the
board.

sID		EQU	your_ID
------------------------------------------------------------------------------
; GetSlotBase
; 
; returns slotBase in D0, clear D0 if no card found
GetSlotBase	PROC
StackFrame	RECORD	{A6Link}
LocalSpBlock		DS	SpBlock
LocalSInfoRecord	DS	SInfoRecord
LocalSize	EQU	LocalSpBlock - *
A6Link		DS.L	1
Return		DS.L	1
		ENDR

	WITH	StackFrame,LocalSpBlock
	Link	A6,#LocalSize
	MOVEM.L	A0/A1/A4/D1/D2,-(SP)

	MOVEQ	#BeginSlot,D2				;;check slots in
reverse order (EI9)
nxt	CMPI	#EndSlot,D2				;;exhausted all
the slots?
	BGE.S	mor
	CLR.L	D0					; yes: return
nothing in D0
	JMP	Eop
mor	MOVE.B	D2,spSlot(A6)				; no: continue
searching next slot
	LEA	LocalSInfoRecord(A6),A1
	MOVE.L	A1,spResult(A6)
	LEA	LocalSpBlock(A6),A0
	_SReadInfo
	MOVE.B	D2,spSlot(A6)
	CLR.B	spId(A6)
	CLR.B	spExtDev(A6)
	MOVEQ	#1,D1
	MOVE.W	D1,spCategory(A6)
	CLR.W	spCType(A6)
	CLR.W	spDrvrSW(A6)
	CLR.W	spDrvrHW(A6)
	LEA	LocalSpBlock(A6),A0
	_SNextTypesRsrc
	MOVE.B	#32,spId(A6)
	LEA	LocalSpBlock(A6),A0
	_SReadWord
	LEA	spResult(A6),A4
	SUBI.W	#sId,2(A4)
	DBEQ	D2,nxt						; on
exit, D2 <- 0000000s

	MOVE.L	D2,D0						; D0 <-
0000000s
	LSL.W	#4,D0						; D0 <-
000000s0
	OR.B	D2,D0						; D0 <-
000000ss
	OR.W	#$F00,D0					; D0 <-
00000Fss
	LSL.W	#4,D0						; D0 <-
0000Fss0
	SWAP	D0
; D0 <- Fss00000
Eop	MOVEM.L	(SP)+,A0/A1/A4/D1/D2
	UNLK	A6
	RTS
	ENDWITH
; StackFrame,LocalSpBlock
	ENDPROC	;GetSlotBase

Hope this helps,
Steven Ting
Linotype Company