Skip to content

Woohoo – 12MHz and 57600 Baud

November 26, 2017


So this is a bit of a rough collection of stuff but it does hang together and work. The video shows the xmodem bootloader operating at 57600 baud which seems pretty remarkable – god knows it’s quick.

The serial monitor is not much improved but I stuck the bootloader on the front of it. The bootloader and monitor are in a narrow ROM that fits below the NVRAM memory on the membership card. The ROM is addressed at 0 so it gets control first. It calls the bootloader which attempts to download a new program to the RAM at 0x8000 and jump to it. If there’s no xmodem sender present the bootloader jumps to the RAM which hopefully has a program already loaded. I can get to my monitor program by using a terminal program to send a character while the bootloader is looking for an xmodem response.

The code block below contains my bootloader/monitor, the xmodem receiver (derived from Mike Riley’s XR, the bitbang serial routines, and the python xmodem sender. The python routine is only special in that it toggles the RTS line connected to the membership card RUN pin to restart on demand.

The gallery below shows how the narrow ROM fits under the RAM slot on the membership card. The ROM and a lot of the info and encouragement to get it going came from Herb Johnson.

I would point out that the address lines going to the narrow slot are scrambled relative to the wide slot. I would say that if you have some fixed thing to put in a ROM using that slot is ok but if you are as crappy a programmer as I am and need to reprogram it a dozen times you should rent some tiny fingers before you start.

UPDATE: Lee Hart apparently has redone the CPU board to make the faster oscillator and descramble the address lines – great that he keeps the design fresh – I’ll be testing it soon. I’m not sure it’s orderable yet but soon I’m sure.

//VserialNW.c - serial demo program
//17-11-21 adapted to use makeit.bat for setting options
#include <olduino.h>
#include <nstdlib.h>
#define putc(x) putcser(x)
unsigned char getcser();
#define getc() getcser()
void putcser(unsigned char);
#include <dumper.c>
#define EOT 4
#define REGADDR (unsigned int *)0xFF00 //where the registers are stored on reset
#define CODEADDR (unsigned char *)0x8000 //address where code is loaded
void regdump(unsigned int* data){
	unsigned int i;
	for(i=0;i<16;i++){
		if (0==(i%4)) printf("\nR%cx ",i);
		printf("%x ",*data++);
	}
	printf("\n");
}
void dispatch(unsigned char * addr){
	asm(" cpy2 r0,r12\n"	//copy target address to R0
		" sex 0\n"			//x register=0
		" sep 0\n"			//and pass control
	);
}
int gethexit(unsigned char cin){ //returns the corresponding hex value for 0-f, -1 otherwise
	if ((cin>='0') && (cin<='9')){
		return cin-'0';
	}else if ((cin>='a') & (cin<='f')){
		return cin-'a'+10;
	}else{
		return -1;
	}
}

int XR(unsigned char *); //xmodem receiver
int bootload(){
	int ret=XR(CODEADDR);
	if (ret==EOT){
		dispatch(CODEADDR);
	} else if(ret=='T'){//timeout flag
		dispatch(CODEADDR);
	} else{
		printf("Interrupt - starting monitor\n");
	}
	return 0;
}

void main(){
	unsigned char cin='?';
	unsigned char seqop=0x7b, reqop=0x7a, brop=0x30;
	unsigned char * addr=0;
	int ret;
	unsigned int caddr=0;
	int hexval;
	asm(" seq\n"); //make sure Q is high to start
	bootload();//try the loader
	printf("\nSerial Monitor Here - CODEADDR is %x. Baudrate 57600\n",CODEADDR);
	while(1){
		printf("> ");
		cin=getc();
		hexval=gethexit(cin);
		while(hexval>=0){//accumulate address entries - non hex digit characters will return -1
			printf("%c",cin);
			caddr*=16;caddr+=hexval;
			cin=getc();
			hexval=gethexit(cin);
		}
		switch (cin){
			case 'x': //xmodem receive
				printf("\nCalling XR in 2 sec\n",ret);
				delay(2000);
				ret=XR(addr);
				printf("XR returns %x\n",ret);
				if (ret==EOT){
					dump(addr,256);
				} else if(ret=='T'){//timeout flag
					printf("Timeout - no transfer\n");
				} else{
					printf("Interrupt - no transfer\n");
				}
				break;
			case '\r':
				printf("->%x\n",caddr);
				addr=(unsigned char *)caddr;caddr=0;
				dump(addr,16);
				break;
			case '?':			//display memory at addr
				printf("?\n");
				dump(addr,16);
				break;
			case '!':			//alter memory at addr
				printf("!\n");
				*addr=seqop;*(addr+1)=reqop;*(addr+2)=brop;*(addr+3)=(unsigned char)((unsigned int)addr&255); //poke in a loop
				dump(addr,16);
				break;
			case 'g':			//go to program at addr (rp=0)
				printf("g\n");
				dispatch(addr);
				break;
			case 'r':
				printf("r\n");
				regdump(REGADDR);
				break;
			case '+':
				printf("+\n");
				addr+=16;
				dump(addr,16);
				break;
			case '-':
				printf("-\n");
				addr-=16;
				dump(addr,16);
				break;
			default:
				printf("%c/%cx unrecognized\n",cin,cin);
				break;
		}
	}
}

void includeser2(){
	asm("BAUDRATE EQU 	57600\n");
	asm(" include xrwjrT3.inc\n");
	asm(" include serwjrT3.inc\n");
}

#include <olduino.c>
#include <nstdlib.c>
void saveregs(){asm("SAVEREGS: EQU 1\n");}
********************XRWJRT3.inc follows
NAK:	EQU 0x15
SOH:	EQU 0x01
EOT:	EQU 0x04
ACK:	EQU 0x06
CAN:	EQU 0x18
Rrcv:	EQU 8
Rsnd:	EQU 9
blksize:	EQU 128
; 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 =EOT for success, 'T' for timeout, or ffxx where xx is the first char received if other than SOH or EOT

	align 64
_XR:	ldaD	Rsnd,serout
	ldaD    Rrcv,serinT
	ld2z	R15	;clear the return code


initNAK: ldi    NAK	; need to send NAK to start
	sep     Rsnd
	sep     Rrcv  	; wait for next incoming character
	bnf     ckeot	;continue if no timeout

	ldi     NAK	; resend NAK to start
      	sep     Rsnd
      	sep     Rrcv    ; wait for next incoming character
        bnf     ckeot	;continue if no timeout

	ldi     NAK	; resend NAK to start
      	sep     Rsnd
      	sep     Rrcv    ; wait for next incoming character
        bnf     ckeot	;continue if no timeout

	ldi	'T'	;set return value to 'T'
	plo	R15
	cretn

filelp:    ;receive address is in R12

;begining of block read. returns to filelp or exits to filedn   				
           sep     Rrcv               ; wait for next incoming character(will not time out)

ckeot:    plo	   R15		; save char received
	   xri     EOT          ; check for EOT
           lbz     filedn       ; jump if so
           glo	   R15		;
           xri	   SOH		; check for SOH   
           lbnz	   interrupt	; interrupted transmission - return interrupting character

	   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
           cretn	           	; and return to caller - R15 contains EOT

interrupt:    
           ldi     CAN                  ; invalid char received - try to cancel the session
           sep     Rsnd
           ldi	   0xff			;make sure R15 isn't 0
           phi     R15
           cretn	           	; and return to caller - R15 contains interrupting character


; *******************************************************************
; *** 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.         ***
; *******************************************************************
; *********************************************************************
; *** 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
******************serWJRT3.inc follows
;bit-bang Serial routines adapted from Josh Bensadon's VELFbios-v3.1.asm
;https://groups.yahoo.com/neo/groups/cosmacelf/files/Member-JoshBensadon/
;Transmit Byte via Q connected to RS232 driver
;call via sep, returns via sep R3
;Byte to send in D
;Destroys r14
;17-12-08 this version times out on the first call only - approx .6 sec
;----------------------------------------------------------------------
 	IFNDEF 	CPUSPEED
CPUSPEED EQU 4000000
 	ENDIF
 	IFNDEF 	BAUDRATE
BAUDRATE EQU 9600
 	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

	align 128
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,CPUSPEED,20,2,{EXPAND}
	br .txcloop	;9.5    loop back to send next bit
.txcret: ghi r14		;7
	bitdelay BAUDRATE,CPUSPEED,16,2
	seq		;11.5 stop bit
	bitdelay BAUDRATE,CPUSPEED,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  approx .6 sec - scales with CPU speed as much as possible
toct	set  (CPUSPEED/1000000)*24
	if toct>255
toct set 255
	endif
	ldi toct
	phi 14
	plo 14
.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
.serinN: bn3 .serinN	;serial input without timeout	
.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,CPUSPEED,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,CPUSPEED,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  .serinN	;for next time - only timeout on first call
;
serinN equ .serinN
_getcser:
	ldad Rrcv,serinN
	sep Rrcv
	plo R15
	ldi 0
	phi R15
	cretn
_putcser:
	ldad Rsnd,serout
	glo R12
	sep Rsnd
	cretn
	
***************Python XMODEM Sender xmboot.py follows
#xmbootb.py xmodem sender for the 1802 olduino
from __future__ import print_function
import sys
import logging
logging.basicConfig()
import serial
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
from xmodem import XMODEM, CRC
from time import sleep
import os
if len(sys.argv)>1:
    filename=sys.argv[1]
else:
    filename="a.bin"
fileSize=os.path.getsize(filename)
print ("File Size is",fileSize)
xpect=(fileSize/128)

def getc(size, timeout=1):
    return port.read(size)
xcount=0
xprog=0
def putc(data, timeout=1):
    global xcount,xprog
    port.write(data)
    if (len(data)==128): # if it's a block
    	xcount=xcount+1
    	newprog=(xcount*50)/xpect
    	for x in range(newprog-xprog):
            sys.stdout.write("#")
        sys.stdout.flush()
        xprog=newprog
    sleep(0.001) # give device time to send ACK

#Main program starts here - define the serial port, set RTS off, then open it
port = serial.Serial(parity=serial.PARITY_NONE,
                     bytesize=serial.EIGHTBITS,
                     stopbits=serial.STOPBITS_ONE,timeout=5,xonxoff=0,
                     rtscts=0,dsrdtr=0,baudrate=57600)
port.rts=False
port.port='COM3'
port.open()
port.rts=True
sleep(0.1)
port.rts=False
#open the file to be loaded
stream = open(filename,'rb')
sleep(0.2) #give olduino a chance to get Q under control
port.reset_input_buffer() # clear any accumulated garbage
#port.read(1) #ditch the 1st char - always seems to be 0

#transfer the file
result=XMODEM(getc, putc).send(stream, quiet = 1)

stream.close()
port.close()

if result:
    print ("\ntransfer successful")
    sleep(.25)
else:
    print ("\ntransfer unsuccessful")
    x=raw_input("press enter to continue...");	

***************Python xmodem sender follows
#xmbootb.py xmodem sender for the 1802 olduino
from __future__ import print_function
import sys
import logging
logging.basicConfig()
import serial
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
from xmodem import XMODEM, CRC
from time import sleep
import os
if len(sys.argv)>1:
    filename=sys.argv[1]
else:
    filename="a.bin"
fileSize=os.path.getsize(filename)
print ("File Size is",fileSize)
xpect=(fileSize/128)

def getc(size, timeout=1):
    return port.read(size)
xcount=0
xprog=0
def putc(data, timeout=1):
    global xcount,xprog
    port.write(data)
    if (len(data)==128): # if it's a block
    	xcount=xcount+1
    	newprog=(xcount*50)/xpect
    	for x in range(newprog-xprog):
            sys.stdout.write("#")
        sys.stdout.flush()
        xprog=newprog
    sleep(0.001) # give device time to send ACK

#Main program starts here - define the serial port, set RTS off, then open it
port = serial.Serial(parity=serial.PARITY_NONE,
                     bytesize=serial.EIGHTBITS,
                     stopbits=serial.STOPBITS_ONE,timeout=5,xonxoff=0,
                     rtscts=0,dsrdtr=0,baudrate=57600)
port.rts=False
port.port='COM3'
port.open()
port.rts=True
sleep(0.1)
port.rts=False
#open the file to be loaded
stream = open(filename,'rb')
sleep(0.2) #give olduino a chance to get Q under control
port.reset_input_buffer() # clear any accumulated garbage
#port.read(1) #ditch the 1st char - always seems to be 0

#transfer the file
result=XMODEM(getc, putc).send(stream, quiet = 1)

stream.close()
port.close()

if result:
    print ("\ntransfer successful")
    sleep(.25)
else:
    print ("\ntransfer unsuccessful")
    x=raw_input("press enter to continue...");

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: