2017年11月14日 星期二

[GCC] inline asm

gcc提供了內嵌語法,使在 C 語言中可以直接撰寫組合語言。


asm voltaile(                                   ; 內嵌起始符號
     assembler template                ; 組合語言程式
     : output operands                 ; : 輸出參數列表
     : input operands                  ; : 輸入參數列表
     : list of clobbered registers     ; : 被更改的暫存器列表
     );     

":" : 分隔符號
assembler template: 組語部分,需存取output/input operands列表內容
%0: 輸出
%1~N:輸入
clobber: 告訴compiler,哪些register被這段code改了

operand register的修飾符(constraint):
  • f : floating point register (有些 cpu 有專屬的 floating point register) 
  • I : 立即定址 immediate operands
  • J : Indexing constants 
  • K : negative value in rhs 
  • L: negative value in rhs 
  • M : for shift 
  • r : General registers -- ARM 一般用這個

  • = : Write-only (通常所有的 output operand 都會加這個符號)
  • + : Read-Write (inline assemnly 不支援這個符號)
  • & : Output only - 這個register 只做 output 使用



參考:
http://stenlyho.blogspot.tw/2008/08/cinline-casmasm-code-asmmovl-1eaxnt.html



2017年11月9日 星期四

周邊裝置操作與記憶體映射

IO(周邊裝置)的操作有兩種方式:
  1. 指令
    • WR R1, LCD #利用WR指令將R1的值寫至LCD(IO)
    • 缺點這種專用指令沒辦法用C


  1. 記憶體映射
    • 利用記憶體存取指令進行輸出入功能的方式(CPU沒有輸出入指令如1)
    • 周邊裝置會配置特定的記憶體位址空間給IO裝置
    • 當對該位址作如store(register->ram)的輸出指令時,就會將資料輸出到該IO
    • 其實對CPU而言不論是記憶體或是周邊裝置都是透過匯流排做溝通(匯流排控制器控制周邊(包含記憶體)主要為位址, 資料, 控制訊號需要處理)
所以本來就可以一是同仁的操作。
  •  

等待方式:

  1. busy waiting: polling
  2. interrupt

2017年11月7日 星期二

[C] How to build up the call tree?


實驗:
利用 compiler tool( https://gcc.godbolt.org/)翻譯為組語
並做說明(留意下註解中的順序)


當呼叫printCallTree即可將call tree上的函式位置printf出來(或存在ram),
然後再用腳本(offline)將位置對應到map檔中的symbo,
得到call tree
這樣的程式可以放在Exception ISR中,
得知fun的呼叫關係,
增加debug的資訊。

p.s 實作時需要參考IC的calling convertion

C:
void printCallTree(){}

void callee(){ callee2();}

void caller(void){callee();}

assembly:
callStack(): #1 暫存器RA可以反查到 text.callee()

...

callee():
addiu $sp,$sp,-32
sw $31,28($sp) #3, 從這可反推RA放在stack的哪,而RA又可以找到caller()_
sw $fp,24($sp)
move $fp,$sp
jal callee2() #2 從text這往上找到 push ra的指令
nop

nop
move $sp,$fp
lw $31,28($sp)
lw $fp,24($sp)
addiu $sp,$sp,32
j $31
nop

caller():
addiu $sp,$sp,-32
sw $31,28($sp) #5 同理
sw $fp,24($sp)
move $fp,$sp
jal callee() #4 同理
nop

nop
move $sp,$fp
lw $31,28($sp)
lw $fp,24($sp)
addiu $sp,$sp,32
j $31
nop

[C] stack frame and frame pointer

定義:
stack frame(堆疊框架): 一個函式所包含的堆疊區塊
frame pointer:用來界定 stace frame 位置(的暫存器

目的:
可利用frame pointer與相對定址存取函式中的變數與參數

實驗:
使用online compilerhttps://gcc.godbolt.org/ ),
翻譯成組語,來查看frame pointer的操作


C:
void caller(void){
int a, b, c;
a=99;
b=123;

c = add(a, b);
}

int add(int a, int b){
int c[1];
c[0] = a;
    return c[0] + b;
}

assembly:
caller():
----------------------------------------------------------------------------- prologue
Audio $sp, $sp, -48 #expand stack
sw $31,44($sp) #push ra
sw $fp,40($sp) #push fp (fp代表函式開頭時的堆疊)
move $fp,$sp # fp = ra
----------------------------------------------------------------------------- body
li $2,99 # 0x63
sw $2,24($fp) #利用fp及相對定址將a存到stack中(sp已經指到後面了,用起來不方便)
li $2,123
sw $2,28($fp)
lw $5,28($fp)
lw $4,24($fp) #add的參數(為副本), 放在堆疊上
jal add(int, int) #呼叫add()
nop
---------------------------------------------------------------------------- eplilogue(動作與prologue相反)
sw $2,32($fp)
nop
move $sp,$fp #回復 sp
lw $31,44($sp) #回復ra
lw $fp,40($sp) #回復fp
addiu $sp,$sp,48 #回復sp
j $31 #return
nop

add(int, int):
addiu $sp,$sp,-24 #expand stack
sw $fp,20($sp) #push fp
move $fp,$sp #fp = ra
sw $4,24($fp) #參數 b(利用fp存取caller的參數)
sw $5,28($fp) #參數 a
lw $2,24($fp)
nop
sw $2,8($fp)
lw $3,8($fp)
lw $2,28($fp)
nop
addu $2,$3,$2
move $sp,$fp
lw $fp,20($sp)
addiu $sp,$sp,24
j $31
nop

重點:
1. frame pointer的作用
2. prologue 與 eplilogue的動作包含:  rafp, sp的處理

reference:

2017年11月1日 星期三

[ThreadX, 9] queue


注意:
  1. Queue 中的mail Size是有限制的(傳給Queue時會Copy一個複本到FIFO trail),且只能是1/2/4/8/16/32 word(UINT),當超過此size spec則傳pointer
#define TX_1_ULONG          1
#define TX_2_ULONG          2
#define TX_4_ULONG          4
#define TX_8_ULONG          8
#define TX_16_ULONG         16

#define TX_32_ULONG         32

[ThreadX, 8] evet

用來同步與通知。

注意:

  • tx_event_flag_set 使用 TX_OR選項時,OS會檢查所有掛起的Thread,滿足條件的thread resume
    • 應避免同一EVENTthread數量,太多ThreadSystem overhead.
  • 當條件滿足時,get能對flagclear(滿足的bits)的動作,如下表

[ThreadX, 7] semaphore

可用來做互斥,通知,同步等動作。

Mutex相比,沒有擁有權的概念,所以會發生幾個狀況:

  1. ThreadA能藉由Put指令將ThreadB Release
  2. ThreadA Get兩次則 dead lock