/*----------------------------------------------------------------------*/
/*									*/
/*	ul.s    	+++ upload core image from 8086 +++	       	*/
/*									*/
/* Phase zero of this program loads phase one into memory.		*/
/* Phase one uploads memory in packets.					*/
/*									*/
/*									*/
/* 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
        MAXUPL	=   0200	| max packet size
        MAXADDR	=   0xf3ff	| high address
        STACKSIZE   =	10	| stack size

|	offsets into frame where various values are stored
	BASE	=   -2		| base address fo upload from
	LENGTH	=   -4	| length of packet
	CHKSUM	=   -6	| checksum
	BYTES	=   -10	| number of bytes in a packet

|	various characters and values
	SOH	=   0x2f
	ACK	=   0171
	NAK	=   0156
	ESC	=   033
        STOPC	=   023	| stop character
        STARTC	=   021	| start character
	ZERO	=   0
	TYPE	=   3		| and int $TYPE will return to the monitor
|
|
| Phase 0: move phase 1 into memory just below phase 0, writing out those
|   	   bytes along the way, and allowing for STACKSIZE bytes between
|	   phasees 0 and 1.
|
| AX contains addr of byte just below start of Phase 0
|
        mov     bx,ax
|
|	move STACKSIZE stack bytes out from just below phase 0
|
        mov     cx,#STACKSIZE
mvstk:
        mov     dx,#STATUS
        in			| poll for transmit ready
        andb    al,#TXRDY
        je      mvstk		| jump if status not transmit ready
|
        mov     dx,#DATA
        mov     ax,(bx)
        out			| output byte from memory
|
        dec     bx
        dec     cx
        jne     mvstk
|
	int	TYPE		| return to 8086 monitor
|
|	bring in phase1 backwards, a byte at a time, and place it in memory
| 	after writing that memory out.
|	CX contains LENGTH in bytes of phase 1
|
start:  
        mov	dx,#STATUS
afull1:	
        in	            | wait for input character ready
	andb	al,#RCRDY
	je	afull1

afull2:	in		    | wait for output character ready
	andb	al,#TXRDY
	je	afull2

|       output the character in location specified by bx
|	put the input character into loc spec by bx
|
	mov	dx,#DATA
        mov     ax,(bx)
        out			| output byte
	in			| input byte
	movb	(bx),al		| replace byte in memory with new byte
|
	dec	bx
	dec	cx
	jnz	start
|
	int	TYPE		| return to 8086 monitor
	inc 	bx		| bx points to phase1
|	jmp	(bx)		| jump to phase1 (upld)
| 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: form packets from memory and write them out until all of memory
|	   has been uploaded (up to place where phase1 resides) or until
| 	   LENGTH bytes have been uploaded.
|
| CX contains the address to start uploading at
| AX contains the number of bytes to upload
| SP contains the address of the byte just below phase 0

upld: 
        mov     dx,bx
        dec     dx		| byte just below phase 1
	mov     bx,sp
	mov	sp,#MAXADDR	| move stack ptr to high memory
        mov     BASE(bx),cx
        mov     LENGTH(bx),ax
|
        cmp     dx,BASE(bx)	| is dx >= BASE ?
        jae     pk		| if so then upload bytes
        call    sendnak		| if not then send NAK and quit
        int     TYPE		| return to 8086 monitor

pk:   
        call    sendack		| indicates that packet(s) are to follow
|
|	compare the number of bytes in memory from base to phase1 with the
|	length of bytes to be uploaded. If length is longer (indicating that
|	ending address is beyond the start of phase1) then replace length 
|	with that number of bytes. (No need to upload past the start of
|	phase1)
|
        mov     cx,dx
        sbb     cx,BASE(bx)
        cmp     LENGTH(bx),cx
        jbe     pkloop
        mov     LENGTH(bx),cx
|
pkloop: 
	mov	ax,#ZERO	| LENGTH == 0 => all done
	cmp	ax,LENGTH(bx)
	je	nomore

        mov     cx,LENGTH(bx)
        cmp     cx,#MAXUPL	| compare length to MAXUPL, if length is <=
				| MAXUPL then jump to enough, otherwise put
				| MAXUPL into bytes
        jbe     enough
|
        mov     cx,#MAXUPL	| move MAXUPL into BYTES
        mov     BYTES(bx),cx
        jmp     check

enough: 
        mov     cx,LENGTH(bx)	| move length into bytes
        mov     BYTES(bx),cx

check:
        sub     LENGTH(bx),cx	| subtract packet size (bytes) from length
|
| format and send a packet
|
retry:
        call    sendpack
        mov     dx,BYTES(bx)
	shr	dx,*1		|so dx counts words instead of bytes
        mov     cx,BASE(bx)
|
send:
        mov     TEMPB,bx
        mov     bx,cx
        movb    al,(bx)		| move byte at base addr out
	inc	bx
	movb 	ah,(bx)		| move next byte out
        mov     bx,TEMPB
        inc     cx		| increment base addr by one word
	inc	cx
        call    putwsum		| output the word in ax
        dec     dx
        jg      send

        mov     ax,CHKSUM(bx)
        call    putw
|
ackloop:			| wait for ACK or NAK
        call    rawgetc
        cmpb    al,#NAK
        je      retry		| try again if NAK received
l:	cmpb    al,#ACK
        jne     ackloop
|
        mov     BASE(bx),cx	| got ACK, move new base addr into BASE
        jmp     pkloop		| go send next packet
|
nomore:				| send packet of length 0 and quit
	mov	BYTES(bx),#ZERO
        call    sendpack
        mov     ax,CHKSUM(bx)
        call    putw
        int     TYPE		| return to 8086 monitor
|
|	send SOH, zero out checksum, send length of packet
|	and its base address
|
sendpack:
        mov     ax,#SOH
        call    rawputc
        mov     CHKSUM(bx),#ZERO
        mov     ax,BYTES(bx)
        call    putwsum
        mov     ax,BASE(bx)
        call    putwsum
        ret
|
|	output a word after adding it to the checksum
|
putwsum:
        add     CHKSUM(bx),ax
putw:				| output a word low byte first
        call    putc
        mov	TEMPA,ax
	xchg	al,ah
        call    putc
	mov	ax,TEMPA
        ret
|
|	output a character escaping it if it is SOH or ESC
|
putc:	
        cmpb    al,#SOH
        je      sendesc
        cmpb    al,#ESC
        jne     notesc
sendesc:
        mov     TEMPB,ax
        mov     ax,#ESC
        call    rawputc
        mov     ax,TEMPB
notesc:
        call    rawputc
        ret
|
|	output a character
|
rawputc:
        mov     TEMPA,ax
        mov     TEMPD,dx
|
        mov     dx,#STATUS
        in			| poll for character
        andb    al,#RCRDY
        mov     ax,TEMPA
        je      sendc		| jump to sendc if there was no character
|
        mov     dx,#DATA
        in
        cmp     ax,#STOPC	| is it a stop character?
        mov     ax,TEMPA
        jne     sendc
        mov     TEMPA,ax
|
|	input characters until a start character is seen, then 
|	go on to sendc
|
stoploop:
        mov     dx,#STATUS
        in
        andb    al,#RCRDY
        je      stoploop
|
        mov     dx,#DATA
        in
|
        cmp     ax,#STARTC
        jne     stoploop
        mov     ax,TEMPA
|
sendc:
        mov     TEMPA,ax
loopc:
        mov     dx,#STATUS
        in		    | poll for transmit ready
        andb    al,#TXRDY
        je      loopc
|
        mov     ax,TEMPA
        mov     dx,#DATA
        out
        mov     dx,TEMPD
        ret
|
|
rawgetc:			| get a character
        mov     TEMPD,dx
loopr:
        mov     dx,#STATUS
        in			| poll for character
        andb    al,#RCRDY
        je      loopr
|
        mov     dx,#DATA
        in
        mov     dx,TEMPD
        ret
|
|
sendnak:
        mov     dx,#STATUS
        in			| poll for transmit ready
        andb    al,#TXRDY
        je      sendnak
|
        mov     ax,#NAK
        mov     dx,#DATA
        out
        ret
|
|
sendack:
	mov	TEMPD,dx
        mov     dx,#STATUS
loopa:  in			| poll for transmit ready
        andb    al,#TXRDY
        je      loopa
|
        mov     ax,#ACK
        mov     dx,#DATA
        out
	mov	dx,TEMPD
        ret
|
|
|
|
.data
TEMPA:	.word	0
TEMPB:	.word	0
TEMPC:	.word	0
TEMPD:	.word	0
