☞ http://ya-n-ds.tistory.com/3103 : Embedded with ARM (1) ARM Register, Compile, ELF
☞ http://ya-n-ds.tistory.com/3137 : Embedded with ARM (2) Scatter file, Map file, Makefile
☞ http://ya-n-ds.tistory.com/3181 : Embedded with ARM (3) Assembly
# Referece : 'Embedded Recipes'(히언, 코너북)
☞ http://recipes.egloos.com/
☞ https://www.cs.utexas.edu/users/fussell/courses/cs429h/lectures/Lecture_20-429h.pdf : Linking
<< Ch.5 Software Vignetting >>
< Context & AAPCS(ARM Architecture Procefure Call Standard) >
- Context : 현재 CPU에 대한 모든 정보 ( R0~R12, R13-SP, R14-LR, R15-PC, CPSR )
cf. CPSR (Current Program Satus Registe) : bit[31:28] NZCV, bit[7:6] IF, bit[5:0] mode
cf. R0~R3 can be used for Return value and Passing parameters of the called function
cf. Call 'Leaf' function (w/o another fucntion call inside) : 'Move pc, lr' is enough to get back
cf. RTOS Context Switching : Complete Context Back-up and Restoration
- Example
void ContextDaugher();
void ContextMother(void);
{
code_before_ContextDaughter; // 0x1500
// Registers(among R0~R12) which will be used(determined in Compile) in 'ContextDauger' are pushed into stack
// SP is changed based on the stack
// R14 <= 0x1504 because this code is to be executed after 'ContextDaughter'
// R14 is pushed into stack ( preparation for the case in which ContextDaughter may call another function )
// push {Rk~Rn, R14}
// CPSR is backed-up only for Exception case
ContextDaugher(); // 0x1502
// pop {Rk~Rn, PC} // (Pushed) R14 is back to R15(PC)
code_after_ContextDaughter; // 0x1504
}
< Pointer, Array, Double Pointer >
* Pointer : word-size data type
int* address
-> address : the address where the integer type data exists
-> *address : the data which is specified by the address and whose type and size is integer
char *text="Recipes"; // text is the address where 'R' exists
// *(text++) -> 'e' - if text is 0x100 then (text++) indicates 0x101
text[1]; // 'e'
*(text+1); // 'e'
char *pointer;
char array[3] = {0,1,2};
pointer=array;
pointer=&array[0]; // Same meaning
// Deliver the pointer as arguments
void swap(int* pa, int* pb)
{
// (&pa)[pa] -> (pa)[*pa], (&pb)[pb] -> (pb)[*pb]
int tmp; // (&tmp)[tmp]
tmp = *pa;
*pa = *pb;
*pb = temp;
return;
}
int process(void)
{
int a,b;
int a=1; // (&a)[1]
int b=2; // (&b)[2]
swap(&a, &b); // &a -> pa, &b -> pb
}
// Example : Address, Data of Pointer
void main()
{
int temp; // (&temp)[temp]
int* p1; // (&p1)[p1] -> (p1)[*p1]
int** pp1; // (&pp1)[pp1] -> (pp1)[*pp1] -> (*pp1)[**pp1]
p1=&temp;
pp1=&p1; // compile error with 'pp1=&temp' because pp1 shall point the pointer-type variable
*p1 = 10; // 'temp' will be set as '10'
}
// Double pointer usage
void gettag(char** ptag)
{
*ptag = (char *)malloc(40);
strncpy(*ptag,"pointer tag",sizeof(char)*40);
}
void process()
{
char *tag;
gettag(&tag);
free(tag);
}
< struct, typedef, PACKED >
* struct : generation of structure-type variable
struct customer{
char* name;
int height;
int weight;
}
=> customer Kim; // Kim is a 'custom'-type variable
struct Structure_Type_Name { declare multiple variables } Variable_name(s);
* typedef : generation of a new data type
tyepdef 'variable type' Type_Name;
typedef struct customer{
char* name;
int height;
int weight;
} Type_Name;
// Type_Name cannot be a variable (e.g. *kim, kim[100], etc.)
// Instead, 'Type_Name Variable_Name;' is used. ( e.g. Type_Name *kim, Type_Name kim[100], etc. )
typedef enum{
START,
WALK,
RUN
} customer_activity_type;
customer_activity_type activity;
switch(acitvity)
{
case START;
...
case RUN;
...
}
< Stack, Heap >
- Stack : LIFO(Last In First Out) structure, push(In), pop(Out), History function
e.g. command history, command abortion(ctrl -z),
cf. implemenation : push(0x1);, push(0x2);, push(0x3); -> pop() //0x3 올라옴, pop() // 0x2 올라옴, pop() // 0x1 올라옴
- Heap : Dynamic Allocation ( Linked List, Tree structure ) via alloc, free
e.g. Method to get the size of Arrays whose size is unknown
void HEAP (int n)
{
int *p;
p=(int *)malloc((sizeof(int))*n);
... }
=> *p, *(p+1), *(p+2), ... ~ p[0], p[1], p[2], ...
< Stack - details >
* Embedded System : Stack and Heap is declared as a 'Global variable'
e.g. Stack : dword recipe_stack[20000]
Heap : static uint32 commonMemoryPool[20000]
cf. Uninitialized Global variable - .bss(ZI)
cf. Growth direction : Stack(Address Decreases), Heap(Address Increases)
- Stack type
a. Ascending(toward the upper address, Increase), Descending(toward the lower address, Decrease)
b. Full(current stack point includes the current data), Empty(current stack point does not include the current data)
c. After(stack pointer changes after data in), Before(stack pointer changes before data in)
e.g.
IB(Increase SP Before Data), IA(Increase SP After Data), DB(Decrease SP Before Data), DA(Decrease SP After Data)
FA(Full Ascending), FD(Full Descening) // SP points to the valid data
EA(Empty Ascending), ED(Empty Descening) // SP points to the invalid data
e.g. STM(STore Multiple)=push(), LDM(LoaD Multiple)=pop()
STMIA r9!, {r0, r1, r5} // STR r0, [R9] & R9++ -> STR r1, [R9] & R9++ -> STR r5, [R9] & R9++ // Same as STMEA
STMIB r9!, {r0, r1, r5} // R9++ & STR r0, [R9] -> R9++ & STR r1, [R9] -> R9++ & STR r5, [R9] // Same as STMFA
STMDA r9!, {r0, r1, r5} == STMED r9!, {r0, r1, r5}
STMDB r9!, {r0, r1, r5} == STMFD r9!, {r0, r1, r5}
- Normal Stack Type : Full Descending ( Increase Before )
stmfd sp!, {r4-r12, lr} // sp(Stack Pointer=R13), lr(Linked Register=R14)
ldmfd sp!, {r4-r12, lr}
e.g. Stack initialization : Change CPU mode to Abort mode -> Link Abort stack to R13
msr CPSR_C, #PSR_Abort ;; msr : Load an immediate value or a contents of general-purpose regiser to PSR(Program Status Register)
lrd r13, =abort_stack+Abort_Stack_Size // Descending : from 'abort_stack+Abort_Stack_Size' to 'abort_stack'
// Ascending : from 'abort_stack' to 'abort_stack+Abort_Stack_Size'
- Cautions!
a. Thumb mode : push/pop only / ARM mode : Multiple Register transfer
b. CMD r9!, {r0, r1, r5} // Store/Load : from r5 for Descending, from r0 for Ascending -> the 1st element lies in the lower address
- Calling Functions
a. Deliver arguments and push the address to return into stack
b. Call functions
c. Prepare the memory space in Stack for local variables
d. Execute the functions
e. Release the local variables from Stack
f. Load the address to return from Stack, and return the caller function
g. Release the arguments
-----