; DMTEther.asm
; Copyright Xerox Corporation 1979, 1980, 1983
; Last modified July 1, 1983  2:55 PM by Boggs

; OUTGOING
.ENT	INITETHER, STOPETHER, STARTETHER
.ENT	INITETHEROUT, STARTETHEROUT, PACKCHAR

; INCOMING
.BEXT	INITINT
.BEXTZ	CHANGEBANK
.BEXT	mayDayPacket, bootLoaderPacket

	.SREL

INITETHER:	.INITETHER
STOPETHER:	.STOPETHER
STARTETHER:	.STARTETHER
INITETHEROUT:	.INITETHEROUT
STARTETHEROUT:	.STARTETHEROUT
PACKCHAR:	.PACKCHAR

ETHERINT:	.ETHERINT

	.ZREL

ETHERCHAN:	0		; INTERRUPT CHANNEL BIT

EPLOC:		600		; ENDING STATUS
EBLOC:		601		; INTERRUPT BIT MASK
EELOC:		602		; ENDING LENGTH
ELLOC:		603		; LOAD
EICLOC:		604		; INPUT BUFFER LENGTH
EIPLOC:		605		; -> INPUT BUFFER
EOCLOC:		606		; OUTPUT BUFFER LENGTH
EOPLOC:		607		; -> OUTPUT BUFFER
EHLOC:		610		; HOST ADDRESS

pEIBUF:		EIBUF		; -> INPUT BUFFER
pEOBUF:		EOBUF		; -> OUTPUT BUFFER

	.NREL

OBL = 300.			; OUTPUT BUFFER LENGTH
IBL = 300.			; INPUT BUFFER LENGTH

EOBUF:	.BLK OBL
EIBUF:	.BLK IBL

;Ethernet encapsulation:
	ether.ds = 0
	ether.type = 1

;Peek format:
	peek.type = 2
	peek.string = 3

;Pup format:
	pup.length = 2
	pup.type = 3
	pup.id = 4
	pup.dPort = 6
	pup.sPort = 11
	pup.words = 14

;-----------------------------------------------------------------------------
.INITETHER:
;-----------------------------------------------------------------------------
	STA 3 IEIRET
	LDA 0 @ppETHERINT	; SET INTERRUPT HANDLER
	JSRII ppINITINT
	STA 0 ETHERCHAN

	MKZERO 0 0		; SET HOST ADDRESS
	SIO
	LDA 1 C377
	AND 1 0
	STA 0 @EHLOC

	JSR .STARTETHER		; START THE RECEIVER
	JMP @IEIRET

IEIRET:		0
ppINITINT:	INITINT
ppETHERINT:	ETHERINT

;-----------------------------------------------------------------------------
.STARTETHER:
;-----------------------------------------------------------------------------
	LDA 0 ETHERCHAN
	JMP SEBLOC

;-----------------------------------------------------------------------------
.STOPETHER:
;-----------------------------------------------------------------------------
	MKZERO 0 0
SEBLOC:	STA 0 @EBLOC
	LDA 0 ETHERRESET
	SIO
	JMP 0 3


;-----------------------------------------------------------------------------
.ETHERINT:			; ETHERNET INTERRUPT
;-----------------------------------------------------------------------------
	STA 0 SAC0		; SAVE STATE
	STA 1 SAC1
	STA 2 SAC2
	STA 3 SAC3
	MOVL 0 0
	STA 0 SCRY

	LDA 0 @EPLOC		; GET STATUS
	LDA 1 C377
	SE 0 1			; RECEIVER DONE STATUS?
	 JMP STARTETHERIN	; NO. RESTART RECEIVER

; FILTER THE NEWLY ARRIVED PACKET

	LDA 2 pEIBUF		; INPUT BUFFER POINTER
	LDA 0 ether.ds,2	; DEST,,SRC
	LDA 1 C177400
	ANDS 1 0
	LDA 1 @EHLOC		; OUR HOST ADDRESS
	SE 1 0			; TO US (No BroadCasts Allowed!!!)?
	 JMP STARTETHERIN	; NO

	LDA 0 etPup
	LDA 1 ether.type,2	; TYPE WORD IN PACKET
	SE 0 1			; IS IT A PUP?
	 JMP STARTETHERIN	; NO

	LDA 0 @EICLOC
	LDA 1 @EELOC
	SUB 1 0			; LENGTH REPORTED BY INTERFACE
	LDA 1 pup.length,2
	LDA 3 C5
	ADDZR 3 1		; LENGTH CLAIMED IN PUP HEADER
	SE 1 0			; DO THEY AGREE?
	 JMP STARTETHERIN	; NO

	LDA 0 C377
	LDA 1 pup.type,2
	AND 1 0			; Pup Type in AC0

	LDA 1 pup.dPort+2,2	; IS SOCKET MISC SERVICES?
	LDA 3 socMiscServ
	SE 1 3
	 JMP NOTMISCSERV	; NO
	LDA 1 pup.dPort+1,2
	SZ 1 1
	 JMP NOTMISCSERV	; NO

	LDA 1 ptIDLEREQUEST
	SNE 0 1			; IDLE REQUEST?
	 JMP IDLEREPLY
	LDA 1 ptKOD
	SE 0 1			; KOD?
	 JMP NOTMISCSERV	; NO
	LDA 0 C170000		; HOP COUNT FIELD MASK
	LDA 1 pup.type,2
	AND# 1 0 SNR		; HOP COUNT MUST BE ZERO
	 JMP NETBOOT		; I.E. SRC MUST BE ON THIS NET

