HOW TO DO A FORBID() IN BCPL
                         ============================

                          By !LAiRFiGHT! of fLATLiNE

To disable task switching on the Amiga, a normal program written in assembler
would do something like this:

		move.l	4.w,a6		;Get base of exec.library
		jsr	-$84(a6)	;Call the Forbid() function

However, parts of the Amiga operating system (the DOS parts) was, in the 1.x
versions, written in a language called BCPL.  Now let's take a look at how a
Forbid() call was implemented in that language...


		;Some other code here...
		;...

		move.l	#-$84,d1	;Line 1
		moveq	#$20,d0		;Line 2
		move.l	$160(a2),a4	;Line 3
		jsr	(a5)		;Line 4

		;...and continue with no task switching.

                                 Explanation:
                                 ------------

Line 1		move.l	#-$84,d1
		This is an argument to the internal dos function "ExecCall".
		It is the normal function offset in exec.library (see the
		first example). The internal ExecCall function actually
		takes some more arguments. They are:
			d1	offset in exec.library
			d2	what to put in d0
			d3	what to put in d1
			d4	what to put in a0
		and the stack (the internal BCPL stack that lies in a1 and
		goes upwards) may contain values to put into a1 and a2.
		Anyway, Forbid() dosn't take any arguments so only d1 need
		to be set in this example.

Line 2		moveq	#$20,d0
		Wow! It uses moveq! =) Anyway, this means that the internal
		BCPL stack should be increased with $20.

Line 3		move.l	$160(a2),a4
		A2 always points to the internal Global Vector Table. This
		table contains addresses to the various functions to be used.
		The address to ExecCall just happens to be at $160, so fetch
		it and place it in a4...

Line 4		jsr	(a5)
		...and jump to A5!?!?

No it isn't a typo...  it actually calls a5!  This is because a5 points to the
Function Call Routine (*sigh*), which looks like this:

		move.l	(a7)+,a3		;Line 1
		movem.l	a1/a3-a4,-12(a1,d0.l)	;Line 2
		adda.l	d0,a1			;Line 3
		movem.l	d1-d4,(a1)		;Line 4
		jmp	(a4)			;Line 5

                                 Explanation:
                                 ------------

Line 1		move.l	(a7)+,a3
		Get the return address. Ofcourse, a BCPL program would NEVER
		do a normal RTS...

Line 2		movem.l	a1/a3-a4,-12(a1,d0.l)
		As mentioned, a1 is the internal stack pointer, and d0 was set
		to a value to increment the stack pointer with. What this line
		does, is to save the old stack pointer, and the return address
		(in a3) and the function address (in a4) just before the
		new stack, so that it can be easily (?) restored later.

Line 3		adda.l	d0,a1
		Increment the stack pointer.

Line 4		movem.l	d1-d4,(a1)
		Save the arguments to the stack. WHY???

Line 5		jmp	(a4)
		Phew!  FINALLY call the Forbid() function.  Or?  Eh..  wait a
		sec...  oh NO!!!?  This isn't Forbid() - This is the *ExecCall*
		routine which will IN TURN call Forbid()!!!!  AAARGH!

Hmm.. let's take a look at the ExecCall routine then. It couldn't be THAT
bad, could it?

		movem.l	a0-a2/a5-a6,-(a7)	;Line 1
		move.l	d1,d7			;Line 2
		move.l	d2,d0			;Line 3
		move.l	d3,d1			;Line 4
		move.l	d4,a0			;Line 5
		move.l	$14(a1),a2		;Line 6
		move.l	$10(a1),a1		;Line 7
		move.l	4.w,a6			;Line 8
		jsr	0(a6,d7.w)		;Line 9
		movem.l	(a7)+,a0-a2/a5-a6	;Line 10
		move.l	d0,d1			;Line 11
		jmp	(a6)			;Line 12


                                 Explanation:
                                 ------------

Line 1		movem.l	a0-a2/a5-a6,-(a7)
		Hmm.. it uses a7 as a stack pointer?? What a funny idea!!

Line 2		move.l	d1,d7
		This is the offset in exec.library to which we will jsr
		later. Place it in d7.

Line 3		move.l	d2,d0
		BCPL arguments are always passed in d1, d2, d3 and d4, so
		take the second argument and place it in d0 (as exec (and
		other) routines often take their arguments in the low
		registers, such as d0).

Line 4		move.l	d3,d1
		Same thing here...

Line 5		move.l	d4,a0
		...and here... Note that Forbid() doesn't require ANY
		registers to be loaded with ANYTHING...

Line 6		move.l	$14(a1),a2
		If it isn't enough with d1, d2, d3 and d4, let's use the
		stack instead... Offset $14 in the internal stack seems to
		contain the argument to put into a2... Note that if the
		main program in rare circumstances actually wants to SET this
		value to something, it isn't just to move it into $14(a1)...
		It has to be moved into $14(a1,d0.l), where d0 contains the
		value to add to the internal stack (as mentioned).

Line 7		move.l	$10(a1),a1
		Same thing here. This will also destroy a1 as a stack pointer.
		(This is why it was saved on a7... a7 isn't trashed by
		exec functions.)

Line 8		move.l	4.w,a6
		Get the pointer to exec.library.

Line 9		jsr	0(a6,d7.w)
		AT LAST!!!!! A call to Forbid()!!! Ta-daaa!!!!

Line 10		movem.l	(a7)+,a0-a2/a5-a6
		Restore what we preserved earlier...

Line 11		move.l	d0,d1
		Well...  exec.library (along with all the other libraries I
		know of) return their result in d0.  However; BCPL programs
		want their return codes in d1 (why amn't I surprised?) so let's
		just move it...  (NB:  Forbid() doesn't return anything
		useful...)

Line 12		jmp	(a6)
		Ehmm... a6??? But I though we put the return address in a3
		a while ago??? Yup, sure did. In BCPL, a6 points to the
		Return From Function Routine, which looks like this:

		movem.l	-12(a1),a1/a3	;Line 1
		move.l	-4(a1),a4	;Line 2
		jmp	(a3)		;Line 3

                                 Explanation:
                                 ------------

Line 1		movem.l	-12(a1),a1/a3
		Get old stackpointer (before we added d0 to it) back. Also
		restore a3 (the return address).

Line 2		move.l	-4(a1),a4
		Get a4 from the OLD stack. A4 will now contain the value
		it had even before we changed it to contain the pointer to
		ExecCall. (It contained/contains a pointer to the section
		of code currently running...)

Line 3		jmp	(a3)
		...and voilá! Return to the main program again!


   Now we just have to go through the same thing again, to do a Permit()...



.-----------------------------------------------------------------------------.
|                   Thanks to Maxwold for the disassembly!                    |
|                                See you all!                                 |
|                           !LAiRFiGHT! of fLATLiNE                           |
`-----------------------------------------------------------------------------'

Note: They HAVE changed it in V36... =)