Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
05/16/07 00:41
Modified:
  05/16/07 02:24

Read: times


 
#139296 - ReceiveString, rev. 2
Responding to: ???'s previous message
Jan said:
I modified slightly the specs. Comments?

Hi Jan,

I modified your program enough to make it work with my old assembler on a Silicon Labs C8051F120. It never really hit me before how much more stuff you have to go through to initialize the 'F120 than one of the simpler derivatives.

Anyway, I have a few comments about your version. Three of them are substantial, and the others are just matters of style. First the substantial ones:
  1. What happens when a DEL character (0FFh) comes along? I personally don't even have a clue what should happen.
  2. Since you went to the trouble of making the TxChar subroutine, is there any reason you didn't call it from inside of ReceiveString?
  3. I've always written TxChar as MOV SBUF/JNB TI,$/CLR TI instead of the way you have it. It seems like that takes care of the "security measure" that you address at the beginning of ReceiveString. Is there something wrong with my way?
Now the more philosophical issues:
  1. In TxCRLF your program uses decimal constants for the CR and LF characters, but in other places it uses hex constants for various control characters. Maybe this inconsistency is part of what led to the original "13h" error in the first place :) Better yet I think would be to EQU some names for the characters so you can forget about the actual numerical values.
  2. Somehow it seems nasty to me that TxHexa falls through into TxChar. Sure, you save a couple of instructions, but TxChar is forever stuck to TxHexa and that just seems bad to me.
  3. Is it fair that the test program magically knows about R0's value on return from ReceiveString? Maybe for a test driver this is okay. You wouldn't want to do that kind of thing in a big program without saying something about R0 in the spec for ReceiveString.
  4. It's probably just as important to comment the test program as it is ReceiveString itself.
I was amused that the "C hater" changed the spec to put a zero at the end of the string instead of a CR, and also that the "C hater" thinks its okay to clobber R0 and ACC because the C compler won't care! :) I haven't written any big assembly language programs in a long, long, long time, but I thought it might actually be a good idea to preserve (at least) R0 in case ReceiveString was being called from an ASM routine that might be using R0 itself.

For the record, here's a revision that works with an old Archimedes assembler and the C8051F120.

-- Russ
; -----------------------------------------------------------------------------
;				  asm120.s03
; -----------------------------------------------------------------------------
; DESCRIPTION:	This is a skeleton program for the C8051F120 evaluation board
;		from Silicon Labs.  It demonstrates Jan's line editor
;		subroutine.
;
; REVISIONS:	14 May 07 - RAC - Adapted from Jan's initial implementation
; -----------------------------------------------------------------------------

	LSTOUT-				; Don't list header file
$f120.inc				; Hardware register and bit definitions
	LSTOUT+				; Listing back on

;------------------------------------------------------------------------------
;			       Names for Numbers
;------------------------------------------------------------------------------

LED		EQU	P1.6		; LED on 'F120 evaluation board

BEEP_CHR	EQU	07h		; Names for ASCII characters
BS_CHR		EQU	08h
CR_CHR		EQU	0Dh
LF_CHR		EQU	0Ah
SPACE_CHR	EQU	20h

RX_BUFFER_SIZE	EQU	10		; Test buffer size

;------------------------------------------------------------------------------
;				 Data Segment
;------------------------------------------------------------------------------

;-----	The data segment loads at address 8, immediately above the registers.

	RSEG	DATA
RxBuffer:
	DS	RX_BUFFER_SIZE

;------------------------------------------------------------------------------
;				 Stack Segment
;------------------------------------------------------------------------------

;-----  The stack starts immediately after all the other RAM variables, and
;       expands upward from there.

	RSEG	CSTACK
StackBegin:
	DS	1

;------------------------------------------------------------------------------
;				  Boot Vector
;------------------------------------------------------------------------------

	COMMON	INTVEC			; Loads at address zero
Startup:
	JMP	Main			; Jump to main routine

;-----	Timer 0 interrupt vector

	ORG	Startup+0Bh

;------------------------------------------------------------------------------
;				     Main
;------------------------------------------------------------------------------
; DESCRIPTION:	Shuts off the watchdog timer, initializes the hardware, then
;		spins a loop forever spitting characters out the serial port.
;
; REVISIONS:	14 May 07 - RAC - Adapted from a similar program written in C.
;------------------------------------------------------------------------------

	RSEG	RCODE			; Loads after INTVEC

Main:
	MOV	SP,#StackBegin-1	; Set up the stack pointer
	CALL	InitializeHardware	; Go set up the chip

MainLoop:

;-----	Get a line of input from the human user

	call	ReceiveString

;-----	Print the length of the received string

	call	TxCRLF			; Print CR/LF
	mov	a,r0			; Get pointer to end of data
	clr	c			; Prepare to subtract
	subb	a,#RxBuffer		; Calculate string length
	call	TxHexa			; Print it
	call	TxCRLF			; Print CR/LF

;-----	Print the string itself

	mov	r0,#RxBuffer		; Start at the beginning of the buffer
Loop1:
	mov	a,@r0			; Get next character
	jz	Loop2			; It's zero - we're done
	call	TxChar			; Not zero - go print it
	inc	r0			; Advance to next character
	sjmp	Loop1			; Repeat for entire string
Loop2:
	call	TxCRLF			; Print CR/LF

	JMP	MainLoop		; Go do it again

; -----------------------------------------------------------------------------
;				    TxChar
; -----------------------------------------------------------------------------
; DESCRIPTION:	Sends the byte in the accumulator out the UART.
;
; REVISIONS:	15 May 07 - RAC - Adapted from an old putchar() routine
; -----------------------------------------------------------------------------

TxChar:
	MOV	SBUF,A			; Send the character
	JNB	TI0,$			; Spin until it's sent
	CLR	TI0			; Reset done flag
	RET				; Done

; -----------------------------------------------------------------------------
;				    RxChar
; -----------------------------------------------------------------------------
; DESCRIPTION:	Waits for a byte from the UART and returns it in the
;		accumulator
;
; REVISIONS:	15 May 07 - RAC - Adapted from an old putchar() routine
; -----------------------------------------------------------------------------

RxChar:
	JNB	RI0,$			; Wait for incoming character
	CLR	RI0			; Clear flag
	MOV	A,SBUF			; Got it
	RET

; -----------------------------------------------------------------------------
;			      InitializeHardware
; -----------------------------------------------------------------------------
; DESCRIPTION:	Sets up the C8051F120 hardware
;
; REVISIONS:	15 May 07 - RAC - Extracted from Main
; -----------------------------------------------------------------------------

InitializeHardware:

;-----	Start with general initialization

	MOV	WDTCN,#0DEh		; Disable the watchdog timer
	MOV	WDTCN,#0ADh

	MOV	SFRPAGE,#CONFIG_PAGE	; Switch to config page
	MOV	XBR2,#40h		; Enable Port I/O crossbar
	ORL	P0MDOUT,#1		; Set UART Tx for push/pull out
	ORL	P1MDOUT,#40h		; Set P1.6 for push/pull out

;-----	Set up Timer 1 as the on-board serial port baud rate generator

	MOV	SFRPAGE,#TIMER01_PAGE	; Timer 1 config page
	MOV	TH1,#0F4h		; Reload value for 115.2 Kbps
	ANL	TMOD,#0Fh		; Clear upper nibble of TMOD
	ORL	TMOD,#20h		; Put Timer 1 into Mode 2
	ORL	CKCON,#10h		; SYSCLK clocks Timer 1
	SETB	TR1			; Start Timer 1

;-----	Set up the onboard UART

	MOV	SFRPAGE,#CONFIG_PAGE	; Switch to config page
	MOV	XBR0,#04h		; Enable UART to I/O pins
	MOV	SFRPAGE,#TIMER01_PAGE	; Timer 1 config page
	MOV	SCON0,#50h		; Mode 1, Rx enabled
	ORL	SSTA0,#10h		; Disable UART divide by 2

;-----	Switch from the internal oscillator to the external crystal oscillator

	MOV	SFRPAGE,#CONFIG_PAGE	; Switch to config page
	MOV	OSCXCN,#67h		; Enable the crystal oscillator

	MOV	R0,#5			; Delay for about 1.2 msec
TimingLoop:
	MOV	R1,#255
	DJNZ	R1,$
	DJNZ	R0,TimingLoop

NotStableYet:				; Wait for oscillator to
	MOV	A,OSCXCN		;  stabilize
	ANL	A,#80h
	JZ	NotStableYet

	MOV	CLKSEL,#1		; Switch to external oscillator

	MOV	SFRPAGE,#LEGACY_PAGE	; Return to default SFR page
	RET				; Done

; -----------------------------------------------------------------------------
;			        Print Utilities
; -----------------------------------------------------------------------------

;-----	Prints CR/LF

TxCRLF:
	mov	a,#CR_CHR		; Get a carriage return
	call	TxChar			; Go print it
	mov	a,#LF_CHR		; Get a line feed
	call	TxChar			; Go print it
	ret				; Done

;-----	Prints accumulator contents as a 2-digit hex number

TxHexa:
	push	acc			; Save for second digit

	swap	a			; Isolate most-significant nibble
	anl	a,#0Fh
	add	a,#TxHexaT-TxHexaX1	; Index into table of hex digits
	movc	a,@a+pc			; Get hex digit
TxHexaX1:
	call	TxChar			; Go print it

	pop	acc			; Recall and isolate least significant
	anl	a,#0Fh			;  nibble
	add	a,#TxHexaT-TxHexaX2	; Index into table of hex digits
	movc	a,@a+pc			; Get hex digit
TxHexaX2:
	call	TxChar			; Go print it
	ret				; Done

TxHexaT:
	db   '0123456789ABCDEF'		; Table of hex digits

;------------------------------------------------------------------------------
;				 ReceiveString
;------------------------------------------------------------------------------
; DESCRIPTION:  This subroutine is called from many places to receive a line of
;               input from a human user via a terminal connected to the onboard
;               UART.  Each line of input starts with the first character
;               entered after this subroutine is called, and ends with a
;               carriage return.
;
;               This subroutine accumulates the data in a buffer called
;               'RxBuffer', which is located in the internal data RAM and is
;               accessed only via indirect addressing (i.e.  can be located in
;               the upper 128 bytes).  The symbol RX_BUFFER_SIZE gives the size
;               of the buffer, in bytes.  Note that to leave room for the
;               trailing zero, the actual number of characters received is
;               limited to RX_BUFFER_SIZE-1.
;
;               On entry, this function does minor internal housekeeping to
;               prepare for a new line of input (i.e.  resets the pointer :-))
;               It then receives characters one by one from the user.  It
;               handles each received character as follows:
;
;                 - Backspace (08h): If the buffer is not empty, removes the
;                   newest character from the buffer and echoes the three-
;                   character sequence 08h 20h 08h (backspace space backspace)
;                   to the terminal to erase the most recently typed character
;                   from the user's screen.  If the buffer is empty when the
;                   backspace character is received, echoes a single 07h (beep)
;                   to the terminal.
;
;                 - Carriage Return (0Dh): Appends zero character to the buffer
;                   to mark the end of the line and returns.
;
;                 - Printable characters (20h through 7Fh, inclusive): If the
;                   buffer is full, echoes a single 07h (beep) to the terminal.
;                   Otherwise appends the character to the buffer.
;
;                 - All other characters: Does nothing.
;
;               As noted above, this function returns when it receives a
;               carriage return.  Nothing specific is returned in registers.
;
;               The function won't guarantee to keep the value of registers
;               (this is the standard behaviour of C routines both in Keil and
;               SDCC), although resources usage will be determined and noted
;               below.
;
;               A test program is written to try the routine, which is not part
;               of the routine.  Test with Hyperterminal or equivalent, 9600
;               baud, 8N1, no handshake, auto terminal mode.  Should beep when
;               10th character is attempted to be entered.  Deleting should
;               "eat" characters until the last one, after it deleting should
;               beep.  After enter, should write number of characters and the
;               string again.
;
; RESOURCE USE:	Uses and destroys ACC and R0
;		A few stack bytes
;		No external memory
;		No interrutps disabled
;
; REVISIONS:	13 May 07 - RAC - Initial specification
;               13 May 07 - JW  - Modified specification and initial
;				   implementation.
; -----------------------------------------------------------------------------

