subtitle "str_lib.asm by L. Wyard-Scott" ;;; ********************************************************************* ;;; Library Name: str_lib.asm ;;; Purpose: Routines for manipulation and construction of ;;; strings and character data. ;;; This module assumes that it is located entirely ;;; within the same page of ROM. ;;; Revision: 0.1 ;;; Date: 03 October 2005 ;;; Author: L. Wyard-Scott ;;; Copyright: Public Domain ;;; Device: PIC16F873, PIC16F874, PIC16F876, PIC16F877. ;;; PIC16F873A, PIC16F874A, PIC16F876A, PIC16F877A. ;;; ********************************************************************* ;;; Special Directions: ;;; To use these routines, include "str_lib.h" in the source code ;;; calling the routines. This file contains information about the ;;; routines and other equates that the calling code requires. ;;; ********************************************************************* ;;; Revision History: ;;; 0.1 - 03 October 2005 ;;; - Added support for 16F87XA devices. ;;; 0.0 - 07 November 2002 ;;; - Creation. ;;; - Several string-related routines are not yet ;;; implemented, notably COPY commands. The ;;; framework for these routines is commented out ;;; at the end of this file. ;;; ********************************************************************* ;;; Ideas for future work: ;;; - see above (R0.0). ;;; ********************************************************************* ;;; ********************************************************************* ;;; NOTE: An error will be generated by the assembler if any labels ;;; defined as global in this file are the same as those in the main ;;; file (or other libraries). list ; Turn on list output. Note that device ; type needs to be specified to the ; assembler (on the command line, or through ; the MPLAB IDE). ;; Include register, bit, and other info specific to ;; the specified device. ifdef __16F873 #include messg "Assembling str_lib.asm for PIC16F873." endif ifdef __16F874 #include messg "Assembling str_lib.asm for PIC16F874." endif ifdef __16F876 #include messg "Assembling str_lib.asm for PIC16F876." endif ifdef __16F877 #include messg "Assembling str_lib.asm for PIC16F877." endif ifdef __16F873A #define A_Device #include messg "Assembling str_lib.asm for PIC16F873A." endif ifdef __16F874A #define A_Device #include messg "Assembling str_lib.asm for PIC16F874A." endif ifdef __16F876A #define A_Device #include messg "Assembling str_lib.asm for PIC16F876A." endif ifdef __16F877A #define A_Device #include messg "Assembling str_lib.asm for PIC16F877A." endif #include "branches.h" ; Conditional branching macros. ;;; -------------------------------------------------------------------- ;;; Assembler Equates Section. Define assembly-time constants here ;;; using the EQU assembler directive. ;;; -------------------------------------------------------------------- ;;; --------------------------------------------------------------------- ;;; Variable Address Assignments. ;;; --------------------------------------------------------------------- TemoraryVars: UDATA_OVR ; Start of the uninitialized data section. ; The following statements reserve memory, ; the address of which is allocated by the ; linker. STR_Storage: res 1 ; Temporary storage for _ToUpper, _ToLower, ; _IsHex, _Length STR_LSNSave: res 1 ; Temporary storage for _ASC2Hex STR_MSNSave: res 1 ; Temporary storage for _ASC2Hex STR_FSRSave: res 1 ; Temporary storage for _ToUpperS, ; _ToLowerS, _IsHexS, _Length ParameterVars: UDATA STR_Pointer: res 1 ; Parameter to _Copy ;; Make selected variables identifiable to calling code. global STR_Pointer ;;; -------------------------------------------------------------------- ;;; Macros. (File-specific) ;;; -------------------------------------------------------------------- ;;; -------------------------------------------------------------------- ;;; Subroutines. ;;; -------------------------------------------------------------------- CODE ; Start the code section. ;;; ******************************************************************** ;;; Subroutine Name: STR_Hex2ASC ;;; Description: Converts a byte value into two ASCII digits ;;; corresponding to the value. The digits are ;;; upper-case. ;;; Requires: W contains the value to convert. ;;; IRP:FSR points to where the two chars are to be ;;; stored. ;;; Returns: Two characters pointed to by IRP:FSR. ;;; Locations Affected: W is destroyed. ;;; ******************************************************************** STR_Hex2ASC: global STR_Hex2ASC ;; The algorithm for this routine is to process each nibble: ;; 0-9: add 0x30 ;; A-F: add 0x30 + 0x07 (0x37). ;; Save the value. In order to avoid creating another variable, ;; this value is saved to where the pointer is pointing. movwf INDF ;; Move the pointer in order to deal with the LSNibble first. incf FSR,F ;; Process the LSNibble. andlw 0x0F ; Isolate the LSNibble. addlw 0x30 ; Add the base number. movwf INDF ; Save the value, temporarily. ;; The following macro call will branch to ProcessMSNibble ;; only if W is lower than 0x3A. brwlok 0x3A, ProcessMSNibble LSNisLetter: ;; The above macro call destroys what is in W, therefore ;; restore it to the value saved before. movf INDF,W ; Restore the nibble. addlw 0x07 ; Add a further 7. movwf INDF ProcessMSNibble: ;; Move the pointer back to the first location (which currently ;; contains the raw value). decf FSR,F swapf INDF,W ; Get the value into W, swapping nibbles. ;; Isolate the MSNibble (now in the LSNibble) and proceed ;; as for the LSNibble. (No further commenting is given). andlw 0x0F addlw 0x30 movwf INDF brwlok 0x3A, Hex2ASCDone movf INDF,W addlw 0x07 movwf INDF Hex2ASCDone: return ;;; ******************************************************************** ;;; Subroutine Name: STR_ASC2Hex ;;; Description: Converts two ASCII characters representing ;;; hexadecimal digits into a byte value. This routine ;;; will accept upper or lower-case ASCII values. ;;; Requires: IRP:FSR point to the first of the two characters. ;;; Returns: W contains the value. ;;; STATUS C bit returns true/false whether the ;;; conversion was successful or not. ;;; This wil be false if either letter is not a valid ;;; hexadecimal digit. ;;; Locations Affected: ;;; ******************************************************************** STR_ASC2Hex: global STR_ASC2Hex banksel STR_LSNSave ;; Read the character corresponding to the LSNibble first ;; (this because correction of the pointer is simpler). incf FSR,F movf INDF,W decf FSR,F ; Reset the pointer to the first character. ;; Ensure the LSNibble is a valid hex character. call STR_IsHex btfss STATUS,C goto STR_ASC2Hex_Fail ;; Convert to uppercase (nothing is done if the character isn't ;; a valid letter). call STR_ToUpper addlw -0x30 ; Subtract 0x30. ;; If the result is > 0x09, then an additional 0x07 is subtracted. movwf STR_LSNSave brwlsk 0x09, STR_ASC2Hex_LSDone movf STR_LSNSave,W addlw -0x07 movwf STR_LSNSave STR_ASC2Hex_LSDone: ;; The LSNibble value is in STR_LSNSave. ;; Now deal with the MSNibble. movf INDF, W call STR_IsHex btfss STATUS,C goto STR_ASC2Hex_Fail movf INDF,W call STR_ToUpper movwf STR_MSNSave addlw -0x30 ; Subract 0x30 movwf STR_MSNSave ;; If result is > 0x09, subtract 0x07. brwlsk 0x09, STR_ASC2Hex_Success movf STR_MSNSave,W addlw -0x07 movwf STR_MSNSave STR_ASC2Hex_Success: ;; Getting to here means that the two temporary variables ;; hold the values. Merge them and return with a "success" ;; flag. swapf STR_MSNSave,W addwf STR_LSNSave,W bsf STATUS,C ; Indicate success. return STR_ASC2Hex_Fail: bcf STATUS,C ; Indicate failure. return ;;; ******************************************************************** ;;; Subroutine Name: STR_IsHex ;;; Description: Determines whether or not an ASCII character is ;;; a valid representation of an ASCII digit. This ;;; routine will accept upper or lower case letter ;;; digits. ;;; 0-9, a-f, A-F are all valid ASCII hex digits. ;;; Requires: W contains the ASCII code to check. ;;; Returns: STATUS,C contains true if the character is ;;; in the ranges outlined, above. False otherwise. ;;; Locations Affected: STR_Storage. ;;; ******************************************************************** STR_IsHex: global STR_IsHex banksel STR_Storage ; Save the character. movwf STR_Storage brwlok '0',STR_IsHex_False movf STR_Storage,W brwlsk '9',STR_IsHex_True movf STR_Storage,W brwlok 'A',STR_IsHex_False movf STR_Storage,W brwlsk 'F',STR_IsHex_True movf STR_Storage,W brwlok 'a',STR_IsHex_False movf STR_Storage,W brwlsk 'f',STR_IsHex_True ;; Falls through to false if exceeds 'f'. STR_IsHex_False: movf STR_Storage, W ; Restore the character. bcf STATUS,C ; Indicate false. return STR_IsHex_True: movf STR_Storage, W ; Restore the character. bsf STATUS,C ; Indicate true. return ;;; ******************************************************************** ;;; Subroutine Name: STR_IsHexS ;;; Description: Determines whether or not a NULL-terminated ;;; string contains nothing but ASCII characters ;;; corresponding to hex digits. ;;; Requires: IRP:FSR point to the start of the NULL-terminated ;;; string. ;;; Returns: STATUS,C contains true if the character is ;;; in the ranges outlined, above. False otherwise. ;;; Locations Affected: W is destroyed, STR_FSRSave ;;; ******************************************************************** STR_IsHexS: global STR_IsHexS banksel STR_FSRSave movf FSR,W movwf STR_FSRSave ; Save the pointer. STR_IsHexS_Loop: ;; Process each byte until the NULL is hit. movf INDF,W btfsc STATUS,Z goto STR_IsHexS_True call STR_IsHex btfss STATUS,C goto STR_IsHexS_False incf FSR, F ; Increment the pointer. goto STR_IsHexS_Loop STR_IsHexS_True: ;; Restore the pointer. movf STR_FSRSave,W movwf FSR bsf STATUS,C ; Indicate true. return STR_IsHexS_False: ;; Restore the pointer. movf STR_FSRSave,W movwf FSR bcf STATUS,C ; Indicate false. return ;;; ******************************************************************** ;;; Subroutine Name: STR_ToUpperS ;;; Description: Converts a NULL-terminated string to upper-case. ;;; Requires: IRP:FSR point to the start of the NULL-terminated ;;; string. ;;; Returns: The string pointed to by IRP:FSR. ;;; Locations Affected: W is destroyed, STR_FSRSave. ;;; ******************************************************************** STR_ToUpperS: global STR_ToUpperS banksel STR_FSRSave movf FSR,W ; Save the pointer. movwf STR_FSRSave STR_ToUpperS_Loop: ;; Process each byte until the NULL is hit. movf INDF,W btfsc STATUS,Z goto STR_ToUpperS_Done call STR_ToUpper movwf INDF incf FSR, F ; Increment the pointer. goto STR_ToUpperS_Loop STR_ToUpperS_Done: ;; Restore the pointer. movf STR_FSRSave,W movwf FSR return ;;; ******************************************************************** ;;; Subroutine Name: STR_ToUpper ;;; Description: Converts a single ASCII character to upper-case. ;;; Requires: W contains the character to convert. ;;; Returns: W contains the upper-case character.; ;;; Locations Affected: STR_Storage. ;;; ******************************************************************** STR_ToUpper: global STR_ToUpper banksel STR_Storage movwf STR_Storage ;; Ensure the character is a lower-case letter, otherwise ;; do nothing. brwlok 'a',STR_ToUpper_Skip movf STR_Storage,W brwlsk 'z',STR_ToUpper_Process STR_ToUpper_Skip: ;; Reaching here means the letter wasn't lower-case. movf STR_Storage,W ; Restore the value. return STR_ToUpper_Process: movf STR_Storage,W ; Restore the value. andlw 0xDF ; Make uppercase. return ;;; ******************************************************************** ;;; Subroutine Name: STR_ToLowerS ;;; Description: Converts a NULL-terminated string to lower-case. ;;; Requires: IRP:FSR point to the start of the NULL-terminated ;;; string. ;;; Returns: The string pointed to by IRP:FSR. ;;; Locations Affected: W is destroyed, STR_FSRSave ;;; ******************************************************************** STR_ToLowerS: global STR_ToLowerS banksel STR_FSRSave movf FSR,W ; Save the pointer. movwf STR_FSRSave STR_ToLowerS_Loop: ;; Process each byte until the NULL is hit. movf INDF,W btfsc STATUS,Z goto STR_ToLowerS_Done call STR_ToLower movwf INDF incf FSR, F ; Increment the pointer. goto STR_ToLowerS_Loop STR_ToLowerS_Done: ;; Restore the pointer. movf STR_FSRSave,W movwf FSR return ;;; ******************************************************************** ;;; Subroutine Name: STR_ToLower ;;; Description: Converts a single ASCII character to lower-case. ;;; Requires: W contains the character to convert. ;;; Returns: W contains the lower-case character. ;;; Locations Affected: STR_Storage. ;;; ******************************************************************** STR_ToLower: global STR_ToLower banksel STR_Storage movwf STR_Storage ;; Ensure the character is an upper-case letter, otherwise ;; do nothing. brwlok 'A',STR_ToLower_Skip movf STR_Storage,W brwlsk 'Z',STR_ToLower_Process STR_ToLower_Skip: ;; Reaching here means the letter wasn't upper-case. movf STR_Storage,W ; Restore the value. return STR_ToLower_Process: movf STR_Storage,W ; Restore the value. iorlw 0x20 ; Make lower case. return ;;; ******************************************************************** ;;; Subroutine Name: STR_Length ;;; Description: Determines the length of a NULL-terminated ;;; string in RAM. ;;; Requires: IRP:FSR points to the string. ;;; Returns: The length (excluding the NULL) in W. ;;; Locations Affected: STR_FSRSave, STR_Storage ;;; ******************************************************************** STR_Length: global STR_Length banksel STR_FSRSave movf FSR,W movwf STR_FSRSave ; Save the pointer. ;; W contains the starting pointer value. STR_Length_Loop: movf INDF,F ; Test the character. btfsc STATUS,Z goto STR_Length_Done incf FSR,F ; Point to the next character. goto STR_Length_Loop STR_Length_Done: ;; The difference between W and FSR is the string length. subwf FSR,W movwf STR_Storage ;; Restore the pointer. movf STR_FSRSave,W movwf FSR ;; Restore the count. movf STR_Storage,W return ; ;;; ******************************************************************** ; ;;; Subroutine Name: STR_LengthK ; ;;; Description: Determines the length of a NULL-terminated ; ;;; string constant in code memory. ; ;;; Requires: ; ;;; Returns: ; ;;; Locations Affected: ; ;;; ******************************************************************** ; STR_LengthK: ; global STR_LengthK ; return ; ;;; ******************************************************************** ; ;;; Subroutine Name: STR_Copy ; ;;; Description: Copies a NULL-terminated RAM string into ; ;;; a new location. ; ;;; Requires: IRP:FSR point to the start of the source ; ;;; string. ; ;;; STR_Pointer points to the start of the buffer ; ;;; used to hold the new string. ; ;;; Returns: W contains the number of bytes copied ; ;;; (excluding the NULL). ; ;;; Locations Affected: STR_FSRSave, STR_Storage ; ;;; ******************************************************************** ; STR_Copy: ; global STR_Copy ; return ; ;;; ******************************************************************** ; ;;; Subroutine Name: STR_CopyN ; ;;; Description: Copies N characters of a source string to ; ;;; a destination. ; ;;; Requires: ; ;;; Returns: ; ;;; Locations Affected: ; ;;; ******************************************************************** ; STR_CopyN: ; global STR_CopyN ; return ; ;;; ******************************************************************** ; ;;; Subroutine Name: STR_CopyK ; ;;; Description: Copies a NULL-terminated string constant into ; ;;; a new (RAM) location. ; ;;; Requires: ; ;;; Returns: ; ;;; Locations Affected: ; ;;; ******************************************************************** ; STR_CopyK: ; global STR_CopyK ; return ; ;;; ******************************************************************** ; ;;; Subroutine Name: STR_CopyKN ; ;;; Description: Copies N characters of a source string constant ; ;;; into a new RAM location. ; ;;; Requires: ; ;;; Returns: ; ;;; Locations Affected: ; ;;; ******************************************************************** ; STR_CopyKN: ; global STR_CopyKN ; return ;;; -------------------------------------------------------------------- ;;; Constant Data (if not placed along with the subroutines). ;;; -------------------------------------------------------------------- END