NOTMISCSERV:
	LDA 1 ptRFC
	SNE 0 1			; RFC?
	 JMP DISKBOOT		; YES

;	LDA 1 ptEFTP
;	SE 0 1			; EFTP?
;	 JMP STARTETHERIN	; NO
;	LDA 0 pup.id+1,2
;	SNZ 0 0			; SEQUENCE NUMBER 0?
;	 JMP DISKBOOT		; YES

STARTETHERIN:
	LDA 0 pEIBUF		; BUFFER POINTER
	STA 0 @EIPLOC
	LDA 0 BUFFLEN		; BUFFER LENGTH
	STA 0 @EICLOC
	MKZERO 0 0
	STA 0 @EPLOC
	LDA 0 ETHERCHAN
	STA 0 @EBLOC
	LDA 0 ETHERINPUT
	SIO
	LDA 0 SCRY
	MOVR 0 0
	LDA 0 SAC0		; RESTORE STATE
	LDA 1 SAC1
	LDA 2 SAC2
	LDA 3 SAC3
	BRI			; DISMISS INTERRUPT

SAC0:		0
SAC1:		0
SAC2:		0
SAC3:		0
SCRY:		0

socMiscServ:	4
ptKOD:		247		; KISS-OF-DEATH
ptRFC:		10		; REQUEST-FOR-CONNECTION
ptEFTP:		30		; EFTP-DATA
ptIDLEREQUEST:	262		; IDLE-REQUEST
ptIDLEREPLY:	263		; IDLE-REPLY
etPup:		1000		; I'm a Pup in an Ether packet

BUFFLEN:	IBL
C5:		5
C6:		6
C3:
ETHERRESET:	3		; ETHER RESET COMMAND
ETHERINPUT:	2		; ETHER INPUT COMMAND
C177400:	177400
C170000:	170000
C377:		377

IDLEREPLY:LDA 0 C3000		; REPLY TO REQUESTING HOST
	NEG 0 0
	INC 0 0 SZR		; DELAY FOR A FEW MS.
	 JMP .-1

	LDA 0 ptIDLEREPLY
	STA 0 pup.type,2	; CHANGE TYPE TO IDLE-REPLY
	LDA 0 LENREPLY
	STA 0 pup.length,2	; FILL IN PUP LENGTH
	LDA 0 IDLEVERSION
	STA 0 pup.words,2	; IDLE REPLY VERSION NUMBER
	VERS
	STA 0 pup.words+1,2	; ALTO UCODE INFORMATION
	MKMINUSONE 0 0
	STA 0 pup.words+2,2	; TURN OFF CHECKSUM

	LDA 0 pup.dPort,2	; SWAP PORTS
	LDA 1 pup.sPort,2
	STA 1 pup.dPort,2
	STA 0 pup.sPort,2
	LDA 0 pup.dPort+1,2
	LDA 1 pup.sPort+1,2
	STA 1 pup.dPort+1,2
	STA 0 pup.sPort+1,2
	LDA 0 pup.dPort+2,2
	LDA 1 pup.sPort+2,2
	STA 1 pup.dPort+2,2
	STA 0 pup.sPort+2,2

	LDA 0 ether.ds,2	; SWAP DEST-SOURCE BYTES
	MOVS 0 0
	STA 0 ether.ds,2

	LDA 0 pup.length,2	; COMPUTE PACKET LENGTH
	LDA 1 C5
	ADDZR 1 0		; PACKETLEN = (PUPLEN + 5)/2
	JSR SENDPACKET		; LENGTH IN AC0, PACKET POINTER IN AC2
	JMP STARTETHERIN

LENREPLY:	32
IDLEVERSION:	1
C3000:		3000

NETBOOT:MKZERO 0 0		; BOOT FROM NET
	JSR @CHANGEBANK		; FLIP BACK INTO BANK 0
	LDA 2 pEIBUF
	LDA 0 pup.id+1,2
	LDA 3 @lvMayDayPacket
	STA 0 pup.id+1,3	; BOOT FILE NUMBER
	LDA 0 pup.sPort,2
	STA 0 pup.dPort,3
	LDA 0 pup.sPort+1,2
	STA 0 pup.dPort+1,3
	LDA 0 pup.sPort+2,2
	STA 0 pup.dPort+2,3	; COPY KOD sPort INTO MAYDAY dPort
	LDA 0 @lvBootLoaderPacket
	INC 0 0
	LDA 1 K400
	LDA 3 LBLT
	BLT			; MOVE LOADER INTO PAGE 0
	JMP 6			; JUMP INTO BOOT LOADER

lvMayDayPacket:	mayDayPacket
lvBootLoaderPacket:	bootLoaderPacket
LBLT:		-401+3
K400:		400

DISKBOOT:LDA 0 @KSTAT		; DISK STATUS
	LDA 1 DISKREADY
	AND 1 0 SZR		; BIT 10 ZERO MEANS DISK READY
	 JMP STARTETHERIN
	STA 0 @DSTART		; TURN OFF DISPLAY
	INC 0 0 SZR		; WAIT FOR IT TO STOP
	 JMP .-1
	JSR @CHANGEBANK

; BUILD A DISK COMMAND TO READ DISK ADDRESS 0 INTO CORE PAGE 0
; STORE THE LABEL BLOCK IN LOC 402-411. HEADER IS ALSO READ INTO
; 402 - JUST TO PUT IT SOMEWHERE - IT IS OVERWRITTEN BY THE LABEL

	JSR DB3			; GET POINTER TO KCB:
	0			; LINK
	0			; STATUS
	44000			; READ HEADER, LABEL, DATA
	412			; HEADER BLOCK ADDRESS
	402			; LABEL BLOCK ADDRESS
	1			; DATA BLOCK ADDRESS
	0			; NO ERROR INTERRUPT WORD
	0			; ERROR INTERRUPT WORD
	0			; NOT USED
	0			; DISK ADDRESS
; *** From here on, can't assume page zero is valid ***
DB3:	LDA 2 pEIBUF		; pEIBUF IS ZREL - CLOBBERED BY THE READ
	MKMINUSONE 0 0
	STA 0 @KADDR		; FORCE A SEEK
	STA 3 @KBLK		; START THE DISK

; WAIT FOR THE DISK COMMAND TO FINISH

WAITDISK:LDA 0 1 3		; NON-ZERO STATUS MEANS DONE
	SNZ 0 0			; DONE?
	 JMP WAITDISK		; NO
	LDA 1 STATUSMASK
	AND 0 1 SNR
	 JMP EVENT
	MKZERO 0 0
	STA 0 1 3
	STA 3 @KBLK
	JMP WAITDISK
STATUSMASK:	267

; BUILD AN EVENT MESSAGE AND LEAVE IT FOR THE BOOTEE.
; THE EVENT VECTOR CONTAINS:
;	CONNECTION ID			(2 WORDS)
;	DESTINATION PORT		(3 WORDS)
;	SOURCE PORT			(3 WORDS)
;	CONNECTION PORT	(RFC ONLY)	(3 WORDS)

EVENT:	LDA 3 2			; POINTER TO EVENT AREA
	MKONE 0 0
	STA 0 0,3		; HEY, OS: THERE'S AN EVENT HERE

	LDA 0 pup.type,2
	LDA 1 C377
	AND 1 0
	LDA 1 ptRFC
	SE 0 1
	 JMP DB1
	LDA 0 EVENTRFC		; IT'S AN RFC EVENT
	STA 0 1,3		; CNT ALREADY CONTAINS 11D

DB2:	LDA 0 4,2		; GET A WORD FROM THE PACKET
	STA 0 2,3		; PUT IT IN THE EVENT VECTOR
	INC 3 3
	INC 2 2
	DSZ CNT
	 JMP DB2

	MKZERO 0 0
	STA 0 2,3		; END OF EVENT VECTOR
	JMP 3			; JUMP INTO THE BOOT LOADER

DB1:	LDA 0 EVENTEFTP		; IT'S AN EFTP EVENT
	STA 0 1,3
	LDA 0 D8		; IT'S 8D WORDS LONG
	STA 0 CNT
	JMP DB2

