
		;   PARALLEL PORT NETWORK LOW LEVEL ROUTINES
		;
		;   CABLE:  Connect D7-D0,SEL,POUT, and BUSY across,
		;	    Connect ACK to SEL locally:
		;	    Connect GND lines indicated
		;
		;   (2-9)   D7-D0   ------------    D7-D0
		;   (12)    POUT    ------------    POUT
		;   (11)    BUSY    ------------    BUSY       PARALLEL PORT
		;   (13)    SEL     --+------+--    SEL
		;   (10)    ACK     -/        \-    ACK
		;   (18-22) GND     ------------    GND
		;
		;   WARNING: you cannot connect RI on the serial port to your
		;	     modem because it interferes with the parallel
		;	     port's SEL line in this configuration.
		;
		;   *	28K/sec bandwidth
		;   *	# machines depends on extra hardware for buffering,
		;	but 3 ought to work fine without any extra hardware.
		;
		;	(network protocol can now handle 254)
		;
		;   Data Line Definitions:
		;	CIAA PORTB :	D7-D0	used for byte data transfer
		;	CIAB PORTA :	D2-D0	used for line aquisition and
		;				handshaking (SEL,POUT,BUSY)
		;
		;   All lines pulled up.  Thus, asserted state is a 0.	Idle
		;   state is an undriven (1).  Protocol transfers a byte at
		;   a time.  Protocol is ethernet style with a small window
		;   of error in the line aquisition routine.
		;
		;   Note:   Timeouts should be set around a second.  Ideally
		;	    defaults should be fixed on faster machines.
		;
		;   CIAB PORTA	D0  ~ACK    hand shake
		;		D1  ~REQ    hand shake
		;		D2   CTL    1 = special byte, 0 = data byte.
		;			    (for address mark, valid when ~REQ
		;			     goes low.	For EOP mark, sample
		;			     when ~REQ goes high)
		;
		;			    PROTOCOL
		;
		;   HandShake	(Reader <- Writer transfer).  A Handshake
		;	    sequence transfers TWO bytes of information.
		;
		;		WRITER			    READER
		;	|-> place data, ~REQ->0
		;	|				 wait for ~REQ->0
		;	|				 read data & store
		;	|				 set ~ACK->0
		;	|   wait ~ACK->0
		;	|   place data, ~REQ->1
		;	|				 wait for ~REQ->1
		;	|				 read data & store
		;	|				 set ~ACK->1
		;	|   wait ~ACK->1
		;	|<- LOOP  (2 bytes written)      LOOP  (2 bytes read)
		;
		;
		;   Read:   (1) Determine if your machine is being addressed
		;		(~REQ=0, data=myaddress, CTL=1)
		;	    (1) set DDR for ~ACK to output and
		;	    (2) Handshake sequence for the address mark, only
		;		first byte valid.
		;	    (3) Handshake sequence for data util rcv byte
		;		with CTL = 1 (EOP), byte must == 0.
		;	    (4) Set ~ACK (bit 0) to input
		;
		;   Write:  (1) AQUIRE THE NETWORK (see below)
		;		involves gaining control and then setting the
		;		DDR for CTL and ~REQ to outputs.
		;
		;		Also checks if somebody is writing to us,
		;		in which case -2 is returned instantaniously
		;		indicating we should do a ParRead().
		;
		;	    (2) Handshake sequence for address mark, send dest
		;		address (second byte garbage).  Note that CTL->1
		;		*BEFORE* we set ~REQ->0
		;	    (3) Handshake sequence for data bytes
		;	    (4) Handshake sequence for EOP mark (Note that CTL->1
		;		*AFTER* we get the ~ACK->1 and before release
		;		~REQ (->1).  Only firstbyte valid and set to 0.
		;
		;	    (5) Set ~ACK and ~CTL to inputs
		;
		;   AQUIRE: Line aquisition prevents two people from writing to
		;	    the net at the same time.
		;
		;	    * A line is considered aquired if ANY of the 3
		;	      control lines is 0.
		;	    * If network is not aquired:
		;		- set ~ACK to output and 1
		;		- bclr ~ACK to 0 and bne success
		;		  (else set ~ACK to input and try again)
		;		- set data lines to output and place my address
		;		  (Must ]be done before CTL is glitched)
		;		- set ~CTL to output and 1
		;		- set CTL to 0 and then 1 (glitch it) to cause
		;		  FLAG interrupt on all other machines
		;		- set ~REQ to output and 0 (beginning of handshake
		;		  sequence)
		;		- lastly, release ~ACK by setting it to an input
		;
		;	      Note that at all times at least one line is a 0
		;	      so no other machine will attempt to aquire the net.
		;
		;   Note that the destination address is placed on the data
		;   lines after we have aquired the line but before we glitch
		;   the CTL line to cause an interrupt.  This allows the
		;   other machines to instantaniously determine who is being
		;   addressed.
		;
		;   Note that the CTL line gets glitched at the end of a packet
		;   too for the EOP mark.  In this case there is a 0 on the
		;   data lines so while an interrupt is generated, nobody
		;   thinks they are being addressed.

		INCLUDE "exec/types.i"
		INCLUDE "exec/execbase.i"

		XREF	_intena

