; TeleSwat.asm
; Copyright Xerox Corporation 1979
; Last modified August 10, 1979  5:24 PM by Boggs

; outgoing procedures
.ent InLd, OutLd

; incoming procedures
.bext UpdateTimer

	.srel

InLd:		.InLd
OutLd:		.OutLd

il1:		.il1
MoveBlock:	.MoveBlock
userCursor:	.userCursor
swatCursor:	.swatCursor
etherState:	.etherState
pbi:		.pbi

	.nrel

			; structure PBI:	//Packet Buffer
			; [
eDestSrc = 0		; eDest byte; eSrc byte
eType = 1		; eType word
			; // The Pup begins here.
length = 2		; length word
type = 3		; transport byte; type byte
pupID = 4		; id word 2
dPort = 6		; dPort: @Port
sPort = 11		; sPort: @Port
address = 14		; address word
value = 15		; value word
lenBlock = 16		; lenBlock word
block = 17		; block word maxBlkLen
			; ]

maxBlkLen = 32.
lenPBI = 2+11+3+maxBlkLen

.lenPBI:	lenPBI

etherReset:	3	; reset the Ethernet interface
etherInput:	2	; start the Ethernet receiver

.ePLoc:		600
.eELoc:		602
.eICLoc:	604
.eIPLoc:	605
.eHLoc:		610

; Call with interrupts disabled.  It is the caller's responsibility
;  to save and restore the interrupt system state.
; Returns to the return address of the most recent call on OutLd
;  with AC0 nonzero.
.InLd:	jsrii .+1		; we are going to use the Ethernet
	 etherState
	mov 3 0
	lda 1 .ePLoc		; so save its old state
	lda 2 lenEtherState
	jsrii .+1
	 MoveBlock

	lda 0 etherReset
	sio			; reset the interface
	lda 1 c377
	and 1 0
	sta 0 @.eHLoc		; our host address

; exchange cursors
	jsrii .+1
	 userCursor
	mov 3 0			; destination
	lda 1 .cursorBitMap	; source
	lda 2 lenCursor		; length
	jsrii .+1		; save user cursor
	 MoveBlock
	lda 0 .cursorBitMap	; destination
	jsrii .+1
	 swatCursor
	mov 3 1			; source
	lda 2 lenCursor		; length
	jsrii .+1		; install swat cursor
	 MoveBlock

; setup to receive a packet
.il1:	jsrii .+1
	 pbi
	sta 3 @.eIPLoc
	lda 0 .lenPBI
	sta 0 @.eICLoc
	mkzero 0 0
	sta 0 @.ePLoc		; done when nonzero
	lda 0 etherInput
	sio			; start the receiver

; wait for a packet to arrive or dally to expire
il2:	jsrii .+1		; keep the calendar clock updated
	 UpdateTimer
	lda 0 dally
	snz 0 0			; are we dallying?
	 jmp il3		; no
	lda 1 @.rtc
	subl# 1 0 szc		; (dally-@realTimeClock) le 0?
	 jmp SwapReply		; yes. dally expired
il3:	lda 0 @.ePLoc		; receiver status
	snz 0 0			; has it finished?
	 jmp il2		; no

; a packet has arrived.  Filter it.
	lda 3 @.eIPLoc		; make ac3 -> pbi
	lda 1 c377
	se 0 1			; good receiver status?
	 jmp .il1		; no.  reject

	lda 0 eDestSrc,3
	and# 1 0 snr		; zero source host?
	 jmp .il1		; yes.  reject
	movs 0 0
	and# 1 0 snr		; broadcast?
	 jmp .il1		; yes.  reject

	lda 0 eType,3
	lda 1 typePup
	se 0 0			; does it claim to be a Pup?
	 jmp .il1		; no. reject

	lda 0 @.eICLoc
	lda 1 @.eELoc
	sub 1 0			; packet length reported by interface
	lda 1 length,3
	lda 2 c5
	addzr 2 1		; length packet claims to be
	se 1 0
	 jmp .il1		; they disagree.  reject

	lda 0 dPort+1,3
	sz 0 0			; high half of dPort.socket
	 jmp .il1		; reject
	lda 0 dPort+2,3
	lda 1 socTeleSwat
	se 0 1			; low half of dPort.socket
	 jmp .il1		; reject

; Looks good so far.  Dispatch on packet type.
	lda 0 type,3
	lda 1 c377
	and 1 0			; mask off transport byte
	lda 1 ptSwatStore
	sne 0 1			; ptSwatStore? (200b)
	 jmp Store		; yes
	inc 1 1
	sne 0 1			; ptSwatFetch? (201b)
	 jmp Fetch		; yes
	inc 1 1
	sne 0 1			; ptSwatSwap? (202b)
	 jmp Swap		; yes
	inc 1 1
	sne 0 1			; ptSwatSwapReply? (203b)
	 jmp SwapReply		; yes
	jmp .il1		; unknown type.  reject

.cursorBitMap:	431
lenCursor:	16.
lenEtherState:	9.
typePup:	1000		; I'm a Pup in an Ether packet
socTeleSwat:	60		; well known server socket
c377:		377
ptSwatStore:	200
lenDally:	5*27.		; ~5 seconds in units of RTC ticks (38 ms)
c5:		5
dally:		0
.rtc:		430		; -> real time clock