ReceiveString:
	mov	r0,#RxBuffer        	; Initialize receiver pointer

;-----	Loop here until a line of input has been received

LoopReceive:
	call	RxChar			; Go get a character
	jb      acc.7,LoopReceive	; It's unprintable (>= 80h) - ignore it

	cjne    a,#20h,$+3		; Is it a control character (<20h)?
	jc      ControlChars		; Yes - process separately
	cjne    r0,#RxBuffer+RX_BUFFER_SIZE-1,StoreChar    ; No - store if no overflow
EchoBeep:				; Overflow or underflow - beep
	mov     a,#BEEP_CHR
	sjmp    SendChar
StoreChar:
	mov     @r0,a			; Put it into buffer
	inc     r0			; Bump pointer
SendChar:
	call	TxChar			; Go print the character
	sjmp    LoopReceive		; Go get next character

ControlChars:
	cjne    a,#BS_CHR,NotBackSpace
	cjne    r0,#RxBuffer,EatCharacter    ;if BackSpace, eat last character
	sjmp    EchoBeep		; if empty buffer, just beep
EatCharacter:
	mov	a,#BS_CHR		; Do what's needed to eat the character
	call	TxChar			;  on the terminal
	mov	a,#SPACE_CHR
	call	TxChar
	mov	a,#BS_CHR
	call	TxChar

	dec     r0			; Eat the character in the buffer
	sjmp    LoopReceive		; Go get next character

NotBackSpace:
	cjne    a,#CR_CHR,LoopReceive	; If not CR, go get next character
	mov     @r0,#0			; Got CR - terminate the string
	ret				; Done

	END




List of 44 messages in thread
TopicAuthorDate
Weekend Quiz - easy            01/01/70 00:00      
   Dumbbbbbb            01/01/70 00:00      
      I know of 3, and it is \"synthtetic\"...            01/01/70 00:00      
   Hi Jan!            01/01/70 00:00      
      2 out of 3            01/01/70 00:00      
   Comment lies!            01/01/70 00:00      
      that makes 4... embarrassing            01/01/70 00:00      
         #4            01/01/70 00:00      
            N-th            01/01/70 00:00      
               Similar            01/01/70 00:00      
         Thats the one I saw first too !            01/01/70 00:00      
   Another lyin\' comment            01/01/70 00:00      
      Bingo!            01/01/70 00:00      
   seems solved - so now for the equivalent in C?            01/01/70 00:00      
      Oops            01/01/70 00:00      
         Gee ... it was just an 'x' ...            01/01/70 00:00      
            Yup ...            01/01/70 00:00      
            "just" an x ?            01/01/70 00:00      
   writing SBUF without checking?            01/01/70 00:00      
      well...            01/01/70 00:00      
      the REAL mistake is using an HLL rather than ASM            01/01/70 00:00      
         Not so            01/01/70 00:00      
   Shall we continue this???            01/01/70 00:00      
      the spec itself is problematic            01/01/70 00:00      
         How would you fix the spec?            01/01/70 00:00      
            handle DEL (0x7f) and BS?            01/01/70 00:00      
               throwing in something to chew on... :-)            01/01/70 00:00      
               Are DEL and BS equivalent ???            01/01/70 00:00      
                  relax.            01/01/70 00:00      
      ReceiveString, rev.1            01/01/70 00:00      
         ReceiveString, rev. 2            01/01/70 00:00      
            there are many ways...            01/01/70 00:00      
               Comments on comments on ...            01/01/70 00:00      
                  (comments on)^3            01/01/70 00:00      
                  Caller-saves            01/01/70 00:00      
                     Caller-save vs. Callee-save            01/01/70 00:00      
                        Compiler trade-off            01/01/70 00:00      
      ReceiveString, rev. 3            01/01/70 00:00      
   Sunday Challenge (rev 4)            01/01/70 00:00      
      hard to beat...            01/01/70 00:00      
         Just one more byte ...            01/01/70 00:00      
            want to spare bytes?            01/01/70 00:00      
               CALL vs ACALL            01/01/70 00:00      
                  it depends            01/01/70 00:00      

Back to Subject List