DISABLE 	MACRO
		MOVE.W	#$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
		ADDQ.B	#1,IDNestCnt(A6)
		ENDM

ENABLE		MACRO
		SUBQ.B	#1,IDNestCnt(A6)
		BGE.S	ENABLE\@
		MOVE.W	#$0C000,_intena     *IF_SETCLR+IF_INTEN
ENABLE\@
		ENDM


		section __MERGED,DATA

		xdef	_ParLLTimeout
		xdef	_ParDAT
		xdef	_ParDDR
		xdef	_ParCollision1
		xdef	_ParCollision2
		xdef	_ParDebug

		;   Note, the timeout is set manually on init by using the
		;   timer.device to time one second.

_ParLLTimeout	dc.l	1000000 	; default timeout value (count). 1 second
_ParDAT 	dc.l	$BFE101 	; data port
_ParDDR 	dc.l	$BFE301 	; data ddr
_ParCAT 	dc.l	$BFD000 	; ctl  port (D0-D2)
_ParCDR 	dc.l	$BFD200 	; ctl  ddr  (D0-D2)
_ParNetAddr	dc.b	0		; default network address (msb 4 bits)
_DummyBuf	dc.b	0		; dummy buffer
		dc.b	0		; dummy buffer
		dc.b	0		; pad
_ParCollision1	dc.l	0		; statistics
_ParCollision2	dc.l	0		;
Null		dc.l	0		; always 0
		dc.l	0		; always 0

