Skip to content

Xmodem Transfer With Timeout

July 20, 2017

The reason for playing with xmodem (and the narrow rom for that matter) is to develop a bootloader that runs over serial so i can get rid of the avr on the olduino board and have the 1802/1806 stand on its own.  A bootloader needs to check to see if there’s anything to load and, if not, jump to the program that’s already loaded in the non-volatile memory.  That amounts to doing a timeout on the serial line after sending the first NAK to start the xmodem sequence.

I have this working although I’m not happy with the code. It turned out to be easy enough to put a timeout into the serin routine.  It just counts R14 down from 0 til it wraps around as in the code below.  It started out as a 4 instruction loop so 65K*4*16 cycles or around 1 second at 4MHZ.  I stuck a couple more tests for the start bit in bringing it to 6 instructions or 1.5 sec at 4MHZ and reducing latency at the same time.  Once I actually start working with host sender i’ll fine tune it. If the start bit doesn’t show up before the time delay pops, serinT sets the DF flag and returns.

serinT:			;serial input with timeout of 65535*6*16 machine cycles - approx 1.5 sec at 4MHZ
	ld2Z R14	;R14 is timeout loop counter
.rxcw:	b3 .okgo	;check for start bit after each instruction
	dec 14
	b3 .okgo	;check for start bit after each instruction
	ghi 14
	b3 .okgo	;check for start bit after each instruction
	bnz .rxcw
;here we've had a timeout - set DF and return
	ldi 1
	shr
	sep R3		;return
	br  serinT	;for next time

The xmodem receiver is checking for the DF flag at the beginning of each block and, if it sees a timeout it 0’s the return address and quits.  In the C test mule this just reports the failure.  I’m not happy because: a) the code seems ugly and b) I don’t really want to time out part way through a bootload and jump to a half-loaded program.

	   ldi     NAK                 ; need to send NAK to start
           sep     Rsnd
filelp:    ;receive address is in R12, length goes in R11
;begining of block read. returns to filelp or exits to filedn(or quits for timeout)   				
           sep     Rrcv               ; wait for next incoming character
           bnf     .ckeot		;continue if no timeout
	   ldaD    R15,0		;set return value to 0
  	   ldi 'T'
	   trc
	   cretn

.ckeot:    smi     EOT              ; check for EOT

Anyway, it works for now and maybe I’ll get smarter with the actual bootloader.
UPDATE: I was thinking this might be less ugly if I did the timeout test in the xmodem routine rather than in the serin code. I looked at it a bit though and it might work better but the code would actually be harder to understand.

#include <olduino.h>
#include <nstdlib.h>
#include <cpu1802spd4port7.h>
int XR(unsigned char *);
void dump(unsigned char* data, unsigned int len){
	unsigned int i=0;
	printf("dumping %d bytes at %x",len,data);
	for(i=0;i<len;i++){
		if (0==(i%8)) printf("\n%x ",data);
		printf("%cx ",*data++);
	}
	printf("\n");
}
void check(unsigned char* data, unsigned int len){
	unsigned int blk,i=0;
	unsigned char csum=0;
	printf("checking %d bytes at %x\n",len,data);
	for (blk=0;blk<len/128;blk++){
		csum=0;
		for (i=0;i<128;i++){
			csum+=*data;
			data++;
		}
		printf("block %d, checksum %cx\n",blk,csum);
	}
}
void main(){
	int ret;
	asm(" seq\n"); //make sure Q is high to start
	delay(500); //long enough to notice
	printf("Calling XR\n",ret);
	ret=XR((unsigned char *)0x7000);
	printf("XR returns %x\n",ret);
	if (ret){
		dump((unsigned char *)0x7000,ret-0x7000);
		check((unsigned char *)0x7000,ret-0x7000);
	} else{
		printf("Timeout - no transfer\n");
	}
	while(1);
}
void includeser(){
	asm(" include xrwjrT.asm");
}
#include <olduino.c>
#include <nstdlib.c>

*************************ASM file follows*************************
NAK:	EQU 0x15;'N'
SOH:	EQU 0x01;'S'
EOT:	EQU 0x04;'T'
ACK:	EQU 0x06;'K'
Rrcv:	EQU 8
Rsnd:	EQU 9
blksize:	EQU 128
trc:	MACRO
	dec 2
	str 2
	out 7
	ENDM
; XMODEM receiver based on xr.asm by Michael H Riley and serial routines by Josh Bensadon   
; See bottom of file for full acknowledgements and links.
; On entry R12 points to memory where received data will go
; On exit R15 has the last byte written
	align 64
_XR:	   ldaD	   Rsnd,serout
	   ldaD    Rrcv,serinT
	ldi '<'
	trc 
	   ldi     NAK                 ; need to send NAK to start
           sep     Rsnd
filelp:    ;receive address is in R12, length goes in R11

;begining of block read. returns to filelp or exits to filedn   				
           sep     Rrcv               ; wait for next incoming character
           bnf     .ckeot		;continue if no timeout
	   ldaD    R15,0		;set return value to 0
  	   ldi 'T'
	   trc
	   cretn

.ckeot:    smi     EOT              ; check for EOT
           lbz     filedn           ; jump if so

	   sep     Rrcv               ; read block number
           sep     Rrcv               ; read inverted block number

           ldi     blksize             ; 128 bytes to receive
           plo     r11

