Shop OBEX P1 Docs P2 Docs Learn Events
Propeller II update - BLOG - Page 48 — Parallax Forums

Propeller II update - BLOG

14546485051223

Comments

  • cgraceycgracey Posts: 14,208
    edited 2012-11-03 22:14
    Prop II update...

    The ROM is now done. It spans from hub byte address $00000 to $00EFF, with $F00 to $1FFFF being RAM. The ROM contains the booter (SPI Flash or Serial) with SHA-256/HMAC authentication to facilitate code protection, and a serial (RX/TX) monitor which starts up if there's no authenticated loader to execute and no security key programmed into the first 128 fuses - you just hit <space> and it auto-bauds and gives you a prompt. The monitor could be used as a very simple development interface, where you just send text scripts to load code and start cogs.

    Below is the code for the monitor which uses the new hardware multi-threading to run concurrent auto-baud detection, serial input, and main monitor code:
    '********************************************************
    '*							*
    '*		Propeller II ROM Monitor		*
    '*							*
    '*		Version 0.1				*
    '*							*
    '*		11/01/2012				*
    '*							*
    '********************************************************
    
    CON
    
      branch1_	= 0
      branch2_	= branch1_	+ 31
      branch3_	= branch2_	+ 35
      hello_	= branch3_	+ 15
      error_	= hello_	+ 33
      hitspace_	= error_	+ 11
      spacesq_	= hitspace_	+ 10
      quotecr_	= spacesq_	+ 4
      help_		= quotecr_	+ 3
    
    
    DAT
    
    '********
    '* Data *
    '********
    
    branch1		byte	cmd_new,	0
    		byte	cmd_byte,	"Y"
    		byte	cmd_word,	"W"
    		byte	cmd_long,	"N"
    		byte	cmd_viewp,	"."
    		byte	cmd_search,	"/"
    		byte	cmd_enter,	":"
    		byte	cmd_map,	"M"
    		byte	cmd_clrp,	"L"
    		byte	cmd_setp,	"H"
    		byte	cmd_notp,	"T"
    		byte	cmd_offp,	"Z"
    		byte	cmd_getp,	"R"
    		byte	cmd_quit,	"Q"
    		byte	cmd_help,	"?"
    		byte	0			'31 bytes
    
    branch2		byte	cmd_view2,	0
    		byte	cmd_view2,	" "
    		byte	cmd_range,	"."
    		byte	cmd_search2,	"/"
    		byte	cmd_enter2,	":"
    		byte	cmd_watch,	"@"
    		byte	cmd_clkset,	"*"
    		byte	cmd_coginit,	"+"
    		byte	cmd_cogstop,	"-"
    		byte	cmd_clrp,	"L"
    		byte	cmd_setp,	"H"
    		byte	cmd_notp,	"T"
    		byte	cmd_offp,	"Z"
    		byte	cmd_getp,	"R"
    		byte	cmd_watchp,	"#"
    		byte	cmd_cfgp,	"|"
    		byte	cmd_setdacs,	"\"
    		byte	0			'35 bytes
    
    branch3		byte	cmd_view3,	0
    		byte	cmd_view3,	" "
    		byte	cmd_search3,	"/"
    		byte	cmd_fill,	":"
    		byte	cmd_move,	">"
    		byte	cmd_move,	"<"
    		byte	cmd_checksum,	"^"
    		byte	0			'15 bytes
    
    hello		byte	13,13,"=== Propeller II Monitor ===",13,13
    		byte	0			'33 bytes
    
    error		byte	"? - Help"
    		byte	13,7,0			'11 bytes
    
    hitspace	byte	"Hit SPACE",0		'10 bytes
    
    spacesq		byte	"  '",0			'4 bytes
    
    quotecr		byte	"'",13,0		'3 bytes
    
    help		byte	13,				"~HUB -",13
    		byte	"{adr{.adr}}",			"`View",13
    		byte	"{adr{.adr}}/{dat{ dat}}",	"`Search",13
    		byte	"{adr{.adr}}:dat{ dat}",	"`Enter",13
    		byte	"adr.adr[</>]adr",		"`Move",13
    		byte	"adr.adr^",			"`Checksum",13
    		byte	"adr@",				"`Watch",13
    		byte	"[Y/W/N]",			"`Byte/word/long",13
    		byte					"~COGS -",13
    		byte	"cog+pgm{+ptr}",		"`Start",13
    		byte	"cog-",				"`Stop",13
    		byte	"M",				"`Map",13
    		byte					"~PINS -",13
    		byte	"{pin}[H/L/T/Z/R]",		"`High/low/toggle/off/read",13
    		byte	"pin#",				"`Watch",13
    		byte	"pin|cfg",			"`Configure",13
    		byte	"dat\",				"`Set DACs",13
    		byte					"~MISC -",13
    		byte	"dat*",				"`Set clock",13
    		byte	"'",				"`Repeat",13
    		byte	"Q",				"`Quit",13
    		byte	0
    
    longs		long
    
    
    '*********
    '* Entry *
    '*********
    
    monitor		org
    
    rx_pin		reps	#$1F6-reserves,#1	'clear reserves (first 5 registers get reused)
    tx_pin		setinda	reserves
    tx_time		mov	inda++,#0
    
    v1		getptrb	base			'get data base pointer
    v2		sub	base,#longs << 2
    
    s0		long	0			'start of search data = 0/nop (s0..s1 get reused)
    
    		getptra	rx_pin			'get rx pin
    		shr	rx_pin,#8
    
    		getptra	tx_pin			'get tx pin
    		setp	tx_pin
    
    		jmptask	#baud_task,#%0010	'enable baud detector task
    		settask	#%%0101
    
    		tjz	period,#$		'wait for <space> to set period
    
    		jmptask	#rx_task,#%0100		'enable serial receiver task
    		settask	#%%0121
    
    		mov	wsize,#1		'init word size to byte
    		call	#set_size
    
    		pusha	#0			'init input line to <enter>
    
    		setptra	#hello_			'print hello message
    
    s1						'end of search data
    
    
    '*************
    '* Main Task *
    '*************
    
    message		call	#tx_string		'print hello/error message
    
    cmd_new		call	#rx_line		'get input line
    
    		call	#parse			'parse first term
    	if_z	tjz	x,#cmd_viewl		'if no hex and eol, view data
    		jmp	#cmd_go			'else, process command
    
    
    cmd_next_crlf	call	#tx_crlf		'print cr/lf
    cmd_next	addspa	#1			'skip chr
    
    cmd_loop	call	#parse			'parse next term
    cmd_go	if_nz	jmp	#cmd_hex		'if hex, branch
    		movd	pinx,#z			'pin update redirected to z
    		setptra	#branch1_		'not hex, vector by chr
    		call	#vector			'if returns, no match
    
    cmd_error	setptra	#error_			'print error message
    		jmp	#message
    
    
    cmd_hex		mov	v1,value		'hex, save v1
    		movd	pinx,#pin		'pin update okay
    		setptra	#branch2_		'vector by chr
    		call	#vector			'if returns, no match
    		jmp	#cmd_view2		'view data
    
    
    cmd_range	call	#parse_next		'hex., get hex
    	if_z	jmp	#cmd_viewp2		'if no hex, view data
    
    		mov	v2,value		'hex.hex, save v2
    		setptra	#branch3_		'vector by chr
    		call	#vector			'if returns, no match
    		jmp	#cmd_view3		'view data
    '
    '
    ' Byte/word/long data
    '
    cmd_byte	mov	wsize,#1	wz	'set byte mode, z=0
    cmd_word if_z	mov	wsize,#2	wz	'set word mode, z=0
    cmd_long if_z	mov	wsize,#4		'set long mode
    
    		call	#set_size
    
    		jmp	#cmd_next		'next command
    '
    '
    ' View data
    '
    cmd_viewl	mov	v2,#$F			'<enter> (eol), show line of data
    		call	#tx_range1
    		jmp	#cmd_new
    
    cmd_viewp	mov	v2,#$FF			'. (more), show page of data
    		call	#tx_range1
    		jmp	#cmd_next
    
    cmd_viewp2	mov	v2,#$FF			'addr. (more), show page of data
    		call	#tx_range2
    		jmp	#cmd_loop
    
    cmd_view2	mov	v2,v1			'addr, show unit of data
    cmd_view3	call	#tx_range		'addr.addr, show range of data
    		jmp	#cmd_loop
    '
    '
    ' Search
    '
    cmd_search	mov	v1,view			'/, search from view to end
    cmd_search2	mov	v2,amask		'addr/, search from address to end
    cmd_search3	call	#check_range		'addr.addr/, search range
    
    		mov	y,#0			'reset search size
    		setinda	s0			'point to search data
    		movs	enter_str,#enter_search	'set search mode
    		call	#parse_str		'get search string
    
    		sub	y,#1		wc	'get search size
    	if_nc	mov	ssize,y			'if 0, search old data again
    
    :start		setptra	v1			'start search, point to search address
    		setinda	s0			'point to search data
    		mov	x,#0			'reset word match counter
    
    :word		call	#rdxxxx			'get memory word
    		cmp	value,inda++	wz	'compare against search data word
    	if_z	jmp	#:match			'if word match, check if string match
    
    		add	v1,wsize		'word mismatch, advance search address
    		cmp	v1,v2		wz,wc	'at end of range?
    	if_be	jmp	#:start			'if not, start next search
    
    		mov	view,v1			'else, update view
    		and	view,amask
    		jmp	#cmd_loop		'next command
    
    :match		incmod	x,ssize		wc	'word match, increment match counter
    	if_nc	jmp	#:word			'if more words to match, compare next word
    
    		mov	v2,ssize		'got string match
    		shl	v2,shift		'v1 = start of found data
    		add	v2,v1			'v2 = end of found data
    		jmp	#cmd_view3		'show found data
    '
    '
    ' Enter data
    '
    cmd_enter2	mov	enter,v1		'addr:, set enter address
    		and	enter,amask		'trim enter address
    
    cmd_enter	mov	z,#0			':, reset fill count
    		call	#parse_enter		'parse and enter data
    
    		jmp	#cmd_loop		'next command
    '
    '
    ' Fill data
    '
    cmd_fill	call	#check_range		'addr.addr:, check range, z=words to fill
    		mov	enter,v1		'set initial enter address
    
    		call	#parse_enter		'parse and enter fill-pattern data (jumps to cmd_loop if fill complete)
    		cmp	enter,v1	wz	'any data entered?
    	if_z	jmp	#cmd_error		'if no data entered, error
    
    		mov	y,enter			'get end-of-fill-pattern address (current enter)
    		setptra	v1			'set start-of-fill-pattern address (initial enter)
    
    :loop		getptra	x			'get current-fill-pattern address
    		cmp	x,y		wz	'compare against end-of-fill-pattern address
    	if_z	setptra	v1			'if same, reset to start-of-fill-pattern address
    		call	#rdxxxx			'get fill-pattern word
    		call	#enter_data		'enter word (jumps to cmd_loop when fill complete)
    		jmp	#:loop			'loop to fill next word
    '
    '
    ' Move data
    '
    cmd_move	mov	y,x			'save ">"/"<"
    
    		call	#check_range		'check 1st address range, get number of words
    
    		call	#parse_hex		'get 2nd address
    
    		max	value,amask		'v1=1st, value=2nd, z=words, y=">"/"<"
    		and	value,amask
    
    		cmp	y,#"<"		wz	'if "<", swap v1 and value
    	if_z	mov	x,v1
    	if_z	mov	v1,value
    	if_z	mov	value,x			'v1=from, value=to, z=words
    
    		cmp	v1,value	wc	'if from < to, downward move
    	if_c	mov	x,z
    	if_c	shl	x,shift
    	if_c	add	v1,x
    	if_c	add	value,x
    	if_c	xor	rdxxxx,#%001_111110	'modify 'rdxxxx value,--ptra'
    	if_c	xor	wrxxxx,#%001_111110	'modify 'wrxxxx value,--ptrb'
    
    		setptra	v1			'set pointers
    		setptrb	value
    
    :loop		call	#rdxxxx			'move data
    		call	#wrxxxx
    		djnz	z,#:loop
    
    	if_c	xor	rdxxxx,#%001_111110	'restore 'rdxxxx value,ptra++'
    	if_c	xor	wrxxxx,#%001_111110	'restore 'wrxxxx value,ptrb++'
    
    		jmp	#cmd_loop		'next command
    '
    '
    ' Checksum
    '
    cmd_checksum	call	#check_range		'check range
    
    		setptra	v1			'sum bytes
    :loop		call	#rdxxxx
    		add	y,value
    		djnz	z,#:loop
    
    		mov	value,y			'print sum
    		mov	hsize,#8
    		call	#tx_hex
    
    		jmp	#cmd_next_crlf		'next command
    '
    '
    ' Watch
    '
    cmd_watchp	movs	rdxxxj,#rdxxxx_ret  wz	'set pin mode, z=0
    		mov	hsize,#1
    
    cmd_watch if_z	movs	rdxxxj,#rdxxxm		'set mem mode
    	  if_z	mov	hsize,wsize		'set hex size by word size
    	  if_z	shl	hsize,#1
    
    		call	#rdxxxp			'get initial value
    
    :loop		mov	z,value			'preserve value
    
    		call	#tx_hex			'print value
    		call	#tx_space		'print space
    
    :wait		call	#rx_check		'if key hit, exit
    	if_nz	jmp	#cmd_next_crlf
    
    		call	#rdxxxp			'get current value
    
    		cmp	value,z		wz	'if same, check again
    	if_z	jmp	#:wait
    
    		jmp	#:loop			'new value, loop
    '
    '
    ' Clkset
    '
    cmd_clkset	setptra	#hitspace_		'print hit-space message
    		call	#tx_string
    
    		clkset	v1			'set clk
    
    :wait		call	#rx			'wait for space
    		cmp	x,#" "		wz
    	if_nz	jmp	#:wait
    
    		jmp	#cmd_next_crlf		'next command
    '
    '
    ' Coginit
    '
    cmd_coginit	setcog	v1			'set cog
    
    		call	#parse_hex		'get program address
    
    		mov	y,value			'save program address
    		mov	value,#0		'clear pointer address
    
    		cmp	x,#"+"		wz	'if '+', get pointer address
    	if_z	call	#parse_hex
    
    		coginit	y,value			'do 'coginit program,pointer'
    
    		jmp	#cmd_loop		'next command
    '
    '
    ' Cogstop
    ' Quit
    '
    cmd_quit	cogid	v1			'quit
    
    cmd_cogstop	cogstop	v1			'stop cog
    
    		jmp	#cmd_next		'next command
    '
    '
    ' Map
    '
    cmd_map		mov	y,#7			'ready for 7..0
    
    cmd_map_loop	call	#tx_space		'print space
    		mov	x,y			'get cog status
    		cogid	x		wc
    cmd_map_c	cmp	x,y		wz
    	if_nc	mov	x,#"0"			'get 0/1/M chr
    	if_c	mov	x,#"1"
    	if_z	mov	x,#"M"
    		call	#tx			'print chr
    		sub	y,#1		wc
    	if_nc	jmp	#cmd_map_loop		'loop until done
    
    		jmp	#cmd_next_crlf		'next command
    '
    '
    ' Pin writes clrp/setp/notp/offp
    ' Pin read
    '
    cmd_clrp	movs	pinop,#$DA	wz	'clrp, z=0
    cmd_setp if_z	movs	pinop,#$DB	wz	'setp, z=0
    cmd_notp if_z	movs	pinop,#$D9	wz	'notp, z=0
    cmd_offp if_z	movs	pinop,#$D8	wz	'offp, z=0
    cmd_getp if_z	movs	pinop,#$D6		'getp, z=1
    
    pinx		mov	pin,v1			'if hex, get pin (d = pin/z)
    
    pinop		getp	pin		wc	'becomes clrp/setp/notp/offp/getp
    
    	if_z	jmp	#cmd_map_c		'if getp, show pin value
    
    		jmp	#cmd_next		'next command
    '
    '
    ' Pin configuration
    '
    cmd_cfgp	call	#parse_hex		'get configuration
    
    		setport	v1			'set pin port
    		decod5	v1			'get pin mask
    		cfgpins	v1,value		'configure pin
    
    		jmp	#cmd_loop		'next command
    '
    '
    ' Setdacs
    '
    cmd_setdacs	setdacs	v1			'set all four dacs with 8-bit values
    
    		jmp	#cmd_next		'next command
    '
    '
    ' Help
    '
    cmd_help	setptra	#help_			'print help message
    		call	#tx_string
    
    		jmp	#cmd_next_crlf		'next command
    
    
    '*************************
    '* Main Task Subroutines *
    '*************************
    '
    '
    ' Vector branch
    '
    vector		addptra	base			'add data base pointer
    
    vector_loop	rdbyte	z,ptra++		'get jump address
    vector_ret	tjz	z,#0			'if 0, no match found, return
    
    		rdbyte	y,ptra++		'get target
    		xor	y,x		wz	'compare to x
    	if_nz	jmp	#vector_loop		'if no match, loop
    
    		jmp	z			'match found, jump, y=0, z=1
    '
    '
    ' Check address range (v1..v2)
    '
    check_range	max	v1,amask		'trim v1
    		and	v1,amask
    
    		max	v2,amask		'trim v2
    		and	v2,amask
    
    		cmp	v2,v1		wc	'make sure v2 => v1
    	if_c	jmp	#cmd_error
    
    		mov	z,v2			'get number of words
    		sub	z,v1
    		shr	z,shift
    		add	z,#1
    
    check_range_ret	ret
    '
    '
    ' Set rdxxxx/wrxxxx and others by word size
    '
    set_size	test	wsize,#%010	wc	'set rdxxxx/wrxxxx by word size
    		setbc	rdxxxx,#26
    		setbc	wrxxxx,#26
    
    		test	wsize,#%100	wc
    		setbc	rdxxxx,#27
    		setbc	wrxxxx,#27
    
    		mov	shift,wsize		'set shift by word size
    		shr	shift,#1
    
    		mov	amask,wsize		'set amask by word size
    		sub	amask,#1
    		xor	amask,h0001FFFF
    
    		and	view,amask		'trim view
    		and	enter,amask		'trim enter
    
    set_size_ret	ret
    
    
    rdxxxp		getp	v1		wc	'read pin as "0" or "1"
    	if_nc	mov	value,#0
    	if_c	mov	value,#1
    rdxxxj		jmp	#rdxxxx_ret		'd = rdxxxx_ret/rdxxxm
    
    rdxxxm		setptra	v1			'read mem
    
    rdxxxx		rdbyte	value,ptra++		'rdbyte/rdword/rdlong
    rdxxxp_ret
    rdxxxx_ret	ret
    
    
    wrxxxx		wrbyte	value,ptrb++		'wrbyte/wrword/wrlong
    
    wrxxxx_ret	ret
    
    
    h0001FFFF	long	$0001FFFF
    '
    '
    ' Input line
    '
    rx_line		setspa	#0			'point to start of line
    
    		mov	x,#">"			'show prompt
    		call	#tx
    
    		call	#rx			'get first chr
    		cmp	x,#"'"		wz	'check for repeat
    	if_nz	jmp	#:first			'if not repeat, first chr
    
    :show		popar	x		wz	'repeat, show line
    	if_nz	call	#tx
    	if_nz	jmp	#:show
    		jmp	#:done
    
    
    :loop		call	#rx			'get next chr
    
    :first		cmp	x,#13		wz	'cr?
    	if_z	jmp	#:cr
    
    		cmp	x,#8		wz	'backspace?
    	if_nz	cmp	x,#127		wz
    	if_z	jmp	#:bs
    
    		cmp	x,#" "		wc	'visible chr?
    	if_nc	cmpr	x,#"~"		wc
    	if_c	jmp	#:loop
    
    		pusha	x			'visible chr, append to line
    		chkspa			wc	'overflow?
    	if_c	subspa	#1			'if overflow, back up
    	if_nc	call	#tx			'if not overflow, print chr
    		jmp	#:loop
    
    :bs		chkspa			wz	'backspace, line empty?
    	if_nz	pushar	x			'if not empty,
    	if_nz	call	#tx			'..print backspace
    	if_nz	call	#tx_space		'..print space
    	if_nz	popar	x			'..print backspace
    	if_nz	call	#tx
    	if_nz	subspa	#1			'..back up
    		jmp	#:loop
    
    :cr		pusha	#0			'cr, end line with 0
    
    :done		setspa	#0			'point to start of line
    
    tx_crlf		mov	x,crlf			'print cr/lf
    		call	#tx
    tx_crlf_ret
    rx_line_ret	ret
    
    
    crlf		long	1 << 18 + $0A << 10 + $0D
    '
    '
    ' Parse string of hex/text for enter/fill or search
    '
    parse_enter	movs	enter_str,#enter_data
    
    parse_str	call	#parse_next		'hex loop, check hex
    	if_nz	call	#enter_str		'if hex, enter value
    		cmp	x,#" "		wz	'check for space (more hex)
    	if_z	jmp	#parse_str		'if more hex, loop
    
    		cmp	x,#"'"		wz	'not hex, "'"?
    	if_nz	jmp	#parse_str_ret		'if not "'", done
    
    :text		addspa	#2			'text loop
    		popa	x			'get and point to next chr
    		cmp	x,#"'"		wz	'check for "'"
    	if_z	jmp	#parse_str		'if "'", back to hex
    		tjz	x,#parse_str_ret	'if eol, done
    		mov	value,x			'text chr
    		call	#enter_str		'enter chr
    		jmp	#:text			'loop
    parse_enter_ret
    parse_str_ret	ret
    
    
    enter_str	jmp	#enter_data		'jump to enter_data or enter_search
    
    enter_search	incmod	y,#s1-s0	wc	'search, check if search limit exceeded
    	if_c	jmp	#cmd_error		'if search limit exceeded, error
    		mov	inda++,value		'store value in search data
    		jmp	#enter_str_ret		'return
    
    enter_data	setptrb	enter			'enter/fill, get pointer
    		call	#wrxxxx			'store value in memory
    		getptrb	enter			'update pointer
    		djz	z,#cmd_loop		'if fill done, abort (don't return)
    enter_data_ret
    enter_str_ret	ret
    '
    '
    ' Parse hex
    '
    parse_hex	call	#parse_next		'try to parse hex
    	if_z	jmp	#cmd_error		'if no hex, error
    
    parse_hex_ret	ret
    '
    '
    ' Parse line (@spa), z=0 if hex (value)
    '
    parse_next	addspa	#1			'advance to next chr
    
    parse		mov	value,#0	wz	'z=1
    
    		call	#skip_spaces	wz	'skip any spaces (preserve z)
    
    :loop		popar	x			'get chr
    		call	#check_hex		'check hex
    	if_c	shl	value,#4		'if hex, append nibble and loop
    	if_c	or	value,x
    	if_c	jmp	#:loop		wz	'z=0
    
    		subspa	#1			'repoint to non-hex chr
    
    		call	#skip_spaces	wz	'skip any post-hex spaces (preserve z)
    
    		call	#check_hex		'check hex
    	if_c	popa	x			'if hex, back up to space chr
    
    		cmpr	x,#"a"-1	wc	'make non-hex chr uppercase
    	if_c	cmp	x,#"z"+1	wc
    	if_c	sub	x,#"a"-"A"
    parse_next_ret
    parse_ret	ret
    '
    '
    ' Skip spaces (@spa)
    '
    skip_spaces	popar	x			'skip space chr(s)
    		cmp	x,#" "		wz
    	if_z	jmp	#skip_spaces
    
    		subspa	#1			'back up to non-space chr
    
    skip_spaces_ret	ret			wz	'restore z
    '
    '
    ' Check hex (x), c=1 if hex (x)
    '
    check_hex	cmpr	x,#"0"-1	wc	'"0".."9" -> $0..$9
    	if_c	cmp	x,#"9"+1	wc
    	if_c	add	x,#"A"-"9"-1
    
    	if_nc	cmpr	x,#"A"-1	wc	'"A".."F" -> $A..$F
    	if_c	cmp	x,#"F"+1	wc
    	if_c	add	x,#"a"-"A"
    
    	if_nc	cmpr	x,#"a"-1	wc	'"a".."f" -> $A..$F
    	if_c	cmp	x,#"f"+1	wc
    	if_c	sub	x,#"a"-10
    
    check_hex_ret	ret
    '
    '
    ' Print range (v1..v2)
    '
    tx_range1	mov	v1,view			'view..view + v2
    tx_range2	and	v2,amask		'v1..v1 + v2
    		add	v2,v1
    
    tx_range	call	#check_range		'check range
    
    		mov	view,v1			'set address
    
    :line		mov	value,view		'print 5-digit address
    		mov	hsize,#5
    		call	#tx_hex
    
    		call	#tx_dspace		'print "- "
    
    		mov	x,wsize			'get number of words on line
    		rev	x,#32-5
    		mov	v1,z
    		max	v1,x
    
    		mov	v2,v1			'get number of ascii bytes on line
    		shl	v2,shift
    
    		sub	z,v1			'update number of words left
    
    		setptra	view			'print hex words
    :hex		call	#rdxxxx
    		mov	hsize,wsize
    		shl	hsize,#1
    		call	#tx_hex
    		call	#tx_space
    		djnz	v1,#:hex
    
    		setptra	#spacesq_		'print "  '"
    		call	#tx_string
    
    		setptra	view			'print ascii bytes
    :ascii		rdbyte	x,ptra++
    		cmp	x,#" "		wc	'visible chr?
    	if_nc	cmpr	x,#"~"		wc
    	if_c	mov	x,#"."			'substitute "." for non-visible chrs
    		call	#tx
    		djnz	v2,#:ascii
    
    		getptra	view			'update address
    
    		setptra	#quotecr_		'print "'" + cr
    		call	#tx_string
    
    		call	#rx_check		'check key hit
    	if_z	tjnz	z,#:line		'if no key hit and more words left, print another line
    tx_range1_ret
    tx_range2_ret
    tx_range_ret	ret
    '
    '
    ' Print string (@ptra)
    '
    tx_string	addptra	base			'add data base pointer
    
    tx_string_loop	rdbyte	x,ptra++		'get chr
    
    tx_string_ret	tjz	x,#0			'if 0, done
    
    		cmp	x,#"`"		wz	'long tab?
    	if_z	subr	y,#32-16
    	if_nz	cmp	x,#"~"		wz	'short tab?
    	if_z	add	y,#16
    :tab	if_z	call	#tx_space
    	if_z	djnz	y,#:tab
    	if_z	call	#tx_dspace
    	if_z	jmp	#tx_string_loop
    
    		cmp	x,#13		wz	'cr?
    	if_z	call	#tx_crlf
    	if_z	mov	y,#0
    
    	if_nz	call	#tx			'other?
    	if_nz	add	y,#1
    		jmp	#tx_string_loop
    '
    '
    ' Print hex (value)
    '
    tx_hex		mov	y,hsize			'pre-rotate to get 1st nibble in top
    		shl	y,#2
    		ror	value,y
    
    		mov	y,hsize			'print nibbles
    :loop		rol	value,#4
    		mov	x,value
    		call	#tx_nib
    		djnz	y,#:loop
    
    tx_hex_ret	ret
    '
    '
    ' Print "- "
    '
    tx_dspace	mov	x,dspace
    		jmp	#tx
    
    
    dspace		long	1 << 18 + " " << 10 + "-"
    '
    '
    ' Print space
    '
    tx_space	mov	x,#" "
    		jmp	#tx
    '
    '
    ' Print nibble (x)
    '
    tx_nib		and	x,#$F			'isolate nibble
    
    		cmp	x,#$A		wc	'alpha or numeric?
    	if_c	add	x,#"0"			'numeric
    	if_nc	add	x,#"A"-$A		'alpha
    '
    '
    ' Transmit chr (x)
    '
    tx		shl	x,#1			'insert start bit
    		setb	x,#9			'set stop bit
    
    		getcnt	tx_time			'get initial time
    
    :loop		add	tx_time,period		'add bit period to time
    		passcnt	tx_time			'loop until bit period elapsed
    		shr	x,#1		wc	'get next bit into c
    		setpc	tx_pin			'write c to tx pin
    		tjnz	x,#:loop		'loop until bits done
    tx_dspace_ret
    tx_space_ret
    tx_nib_ret
    tx_ret		ret
    '
    '
    ' Receive chr (x)
    '
    rx		call	#rx_check		'wait for rx chr
    	if_z	jmp	#rx
    
    rx_ret		ret
    '
    '
    ' Check receiver, z=0 if chr (x)
    '
    rx_check	or	rx_tail,#$80		'if start or rollover, reset tail
    
    		getspb	rx_temp		wz	'if head uninitialized, z=1
    	if_nz	cmp	rx_temp,rx_tail	wz	'if head-tail mismatch, byte ready, z=0
    
    	if_nz	getspa	rx_temp			'preserve spa
    	if_nz	setspa	rx_tail			'get tail
    	if_nz	popar	x			'get byte at tail
    	if_nz	getspa	rx_tail			'update tail
    	if_nz	setspa	rx_temp			'restore spa
    
    rx_check_ret	ret
    
    
    '************************
    '* Serial Receiver Task *
    '************************
    
    rx_task		chkspb			wz	'if start or rollover, reset head
    	if_z	setspb	#$80
    
    		mov	rx_bits,#9		'ready for 8 data bits + 1 stop bit
    
    		neg	rx_time,period		'get -0.5 period
    		sar	rx_time,#1
    
    		jp	rx_pin,#$		'wait for start bit
    
    		subcnt	rx_time			'get time + 0.5 period for initial 1.5 period delay
    
    :bit		rcr	rx_data,#1		'rotate c into byte
    		add	rx_time,period		'add 1 period
    		passcnt	rx_time			'wait for center of next bit
    		getp	rx_pin		wc	'read rx pin into c
    		djnz	rx_bits,#:bit		'loop until 8 data bits + 1 stop bit received
    
    		shr	rx_data,#32-8		'align byte
    		pushb	rx_data			'store byte at head, inc head
    
    		jmp	#rx_task		'wait for next byte
    
    
    '**********************
    '* Baud Detector Task *
    '**********************
    
    baud_task	movd	ctr,rx_pin		'set ctra to time rx pin states
    
    :loop		notb	ctr,#5		wc	'if 1,0 sample set, c=0
    		setctra	ctr			'($20 -> 10000001001 -> 1, 6x 0, 1x 1, 2x 0, 1)
    
    	if_nc	mov	limh,buff0		'if 1,0 sample set,
    	if_nc	shr	limh,#4			'..make window from 1st 0 (6x if $20)
    	if_nc	neg	liml,limh
    	if_nc	add	limh,buff0
    	if_nc	add	liml,buff0
    
    	if_nc	mov	comp,buff1		'if 1,0 sample set,
    	if_nc	mul	comp,#6			'..normalize 2nd 1 (1x if $20) to 6x
    	if_nc	cmpr	comp,limh	wc	'..check if within window
    	if_nc	cmp	comp,liml	wc
    
    	if_nc	mov	comp,buff2		'if 1,0 sample set,
    	if_nc	mul	comp,#3			'..normalize 2nd 0 (2x if $20) to 6x
    	if_nc	cmpr	comp,limh	wc	'..check if within window
    	if_nc	cmp	comp,liml	wc
    
    	if_nc	add	buff0,buff2		'if $20,
    	if_nc	shr	buff0,#3		'..compute period from 6x 0 and 2x 0
    	if_nc	mov	period,buff0		'..update period
    
    		mov	buff0,buff1		'scroll sample buffer
    		mov	buff1,buff2
    
    :wait		getcosa	buff2			'wait for next sample
    		tjnz	buff2,#:loop
    		jmp	#:wait
    
    
    ctr		long	%100_01001		'ctr configuration for timing low on rx pin
    
    
    '*************
    '* Variables *
    '*************
    
    reserves
    
    base		res	1			'main task
    x		res	1
    y		res	1
    z		res	1
    value		res	1
    view		res	1
    enter		res	1
    pin		res	1
    ssize		res	1
    hsize		res	1
    wsize		res	1
    shift		res	1
    amask		res	1
    
    rx_tail		res	1			'serial receiver task
    rx_temp		res	1
    rx_time		res	1
    rx_data		res	1
    rx_bits		res	1
    
    buff0		res	1			'baud detector task
    buff1		res	1
    buff2		res	1
    limh		res	1
    liml		res	1
    comp		res	1
    period		res	1
    
    


    Here is a conversation with it, from start-up:
    === Propeller II Monitor ===
    
    >?
    
                    - HUB -
    {adr{.adr}}                     - View
    {adr{.adr}}/{dat{ dat}}         - Search
    {adr{.adr}}:dat{ dat}           - Enter
    adr.adr[</>]adr                 - Move
    adr.adr^                        - Checksum
    adr@                            - Watch
    [Y/W/N]                         - Byte/word/long
                    - COGS -
    cog+pgm{+ptr}                   - Start
    cog-                            - Stop
    M                               - Map
                    - PINS -
    {pin}[H/L/T/Z/R]                - High/low/toggle/off/read
    pin#                            - Watch
    pin|cfg                         - Configure
    dat\                            - Set DACs
                    - MISC -
    dat*                            - Set clock
    '                               - Repeat
    Q                               - Quit
    
    >0.
    00000- 50 72 6F 70 65 6C 6C 65 72 20 49 49 20 20 76 31   'Propeller II  v1'
    00010- 45 FE C1 0D E3 B6 FC 0C 01 D0 7C 0C 01 D0 7C 0D   'E.........|...|.'
    00020- 01 D0 FC 80 1F D0 7C 62 01 EE FC 30 6D 0C A8 80   '......|b...0m...'
    00030- 01 D8 7C 0C 5A BE FC 1C 83 08 BD A0 5A BE FC 1C   '..|.Z.......Z...'
    00040- 83 08 BD 80 01 08 FD 28 FA FE FC A0 5A BE FC 1C   '.......(....Z...'
    00050- 01 D6 7C 62 24 00 64 1C B2 D6 7C 61 01 D6 FC 34   '..|b$.d...|a...4'
    00060- 0F FE FC F6 02 FF FC A0 08 FE 7C 86 52 D6 E8 A0   '..........|.R...'
    00070- 01 D6 7C 62 60 CE FC 1C B2 D6 7C 61 01 D6 FC 34   '..|b`.....|a...4'
    00080- 16 FE FC F6 2F 00 7C 1C 77 43 FC 0C 0D 04 FD 0C   '..../.|.wC......'
    00090- 69 04 BD 80 6A D4 3C FF 57 43 FC 0C 00 00 4C 1C   'i...j.<.WC....L.'
    000A0- 04 FE FC A0 DB B2 FC 0C DA B0 FC 0C 44 3E C0 0D   '............D>..'
    000B0- DA B2 FC 0C 01 FE 7C E1 01 D8 CC 27 DC AE FC 0C   '......|....'....'
    000C0- DB B0 FC 0C DA B0 FC 0C 25 FE FC F6 B2 E6 7C 0C   '........%.....|.'
    000D0- 6D FE BC A0 20 00 FD A0 5A BE E8 1C D6 AC D4 0D   'm... ...Z.......'
    000E0- DB B0 D4 0C DA B0 D4 0C 01 02 FD 34 32 00 FD F6   '...........42...'
    000F0- C1 02 7D 08 31 FE FC F6 40 0E C0 0D 77 00 04 E0   '..}.1...@...w...'
    >n
    >0.
    00000- 706F7250 656C6C65 49492072 31762020   'Propeller II  v1'
    00010- 0DC1FE45 0CFCB6E3 0C7CD001 0D7CD001   'E.........|...|.'
    00020- 80FCD001 627CD01F 30FCEE01 80A80C6D   '......|b...0m...'
    00030- 0C7CD801 1CFCBE5A A0BD0883 1CFCBE5A   '..|.Z.......Z...'
    00040- 80BD0883 28FD0801 A0FCFEFA 1CFCBE5A   '.......(....Z...'
    00050- 627CD601 1C640024 617CD6B2 34FCD601   '..|b$.d...|a...4'
    00060- F6FCFE0F A0FCFF02 867CFE08 A0E8D652   '..........|.R...'
    00070- 627CD601 1CFCCE60 617CD6B2 34FCD601   '..|b`.....|a...4'
    00080- F6FCFE16 1C7C002F 0CFC4377 0CFD040D   '..../.|.wC......'
    00090- 80BD0469 FF3CD46A 0CFC4357 1C4C0000   'i...j.<.WC....L.'
    000A0- A0FCFE04 0CFCB2DB 0CFCB0DA 0DC03E44   '............D>..'
    000B0- 0CFCB2DA E17CFE01 27CCD801 0CFCAEDC   '......|....'....'
    000C0- 0CFCB0DB 0CFCB0DA F6FCFE25 0C7CE6B2   '........%.....|.'
    000D0- A0BCFE6D A0FD0020 1CE8BE5A 0DD4ACD6   'm... ...Z.......'
    000E0- 0CD4B0DB 0CD4B0DA 34FD0201 F6FD0032   '...........42...'
    000F0- 087D02C1 F6FCFE31 0DC00E40 E0040077   '..}.1...@...w...'
    >y
    >0/'Propeller
    00000- 50 72 6F 70 65 6C 6C 65 72   'Propeller'
    >/
    005CF- 50 72 6F 70 65 6C 6C 65 72   'Propeller'
    >e00.
    00E00- 00 00 7C 1C 80 D4 FF 68 17 D6 FF 0E EA D7 17 86   '..|....h........'
    00E10- 16 D6 D7 0C A2 D4 57 0C 18 BC D7 0C 16 D4 D7 0C   '......W.........'
    00E20- A2 D6 57 0C 00 00 7C 1C 17 00 7C 0E A3 00 E9 0C   '..W...|...|.....'
    00E30- 09 DC FF A0 F5 D9 BF A4 01 D8 FF 38 BA 01 FC F8   '...........8....'
    00E40- 0C D8 FF 0C 01 DA FF 30 F5 D9 BF 80 0D D8 7F 0C   '.......0........'
    00E50- D6 00 7C 0D BC DD FF F6 18 DA FF 28 AB DA 7F 0C   '..|........(....'
    00E60- B5 01 7C 1C 00 B8 BF 54 25 B9 FF 0D F0 B8 7F 0C   '..|....T%.......'
    00E70- EF E5 8F A0 04 E4 CF 28 F2 E7 8F A4 EF E5 8F 80   '.......(........'
    00E80- EF E7 8F 80 F0 E9 8F A0 06 E8 CF 10 F2 E9 0F E1   '................'
    00E90- F3 E9 0F 85 F1 E9 8F A0 03 E8 CF 10 F2 E9 0F E1   '................'
    00EA0- F3 E9 0F 85 F1 DF 8F 80 03 DE CF 28 EF EB 8F A0   '...........(....'
    00EB0- F0 DF BF A0 F1 E1 BF A0 3A E2 FF 0C C5 E3 7F FA   '........:.......'
    00EC0- D9 01 7C 1C 89 00 00 00 00 00 00 00 9A 62 22 77   '..|..........b"w'
    00ED0- 20 43 6F 70 79 72 69 67 68 74 20 32 30 31 33 20   ' Copyright 2013 '
    00EE0- 20 50 61 72 61 6C 6C 61 78 2C 20 49 6E 63 2E 20   ' Parallax, Inc. '
    00EF0- 77 77 77 2E 70 61 72 61 6C 6C 61 78 2E 63 6F 6D   'www.parallax.com'
    >..
    00F00- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01000- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01010- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01020- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01030- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01040- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01050- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01060- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01070- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01080- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01090- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010A0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010B0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010C0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010D0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010E0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010F0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >1ff00.
    1FF00- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF10- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f00:1 2 3 4 5 6
    >f00.f0f
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    >f10:'Hello!' 77
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f00.f1f>f80
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f30.f7f:'abc
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61   'abcabcabcabcabca'
    00F40- 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62   'bcabcabcabcabcab'
    00F50- 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63   'cabcabcabcabcabc'
    00F60- 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61   'abcabcabcabcabca'
    00F70- 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62   'bcabcabcabcabcab'
    00F80- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >m
     0 0 0 0 0 0 0 M
    >6+1ec+1000
    >m
     0 1 0 0 0 0 0 M
    >6-
    >m
     0 0 0 0 0 0 0 M
    >
    
    


    I never got around to adding the SDRAM boot, as it was a lot of work just to get what's in there ironed out. Of the 3,840 ROM bytes, the monitor takes 2,384 bytes, which is a lot, but I think it's a really nice thing to have. Both the monitor and the SHA-256/HMAC programs can be executed independently from user application code and are very simple to operate.
  • Martin HodgeMartin Hodge Posts: 1,246
    edited 2012-11-03 23:00
    Pure genius!
  • SapiehaSapieha Posts: 2,964
    edited 2012-11-03 23:09
    Hi Chip.


    From that I assume You have now info on dedicated PIN's for -- Serial and SPI.

    Can Ypu post that so it be possible to made experimenting PCB for Propeller II.

    Ps. In my opinion -- bad decision on SD -- But that is life.


    cgracey wrote: »
    Prop II update...

    The ROM is now done. It spans from hub byte address $00000 to $00EFF, with $F00 to $1FFFF being RAM. The ROM contains the booter (SPI Flash or Serial) with SHA-256/HMAC authentication to facilitate code protection, and a serial (RX/TX) monitor which starts up if there's no authenticated loader to execute and no security key programmed into the first 128 fuses - you just hit <space> and it auto-bauds and gives you a prompt. The monitor could be used as a very simple development interface, where you just send text scripts to load code and start cogs.

    Below is the code for the monitor which uses the new hardware multi-threading to run concurrent auto-baud detection, serial input, and main monitor code:
    '********************************************************
    '*                            *
    '*        Propeller II ROM Monitor        *
    '*                            *
    '*        Version 0.1                *
    '*                            *
    '*        11/01/2012                *
    '*                            *
    '********************************************************
    
    CON
    
      branch1_    = 0
      branch2_    = branch1_    + 31
      branch3_    = branch2_    + 35
      hello_    = branch3_    + 15
      error_    = hello_    + 33
      hitspace_    = error_    + 11
      spacesq_    = hitspace_    + 10
      quotecr_    = spacesq_    + 4
      help_        = quotecr_    + 3
    
    
    DAT
    
    '********
    '* Data *
    '********
    
    branch1        byte    cmd_new,    0
            byte    cmd_byte,    "Y"
            byte    cmd_word,    "W"
            byte    cmd_long,    "N"
            byte    cmd_viewp,    "."
            byte    cmd_search,    "/"
            byte    cmd_enter,    ":"
            byte    cmd_map,    "M"
            byte    cmd_clrp,    "L"
            byte    cmd_setp,    "H"
            byte    cmd_notp,    "T"
            byte    cmd_offp,    "Z"
            byte    cmd_getp,    "R"
            byte    cmd_quit,    "Q"
            byte    cmd_help,    "?"
            byte    0            '31 bytes
    
    branch2        byte    cmd_view2,    0
            byte    cmd_view2,    " "
            byte    cmd_range,    "."
            byte    cmd_search2,    "/"
            byte    cmd_enter2,    ":"
            byte    cmd_watch,    "@"
            byte    cmd_clkset,    "*"
            byte    cmd_coginit,    "+"
            byte    cmd_cogstop,    "-"
            byte    cmd_clrp,    "L"
            byte    cmd_setp,    "H"
            byte    cmd_notp,    "T"
            byte    cmd_offp,    "Z"
            byte    cmd_getp,    "R"
            byte    cmd_watchp,    "#"
            byte    cmd_cfgp,    "|"
            byte    cmd_setdacs,    "\"
            byte    0            '35 bytes
    
    branch3        byte    cmd_view3,    0
            byte    cmd_view3,    " "
            byte    cmd_search3,    "/"
            byte    cmd_fill,    ":"
            byte    cmd_move,    ">"
            byte    cmd_move,    "<"
            byte    cmd_checksum,    "^"
            byte    0            '15 bytes
    
    hello        byte    13,13,"=== Propeller II Monitor ===",13,13
            byte    0            '33 bytes
    
    error        byte    "? - Help"
            byte    13,7,0            '11 bytes
    
    hitspace    byte    "Hit SPACE",0        '10 bytes
    
    spacesq        byte    "  '",0            '4 bytes
    
    quotecr        byte    "'",13,0        '3 bytes
    
    help        byte    13,                "~HUB -",13
            byte    "{adr{.adr}}",            "`View",13
            byte    "{adr{.adr}}/{dat{ dat}}",    "`Search",13
            byte    "{adr{.adr}}:dat{ dat}",    "`Enter",13
            byte    "adr.adr[</>]adr",        "`Move",13
            byte    "adr.adr^",            "`Checksum",13
            byte    "adr@",                "`Watch",13
            byte    "[Y/W/N]",            "`Byte/word/long",13
            byte                    "~COGS -",13
            byte    "cog+pgm{+ptr}",        "`Start",13
            byte    "cog-",                "`Stop",13
            byte    "M",                "`Map",13
            byte                    "~PINS -",13
            byte    "{pin}[H/L/T/Z/R]",        "`High/low/toggle/off/read",13
            byte    "pin#",                "`Watch",13
            byte    "pin|cfg",            "`Configure",13
            byte    "dat\",                "`Set DACs",13
            byte                    "~MISC -",13
            byte    "dat*",                "`Set clock",13
            byte    "'",                "`Repeat",13
            byte    "Q",                "`Quit",13
            byte    0
    
    longs        long
    
    
    '*********
    '* Entry *
    '*********
    
    monitor        org
    
    rx_pin        reps    #$1F6-reserves,#1    'clear reserves (first 5 registers get reused)
    tx_pin        setinda    reserves
    tx_time        mov    inda++,#0
    
    v1        getptrb    base            'get data base pointer
    v2        sub    base,#longs << 2
    
    s0        long    0            'start of search data = 0/nop (s0..s1 get reused)
    
            getptra    rx_pin            'get rx pin
            shr    rx_pin,#8
    
            getptra    tx_pin            'get tx pin
            setp    tx_pin
    
            jmptask    #baud_task,#%0010    'enable baud detector task
            settask    #%%0101
    
            tjz    period,#$        'wait for <space> to set period
    
            jmptask    #rx_task,#%0100        'enable serial receiver task
            settask    #%%0121
    
            mov    wsize,#1        'init word size to byte
            call    #set_size
    
            pusha    #0            'init input line to <enter>
    
            setptra    #hello_            'print hello message
    
    s1                        'end of search data
    
    
    '*************
    '* Main Task *
    '*************
    
    message        call    #tx_string        'print hello/error message
    
    cmd_new        call    #rx_line        'get input line
    
            call    #parse            'parse first term
        if_z    tjz    x,#cmd_viewl        'if no hex and eol, view data
            jmp    #cmd_go            'else, process command
    
    
    cmd_next_crlf    call    #tx_crlf        'print cr/lf
    cmd_next    addspa    #1            'skip chr
    
    cmd_loop    call    #parse            'parse next term
    cmd_go    if_nz    jmp    #cmd_hex        'if hex, branch
            movd    pinx,#z            'pin update redirected to z
            setptra    #branch1_        'not hex, vector by chr
            call    #vector            'if returns, no match
    
    cmd_error    setptra    #error_            'print error message
            jmp    #message
    
    
    cmd_hex        mov    v1,value        'hex, save v1
            movd    pinx,#pin        'pin update okay
            setptra    #branch2_        'vector by chr
            call    #vector            'if returns, no match
            jmp    #cmd_view2        'view data
    
    
    cmd_range    call    #parse_next        'hex., get hex
        if_z    jmp    #cmd_viewp2        'if no hex, view data
    
            mov    v2,value        'hex.hex, save v2
            setptra    #branch3_        'vector by chr
            call    #vector            'if returns, no match
            jmp    #cmd_view3        'view data
    '
    '
    ' Byte/word/long data
    '
    cmd_byte    mov    wsize,#1    wz    'set byte mode, z=0
    cmd_word if_z    mov    wsize,#2    wz    'set word mode, z=0
    cmd_long if_z    mov    wsize,#4        'set long mode
    
            call    #set_size
    
            jmp    #cmd_next        'next command
    '
    '
    ' View data
    '
    cmd_viewl    mov    v2,#$F            '<enter> (eol), show line of data
            call    #tx_range1
            jmp    #cmd_new
    
    cmd_viewp    mov    v2,#$FF            '. (more), show page of data
            call    #tx_range1
            jmp    #cmd_next
    
    cmd_viewp2    mov    v2,#$FF            'addr. (more), show page of data
            call    #tx_range2
            jmp    #cmd_loop
    
    cmd_view2    mov    v2,v1            'addr, show unit of data
    cmd_view3    call    #tx_range        'addr.addr, show range of data
            jmp    #cmd_loop
    '
    '
    ' Search
    '
    cmd_search    mov    v1,view            '/, search from view to end
    cmd_search2    mov    v2,amask        'addr/, search from address to end
    cmd_search3    call    #check_range        'addr.addr/, search range
    
            mov    y,#0            'reset search size
            setinda    s0            'point to search data
            movs    enter_str,#enter_search    'set search mode
            call    #parse_str        'get search string
    
            sub    y,#1        wc    'get search size
        if_nc    mov    ssize,y            'if 0, search old data again
    
    :start        setptra    v1            'start search, point to search address
            setinda    s0            'point to search data
            mov    x,#0            'reset word match counter
    
    :word        call    #rdxxxx            'get memory word
            cmp    value,inda++    wz    'compare against search data word
        if_z    jmp    #:match            'if word match, check if string match
    
            add    v1,wsize        'word mismatch, advance search address
            cmp    v1,v2        wz,wc    'at end of range?
        if_be    jmp    #:start            'if not, start next search
    
            mov    view,v1            'else, update view
            and    view,amask
            jmp    #cmd_loop        'next command
    
    :match        incmod    x,ssize        wc    'word match, increment match counter
        if_nc    jmp    #:word            'if more words to match, compare next word
    
            mov    v2,ssize        'got string match
            shl    v2,shift        'v1 = start of found data
            add    v2,v1            'v2 = end of found data
            jmp    #cmd_view3        'show found data
    '
    '
    ' Enter data
    '
    cmd_enter2    mov    enter,v1        'addr:, set enter address
            and    enter,amask        'trim enter address
    
    cmd_enter    mov    z,#0            ':, reset fill count
            call    #parse_enter        'parse and enter data
    
            jmp    #cmd_loop        'next command
    '
    '
    ' Fill data
    '
    cmd_fill    call    #check_range        'addr.addr:, check range, z=words to fill
            mov    enter,v1        'set initial enter address
    
            call    #parse_enter        'parse and enter fill-pattern data (jumps to cmd_loop if fill complete)
            cmp    enter,v1    wz    'any data entered?
        if_z    jmp    #cmd_error        'if no data entered, error
    
            mov    y,enter            'get end-of-fill-pattern address (current enter)
            setptra    v1            'set start-of-fill-pattern address (initial enter)
    
    :loop        getptra    x            'get current-fill-pattern address
            cmp    x,y        wz    'compare against end-of-fill-pattern address
        if_z    setptra    v1            'if same, reset to start-of-fill-pattern address
            call    #rdxxxx            'get fill-pattern word
            call    #enter_data        'enter word (jumps to cmd_loop when fill complete)
            jmp    #:loop            'loop to fill next word
    '
    '
    ' Move data
    '
    cmd_move    mov    y,x            'save ">"/"<"
    
            call    #check_range        'check 1st address range, get number of words
    
            call    #parse_hex        'get 2nd address
    
            max    value,amask        'v1=1st, value=2nd, z=words, y=">"/"<"
            and    value,amask
    
            cmp    y,#"<"        wz    'if "<", swap v1 and value
        if_z    mov    x,v1
        if_z    mov    v1,value
        if_z    mov    value,x            'v1=from, value=to, z=words
    
            cmp    v1,value    wc    'if from < to, downward move
        if_c    mov    x,z
        if_c    shl    x,shift
        if_c    add    v1,x
        if_c    add    value,x
        if_c    xor    rdxxxx,#%001_111110    'modify 'rdxxxx value,--ptra'
        if_c    xor    wrxxxx,#%001_111110    'modify 'wrxxxx value,--ptrb'
    
            setptra    v1            'set pointers
            setptrb    value
    
    :loop        call    #rdxxxx            'move data
            call    #wrxxxx
            djnz    z,#:loop
    
        if_c    xor    rdxxxx,#%001_111110    'restore 'rdxxxx value,ptra++'
        if_c    xor    wrxxxx,#%001_111110    'restore 'wrxxxx value,ptrb++'
    
            jmp    #cmd_loop        'next command
    '
    '
    ' Checksum
    '
    cmd_checksum    call    #check_range        'check range
    
            setptra    v1            'sum bytes
    :loop        call    #rdxxxx
            add    y,value
            djnz    z,#:loop
    
            mov    value,y            'print sum
            mov    hsize,#8
            call    #tx_hex
    
            jmp    #cmd_next_crlf        'next command
    '
    '
    ' Watch
    '
    cmd_watchp    movs    rdxxxj,#rdxxxx_ret  wz    'set pin mode, z=0
            mov    hsize,#1
    
    cmd_watch if_z    movs    rdxxxj,#rdxxxm        'set mem mode
          if_z    mov    hsize,wsize        'set hex size by word size
          if_z    shl    hsize,#1
    
            call    #rdxxxp            'get initial value
    
    :loop        mov    z,value            'preserve value
    
            call    #tx_hex            'print value
            call    #tx_space        'print space
    
    :wait        call    #rx_check        'if key hit, exit
        if_nz    jmp    #cmd_next_crlf
    
            call    #rdxxxp            'get current value
    
            cmp    value,z        wz    'if same, check again
        if_z    jmp    #:wait
    
            jmp    #:loop            'new value, loop
    '
    '
    ' Clkset
    '
    cmd_clkset    setptra    #hitspace_        'print hit-space message
            call    #tx_string
    
            clkset    v1            'set clk
    
    :wait        call    #rx            'wait for space
            cmp    x,#" "        wz
        if_nz    jmp    #:wait
    
            jmp    #cmd_next_crlf        'next command
    '
    '
    ' Coginit
    '
    cmd_coginit    setcog    v1            'set cog
    
            call    #parse_hex        'get program address
    
            mov    y,value            'save program address
            mov    value,#0        'clear pointer address
    
            cmp    x,#"+"        wz    'if '+', get pointer address
        if_z    call    #parse_hex
    
            coginit    y,value            'do 'coginit program,pointer'
    
            jmp    #cmd_loop        'next command
    '
    '
    ' Cogstop
    ' Quit
    '
    cmd_quit    cogid    v1            'quit
    
    cmd_cogstop    cogstop    v1            'stop cog
    
            jmp    #cmd_next        'next command
    '
    '
    ' Map
    '
    cmd_map        mov    y,#7            'ready for 7..0
    
    cmd_map_loop    call    #tx_space        'print space
            mov    x,y            'get cog status
            cogid    x        wc
    cmd_map_c    cmp    x,y        wz
        if_nc    mov    x,#"0"            'get 0/1/M chr
        if_c    mov    x,#"1"
        if_z    mov    x,#"M"
            call    #tx            'print chr
            sub    y,#1        wc
        if_nc    jmp    #cmd_map_loop        'loop until done
    
            jmp    #cmd_next_crlf        'next command
    '
    '
    ' Pin writes clrp/setp/notp/offp
    ' Pin read
    '
    cmd_clrp    movs    pinop,#$DA    wz    'clrp, z=0
    cmd_setp if_z    movs    pinop,#$DB    wz    'setp, z=0
    cmd_notp if_z    movs    pinop,#$D9    wz    'notp, z=0
    cmd_offp if_z    movs    pinop,#$D8    wz    'offp, z=0
    cmd_getp if_z    movs    pinop,#$D6        'getp, z=1
    
    pinx        mov    pin,v1            'if hex, get pin (d = pin/z)
    
    pinop        getp    pin        wc    'becomes clrp/setp/notp/offp/getp
    
        if_z    jmp    #cmd_map_c        'if getp, show pin value
    
            jmp    #cmd_next        'next command
    '
    '
    ' Pin configuration
    '
    cmd_cfgp    call    #parse_hex        'get configuration
    
            setport    v1            'set pin port
            decod5    v1            'get pin mask
            cfgpins    v1,value        'configure pin
    
            jmp    #cmd_loop        'next command
    '
    '
    ' Setdacs
    '
    cmd_setdacs    setdacs    v1            'set all four dacs with 8-bit values
    
            jmp    #cmd_next        'next command
    '
    '
    ' Help
    '
    cmd_help    setptra    #help_            'print help message
            call    #tx_string
    
            jmp    #cmd_next_crlf        'next command
    
    
    '*************************
    '* Main Task Subroutines *
    '*************************
    '
    '
    ' Vector branch
    '
    vector        addptra    base            'add data base pointer
    
    vector_loop    rdbyte    z,ptra++        'get jump address
    vector_ret    tjz    z,#0            'if 0, no match found, return
    
            rdbyte    y,ptra++        'get target
            xor    y,x        wz    'compare to x
        if_nz    jmp    #vector_loop        'if no match, loop
    
            jmp    z            'match found, jump, y=0, z=1
    '
    '
    ' Check address range (v1..v2)
    '
    check_range    max    v1,amask        'trim v1
            and    v1,amask
    
            max    v2,amask        'trim v2
            and    v2,amask
    
            cmp    v2,v1        wc    'make sure v2 => v1
        if_c    jmp    #cmd_error
    
            mov    z,v2            'get number of words
            sub    z,v1
            shr    z,shift
            add    z,#1
    
    check_range_ret    ret
    '
    '
    ' Set rdxxxx/wrxxxx and others by word size
    '
    set_size    test    wsize,#%010    wc    'set rdxxxx/wrxxxx by word size
            setbc    rdxxxx,#26
            setbc    wrxxxx,#26
    
            test    wsize,#%100    wc
            setbc    rdxxxx,#27
            setbc    wrxxxx,#27
    
            mov    shift,wsize        'set shift by word size
            shr    shift,#1
    
            mov    amask,wsize        'set amask by word size
            sub    amask,#1
            xor    amask,h0001FFFF
    
            and    view,amask        'trim view
            and    enter,amask        'trim enter
    
    set_size_ret    ret
    
    
    rdxxxp        getp    v1        wc    'read pin as "0" or "1"
        if_nc    mov    value,#0
        if_c    mov    value,#1
    rdxxxj        jmp    #rdxxxx_ret        'd = rdxxxx_ret/rdxxxm
    
    rdxxxm        setptra    v1            'read mem
    
    rdxxxx        rdbyte    value,ptra++        'rdbyte/rdword/rdlong
    rdxxxp_ret
    rdxxxx_ret    ret
    
    
    wrxxxx        wrbyte    value,ptrb++        'wrbyte/wrword/wrlong
    
    wrxxxx_ret    ret
    
    
    h0001FFFF    long    $0001FFFF
    '
    '
    ' Input line
    '
    rx_line        setspa    #0            'point to start of line
    
            mov    x,#">"            'show prompt
            call    #tx
    
            call    #rx            'get first chr
            cmp    x,#"'"        wz    'check for repeat
        if_nz    jmp    #:first            'if not repeat, first chr
    
    :show        popar    x        wz    'repeat, show line
        if_nz    call    #tx
        if_nz    jmp    #:show
            jmp    #:done
    
    
    :loop        call    #rx            'get next chr
    
    :first        cmp    x,#13        wz    'cr?
        if_z    jmp    #:cr
    
            cmp    x,#8        wz    'backspace?
        if_nz    cmp    x,#127        wz
        if_z    jmp    #:bs
    
            cmp    x,#" "        wc    'visible chr?
        if_nc    cmpr    x,#"~"        wc
        if_c    jmp    #:loop
    
            pusha    x            'visible chr, append to line
            chkspa            wc    'overflow?
        if_c    subspa    #1            'if overflow, back up
        if_nc    call    #tx            'if not overflow, print chr
            jmp    #:loop
    
    :bs        chkspa            wz    'backspace, line empty?
        if_nz    pushar    x            'if not empty,
        if_nz    call    #tx            '..print backspace
        if_nz    call    #tx_space        '..print space
        if_nz    popar    x            '..print backspace
        if_nz    call    #tx
        if_nz    subspa    #1            '..back up
            jmp    #:loop
    
    :cr        pusha    #0            'cr, end line with 0
    
    :done        setspa    #0            'point to start of line
    
    tx_crlf        mov    x,crlf            'print cr/lf
            call    #tx
    tx_crlf_ret
    rx_line_ret    ret
    
    
    crlf        long    1 << 18 + $0A << 10 + $0D
    '
    '
    ' Parse string of hex/text for enter/fill or search
    '
    parse_enter    movs    enter_str,#enter_data
    
    parse_str    call    #parse_next        'hex loop, check hex
        if_nz    call    #enter_str        'if hex, enter value
            cmp    x,#" "        wz    'check for space (more hex)
        if_z    jmp    #parse_str        'if more hex, loop
    
            cmp    x,#"'"        wz    'not hex, "'"?
        if_nz    jmp    #parse_str_ret        'if not "'", done
    
    :text        addspa    #2            'text loop
            popa    x            'get and point to next chr
            cmp    x,#"'"        wz    'check for "'"
        if_z    jmp    #parse_str        'if "'", back to hex
            tjz    x,#parse_str_ret    'if eol, done
            mov    value,x            'text chr
            call    #enter_str        'enter chr
            jmp    #:text            'loop
    parse_enter_ret
    parse_str_ret    ret
    
    
    enter_str    jmp    #enter_data        'jump to enter_data or enter_search
    
    enter_search    incmod    y,#s1-s0    wc    'search, check if search limit exceeded
        if_c    jmp    #cmd_error        'if search limit exceeded, error
            mov    inda++,value        'store value in search data
            jmp    #enter_str_ret        'return
    
    enter_data    setptrb    enter            'enter/fill, get pointer
            call    #wrxxxx            'store value in memory
            getptrb    enter            'update pointer
            djz    z,#cmd_loop        'if fill done, abort (don't return)
    enter_data_ret
    enter_str_ret    ret
    '
    '
    ' Parse hex
    '
    parse_hex    call    #parse_next        'try to parse hex
        if_z    jmp    #cmd_error        'if no hex, error
    
    parse_hex_ret    ret
    '
    '
    ' Parse line (@spa), z=0 if hex (value)
    '
    parse_next    addspa    #1            'advance to next chr
    
    parse        mov    value,#0    wz    'z=1
    
            call    #skip_spaces    wz    'skip any spaces (preserve z)
    
    :loop        popar    x            'get chr
            call    #check_hex        'check hex
        if_c    shl    value,#4        'if hex, append nibble and loop
        if_c    or    value,x
        if_c    jmp    #:loop        wz    'z=0
    
            subspa    #1            'repoint to non-hex chr
    
            call    #skip_spaces    wz    'skip any post-hex spaces (preserve z)
    
            call    #check_hex        'check hex
        if_c    popa    x            'if hex, back up to space chr
    
            cmpr    x,#"a"-1    wc    'make non-hex chr uppercase
        if_c    cmp    x,#"z"+1    wc
        if_c    sub    x,#"a"-"A"
    parse_next_ret
    parse_ret    ret
    '
    '
    ' Skip spaces (@spa)
    '
    skip_spaces    popar    x            'skip space chr(s)
            cmp    x,#" "        wz
        if_z    jmp    #skip_spaces
    
            subspa    #1            'back up to non-space chr
    
    skip_spaces_ret    ret            wz    'restore z
    '
    '
    ' Check hex (x), c=1 if hex (x)
    '
    check_hex    cmpr    x,#"0"-1    wc    '"0".."9" -> $0..$9
        if_c    cmp    x,#"9"+1    wc
        if_c    add    x,#"A"-"9"-1
    
        if_nc    cmpr    x,#"A"-1    wc    '"A".."F" -> $A..$F
        if_c    cmp    x,#"F"+1    wc
        if_c    add    x,#"a"-"A"
    
        if_nc    cmpr    x,#"a"-1    wc    '"a".."f" -> $A..$F
        if_c    cmp    x,#"f"+1    wc
        if_c    sub    x,#"a"-10
    
    check_hex_ret    ret
    '
    '
    ' Print range (v1..v2)
    '
    tx_range1    mov    v1,view            'view..view + v2
    tx_range2    and    v2,amask        'v1..v1 + v2
            add    v2,v1
    
    tx_range    call    #check_range        'check range
    
            mov    view,v1            'set address
    
    :line        mov    value,view        'print 5-digit address
            mov    hsize,#5
            call    #tx_hex
    
            call    #tx_dspace        'print "- "
    
            mov    x,wsize            'get number of words on line
            rev    x,#32-5
            mov    v1,z
            max    v1,x
    
            mov    v2,v1            'get number of ascii bytes on line
            shl    v2,shift
    
            sub    z,v1            'update number of words left
    
            setptra    view            'print hex words
    :hex        call    #rdxxxx
            mov    hsize,wsize
            shl    hsize,#1
            call    #tx_hex
            call    #tx_space
            djnz    v1,#:hex
    
            setptra    #spacesq_        'print "  '"
            call    #tx_string
    
            setptra    view            'print ascii bytes
    :ascii        rdbyte    x,ptra++
            cmp    x,#" "        wc    'visible chr?
        if_nc    cmpr    x,#"~"        wc
        if_c    mov    x,#"."            'substitute "." for non-visible chrs
            call    #tx
            djnz    v2,#:ascii
    
            getptra    view            'update address
    
            setptra    #quotecr_        'print "'" + cr
            call    #tx_string
    
            call    #rx_check        'check key hit
        if_z    tjnz    z,#:line        'if no key hit and more words left, print another line
    tx_range1_ret
    tx_range2_ret
    tx_range_ret    ret
    '
    '
    ' Print string (@ptra)
    '
    tx_string    addptra    base            'add data base pointer
    
    tx_string_loop    rdbyte    x,ptra++        'get chr
    
    tx_string_ret    tjz    x,#0            'if 0, done
    
            cmp    x,#"`"        wz    'long tab?
        if_z    subr    y,#32-16
        if_nz    cmp    x,#"~"        wz    'short tab?
        if_z    add    y,#16
    :tab    if_z    call    #tx_space
        if_z    djnz    y,#:tab
        if_z    call    #tx_dspace
        if_z    jmp    #tx_string_loop
    
            cmp    x,#13        wz    'cr?
        if_z    call    #tx_crlf
        if_z    mov    y,#0
    
        if_nz    call    #tx            'other?
        if_nz    add    y,#1
            jmp    #tx_string_loop
    '
    '
    ' Print hex (value)
    '
    tx_hex        mov    y,hsize            'pre-rotate to get 1st nibble in top
            shl    y,#2
            ror    value,y
    
            mov    y,hsize            'print nibbles
    :loop        rol    value,#4
            mov    x,value
            call    #tx_nib
            djnz    y,#:loop
    
    tx_hex_ret    ret
    '
    '
    ' Print "- "
    '
    tx_dspace    mov    x,dspace
            jmp    #tx
    
    
    dspace        long    1 << 18 + " " << 10 + "-"
    '
    '
    ' Print space
    '
    tx_space    mov    x,#" "
            jmp    #tx
    '
    '
    ' Print nibble (x)
    '
    tx_nib        and    x,#$F            'isolate nibble
    
            cmp    x,#$A        wc    'alpha or numeric?
        if_c    add    x,#"0"            'numeric
        if_nc    add    x,#"A"-$A        'alpha
    '
    '
    ' Transmit chr (x)
    '
    tx        shl    x,#1            'insert start bit
            setb    x,#9            'set stop bit
    
            getcnt    tx_time            'get initial time
    
    :loop        add    tx_time,period        'add bit period to time
            passcnt    tx_time            'loop until bit period elapsed
            shr    x,#1        wc    'get next bit into c
            setpc    tx_pin            'write c to tx pin
            tjnz    x,#:loop        'loop until bits done
    tx_dspace_ret
    tx_space_ret
    tx_nib_ret
    tx_ret        ret
    '
    '
    ' Receive chr (x)
    '
    rx        call    #rx_check        'wait for rx chr
        if_z    jmp    #rx
    
    rx_ret        ret
    '
    '
    ' Check receiver, z=0 if chr (x)
    '
    rx_check    or    rx_tail,#$80        'if start or rollover, reset tail
    
            getspb    rx_temp        wz    'if head uninitialized, z=1
        if_nz    cmp    rx_temp,rx_tail    wz    'if head-tail mismatch, byte ready, z=0
    
        if_nz    getspa    rx_temp            'preserve spa
        if_nz    setspa    rx_tail            'get tail
        if_nz    popar    x            'get byte at tail
        if_nz    getspa    rx_tail            'update tail
        if_nz    setspa    rx_temp            'restore spa
    
    rx_check_ret    ret
    
    
    '************************
    '* Serial Receiver Task *
    '************************
    
    rx_task        chkspb            wz    'if start or rollover, reset head
        if_z    setspb    #$80
    
            mov    rx_bits,#9        'ready for 8 data bits + 1 stop bit
    
            neg    rx_time,period        'get -0.5 period
            sar    rx_time,#1
    
            jp    rx_pin,#$        'wait for start bit
    
            subcnt    rx_time            'get time + 0.5 period for initial 1.5 period delay
    
    :bit        rcr    rx_data,#1        'rotate c into byte
            add    rx_time,period        'add 1 period
            passcnt    rx_time            'wait for center of next bit
            getp    rx_pin        wc    'read rx pin into c
            djnz    rx_bits,#:bit        'loop until 8 data bits + 1 stop bit received
    
            shr    rx_data,#32-8        'align byte
            pushb    rx_data            'store byte at head, inc head
    
            jmp    #rx_task        'wait for next byte
    
    
    '**********************
    '* Baud Detector Task *
    '**********************
    
    baud_task    movd    ctr,rx_pin        'set ctra to time rx pin states
    
    :loop        notb    ctr,#5        wc    'if 1,0 sample set, c=0
            setctra    ctr            '($20 -> 10000001001 -> 1, 6x 0, 1x 1, 2x 0, 1)
    
        if_nc    mov    limh,buff0        'if 1,0 sample set,
        if_nc    shr    limh,#4            '..make window from 1st 0 (6x if $20)
        if_nc    neg    liml,limh
        if_nc    add    limh,buff0
        if_nc    add    liml,buff0
    
        if_nc    mov    comp,buff1        'if 1,0 sample set,
        if_nc    mul    comp,#6            '..normalize 2nd 1 (1x if $20) to 6x
        if_nc    cmpr    comp,limh    wc    '..check if within window
        if_nc    cmp    comp,liml    wc
    
        if_nc    mov    comp,buff2        'if 1,0 sample set,
        if_nc    mul    comp,#3            '..normalize 2nd 0 (2x if $20) to 6x
        if_nc    cmpr    comp,limh    wc    '..check if within window
        if_nc    cmp    comp,liml    wc
    
        if_nc    add    buff0,buff2        'if $20,
        if_nc    shr    buff0,#3        '..compute period from 6x 0 and 2x 0
        if_nc    mov    period,buff0        '..update period
    
            mov    buff0,buff1        'scroll sample buffer
            mov    buff1,buff2
    
    :wait        getcosa    buff2            'wait for next sample
            tjnz    buff2,#:loop
            jmp    #:wait
    
    
    ctr        long    %100_01001        'ctr configuration for timing low on rx pin
    
    
    '*************
    '* Variables *
    '*************
    
    reserves
    
    base        res    1            'main task
    x        res    1
    y        res    1
    z        res    1
    value        res    1
    view        res    1
    enter        res    1
    pin        res    1
    ssize        res    1
    hsize        res    1
    wsize        res    1
    shift        res    1
    amask        res    1
    
    rx_tail        res    1            'serial receiver task
    rx_temp        res    1
    rx_time        res    1
    rx_data        res    1
    rx_bits        res    1
    
    buff0        res    1            'baud detector task
    buff1        res    1
    buff2        res    1
    limh        res    1
    liml        res    1
    comp        res    1
    period        res    1
    
    


    Here is a conversation with it, from start-up:
    === Propeller II Monitor ===
    
    >?
    
                    - HUB -
    {adr{.adr}}                     - View
    {adr{.adr}}/{dat{ dat}}         - Search
    {adr{.adr}}:dat{ dat}           - Enter
    adr.adr[</>]adr                 - Move
    adr.adr^                        - Checksum
    adr@                            - Watch
    [Y/W/N]                         - Byte/word/long
                    - COGS -
    cog+pgm{+ptr}                   - Start
    cog-                            - Stop
    M                               - Map
                    - PINS -
    {pin}[H/L/T/Z/R]                - High/low/toggle/off/read
    pin#                            - Watch
    pin|cfg                         - Configure
    dat\                            - Set DACs
                    - MISC -
    dat*                            - Set clock
    '                               - Repeat
    Q                               - Quit
    
    >0.
    00000- 50 72 6F 70 65 6C 6C 65 72 20 49 49 20 20 76 31   'Propeller II  v1'
    00010- 45 FE C1 0D E3 B6 FC 0C 01 D0 7C 0C 01 D0 7C 0D   'E.........|...|.'
    00020- 01 D0 FC 80 1F D0 7C 62 01 EE FC 30 6D 0C A8 80   '......|b...0m...'
    00030- 01 D8 7C 0C 5A BE FC 1C 83 08 BD A0 5A BE FC 1C   '..|.Z.......Z...'
    00040- 83 08 BD 80 01 08 FD 28 FA FE FC A0 5A BE FC 1C   '.......(....Z...'
    00050- 01 D6 7C 62 24 00 64 1C B2 D6 7C 61 01 D6 FC 34   '..|b$.d...|a...4'
    00060- 0F FE FC F6 02 FF FC A0 08 FE 7C 86 52 D6 E8 A0   '..........|.R...'
    00070- 01 D6 7C 62 60 CE FC 1C B2 D6 7C 61 01 D6 FC 34   '..|b`.....|a...4'
    00080- 16 FE FC F6 2F 00 7C 1C 77 43 FC 0C 0D 04 FD 0C   '..../.|.wC......'
    00090- 69 04 BD 80 6A D4 3C FF 57 43 FC 0C 00 00 4C 1C   'i...j.<.WC....L.'
    000A0- 04 FE FC A0 DB B2 FC 0C DA B0 FC 0C 44 3E C0 0D   '............D>..'
    000B0- DA B2 FC 0C 01 FE 7C E1 01 D8 CC 27 DC AE FC 0C   '......|....'....'
    000C0- DB B0 FC 0C DA B0 FC 0C 25 FE FC F6 B2 E6 7C 0C   '........%.....|.'
    000D0- 6D FE BC A0 20 00 FD A0 5A BE E8 1C D6 AC D4 0D   'm... ...Z.......'
    000E0- DB B0 D4 0C DA B0 D4 0C 01 02 FD 34 32 00 FD F6   '...........42...'
    000F0- C1 02 7D 08 31 FE FC F6 40 0E C0 0D 77 00 04 E0   '..}.1...@...w...'
    >n
    >0.
    00000- 706F7250 656C6C65 49492072 31762020   'Propeller II  v1'
    00010- 0DC1FE45 0CFCB6E3 0C7CD001 0D7CD001   'E.........|...|.'
    00020- 80FCD001 627CD01F 30FCEE01 80A80C6D   '......|b...0m...'
    00030- 0C7CD801 1CFCBE5A A0BD0883 1CFCBE5A   '..|.Z.......Z...'
    00040- 80BD0883 28FD0801 A0FCFEFA 1CFCBE5A   '.......(....Z...'
    00050- 627CD601 1C640024 617CD6B2 34FCD601   '..|b$.d...|a...4'
    00060- F6FCFE0F A0FCFF02 867CFE08 A0E8D652   '..........|.R...'
    00070- 627CD601 1CFCCE60 617CD6B2 34FCD601   '..|b`.....|a...4'
    00080- F6FCFE16 1C7C002F 0CFC4377 0CFD040D   '..../.|.wC......'
    00090- 80BD0469 FF3CD46A 0CFC4357 1C4C0000   'i...j.<.WC....L.'
    000A0- A0FCFE04 0CFCB2DB 0CFCB0DA 0DC03E44   '............D>..'
    000B0- 0CFCB2DA E17CFE01 27CCD801 0CFCAEDC   '......|....'....'
    000C0- 0CFCB0DB 0CFCB0DA F6FCFE25 0C7CE6B2   '........%.....|.'
    000D0- A0BCFE6D A0FD0020 1CE8BE5A 0DD4ACD6   'm... ...Z.......'
    000E0- 0CD4B0DB 0CD4B0DA 34FD0201 F6FD0032   '...........42...'
    000F0- 087D02C1 F6FCFE31 0DC00E40 E0040077   '..}.1...@...w...'
    >y
    >0/'Propeller
    00000- 50 72 6F 70 65 6C 6C 65 72   'Propeller'
    >/
    005CF- 50 72 6F 70 65 6C 6C 65 72   'Propeller'
    >e00.
    00E00- 00 00 7C 1C 80 D4 FF 68 17 D6 FF 0E EA D7 17 86   '..|....h........'
    00E10- 16 D6 D7 0C A2 D4 57 0C 18 BC D7 0C 16 D4 D7 0C   '......W.........'
    00E20- A2 D6 57 0C 00 00 7C 1C 17 00 7C 0E A3 00 E9 0C   '..W...|...|.....'
    00E30- 09 DC FF A0 F5 D9 BF A4 01 D8 FF 38 BA 01 FC F8   '...........8....'
    00E40- 0C D8 FF 0C 01 DA FF 30 F5 D9 BF 80 0D D8 7F 0C   '.......0........'
    00E50- D6 00 7C 0D BC DD FF F6 18 DA FF 28 AB DA 7F 0C   '..|........(....'
    00E60- B5 01 7C 1C 00 B8 BF 54 25 B9 FF 0D F0 B8 7F 0C   '..|....T%.......'
    00E70- EF E5 8F A0 04 E4 CF 28 F2 E7 8F A4 EF E5 8F 80   '.......(........'
    00E80- EF E7 8F 80 F0 E9 8F A0 06 E8 CF 10 F2 E9 0F E1   '................'
    00E90- F3 E9 0F 85 F1 E9 8F A0 03 E8 CF 10 F2 E9 0F E1   '................'
    00EA0- F3 E9 0F 85 F1 DF 8F 80 03 DE CF 28 EF EB 8F A0   '...........(....'
    00EB0- F0 DF BF A0 F1 E1 BF A0 3A E2 FF 0C C5 E3 7F FA   '........:.......'
    00EC0- D9 01 7C 1C 89 00 00 00 00 00 00 00 9A 62 22 77   '..|..........b"w'
    00ED0- 20 43 6F 70 79 72 69 67 68 74 20 32 30 31 33 20   ' Copyright 2013 '
    00EE0- 20 50 61 72 61 6C 6C 61 78 2C 20 49 6E 63 2E 20   ' Parallax, Inc. '
    00EF0- 77 77 77 2E 70 61 72 61 6C 6C 61 78 2E 63 6F 6D   'www.parallax.com'
    >..
    00F00- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01000- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01010- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01020- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01030- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01040- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01050- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01060- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01070- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01080- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    01090- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010A0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010B0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010C0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010D0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010E0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    010F0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >1ff00.
    1FF00- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF10- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FF90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    1FFF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f00:1 2 3 4 5 6
    >f00.f0f
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    >f10:'Hello!' 77
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f00.f1f>f80
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F40- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F50- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F60- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F70- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F80- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >f30.f7f:'abc
    >f00.
    00F00- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F10- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00F20- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00F30- 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61   'abcabcabcabcabca'
    00F40- 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62   'bcabcabcabcabcab'
    00F50- 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63   'cabcabcabcabcabc'
    00F60- 61 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61   'abcabcabcabcabca'
    00F70- 62 63 61 62 63 61 62 63 61 62 63 61 62 63 61 62   'bcabcabcabcabcab'
    00F80- 01 02 03 04 05 06 00 00 00 00 00 00 00 00 00 00   '................'
    00F90- 48 65 6C 6C 6F 21 77 00 00 00 00 00 00 00 00 00   'Hello!w.........'
    00FA0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FB0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FC0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FD0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FE0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    00FF0- 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   '................'
    >m
     0 0 0 0 0 0 0 M
    >6+1ec+1000
    >m
     0 1 0 0 0 0 0 M
    >6-
    >m
     0 0 0 0 0 0 0 M
    >
    
    


    I never got around to adding the SDRAM boot, as it was a lot of work just to get what's in there ironed out. Of the 3,840 ROM bytes, the monitor takes 2,384 bytes, which is a lot, but I think it's a really nice thing to have. Both the monitor and the SHA-256/HMAC programs can be executed independently from user application code and are very simple to operate.
  • potatoheadpotatohead Posts: 10,261
    edited 2012-11-04 00:48
    This is a pretty excellent monitor. And it appears we've got nice autobaud and serial in ROM now, standard. :)

    Pure Genius indeed.
  • Heater.Heater. Posts: 21,230
    edited 2012-11-04 01:42
    rod1963,

    No flipping or hurt feelings here. I was just pointing out that such an OS choice would not light the fires of community support.

    I'm sure QNX is quite fine, I have used many such embedded operating systems and would always advise against trying to use Linux for fast real-time work. Linux was never intended for that use. Try flipping a GPIO pin on a Raspi with any hard timing constaints and you'll see what I mean (See I'm not such a "fanboi").
    In the context of my little dream system a hard real-time OS is not required anyway. As I said the Prop takes care of the hard real-time, multi-threaded, real world interfacing and the ARM can slouch along doing the heavy lifting of file system, networking, GUI, and other such tasks.
    I might add that one reason I am a fan of the Propeller, and dare I say it XMOS, is that it does not require an OS to get that multi-tasking, real-time work done. Now that the Prop II has the abilty to run multiple threads in a COG that situation is made even better.
  • jmgjmg Posts: 15,175
    edited 2012-11-04 02:40
    cgracey wrote: »
    The ROM contains the booter (SPI Flash or Serial) with SHA-256/HMAC authentication to facilitate code protection, and a serial (RX/TX)

    What is the smallest/cheapest SPI device supported ?
    Will this boot from a QuadSPI part (even if first load is in 1 bit SPI mode ? )

    I can see SOT23-6 SPI parts, but they seem to cost more than the 13c/3K that a SO8 SPI part costs.
    Unlike i2c, where SOT23 are among the lowest cost parts available
  • Bill HenningBill Henning Posts: 6,445
    edited 2012-11-04 06:05
    Thanks for the update Chip!

    my thoughts:

    - The monitor looks great!

    - Lack of SD boot is not a big deal, SPI flash is dirt cheap now.

    - the rom now fully occupies the RDxxxx/WRxxxx direct address range

    (Unless of course you've already changed the "upper" address bits for the direct 8 bit address to correspond to the last 256 bytes of ram...)

    Did I mention that the monitor looks great???? :-)
    cgracey wrote: »
    Prop II update...

    The ROM is now done. It spans from hub byte address $00000 to $00EFF, with $F00 to $1FFFF being RAM. The ROM contains the booter (SPI Flash or Serial) with SHA-256/HMAC authentication to facilitate code protection, and a serial (RX/TX) monitor which starts up if there's no authenticated loader to execute and no security key programmed into the first 128 fuses - you just hit <space> and it auto-bauds and gives you a prompt. The monitor could be used as a very simple development interface, where you just send text scripts to load code and start cogs.

    ...

    I never got around to adding the SDRAM boot, as it was a lot of work just to get what's in there ironed out. Of the 3,840 ROM bytes, the monitor takes 2,384 bytes, which is a lot, but I think it's a really nice thing to have. Both the monitor and the SHA-256/HMAC programs can be executed independently from user application code and are very simple to operate.
  • Invent-O-DocInvent-O-Doc Posts: 768
    edited 2012-11-04 08:53
    Congratulations on the rom code completion. Love the monitor!
  • David BetzDavid Betz Posts: 14,516
    edited 2012-11-04 10:31
    cgracey wrote: »
    Of the 3,840 ROM bytes, the monitor takes 2,384 bytes, which is a lot, but I think it's a really nice thing to have. Both the monitor and the SHA-256/HMAC programs can be executed independently from user application code and are very simple to operate.
    The monitor looks really cool but are you sure we're not going be sorry we lost the extra 2K hub RAM bytes? I know we have a lot more hub RAM space in P2 but competing microcontrollers often have twice the program space and a fair amount of SRAM as well.
  • potatoheadpotatohead Posts: 10,261
    edited 2012-11-04 10:40
    IMHO, the real question is whether or not that RAM would make the difference. I don't think it would, and we've got some better means of employing external storage in P2.
  • jmgjmg Posts: 15,175
    edited 2012-11-04 11:26
    David Betz wrote: »
    The monitor looks really cool but are you sure we're not going be sorry we lost the extra 2K hub RAM bytes? I know we have a lot more hub RAM space in P2 but competing microcontrollers often have twice the program space and a fair amount of SRAM as well.

    If the Monitor was Top-level single mask stuff, then that would allow some choice, (and cheaper bug fixes) but it sounds like it is compile-time ROM, which is really cast-in-stone stuff. You have to be very sure there are no bugs, and no drop-dead's.

    At what size, does true-rom ( or even OTP ?) become more area efficient than Ram-As-Rom ?

    With no tables anymore, this ROM does not need to be RAM-stealing, from an operational viewpoint.
    It has to load into COG-RAM anyway, and does not have to be in the time-critical address decode/mux path ?
  • potatoheadpotatohead Posts: 10,261
    edited 2012-11-04 11:53
    And again, would that ram make the difference?

    I'm not convinced it would.

    Is 2K worth an additional plan, synthesize, test, cycle? That is the cost of changing it to some copy to COG on boot option...

    Basically, this makes the monitor a freebie. High value add, little to no downside. (Of course, I'm a fan too, so the high value is in the eyes of all of us.)
  • Dr. MarioDr. Mario Posts: 331
    edited 2012-11-04 15:08
    I can say I approve this ROM. Things are looking easy from on - it would also come in handy for the debugging purpose - at least for the host microcontroller (like MPC5200 or ARM9/M4 MCUs in clustered system), even when dealing with a bad flash.

    And it could be possible that you might be able to run QNX RTOS. Same for FreeRTOS if you want open source. (uCLinux is already a RTOS anyhow.)

    Nevertheless, I am waiting for when it is released so I can buy Quickstart-like board to start doing prototype software - maybe a port of uCLinux. And, afterwards start designing the hardware.
  • User NameUser Name Posts: 1,451
    edited 2012-11-04 15:41
    I'm a big fan of bootstrapping through a serial link. It is exactly how I want to deploy my first Prop2. Also very exciting is how quickly you've implemented and exploited the hardware multi-threading hook. Great stuff!

    setdacs - :)
  • SeairthSeairth Posts: 2,474
    edited 2012-11-07 06:13
    Would it be possible to get the information at the following links (and referenced PDFs) updated? I'm particularly interested in more detailed documentation of the new instructions, but can probably fill in some of the details by looking at their usage in the posted monitor code.

    http://www.parallaxsemiconductor.com/Products/propeller2specs
    http://www.parallax.com/Propeller2FeatureList/tabid/898/Default.aspx
  • SeairthSeairth Posts: 2,474
    edited 2012-11-07 06:22
    cgracey wrote: »
    Prop II update...

    The ROM is now done.
    '********************************************************
    '*							*
    '*		Propeller II ROM Monitor		*
    '*							*
    '*		Version 0.1				*
    '*							*
    '*		11/01/2012				*
    '*							*
    '********************************************************
    
    
    DAT
    
    hello		byte	13,13,"=== Propeller II Monitor ===",13,13
    		byte	0			'33 bytes
    
    

    I may be doing too much reading between the lines, but does this mean that the product is going to officially be called "Propeller II"?
  • David BetzDavid Betz Posts: 14,516
    edited 2012-11-07 08:36
    Seairth wrote: »
    I may be doing too much reading between the lines, but does this mean that the product is going to officially be called "Propeller II"?
    Good question. Their preliminary feature list calls it "Propeller 2" so they've used both names. I call it "P2" myself because I'm too lazy to type the longer name! :-)
  • Heater.Heater. Posts: 21,230
    edited 2012-11-07 11:15
    I'm in two minds about this monitor idea.
    Chip has said "Of the 3,840 ROM bytes, the monitor takes 2,384 bytes,"
    What does this mean?. I thought there was leeway to swap RAM and ROM around now it seems 3,840 ROM bytes are fixed already.
    A monitor is nice but how often would it be used in production? In many apps people run up aganst a RAM limit first.
    I would rather have the RAM space for apps and data than consumed by a monitor that will rarely be used in finished products.
    You can always load a monitor if you like for tinkering about, as the Forth guys will tell you.
  • RaymanRayman Posts: 14,762
    edited 2012-11-07 11:36
    If we're using big SDRAMs, does an extra 2K of HUB RAM matter?
    Anybody remember how much RAM P2 will have?
  • David BetzDavid Betz Posts: 14,516
    edited 2012-11-07 11:40
    Rayman wrote: »
    If we're using big SDRAMs, does an extra 2K of HUB RAM matter?
    Anybody remember how much RAM P2 will have?

    I believe it's 128k minus the size of the ROM.
  • Heater.Heater. Posts: 21,230
    edited 2012-11-07 13:50
    Rayman,

    What big SDRAMS? This is a micro-contoller, it should stand alone in most applications. Those external RAMs are just for us freaks who want to turn an MCU into a CP/M machine or other such off the wall stuff for fun.

    2K out of a possible 128 K is almost 2% or RAM wasted. That's huge given that it will rarely be used.
  • mindrobotsmindrobots Posts: 6,506
    edited 2012-11-07 13:59
    Early on, I didn't think there was a 1:1 exchange rate for RAM and ROM. I thought RAM was more expensive space-wise. I almost thought it was like 1:6, if so then 2K of ROM would be only 350 bytes of RAM. But to your point, the poor guy that never uses the monitor but has a program 300 bytes too big! Then there will always be the "if only I had 20 more bytes" scenario at some upper boundary.
  • Heater.Heater. Posts: 21,230
    edited 2012-11-07 14:21
    mindrobots,

    If I understand the situation correcty RAM cells are much bigger than ROM cells. In the Prop II we have space for 128K of RAM.
    BUT it is possible to butcher some of the RAM cells to make ROM, in the same address space. Still taking the same physical space as what would have been RAM.

    So, the more code you make in ROM the less RAM you have. Ergo the ROM monitor is eating valuable RAM for little benifit in general usage.
  • mindrobotsmindrobots Posts: 6,506
    edited 2012-11-07 14:34
    Point taken! I can't speak to the value of having an in-ROM monitor in an embedded device that won't boot. I'm just a hobbyist so my failure and recovery scenarios are different than a production user.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2012-11-07 14:37
    I can see Chip's vision being drowned out by us yokels always seeing a feature or something different as a problem. Someone will always find and hit a wall and want to knock it down. Someone will always want more of A than B. Someone will always want more of B then A. Someone will always want an MCU to be an MPU. Someone will always want you to do it their way even though it's your baby. Someone is us.

    I've been pretty much just sitting back just waiting for that apple pie to come out of the oven. Knowing the cook I'm sure that even though he messes the recipe it's going to extremely tasty. I just want to sit down and enjoy, and make the most of it.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-11-07 14:41
    So now the RAM is down to 124.2K? Maybe most of the monitor program is needed for talking to the host computer and downloading code.

    EDIT: I missed Peter's post while I was posting my message. So now I understand. The extra code is needed to monitor the apple pie while it's baking. :)
  • Heater.Heater. Posts: 21,230
    edited 2012-11-07 14:45
    Peter,

    Yes, sorry, being a Brit I'm prone to the affliction observed by Charles Babbage:

    "Propose to an Englishman any principle, or any instrument, however admirable, and you will observe that the whole effort of the English mind is directed to find a difficulty, a defect, or an impossibility in it. If you speak to him of a machine for peeling a potato, he will pronounce it impossible: if you peel a potato with it before his eyes, he will declare it useless, because it will not slice a pineapple. Impart the same principle or show the same machine to an American or to one of our Colonists, and you will observe that the whole effort of his mind is to find some new application of the principle, some new use for the instrument. "
  • AntoineDoinelAntoineDoinel Posts: 312
    edited 2012-11-07 14:54
    Heater. wrote: »
    Peter,

    Yes, sorry, being a Brit I'm prone to the affliction observed by Charles Babbage:

    "Propose to an Englishman any principle, or any instrument, however admirable, and you will observe that the whole effort of the English mind is directed to find a difficulty, a defect, or an impossibility in it. If you speak to him of a machine for peeling a potato, he will pronounce it impossible: if you peel a potato with it before his eyes, he will declare it useless, because it will not slice a pineapple. Impart the same principle or show the same machine to an American or to one of our Colonists, and you will observe that the whole effort of his mind is to find some new application of the principle, some new use for the instrument. "

    This might be true for your comment about large SDRAMs? :lol:

    While I confess being part of that bunch that wants to turn the MCU in MPU, I thought bandwidth is going to be adequate for a graphics display and many more "serious" applications too.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-11-07 15:59
    Without initializing, RAM bits come up in a random state. Instead of ROM, would it be possible simply to bias those corresponding bits of RAM on power-up to contain the "ROM" code? Then they could be reused by the app program.

    -Phil
  • CircuitsoftCircuitsoft Posts: 1,166
    edited 2012-11-07 16:01
    Without initializing, RAM bits come up in a random state. Instead of ROM, would it be possible simply to bias those corresponding bits of RAM on power-up to contain the "ROM" code? Then they could be reused by the app program.

    -Phil
    I asked exactly that a while back, but it was determined that 7t SRAM cells won't fit where 6t SRAM cells are designed to go.

    Edit: Found it!
    cgracey wrote: »
    I wonder, would it be possible to swap on the 6T-SRAM for 7T-SRAM with reset? Could "ROM" be done by having the reset mode of some cells be different than others, in order to make the ROM code? That way we wouldn't lose the RAM space for ROM, but would still be able to boot easily.
    If we had more area within the bit cell and more wiring space, we could do a 7T cell with initialization. Too late for that now, though. 6T or less is all that will fit in those bit cell spaces.
Sign In or Register to comment.