_ParDebug	ds.l	16		; 16 longword debug entries

		section text,code

		;   (void) ParAddress(myaddr)
		;	Set my address to (1-254)
		;
		;	0 and 255 are reserved!
		;
		;   int  = ParDataReady()
		;	returns 1  if packet pending
		;	returns 0  if line is currently idle
		;	returns -1 if packet isn't for you
		;
		;	if line has been aquired but no control address has been
		;	put on it yet, ParDataReady() will wait for a control
		;	address.  Thus, after a signal, a single call to
		;	ParDataReady() should suffice.
		;
		;   n = ParReadV (buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
		;	(buffer sizes must be even)
		;   n = ParRead (buf, bytes)
		;	read a pending packet.	Returns n = -1 (1 second timeout
		;	no packet pending), n = 0 to bytes -1 (1 second timeout
		;	after transmission interrupted), n = bytes (success),
		;	or n > bytes (transmitting machine's packet was larger
		;	than we can handle, extra bytes thrown out)
		;
		;	NOTE: requesting an odd number of bytes is O.K. but
		;	      if you request N where N is odd and the writer
		;	      sends N + 1 you will never know (N will be
		;	      returned).  See ParWrite() below
		;
		;   n = ParWriteV (destadr, buf1, bytes1, buf2, bytes2, ..., NULL, NULL);
		;	(buffer sizes must be even)
		;   n = ParWrite(destadr, buf, bytes)
		;	write a packet.  Returns:
		;	n = -2	Cannot write anything, a packet is pending
		;		(instantanious)
		;	n = -1	Destination machine does not respond (1 sec to)
		;	n = N	N bytes written ok (success if n == bytes)
		;
		;	NOTE: sending an odd number of bytes is O.K. but if
		;	you write N where N is odd and the reader requests
		;	N + 1 he will get N + 1 the last byte being garbage.
		;
		;
		;   CIAA PORTB	:  DATA ONLY
		;   CIAB PORTA	:  D0	~DAck
		;		   D1	~DRdy
		;		   D2	Ctl

		xdef	_ParRead
		xdef	_ParReadV
		xdef	_ParWrite
		xdef	_ParWriteV
		xdef	_ParAddress
		xdef	_ParDataReady
		xdef	_LongCheckSum
		xdef	_Time10000

_ParAddress:	move.l	4(sp),D0                ;   address 1-254
		move.b	D0,_ParNetAddr		;   store
		rts

		;   ParDataReady()
		;
		;   -1	packet isn't for you
		;   0	line is idle
		;   1	packet probably pending for you

_ParDataReady:	move.l	_ParDAT,A0		;   data register
		move.l	_ParCAT,A1		;   data control register

.pdstable	move.b	(A1),D0
		move.b	(A0),D1
		cmp.b	(A1),D0                 ;   control lines stable?
		bne	.pdstable

		;   Now, ParDataReady might be called after the sending machine
		;   has aquired but before it can assert REQ.  However, the
		;   sending machine has already (guarenteed) placed its address
		;   on the data port.  So while the address matches, loop while
		;   REQ not asserted.

		btst.l	#1,D0			;   ~Req asserted?
		beq	.pd10			;   beq yes
		cmp.b	_ParNetAddr,D1		;   no, does data match anyway?
		beq	.pdstable		;   YES, loop until get ~REQ or
		bra	.pdfail 		;   data bad.

.pd10		btst.l	#2,D0			;   yes, Ctl ?
		beq	.pdrn			;   no, middle of some packet
		cmp.b	_ParNetAddr,D1		;   yes, my address?
		bne	.pdrn
		moveq.l #1,D0			;   yes, packet (probably) for us
		rts

.pdfail 	btst.l	#2,D0			;   fail due to ~Req not asserted
		beq	.pdrn			;   Ctl = 0, line busy
.pdr0		moveq.l #0,D0			;   line idle
		rts
.pdrn		moveq.l #-1,D0			;   line busy, packet not for me
		rts

_ParReadV:					;   Read Into Vector
		movem.l D2-D7/A2-A5,-(sp)
		lea	12+40(sp),A3
		bra	.rm000

_ParRead:
		movem.l D2-D7/A2-A5,-(sp)
		lea	Null,A3 		;   Pointer to next vector
.rm000		move.l	4+40(sp),A0             ;   A0 = buffer to read into
		move.l	8+40(sp),D7             ;   D7 = # bytes to read (maximum)
		move.l	_ParDAT,A1		;   A1 = data reg
		move.l	_ParDDR,A2		;   A2 = ddr
		move.l	_ParCAT,A4		;   A4 = data reg
		move.l	_ParCDR,A5		;   A5 = ddr

		move.b	#0,(A2)                 ;   ensure all are inputs
		bclr.b	#0,(A5)
		bclr.b	#1,(A5)
		bclr.b	#2,(A5)

		move.l	_ParLLTimeout,D5	;   D5 = timeout load
		moveq.l #-1,D6			;   D6 = # bytes read so far

		;   WAIT LOOK FOR ADDRESS MARK
		;
		;   Ctl = 1, ~DReq = 0

		move.l	D5,D4			;   D4 = timeout countdown
.rmstab 	move.b	(A4),D0                 ;   control data
		move.b	(A1),D1                 ;   data data (network addr)
		cmp.b	(A4),D0
		bne	.rmstab
		btst.l	#2,D0			;   expect CTL = 1
		beq	.rms1			;   nope
		btst.l	#1,D0			;   expect ~REQ = 0
		beq	.rms2			;   yes
.rms1
		add.l	#1,_ParDebug+0
		subq.l	#1,D4			;   timeout
		bne	.rmstab
		bra	.rmend			;   no address mark!

.rms2		cmp.b	_ParNetAddr,D1		;   my address?
		bne	.rms1			;   no, timeout loop

		;   My address, ~Ack byte.

		bclr.b	#0,(A4)                 ;   set ~ACK to 0
		bset.b	#0,(A5)                 ;   set to output

		move.l	D5,D4			;   reset timeout
.rms4		btst.b	#1,(A4)                 ;   wait for ~REQ to go away
		bne	.rms5
		add.l	#1,_ParDebug+4
		subq.l	#1,D4
		bne	.rms4
		moveq.l #-2,D6			;   ~REQ not released ?????
		bra	.rmend

.rms5		bset.b	#0,(A4)                 ;   release ~ACK
		moveq.l #0,D6			;   set # bytes read to 0
		bra	.rms10			;   skip past move

		;   MAIN READ LOOP
		;
		;   D6 holds cnt, A0 buffer ptr, D0-D4 free to allocate

.rms10loop
		move.b	D0,(A0)                 ;   store data
		addq.l	#1,A0			;   next addr.

.rms10		btst.b	#1,(A4)                 ;   wait for ~REQ asserted
		beq	.rms20
		btst.b	#1,(A4)
		beq	.rms20
		move.l	D5,D4			;   load timeout
.rms11		btst.b	#1,(A4)                 ;   wait for ~REQ asserted w/to
		beq	.rms20
		add.l	#1,_ParDebug+8
		subq.l	#1,D4
		bne	.rms11
		bra	.rmend

.rms20		move.b	(A1),D0                 ;   get data and
		bclr.b	#0,(A4)                 ;   assert ~ACK

		;   note, on CTL = 1 end sequence this data item is a dummy

		move.b	D0,(A0)                 ;   store data
		addq.l	#1,A0			;   next addr.
		addq.l	#2,D6			;   optimized but not quite
						;   true, we've only written 1 sf.
		btst.b	#1,(A4)                 ;   wait for ~REQ released
		bne	.rms30
		btst.b	#1,(A4)
		bne	.rms30
		move.l	D5,D4
.rms21		btst.b	#1,(A4)                 ;   wait for ~REQ rel w/ to
		bne	.rms30
		add.l	#1,_ParDebug+12
		subq.l	#1,D4
		bne	.rms21
		bra	.rmendsub		;   sub because D6 is 2 ahead

.rms30		move.b	(A1),D0                 ;   get data
		move.b	(A4),D1                 ;   get CTL status
		bset.b	#0,(A4)                 ;   release ~ACK
		btst.l	#2,D1			;   EOP if CTL = 1
		bne	.rmeop

		;   CANNOT STORE DATA HERE!  In case odd # bytes requested,
		;   second byte would overflow buffer

		subq.l	#2,D7			;   # bytes remaining
		bgt	.rms10loop
		bne	.rmnlb
		move.b	D0,(A0)                 ;   if D7 = 0 its even and we
						;   should store the last byte
.rmnlb		cmp.l	#-1,D7			;   -1 = was odd #
		bne	.rmeven 		;   fixup count
		subq.l	#1,D6

.rmeven
.rmsev0 	tst.l	(A3)                    ;   if next buffer NULL
		beq	.rmovflow
		move.l	(A3)+,A0                ;   next buffer
		move.l	(A3)+,D7
		beq	.rmsev0 		;   0 bytes, goto next buffer
		bra	.rms10			;   loop, continue reading

.rmovflow
		lea	_DummyBuf,A0		;   overflow, dummy buffer
		bra	.rms10

.rmeop		tst.b	D0			;   EOP data better be 0!
		beq	.rmendsub
		moveq.l #-3,D6
		bra	.rmend

.rmendsub	subq.l	#2,D6			;   because we were two ahead

.rmend		bset.b	#0,(A4)                 ;   active pull up before (?)
		bclr.b	#0,(A5)                 ;   setting ~ACK to input
		move.l	D6,D0			;   return value
		movem.l (sp)+,D2-D7/A2-A5       ;   restore registers
		rts

_ParWriteV:	movem.l D2-D7/A2-A6,-(sp)       ;   write vector
		lea	16+44(sp),A3
		bra	.wm000

_ParWrite:
		movem.l D2-D7/A2-A6,-(sp)
		lea	Null,A3
.wm000		move.l	4+44(sp),D3             ;   D3 = destination address
		move.l	8+44(sp),A0             ;   A0 = buffer to write
		move.l	12+44(sp),D7            ;   D7 = # bytes to write
		move.l	_ParDAT,A1		;   A1 = data reg
		move.l	_ParDDR,A2		;   A2 = ddr
		move.l	_ParCAT,A4		;   A4 = data reg
		move.l	_ParCDR,A5		;   A5 = ddr
		move.l	4,A6			;   SYSBase

		move.b	#0,(A2)
		and.b	#%11111000,(A5)
		move.l	_ParLLTimeout,D5	;   D5 = timeout load

		move.l	D5,D4			;   D4 = timeout countdown
		moveq.l #-2,D6			;   D6 = # bytes written

		;   AQUIRE THE LINE USING ~ACK

.wmstab
		bset.b	#0,(A4)                 ;   so is a 1 when we set it to w

		DISABLE

		move.b	(A4),D0                 ;   get stable data
		move.b	(A1),D1
		cmp.b	(A4),D0
		beq	.wmstab1

		ENABLE

		bra	.wmstab

		;   Ints still disabled
		;   D0 holds ~ACK ~REQ CTL status

.wmstab1	and.b	#%111,D0		;   ~ACK=1, ~REQ=1, CTL=1
		cmp.b	#%111,D0
		beq	.wm02

		;   no, if CTL = 1, ~REQ = 0, and D1 = my address then
		;   return w/ -2

		btst.l	#1,D0
		bne	.wm01
		btst.l	#2,D0
		beq	.wm01
		cmp.b	_ParNetAddr,D1		;   somebody calling me?
		bne	.wm01

		ENABLE
		bra	.wmend

.wm01
		ENABLE

		add.l	#1,_ParDebug+16
		subq.l	#1,D4
		bne	.wmstab
		bra	.wmend

		;   interrupts still disabled
		;   we almost own the line

.wm02		bset.b	#0,(A5)                 ;   set ~ACK to an output
		nop
		bclr.b	#0,(A4)                 ;   assert ~ACK
		bne	.wm05			;   was released before, have line!

						;   don't have line,
		bclr.b	#0,(A5)                 ;   set back to input
		bra	.wm01

		;   Line now aquired.

.wm05
		ENABLE

		move.b	#$FF,(A2)               ;   set data ddr to outputs
		move.b	D3,(A1)                 ;   set data lines to our addr

		;   Before asserting ~REQ pulse CTL to cause interrupt on remote
		;   machines.  Note that our address is already on the data
		;   lines.

		bset.b	#2,(A5)                 ;   set CTL to output
		bclr.b	#2,(A4)                 ;   pulse CTL to cause FLAG int
		or.b	#%00000111,(A4)         ;   set CTL = 1 and make sure
						;   REQ will be one when we
		bset.b	#1,(A5)                 ;   set ~REQ to output

		bclr.b	#1,(A4)                 ;   assert ~REQ

		bclr.b	#0,(A5)                 ;   make ~ACK an input
						;   (note that REQ->0 before ACK->release)

		moveq.l #-1,D6			;   D6 = # bytes written

		;   INTERRUPTS ENABLED FOR TXFER (fully handshaked)
		;
		;   Address mark ~ACK, wait for ~ACK asserted

.wm10		btst.b	#0,(A4)
		beq	.wm15
		move.l	D5,D4			;   D4 = timeout countdown
.wm11		btst.b	#0,(A4)
		beq	.wm15
		add.l	#1,_ParDebug+20
		subq.l	#1,D4
		bne	.wm11
		bra	.wmend

		;   got ack, now set CTL = 0 (leaves at least one line 0 so
		;   nobody else thinks the bus is idle!)
		;
		;   note:   Since this is the address mark, and is sampled by
		;	    the reader before it asserts ~ACK, I can set CTL
		;	    = 0 now instead of waiting till after ~ACK is
		;	    released.

.wm15		bclr.b	#2,(A4)                 ;   set CTL = 0 for duration of pkt
		nop				;   ???
		bset.b	#1,(A4)                 ;   release ~REQ


		moveq.l #0,D6			;   # bytes written

		;   DATA XFER LOOP
		;
		;   wait for ~ACK to be released (->1).  If no more bytes
		;   then skip to .wm50

.wm20
		tst.l	D7			;   more data in this buffer?
		ble	.wm50			;   nope.

		btst.b	#0,(A4)                 ;   wait ~ACK released
		bne	.wm30
		move.l	D5,D4			;   D4 = timeout countdown
.wm21		btst.b	#0,(A4)
		bne	.wm30			;   need the timeout here?
		btst.b	#0,(A4)
		bne	.wm30
		add.l	#1,_ParDebug+24
		subq.l	#1,D4
		bne	.wm21
		bra	.wmend

		;   Assert ~REQ for this data byte and wait for ~ACK

.wm30
		move.b	(A0)+,D0                ;   get next data byte
		move.b	D0,(A1)                 ;   store data and
		bclr.b	#1,(A4)                 ;   assert ~REQ

		move.b	(A0)+,D0                ;   get next data byte
		subq.l	#2,D7			;   one less byte (this and next)
		addq.l	#1,D6			;   # bytes written (this only)
						;   (not valid until we get ACK
						;    which is why the wmendsub

		btst.b	#0,(A4)                 ;   wait for ACK
		beq	.wm40
		btst.b	#0,(A4)
		beq	.wm40
		move.l	D5,D4			;   D4 = timeout countdown
.wm31		btst.b	#0,(A4)
		beq	.wm40
		add.l	#1,_ParDebug+28
		subq.l	#1,D4
		bne	.wm31
		bra	.wmendsub

		;   Have ~ACK, byte transmitted.  ++bytes written, --bytes left
		;   and loop

.wm40		move.b	D0,(A1)                 ; store second byte
		bset.b	#1,(A4)                 ; release ~REQ

		addq.l	#1,D6			; # bytes written

		bra	.wm20

		;   Last byte in buffer has been transmitted.
		;
		;   Get next buffer in vector

.wm50		tst.l	(A3)
		beq	.wm50a
		move.l	(A3)+,A0                ;   buffer ptr
		move.l	(A3)+,D7                ;   # bytes
		bra	.wm20			;   loop to top

.wm50a
		;   Last byte has been transmitted,
		;
		;   Wait for ~ACK to be released and then assert ~REQ with
		;   EOP & CTL = 1
		;
		;   (timing on read is that CTL is sampled when ~REQ is
		;   RELEASED so no timing window here)

		btst.b	#0,(A4)                 ;   Wait ~ACK released
		beq	.wm50

		move.b	#0,(A1)                 ;   EOP mark (0)
		bclr.b	#1,(A4)                 ;   assert ~REQ

		;   Wait for ~ACK asserted

		btst.b	#0,(A4)
		beq	.wm60
		move.l	D5,D4
.wm51		btst.b	#0,(A4)
		beq	.wm60
		add.l	#1,_ParDebug+32
		subq.l	#1,D4
		bne	.wm51
		moveq.l #-3,D6			;   EOP failed
		bra	.wmend

		;   Set CTL = 1 then release ~REQ, then wait for ~ACK released

.wm60		or.b	#%00000100,(A4) ;   set CTL = 1
		or.b	#%00000110,(A4) ;   release ~REQ

		;   Wait ~ACK released ?

.wm61		btst.b	#0,(A4)
		beq	.wm61

		;   Add D7 to D6.  This handles fixup if an odd number of bytes
		;   were requested written, D7 will be -1 (odd) or 0 (even) and
		;   D6 will be one too large (odd) or perfect (even)

		add.l	D7,D6

		bra	.wmend

.wmendsub	subq.l	#1,D6		;   was ahead in count

.wmend		move.b	#0,(A2)         ;   set data port to input
		and.b	#%11111000,(A5) ;   set data port for ctl lines to input

		move.l	D6,D0			;   return value
		movem.l (sp)+,D2-D7/A2-A6       ;   restore registers
		rts

		;   sum = LongCheckSum(buf, bytes)
		;   (buffer must be lw aligned and bytes must be multiples of 4)

_LongCheckSum:
		moveq.l #0,D0			;   D0 = accumulated checksum
		move.l	4(sp),A0                ;   A0 = ptr
		move.l	8(sp),D1                ;   D1 = bytes
		beq	.pcrts
.pc10		add.l	(A0)+,D0
		subq.l	#4,D1
		bgt	.pc10
		tst.l	D1
		bne	.pc20			;   not multiple of 4 bytes!
.pcrts		rts				;   return checksum
.pc20		illegal 			;   cause task-held msg
		rts

		;   Delays 10000 rough timeout loops, used to determine
		;   timeout on init

_Time10000:
		move.l	#10000,D4
t10		move.l	D4,D4
		move.l	D4,D4
		move.l	D4,D4
		move.l	D4,D4
		subq.l	#1,D4
		bne	t10
		rts

		END

