/*----------------------------------------------------------------------*/
/*									*/
/*	dl.s    	+++ load programs into 8086 +++	         	*/
/*									*/
/* Phase zero of this program downloads phase one into high memory.	*/
/* Phase one downloads the user program into the appropriate place	*/
/* in memory. 								*/
/*									*/
/*									*/
/* Authors:								*/
/*      F. J. Newbery							*/
/*      K. L. Rives                                                     */
/*	Purdue University/CS Deptartment				*/
/*      January, 1984 - March, 1984                                     */
/*									*/
/* (c) Copyright, 1982, All rights reserved.				*/
/*									*/
/*									*/
/*----------------------------------------------------------------------*/
	RCRDY=0002	| receive ready
	TXRDY=0001	| transmit ready
	DATA=0xD8	| data port
	STATUS=0xDA	| status port
	PACKSIZE=0x80	| max size of packet
	FRAMESIZE=0420	| size of packet buffer

|	offsets into frame where various values are stored
	BSSLEN=-2	| bss length
	DELAY=-4 	| delay before autostart
	PSTART=-6	| address to start user program at
	PACKBUF=-12	| address of the packet buffer
	BASEADDR=-14	| base address to download to
	LENGTH=-16	| length of a packet

|	various characters and values
	SOH=0x2f
	ACK=0171
	NAK=0156
	ESC=033
	TYPE=3		| an int #TYPE will return to the monitor
|
|
| Phase 0: download phase 1 backwards and stuff it into the location
| 	   pointed to by BX
|
| BX is the address where phase 1 is places (high memory)
| CX is the number of bytes of phase 1 to download
|
|
start:  mov	dx,#STATUS 	| poll for a character to input
afull:	in
	andb	al,#RCRDY
	je	afull		| jump if status was not receive ready
|
|	input the character and put into loc spec by bx
|
	mov	dx,#DATA
	in
	movb	(bx),al
	dec	bx
	dec	cx
	jnz	start		| get the next character if cx != 0
|
|	set sp to byte right below phase one
|
	mov	sp,bx
	int	TYPE		| return to 8086 monitor
        inc     bx		| bx points to phase 1
|	jmp	(bx)		| jump to phase 1 
| the assembler cannot generate code for this (it seems) so I will
| hack it in.
	.byte	0xff
	.byte	0xe3
        .even
	.byte	0xff
	.byte	0xff
|
|
| Phase 1: Get a packet, put it into packet buffer, move it into memory,
|          and send an ACK. Send a NAK if something goes wrong and the
|          packet will be resent. Do this until a packet of length zero is
|          encountered. Zero out bss and quit.
|
| AX is the bss length
| DX is the pstart
| SP points to the byte just below phase 1
|
|
phase1: 
        mov	bx,sp
	sbb	sp,#FRAMESIZE
	mov	BSSLEN(bx),ax
	mov	PSTART(bx),dx
	mov	PACKBUF(bx),sp
|
|	get a character until SOH is found
retry: 	call	rawgetc
| 	character now in ax
	cmpb	al,#SOH
	jnz	retry
|
	call	getwsum		| get base address where packet will be put
	mov	BASEADDR(bx),ax
|
	call	getwsum		| get length of packet 
	mov	LENGTH(bx),ax
|
	mov	cx,#PACKSIZE
	cmp	cx,ax		| compare length to max packsize
	jl	sendnak		| send a nak if length is too big
|
|	read data words into the packet buffer on the stack
|
	mov	dx,ax
        cmp     dx,*0	| is the packet length zero?
	jz	getsum		| yes -- skip over reading of packet
|
	mov	TEMPB,bx
	mov	cx,PACKBUF(bx)
	mov	bx,cx
|
|	read words and put into packet buffer (bx) until length (dx) is zero
|
l1:	call	getwsum
	mov 	(bx),ax
	inc	bx		| increment bx by 2 bytes (1 word)
	inc	bx
	dec	dx
	cmp	dx,*0
	jg	l1
	mov	bx,TEMPB
|
|	Read and check checksum. The negative of the checksum will
|	be sent. It is input, added to the checksum and then checked
|	to see if it is zero. Copy packet from packet buffer into 
|	memory.
|
getsum: call	getwsum
	test	SUM,*0
	je	copypack
|
|	invalid packet -- send #NAK and retry
|
sendnak:
	movb	al,#NAK
	call	rawputc
	jmp	retry
|
|	valid packet, copy into memory from packet buffer.
|
copypack:
	mov	cx,BASEADDR(bx)	| place at which to put packet
	mov	dx,LENGTH(bx)	| length of packet
	mov	STACKB,bx
	mov	bx,PACKBUF(bx)
|
	cmp	dx,*0	| send ACK if length was zero
	je	sendack
|
|	move packet from packet buffer to mamory at base address
|
l0:	mov	ax,(bx)
|
	mov	TEMPB,bx
	mov	bx,cx
	mov	(bx),ax		| move word into memory at cx
	mov	bx,TEMPB
|
	inc	bx		| increment bx and cx by 2 bytes (1 word)
	inc	bx
	inc	cx
	inc	cx		
	dec	dx
|
	jnz	l0
|
|	everything is OK, send ACK
|
sendack:
	mov	bx,STACKB
	movb	al,#ACK
	call	rawputc
|
|	if the length was zero then all done, otherwise get next packet
|
	cmp	LENGTH(bx),*0
	jz	10$
	jmp	retry
10$:
|
|	zero out bss - if there is any
|
	mov	cx,BSSLEN(bx)
	cmp	cx,*0
	je	l4
|
	mov	TEMPB,bx
	mov	bx,BASEADDR(bx)
|
l3:	mov	dx,*0
	mov	(bx),dx
	inc	bx
	dec	cx
	cmp	cx,*0
	jnz	l3
	mov	bx,TEMPB
l4:
|
|	(may want to take this out later)
|	return control to the iAPX monitor 
|
|
	int	TYPE		| return to 8086 monitor

|	start program
|
	add	bx,*PSTART
|
|	jmp	(bx)	
| the assembler cannot generate code for this (it seems) so I will
| hack it in.
	.byte	0xff
	.byte	0xe3

|
|
|	getwsum - get a word and add into the checksum
|
getwsum:
	call 	getw
	add	SUM,ax
	ret
|
|	getw - get a word from the line
|
getw: 	call 	getc		| get low order byte
	mov	cx,ax
	call	getc		| get high order byte
	xchg	al,ah		| switch high and low of ax
	xorb	al,al
	xorb	ch,ch
	or	ax,cx		| combine ah and cl to form word
	ret
|
|	getc - get a character, honor #ESCing
|
getc: 	call 	rawgetc		| get a character
	cmpb	al,#ESC		| is it an escape?
	jne	l5
	call 	rawgetc		| get the real one
l5:	ret
|
|	rawgetc - get a character from the line
|
rawgetc:
	mov	TEMPD,dx
|
	mov	dx,#STATUS
afull2:	in			| poll for char
	andb	al,#RCRDY
	je	afull2
|
	mov	dx,#DATA
	in			| read char
|
	mov	dx,TEMPD	| restore d reg
	ret
|
|rawputc - put a character on the line
|
rawputc:
	mov	TEMPD,dx
	mov	TEMPA,ax
|
	mov	dx,#STATUS
afull3:	in	 		| poll for transmit character	
	andb	al,#TXRDY
	je	afull3
|
	mov	dx,#DATA
	mov	ax,TEMPA
	out			| write out the char
|
	mov	dx,TEMPD
	ret
|
|
|
|
|
	.data
|
TEMPA:	.word	0
TEMPB:	.word	0
TEMPC:	.word	0
TEMPD:	.word	0
STACKB:	.word	0
SUM:	.word	0
