/*
*****************************************************************
*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