.OutLd:	sta 3 OutLdRet
	mkzero 0 0
	sta 0 @.dumperFlg	; page 0 is OK
	jmp 1 3

OutLdRet:	.blk 1
.dumperFlg:	706

SwapReply: lda 0 dally
	snz 0 0			; are we dallying?
	 jmp sa1		; no.  hmmm.
	lda 0 .cursorBitMap
	jsrii .+1		; restore user cursor
	 userCursor
	mov 3 1
	lda 2 lenCursor
	jsrii .+1
	 MoveBlock
	lda 0 .ePLoc1		; restore Ethernet state
	jsrii .+1
	 etherState
	mov 3 1
	lda 2 lenEtherState
	jsrii .+1
	 MoveBlock
	mkzero 1 1		; no longer dallying
	sta 1 dally
	lda 3 OutLdRet
	jmp 1 3			; resume user program

Store:	lda 0 value,3
	sta 0 @address,3
	jmp SendBlk

Fetch:	lda 0 @address,3
	sta 0 value,3		; fall through into SendBlk

; see if user is requesting a block.
SendBlk:lda 0 length,3
	lda 1 lenAckPup
	sgeu 0 1		; long enough to request a block?
	 jmp sb1		; no
	lda 2 lenBlock,3
	snz 2 2			; is he requesting one?
	 jmp sb1		; no
	lda 1 .maxBlkLen
	sgeu 1 2
	 mov 1 2		; Max(requested length, our limit)
	sta 2 lenBlock,3	; # words we are sending
	neg 2 0
	lda 1 address,3
	and 0 1			; source base address = address & -length
	lda 0 .block
	add 3 0			; destination = PBI.block
	jsrii .+1		; move the block into the packet
	 MoveBlock
	jsrii .+1
	 pbi
sb1:	mkzero 0 0
	jmp SendAck

.maxBlkLen:	maxBlkLen
.block:		block

Swap:	mkzero 0 0
	sta 0 lenBlock,3
	lda 0 lenDally
	lda 1 @.rtc
	add 1 0			; fall through into SendAck

SendAck:sta 0 dally

	lda 1 lenCursor		; Invert the cursor
	neg 1 1
	lda 2 .cursorBitMap
sa2:	lda 0 0 2
	com 0 0
	sta 0 0 2
	inc 2 2
	inc 1 1 szr
	 jmp sa2

	lda 0 eDestSrc,3	; exchange Ethernet addresses
	movs 0 0
	sta 0 eDestSrc,3

	lda 2 lenBlock,3
	movzl 2 2		; convert to bytes
	lda 1 lenAckPup
	add 1 2
	sta 2 length,3		; Pup.length

	mkminusone 0 0
	addor 0 2		; (Pup.length-1)/2 = checksum offset
	add 3 2			; Pup base address
	sta 0 2,2		; 2 accounts for the encapsulation
	
	lda 0 ptSwatAck
	sta 0 type,3		; Pup.type

	lda 0 sPort,3		; exchange Pup ports
	lda 1 dPort,3
	sta 0 dPort,3
	sta 1 sPort,3
	lda 0 sPort+1,3
	lda 1 dPort+1,3
	sta 0 dPort+1,3
	sta 1 sPort+1,3
	lda 0 sPort+2,3
	lda 1 dPort+2,3
	sta 0 dPort+2,3
	sta 1 sPort+2,3

	lda 0 c3777		; delay about 4 ms to ensure that
	neg 0 0			; our ack is heard
	inc 0 0 szr
	 jmp .-1

	sta 0 @.ePLoc1		; status
	sta 0 @.eLLoc		; zero load
	sta 0 @.eICLoc1		; no input under output
	sta 3 @.eOPLoc
	lda 3 length,3
	lda 0 c5
	addzr 3 0		; physical length = (Pup.length+5)/2
	sta 0 @.eOCLoc
	mkone 0 0		; etherOutput command
	sio			; start transmitter

	lda 0 @.ePLoc1
	snz 0 0			; done?
	 jmp .-2		; no
sa1:	jsrii .+1
	 il1

c3777:		3777
lenAckPup:	28.		; pupOvBytes + 6
ptSwatAck:	204

.ePLoc1:	600
.eLLoc:		603
.eICLoc1:	604
.eOCLoc:	606
.eOPLoc:	607

.MoveBlock:			; AC0 = dest, AC1 = src, AC2 = length
	sta 3 mbRet
	mkone 3 3
	sub 3 1
	sub 0 3
	mov 1 0
	neg 3 1
	mov 2 3
	add 3 1
	neg 3 3
	blt
	lda 3 mbRet
	jmp 1 3

mbRet:		.blk 1

.pbi:		jsr 1,3
		.blk lenPBI

		125252
		125252
		125252
		125252

.etherState:	jsr 1,3
		.blk 9.

.userCursor:	jsr 1,3
		.blk 16.

.swatCursor:	jsr 1,3
		0
		73507
		22104
		23106		; Tele
		22104
		23567
		0
		0
		65227
		105252
		45252		; Swat
		25272
		142452
		0
		0
		0

	.end