Sunday, July 5, 2015

Phase 1: tclib

/*
 *****************************************************************
 *name:         tclib.h
 *author:       Samuel Igwe
 *date:         06/07/2015 (c) copyright
 *description:  tclib (my thumb) library header.
 *****************************************************************
 */
#ifndef TCLIB_H
#define TCLIB_H


    extern  int     IE_tclib_atoi(unsigned char *ptrAscStr);
    extern  void    IE_tclib_itoa(unsigned int wdValue,\
                                  unsigned char *ptrAscStr);
    extern  int     IE_tclib_bswap(unsigned int wdValue);
    extern  int     IE_tclib_swap(unsigned int wdValue);
    extern  int     IE_tclib_strlen(unsigned char *ptrStrSrc);
    extern  int     IE_tclib_strcmp(unsigned char *ptrStrSrc,\
                                    unsigned char *ptrStrDst);
    extern  void    IE_tclib_memset(unsigned char *ptrString,\
                                    unsigned int wdValue,\
                                    unsigned int wdSize);
    extern  void    IE_tclib_memcpy(unsigned char *ptrDstStr,\
                                    unsigned char *ptrSrcStr,\
                                    unsigned int wdSize);
    extern  int     IE_tclib_acquire_semaphore(unsigned int *ptrWord);
    extern  int     IE_tclib_release_semaphore(unsigned int *ptrWord);


#endif
 



 
 
 
 

/*
 *****************************************************************
 *name:         tclib.S
 *author:       Samuel Igwe
 *date:         06/07/2015
 *description:  my thumb2 library. asm optimized generic routines
 *
 *notes:        from ARM technical reference manual
 *              instructions are conditional
 *              eq/ne (eq = 0, ne = not 0)
 *              ge/gt/le/lt
 *              memory addressing formats ldr(s)/str
 *              pre-index with writeback   ldr r0, [r1,#4]!
 *                              data = mem[base+offset] 
 *                      base addr reg= base+offset
 *              pre-index                  ldr r0, [r1,#4]
 *                              data = mem[base+offset]
 *                      base addr reg= not updated
 *              post-index                 ldr r0, [r1],#4
 *                              data = mem[base]
 *                      base addr reg= base+offset 
 *
 *              #4 above could be replaced by another register
 *****************************************************************
 */
#ifndef TCLIB_S
    .thumb
    .text
    .syntax unified


/*
 *****************************************************************
 *description:  C initializer. basically just setups up the stack
 *note:         not really needed since offset 0 of the ivt setups
 *              up the main stack pointer. this routine exists for
 *              when i want to change it which is UNLIKELY
 *****************************************************************
 */
    .align      2
    .global tclib_cinit
    .thumb_func
    .equ        LPC177X_SRAM_BASE, 0x10000000
    .equ        SRAM_TOP, (LPC177X_SRAM_BASE + (64*1024))
    tclib_cinit:
    ldr sp, =SRAM_TOP
    mov pc, lr





/*
 *****************************************************************
 *description:  software divider. meanth to be called from asm
 *              takes 
 *inputs:       r0 = dividend
 *              r1 = divisor
 *outputs:      r0 = quotient
 *              r1 = remainder
 *output:       0 on error 1 on success
 *****************************************************************
 */
    .align  2
    .global tclib_softdiv
    .thumb_func
    tclib_softdiv:
    push    {r2, lr}

    mov r2, r0                                  /*put r0 in r2*/
    mov r0, #0                                  /*zero out quotient*/

    tclib_softdiv_loop:
    cmp r2, r1
    blt tclib_softdiv_exit
    sub r2, r2, r1
    add r0, r0, #1
    b tclib_softdiv_loop

    tclib_softdiv_exit:
    mov r1, r2                                  /*r1 remainder*/

    pop {r2, lr}
    mov pc, lr





/*
 *****************************************************************
 *description:  acquire semaphore
 *input:        char *ptrWord   = pointer to memory word
 *output:       0 on error 1 on success
 *void
 *tclib_acquire_semaphore(unsigned char *ptrWord)
 *****************************************************************
 */
    .align  2
    .global tclib_acquire_semaphore
/*
 *****************************************************************
 *r0 = ptrWord
 *****************************************************************
 */
    .thumb_func
    tclib_acquire_semaphore:
    push    {r1-r2}


    mov     r1, #1
    mov     r2, r0

    ldrexb  r0, [r2]                        /*get value*/
    cmp     r0, #0
    itt     ne
    eorne   r0, #1
    bne     tclib_get_mutex_exit

    strexb  r0, r1, [r2]
    eor     r0, #1

    tclib_get_mutex_exit:
    clrex

    pop     {r1-r2}
    mov     pc, lr





/*
 *****************************************************************
 *description:  release semaphore
 *input:        char *ptrWord   = pointer to memory word
 *output:       0 on error 1 on success
 *void
 *tclib_release_semaphore(unsigned char *ptrWord)
 *****************************************************************
 */
    .align  2
    .global tclib_release_semaphore
/*
 *****************************************************************
 *r0 = ptrWord
 *****************************************************************
 */
    .thumb_func
    tclib_release_semaphore:
    push    {r1-r2}


    mov     r1, #0
    mov     r2, r0

    ldrexb  r0, [r2]                        /*get value*/
    cmp     r0, #0
    ite     ne
    eorne   r0, #1
    beq     tclib_release_mutex_exit

    strexb  r0, r1, [r2]
    eor     r0, #1

    tclib_release_mutex_exit:
    clrex

    pop     {r1-r2}
    mov     pc, lr





/*
 *****************************************************************
 *description:  sets a string buffer to a certain value
 *input:        char *ptrString =pointer to string
 *              int  wdValue    =value
 *              int  wdSize     =maximum length of string
 *void
 *tclib_memset(unsigned char *ptrString, int wdValue, int wdSize)
 *{
 *while ((wdSize--) >0)
 *       *(ptrString++) = (char)wdValue;
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_memset
/*
 *****************************************************************
 *r0 = ptrString
 *r1 = wdValue
 *r2 = wdSize
 *r3 = scratch
 *****************************************************************
 */
    .thumb_func
    tclib_memset:
    push    {r0-r3, lr}

    mov     r3, r1, lsl #8
    orr     r1, r1, r3                      /*put byte into word*/
    mov     r3, r1, lsl #16
    orr     r1, r1, r3                      /*put word into dword*/

/*
 *****************************************************************
 *the instructions below
 orr     r1, r1, lsl #8                 
 orr     r1, r1, lsl #16
 *
 *generate the error
 tclib/tclib.S: Assembler messages:
 tclib/tclib.S:203: Error: garbage following instruction -- `orr r1,r1,lsl#8'
 tclib/tclib.S:204: Error: garbage following instruction -- `orr r1,r1,lsl#16'
 *under arm-linux-gnueabi-gcc version 4.4.5
 *so I revised it to the instructions above this comment
 *****************************************************************
 */

    andS    r3, r0, #0x3                /*determine dword alignment*/
    beq     tclib_memset_loop        /*take action if aligned*/


        tclib_memset_align:
        strb    r1, [r0], #1            /*store one byte - autoincr*/
        subS    r2, r2, #1              /*decrement counter*/
        itt     EQ
        popeq   {r0-r3, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        andS    r3, r0, #0x3            /*determine dword alignment*/
        bne     tclib_memset_align


        tclib_memset_loop:           /*optimization*/
        cmp     r2, #4                  /*r2 >= 4*/
        blt     tclib_memset_align
                                        /*else*/
        str     r1, [r0], #4            /*dword*/
        subS    r2, #4                  /*decrement counter*/
        bne     tclib_memset_loop      
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/




/*
 *****************************************************************
 *description:  copy from source to destination buffer
 *input:        char *ptrDstStr =pointer to dst string
 *              char *ptrSrcStr =pointer to src string
 *              int  wdSize     =max length of string
 *void
 *tclib_memcpy(unsigned char *ptrDstStr,\
 *              unsigned char *ptrSrcStr, \
 *              int wdSize)
 *{
 *while ((wdSize--) >0)
 *       *(ptrDstStr++) = *(ptrSrcStr++);
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_memcpy
/*
 *****************************************************************
 *r0 = ptrDst
 *r1 = ptrSrc
 *r2 = wdSize
 *r3 = scratch
 *****************************************************************
 */
    .thumb_func
    tclib_memcpy:
    push    {r0-r3, lr}

    andS    r3, r0, #0x3                /*check if dst aligned*/                        
    bne     tclib_memcpy_bcopy
    andS    r3, r1, #0x3                /*check if src aligned*/
    bne     tclib_memcpy_bcopy


        tclib_memcpy_loop:           /*optimization*/
        cmp     r2, #4                  /*check if size >= 4*/
        blt     tclib_memcpy_bcopy
                                        /*else*/
        ldr     r3, [r1], #4            /*get from src*/
        str     r3, [r0], #4            /*put in   dst*/
        subS    r2, #4                  /*decrement counter*/
        bne     tclib_memcpy_loop
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/


        tclib_memcpy_bcopy:
        ldrb    r3, [r1], #1            /*get from src*/
        strb    r3, [r0], #1            /*put in   dst*/
        subS    r2, #1                  /*decrement counter*/
        bne     tclib_memcpy_bcopy
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/





/*
 *****************************************************************
 *description:  ascii to integer
 *input:        char *ptrAscStr =pointer to string
 *output:       int             =value
 *int
 *tclib_atoi(unsigned char *ptrAscStr)
 *{
 *unsigned char     *ptrTemp;
 *volatile int wdValue,wdWeight,wdTemp;
 *
 *wdValue =0;
 *wdWeight=1;
 *ptrTemp =ptrAscStr;
 *
 *while ((*ptrTemp) != NULL)
 *       ptrTemp++;
 *
 *while ((--ptrTemp) >= ptrAscStr)
 *       {
 *       wdTemp = *ptrTemp;
 *       if (wdTemp >= '0' && wdTemp <='9')
 *               wdTemp-= '0';
 *       else
 *               {
 *               if (wdTemp >='a' && wdTemp <='f')
 *                       {
 *                       wdTemp-= 'a';
 *                       wdTemp+= 10;
 *                       }
 *               else
 *                       {
 *                       if (wdTemp >= 'A' && wdTemp <= 'F')
 *                               {
 *                               wdTemp-= 'A';
 *                               wdTemp+= 10;
 *                               }
 *                       else
 *                               return 0;
 *                       }
 *               }
 *
 *       wdValue  += wdTemp * wdWeight;
 *       wdWeight<<= 4;
 *       }
 *
 *return wdValue;
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_atoi
/*
 *****************************************************************
 *r0 = ptrString
 *returns r0
 *r1 = r0 - address
 *r2 = scratch - wdValue
 *r3 = scratch - wdWeight
 *r4 = scratch
 *****************************************************************
 */
    .thumb_func
    tclib_atoi:
    push    {r1-r4, lr}

    mov     r1, r0                      /*to be return value*/
    bl      tclib_strlen                /*of strlen()*/
    cmp     r0, #0                      /*is it zero?*/
    itt     EQ
    popeq   {r1-r4, lr}
    moveq   pc, lr

    mov     r3, #1                      /*init wdWeight*/
    mov     r2, #0                      /*zero out*/


        tclib_atoi_loop:
        subS    r0, r0, #1              /*decrement loop*/
        ittt    LT
        movlt   r0, r2                  /*copy out arg when done*/
        poplt   {r1-r4, lr}
        movlt   pc, lr

        ldrb    r4, [r1,r0]             /*preindex without update*/
        and     r4, r4, #0x0ff          /*clear upper bits*/

        cmp     r4, #'0'
        ittt    LT
        movlt   r0, #0                  /*zero out before exiting*/
        poplt   {r1-r4, lr}             /*exit if less than '0'*/
        movlt   pc, lr                  /*exit*/

        cmp     r4, #'9'
        bgt     tclib_atoi_lcase
        sub     r4, r4, #'0'
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4          /*adjust 16^x*/
        b       tclib_atoi_loop


        tclib_atoi_lcase:
        cmp     r4, #'a'
        blt     tclib_atoi_ucase
        cmp     r4, #'f'
        ittt    GT
        movgt   r0, #0                  /*zero out before exiting*/
        popgt   {r1-r4, lr}             /*exit if greater than 'f'*/
        movgt   pc, lr                  /*exit*/

        sub     r4, r4, #'a'
        add     r4, r4, #10
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4
        b       tclib_atoi_loop

                
        tclib_atoi_ucase:
        cmp     r4, #'A'
        ittt    LT
        movlt   r0, #0                  /*zero out before exiting*/
        poplt   {r1-r4, lr}
        movlt   pc, lr

        cmp     r4, #'F'
        ittt    GT
        movgt   r0, #0                  /*zero out before exiting*/
        popgt   {r1-r4, lr}             /*exit if greater than 'F'*/
        movgt   pc, lr                  /*exit*/

        sub     r4, r4, #'A'
        add     r4, r4, #10
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4
        b       tclib_atoi_loop
        




/*
 *****************************************************************
 *description:  integer to ascii. convert nibbles
 *input:        int     wdValue     =value
 *              char    *ptrAscStr  =pointer to string
 *void
 *tclib_itoa(int wdValue, unsigned char *ptrAscStr)
 *{
 *volatile int wdIndex,wdTemp;
 *
 *if (wdValue < 0)
 *       wdIndex =8;
 *else
 *       {
 *       if (wdValue < (1 << 8))
 *               wdIndex =2;
 *       else
 *               {
 *               if (wdValue < (1 << 16))
 *                       wdIndex =4;
 *               else
 *                       {
 *                       if (wdValue < (1 << 24))
 *                               wdIndex =6;
 *                       else
 *                               wdIndex =8;
 *                       }
 *               }
 *       }
 *
 *ptrAscStr[wdIndex--] =NULL;
 *while (wdIndex >=0)
 *       {
 *       wdTemp   = wdValue;
 *       wdTemp  &= 0x0f;
 *       wdValue>>= 4;
 *
 *       if (wdTemp >=0 && wdTemp < 10)
 *               ptrAscStr[wdIndex--] = wdTemp +'0';
 *       else
 *               {
 *               wdTemp -=10;
 *               ptrAscStr[wdIndex--] = wdTemp +'A';     
 *               }
 *       }
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_itoa
/*
 *****************************************************************
 *r0 = value
 *r1 = ptrString
 *r2 = scratch - index
 *r3 = scratch
 *r4 = 1
 *****************************************************************
 */
    .thumb_func
    tclib_itoa:
    push    {r0-r4, lr}

    mov     r4, #1
    mov     r3, r4, lsl #8              /*(wdValue< (1<<8))*/
    cmp     r0, r3
    itt     LO
    movlo   r2, #2
    blo     tclib_itoa_prep_loop

    mov     r3, r4, lsl #16             /*(wdValue< (1<<16))*/
    cmp     r0, r3
    itt     LO
    movlo   r2, #4
    blo     tclib_itoa_prep_loop

    mov     r3, r4, lsl #24             /*(wdValue< (1<<24))*/
    cmp     r0, r3
    ite     LO
    movlo   r2, #6
    movhs   r2, #8


    tclib_itoa_prep_loop:
    add     r1, r1, r2                  /*setup addresses*/
    mov     r3, #0
    strb    r3, [r1],#-1                /*nullify string*/


        tclib_itoa_loop:
        sub     r2, r2, #1              /*decrement counter*/
        cmp     r2, #0
        itt     LT
        poplt   {r0-r4, lr}             /*exit*/
        movlt   pc, lr                  /*exit*/

        mov     r3, r0                  /*save r0 temporarily*/
        mov     r0, r0, lsr #4          /*new value to work on*/
        and     r3, r3, #0x0f           /*nibble*/

        cmp     r3, #10                 /*prepare to adjust*/
        itee    LT
        addlt   r3, r3, #'0'
        subge   r3, r3, #10
        addge   r3, r3, #'A'
        
        strb    r3, [r1],#-1            /*store with auto-decr*/
        b       tclib_itoa_loop





/*
 *****************************************************************
 *description:  word swap
 *input:        int wdValue = value 
 *output:       int
 *int
 *tclib_word_swap(int wdValue)
 *{
 *unsigned int dwTemp;
 *
 *(dwTemp = 0;
 *dwTemp|= (wdValue << 24) & 0xff000000;
 *dwTemp|= (wdValue << 8 ) & 0x00ff0000;
 *dwTemp|= (wdValue >> 24) & 0x0ff;
 *dwTemp|= (wdValue >> 8 ) & 0x0ffff;
 *
 *return dwTemp;
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_swap
/*
 *****************************************************************
 *r0 = value
 *returns r0 = word swapped value
 *r1 = scratch
 *r2 = scratch
 *r3 = 0x0ff
 *****************************************************************
 */
    .thumb_func
    tclib_swap:
    push    {r1, lr}

    mov     r1, r0                      /*safe keep - r0 = return*/
    rev     r0, r1                      /*theres a single thumb ins*/
                                        /*for this now*/
    pop     {r1, lr}                    /*exit*/
    mov     pc, lr                      /*exit*/





/*
 *****************************************************************
 *description:  byte swap
 *input:        int wdValue = value 
 *output:       int
 *int
 *tclib_byte_swap(int wdValue)
 *{
 *unsigned int dwTemp;
 *
 *dwTemp = 0;
 *dwTemp|= (wdValue << 8 ) & 0xff00;
 *dwTemp|= (wdValue >> 8 ) & 0x0ff;
 *
 *return dwTemp;
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_bswap
/*
 *****************************************************************
 *r0 = value
 *returns r0 = byte swapped value
 *r1 = scratch
 *r2 = scratch old value
 *****************************************************************
 */
    .thumb_func
    tclib_bswap:
    push    {r1, lr}

    mov     r1, r0
    rev     r0, r1                          /*save original value*/
    mov     r0, r0, lsl #16

    pop     {r1, lr}                        /*exit*/
    mov     pc, lr                          /*exit*/
 




/*
 *****************************************************************
 *description:  string len computation function
 *inputs:       char *ptrStrSrc
 *output:       int  = lenght of string
 *int
 *tclib_strlen(unsigned char *ptrStrSrc)
 *{
 *unsigned int wdCount;
 *for (wdCount=0; ptrStrSrc[wdCount]!=NULL; wdCount++)
 *      ;
 *
 *return wdCount;
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_strlen
/*
 *****************************************************************
 *r0 = ptrString
 *returns r0 = byte length
 *r1 = ptrString
 *r2 = scratch
 *****************************************************************
 */
    .thumb_func
    tclib_strlen:
    push    {r1-r2, lr}

    mov     r1, r0                      /*put pointer in r1*/
    mov     r0, #0                      /*zero out r0*/


        tclib_strlen_loop:
        ldrb    r2, [r1], #1            
        andS    r2, r2, #0x0ff          /*clear lower bits*/
            
        itee    NE
        addne   r0, r0, #1              /*track strlen results*/

        popeq   {r1-r2, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        b       tclib_strlen_loop              





/*
 *****************************************************************
 *description:  string comparison 
 *inputs:       char *ptrStrSrc=string 1
 *              char *ptrStrDst=string 2
 *              int  wdCount   =number of characters to compare 
 *output:       int = 0 on success failing index on error
 *int
 *tclib_strcmp(unsigned char *ptrStrSrc,\
 *             unsigned char *ptrStrDst,\
 *             int wdCount)
 *{
 *unsigned int wdIndex;
 *
 *for(wdIndex=0; wdIndex <wdCount; wdIndex++)
 *      {
 *      if (ptrStrSrc[wdIndex] == NULL || \
 *           ptrStrDst[wdIndex] == NULL || \
 *          (ptrStrSrc[wdIndex] - ptrStrDst[wdIndex]) !=0)
 *              return wdIndex;
 *      }
 *
 *return 0;          
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_strcmp
/*
 *****************************************************************
 *r0 = ptrDst
 *r1 = ptrSrc
 *returns r0 strcmp value
 *r1 = src1
 *r2 = src2
 *r3 = scratch
 *r4 = scratch
 *r0 = cmp
 *****************************************************************
 */
    .thumb_func
    tclib_strcmp:
    push    {r1-r4, lr}

    mov     r2, r0                      /*save src1 in r2*/
    mov     r0, #0                      /*zero out r0*/


        tclib_strcmp_loop:
        ldrb    r3, [r1], #1            
        andS    r3, r3, #0x0ff          /*clear upper bits*/
        orrS    r3, r3, #0              /*end of string?*/
        beq     tclib_strcmp_exit

        ldrb    r4, [r2], #1
        andS    r4, r4, #0x0ff          /*clear upper bits*/
        orrS    r4, r4, #0              /*end of string?*/
        beq     tclib_strcmp_exit

        cmp     r4, r3
        it      EQ
        beq     tclib_strcmp_loop
                                        /*else*/
        ite     HI
        addhi   r0, r0, #1              /*track strcmp results*/
        subls   r0, r0, #1              /*ditto*/

        itt     NE
        popne   {r1-r4, lr}             /*exit*/
        movne   pc, lr                  /*exit*/
        
        
        tclib_strcmp_exit:
        itt     EQ
        popeq   {r1-r4, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        b       tclib_strcmp_loop





    .end
#endif

No comments:

Post a Comment