EVENTRFC:	4B11+13+1	; TYPE RFC, LENGTH 13
EVENTEFTP:	7B11+10+1	; TYPE EFTPDATA, LENGTH 10
KADDR:		523		; -> DISK ADDR OF LAST COMMAND
KSTAT:		522		; -> SECTOR STATUS
KBLK:		521		; -> DISK COMMAND LIST
DSTART:		420		; -> DISPLAY COMMAND LIST
DISKREADY:	40		; DISK READY BIT IN STATUS WORD
C4:		4
D8:		8.		; SIZE OF AN EFTP EVENT
CNT:		11.		; SIZE OF AN RFC EVENT

;-----------------------------------------------------------------------------
.STARTETHEROUT:			; START ETHER OUTPUT
;-----------------------------------------------------------------------------
	STA 3 SEORET
	JSRII ppSTOPETHER
	LDA 2 pEOBUF		; OUTPUT BUFFER
	LDA 0 peek.string,2
	LDA 1 RIGHTMASK		; AKA C377
	MOVS 0 0		; STRING BYTE COUNT
	ANDZR 1 0		; WORDCOUNT +0,-1
	LDA 1 C4		; 3 FOR HEADER, 1 FOR POSSIBLE LEFT OVER BYTE
	ADD 1 0			; PACKET LENGTH IN WORDS
	JSR SENDPACKET
	JSRII ppSTARTETHER
	JSR .INITETHEROUT
	JMP @SEORET

ppSTOPETHER:	STOPETHER
ppSTARTETHER:	STARTETHER
SEORET:		0

;-----------------------------------------------------------------------------
SENDPACKET:			; OUTPUT A PACKET
; ASSUMES PACKET LENGTH IN AC0, PACKET POINTER IN AC2, RETURN IN AC3
;-----------------------------------------------------------------------------
	STA 0 @EOCLOC
	STA 2 @EOPLOC
	MKZERO 0 0
	STA 0 @EPLOC
	STA 0 @ELLOC
	STA 0 @EICLOC
	STA 0 @EIPLOC
	LDA 0 POSTTIME		; SET UP WAIT COUNTER
	STA 0 POSTCNT
	LDA 0 ETHEROUTPUT
	SIO			; START TRANSMITTER

WAIT:	LDA 0 @EPLOC		; NON ZERO MEANS DONE
	MOV 0 0 SZR
	 JMP DONE		; DONE
	DSZ POSTCNT		; NOT DONE...WAIT
	 JMP WAIT

DONE:	JMP 0 3			; RETURN

POSTTIME:	5000.		; ABOUT 50 MS.
POSTCNT:	0
ETHEROUTPUT:	1


;-----------------------------------------------------------------------------
.INITETHEROUT:
;-----------------------------------------------------------------------------
	LDA 2 pEOBUF		; OUTPUT BUFFER
	LDA 0 PEEKER		; PEEKER,,0
	LDA 1 @EHLOC		; 0,,US
	ADD 1 0
	STA 0 ether.ds,2	; PEEKER,,US
	LDA 0 TYPE		; PACKET TYPE
	STA 0 ether.type,2
	MKONE 0 0
	STA 0 peek.type,2
	MKZERO 0 0
	STA 0 peek.string,2	; STRING LENGTH = 0
	JMP 0 3

PEEKER:		376B7		; PEEK ADDRESS,,0
TYPE:		402		; PEEK PACKET TYPE

;-----------------------------------------------------------------------------
.PACKCHAR:	; PACK 7 BIT CHARACTER IN AC1 INTO OUTPUT BUFFER
;-----------------------------------------------------------------------------
	STA 3 PCRET		; RETURN
	LDA 2 pEOBUF		; OUTPUT BUFFER
	LDA 0 STRINGOFF
	ADD 0 2
	LDA 0 0 2		; ->BCPL STRING
	LDA 3 C400
	ADD 3 0			; INCREMENT BYTE COUNT
	STA 0 0 2
	MOVS 0 0
	LDA 3 RIGHTMASK
	ANDZR 3 0		; AC0=WRD OFFS, CRY='PUT IN RIGHT BYTE'
	ADD 0 2			; CAN'T CARRY
	LDA 0 0 2		; TARGET WORD
	LDA 3 LEFTMASK
	MOV# 0 0 SNC		; LEFT OR RIGHT?
	 MOVS 0 0		; LEFT
	AND 3 0
	ADD 1 0 SNC		; ADD CAN'T CARRY
	 MOVS 0 0
	STA 0 0 2
	JMP @PCRET

STRINGOFF:	peek.string
C400:		400
PCRET:		0
RIGHTMASK:	377
LEFTMASK:	177400

	.END