readlp:    sep     Rrcv               ; read data byte
           str     r12                  ; store into output buffer
           inc     r12                  ; point to next position
           dec     r11                  ; decrement block count
           glo     r11                  ; see if done
           bnz     readlp              ; loop back if not
;end of block read
           sep     Rrcv               ; read checksum byte


           ldi     ACK                  ; send an ACK
           sep     Rsnd
           lbr     filelp              ; loop back for more
filedn:    
           ldi     ACK                  ; acknowledge end of transmission
           sep     Rsnd
	   glo	   R12			;copy last address to return register
	   plo     R15
	   ghi     R12
	   phi     R15
	ldi '>'
	trc	   
           cretn	           	; and return to caller


; *******************************************************************
; *** This software is copyright 2005 by Michael H Riley          ***
; *** You have permission to use, modify, copy, and distribute    ***
; *** this software so long as this copyright notice is retained. ***
; *** This software may not be used in commercial applications    ***
; *** without express written permission from the author.         ***
; *******************************************************************
;**********************************************************************
;bit-bang Serial routines adapted from Josh Bensadon's VELFbios-v3.1.asm
;Transmit Byte via Q connected to RS232 driver
;call via SCRT
;Byte to send in D
;Destroys r14
;----------------------------------------------------------------------
 	IFNDEF 	LCC1802CPUSPEED
LCC1802CPUSPEED EQU 4000000
 	ENDIF
 	MACEXP ON
bitdelay: MACRO baudrate,cpuspeed,baseline,xreg
	rept ((cpuspeed/(baudrate*8)-baseline))/3
	NOP
	endm
	rept (((cpuspeed/(baudrate*8)-baseline)#3))>=1
	sex xreg
	endm
	ENDM
__BAUDRATE EQU 	9600
	align 64
serout:			;entry from assembly with char in D
	phi R14		;save char in R14.1
	ldi 9		;9 bits to transmit (1 start + 8 data)
	plo r14
	ghi R14
	shl		;set start bit
	rshr		;DF=0

.txcloop:
	bdf $+5		;10.5   jump to seq to send a 1 bit
	req		;11.5   send a 0 bit
	br $+5		;1      jump +5 to next shift
	seq		;11.5   send a 1 bit
	br $+2		;1      jump +2 to next shift (NOP for timing)
	rshr		;2      shift next bit to DF flag
	phi r14		;3      save D in r14.1
	DEC r14		;4      dec bit count
	glo r14		;5      get bit count
	bz .txcret	;6      if 0 then all 9 bits (start and data) sent
	ghi r14		;7      restore D
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2,{EXPAND}
	br .txcloop	;9.5    loop back to send next bit
.txcret: ghi r14		;7
	bitdelay __BAUDRATE,LCC1802CPUSPEED,16,2
	seq		;11.5 stop bit
	bitdelay __BAUDRATE,LCC1802CPUSPEED,4,2
	sep R3		;return 
	br serout	;reset for next time
;**********************************************************************
;serinT
;Receive Byte via EF3 connected to RS232 receiver
;Receives 8 bits
;call via sep
;Returns with Byte received in D, DF is set if the start bit is never seen
;Destroys r14
;----------------------------------------------------------------------
	align 64
serinT:			;serial input with timeout of 65535*6*16 machine cycles - approx 1.5 sec at 4MHZ
	ld2Z R14	;R14 is timeout loop counter
.rxcw:	b3 .okgo	;check for start bit after each instruction
	dec 14
	b3 .okgo	;check for start bit after each instruction
	ghi 14
	b3 .okgo	;check for start bit after each instruction
	bnz .rxcw
;here we've had a timeout - set DF and return
	ldi 1
	shr
	sep R3		;return
	br  serinT	;for next time
	
 .okgo:			;here we know the start bit is present
 	ldi 8		;start bit +7 bits from loop, last bit on returning
	plo r14
	ldi 0
	NOP		;delay to center samples

.rxcloop:
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2
	b3 $+6		;11.5 sample rx input bit
	ori 80h		;1
	br $+4		;2
	phi r14		;1
	phi r14		;2
	shr		;3
	phi r14		;4
	DEC r14		;5
	glo r14		;6
	bz .rxcret	;7
	ghi r14		;8
	br  .rxcloop	;9
.rxcret: ghi r14	;8
	ghi r14		;9
	bitdelay __BAUDRATE,LCC1802CPUSPEED,20,2
	b3 $+4		;11.5 sample last rx input bit
	ori 80h		; for a 1 bit
	adi 0		;clear the DF flag because no timeout
	sep R3		;return
	br  serinT	;for next time
	
_putcser:
	ldad Rsnd,serout
	glo R12
	sep Rsnd
	cretn
	
_getcser:
	ldad Rrcv,serinT
	sep Rrcv
	plo R15
	ldi 0
	phi R15
	cretn
; *********************************************************************
; *** xmodem code based on xr.asm copyright 2005 by Michael H Riley ***
; *** You have permission to use, modify, copy, and distribute      ***
; *** this software so long as this copyright notice is retained.   ***
; *** This software may not be used in commercial applications      ***
; *** without express written permission from the author.           ***
; *********************************************************************
;http://www.elf-emulation.com/software.html
;**********************************************************************
; The serial code is based on VELFbios-v3.1.asm by Josh Bensadon    ***
;**********************************************************************
;https://groups.yahoo.com/neo/groups/cosmacelf/files/Member-JoshBensadon/
	

I always want the last word so that wordpress doesn’t eat my code!

Advertisements

From → Uncategorized

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: