2015年9月29日 星期二

資料結構: 堆疊應用與後序轉換


以前在大四升碩0的時後,因為太菜了,所以被老板要求寫這些資料結構程式當作練功,資料結構在研究所考試時是必考的,所以我以為我還算熟 , 但要實作程式出來又是另一回事了,可見在大學時真的背太多了 最近整裡硬碟資料找到當初寫的code,所以在此做一下紀錄

主要是參考 Horowitz 資料結構聖經版 
http://www.amazon.com/Fundamentals-Data-Structures-Ellis-Horowitz/dp/0929306406

 這個中序轉後序程式可分為三個部份:
    1.  運算元(A-Z ,0-9)與運算子( + - * / )的分離
               -   使用isalnum()可以將數字/字母與符號分離
    2.  堆疊的操作
               -   push()  &  pop()
    3.  後序轉換演算法
               -  在於比較運算子的優先權:左右括號  >  乘除  >加減


#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>

#define STACK_SIZE 50

#define ADD_SUB   1       /* 代表 加減  */
#define MULT_DIV  2   /* 代表 乘除 */
#define LEFT      3             /* 代表左括號 */
#define RIGHT     4            /* 代表右括號 */

char stack[STACK_SIZE];       /* 堆疊陣列 */
int top=-1;                  /* 堆疊頂端指標 */ 
int priority[STACK_SIZE];        /*優先權堆疊 */


void push(char s,int number){
   if(top>=STACK_SIZE-1){
      printf("堆疊滿了");
   }
   else{
     top++;
     stack[top]=s;
     priority[top]=number;
   }
}

void pop(){
    if (top==-1){
      printf("堆疊已空\n");
    }
    else{
  /*不要印出  '('*/
       if( priority[top ]!=LEFT){
    printf("%c",stack[top]);
       }
       top--;
    }
} 
/* 運算子處理 */
void Operator(char ch,int number) {

  if(top==-1&&number!=RIGHT) /* 若堆疊為空 直接push */
      push(ch,number);
  else{
        switch(number){          
             /* 若輸入為 ')' 從堆疊頂端依序pop直到出現'('  */
           case RIGHT:
                for(priority[top];priority[top]!=LEFT;pop()) ;
                    pop();//把最後的 '(' pop 但不印出 
                break;                       
            /* 若輸入為 '('  直接 PUSH  */
           case LEFT:
                push(ch,number);
                break;    
            /* 若輸入是 '+' '-' '*' '/' */
           case ADD_SUB:
           case MULT_DIV:
                if( priority[top]==LEFT||priority[top]<number){
                   push(ch,number);
                }
                else{
                     /* 若堆疊內優先權 大於number  */
                    while((priority[top]>=number)&&priority[top]!=LEFT)
                           pop();  /* 先POP 堆疊內再PUSH number  */ 
                    push(ch,number);
                }   
                break;
            /*當字串已scan完 堆疊不為空 pop 剩下的運算子*/           
            case 0:  
       while(top!=-1) 
                      pop();
                 break;
        }        
    }  
}      
int main(void){
    
    char *IndString;
    char buf[STACK_SIZE];
    int i=0;
    int error_OP = 0;
    printf("請輸入中序 :");
    IndString=gets(buf);//中序輸入
    printf("\n");
    printf("後序為:");

   /*若不等於結束字元*/ 
   while(*(IndString+i)!='\0' & !error_OP) {

       /*數字和字母是運算元所以直接印出 */
      if(isalnum(*(IndString+i))) {    
               printf("%c",*(IndString+i));
      }
      else if(ispunct(*(IndString+i))) {     //若不是數字 空白 字母  則為真 
       
             switch(*(IndString+i)){
                case '+':
                             Operator(*(IndString+i),ADD_SUB);                       
                             break;
                case '-':   
                             Operator(*(IndString+i),ADD_SUB);                       
                             break;         
             
                case '*':
                             Operator(*(IndString+i),MULT_DIV);
                             break;
                case '/':
                             Operator(*(IndString+i),MULT_DIV);
                             break;
                case '(':
                             Operator(*(IndString+i),LEFT);
                             break; 
                case ')':
                            Operator(*(IndString+i),RIGHT);
                            break;  
                default:
                            printf(" error Operator\n");
                            error_OP = 1;
       break;
            }   
       }     
     i++; 
   } 

   Operator('\0',0);//字串scan結束 
   puts("\n------------------------------------\n");
   return 0;
}

ps:  程式裡有使用到gets,通常建議改成fgets使用,不過懶得改了
執行結果:





2015年9月25日 星期五

在Uboot下遇到的DMA快取一致性問題



關於DMA快取一致性(Cache coherency)的問題以前只在書上看過,但沒想到真的讓我遇到了。事情是這樣的,我原本的目的是想在u-boot下做一些memory的測試,所以在U-boot裡加入了DMA功能,並且做成了一個u-boot Command

首先講一下DMA是什麼:
DMA的基本原理就是不需經過CPU進行memory讀寫操作,而是由DMA控制器來負責,可以把DMA想像成另一顆只負責處理memory存取的processor,當需要將一大塊memory區塊搬到另一目的位址時,使用DMA會有很好的效果,許多周邊裝置都會使用到DMA,例如GPU或網卡等。

那麼何謂DMA快取一致性(Cache coherency)?
維基如是說 :

粗略地畫一下簡圖
以下是我的環境:
Platform: Arm arch , TI DM81xx
DMA: TI EDMA control
u-boot:
來源位址: 0x84000000
目標位址: 0xA0000000 (要被DMA寫入的位址)


一開始在來源位址: 0x84000000 寫入4k大小的 pattern value ( 0x55 )

再來執行DMACopy動作

接著使用md 指令:
   可以看到從目標位址: 0xA0000000開始確實有寫入了4K大小的pattern
   DMA正常動作


但之後要寫入另一個pattern(0x33)並執行DMA Copy發現目標位址的值沒有改變,試了很多次都一樣



將目標位址全部印出之後才發現只有後半段有更新到,這時才發覺可能是快取的問題。


解決方法: 

    1. 下U-boot指令, d-cache off 可以將資料快取(Data cache)整個關掉,
         但這個方法會讓CPU的讀寫速度變得很慢
    2. 在每次要執行DMA存取前先將快取給清除掉,Uboot裡有提供flush_dcache_all
        這個函式可以把資料快取(Data cache)清除 

2015年9月16日 星期三

Arm linux下 QRcode library安裝使用

所需套件

1. qrencode -->  qrencode-3.2.0.tar.gz
下載
http://pkgs.fedoraproject.org/repo/pkgs/qrencode/qrencode-3.2.0.tar.gz/

2. libpng --> libpng-1.6.12.tar.gz
下載
http://pkgs.fedoraproject.org/repo/pkgs/libpng/libpng-1.6.12.tar.gz/297388a6746a65a2127ecdeb1c6e5c82/


Step 1: 安裝 libpng

    $:  tar zxvf libpng-1.6.12.tar.gz ;

    $:  cd libpng-1.6.12

    $:  ./configure --prefix=/usr/local/Jinyo_linpng(安裝路徑) \

        --host =arm-linux(主機架構) \

        CC= arm-arago-linux-gnueabi-gcc(gcc 路徑) \

        LD= arm-arago-linux-gnueabi-ld( ld 路徑) ;

    $:  make ; make install ;



Step 2: 安裝 qrencode
    $:  tar zxvf qrencode-3.2.0.tar.gz  ;
    $:  cd qrencode-3.2.0 ;
    $:  ./configure PKG_CONFIG_PATH= \
         $PKG_CONFIG_PATH:/usr/local/Jinyo_linpng/lib/pkgconfig \
         --host= arm-linux --prefix=/usr/local/jinyo_qrencode --enable-static \
         CC= arm-arago-linux-gnueabi-gcc \
         LD= arm-arago-linux-gnueabi-ld ;
    $:   make ; make install ;

Step 3: ADD project
   安裝完成後就可以將qrencode.h 和 libqrencode.a 加入自己的project來使用
   $: cp /usr/local/jinyo_qrencode/include/qrencode.h   / your project/include/
   $: cp /usr/local/jinyo_qrencode/lib/libqrencode.a     / your project/lib/

   主要是呼叫這個API
   QRcode_encodeString("www.xxx.com", 1, QR_ECLEVEL_L, QR_MODE_8,0) ;
   原形如下
QRcode *QRcode_encodeString( const char *string,
                                    int version,
                                    QRecLevel level,
                                    QRencodeMode hint,
                                    int casesensitive   ) {

    return QRcode_encodeStringReal( string,
                                    version, 
                                    level, 
                                    0, 
                                    hint,
                                    casesensitive  );

}

   string:     輸入字串,ex:www.xxx.com
   version:  版本號
   level:      錯誤更正碼(Error correction)的等級,共4級
                 參考wiki
                  https://en.wikipedia.org/wiki/QR_code#Error_correction
              

  hint:           ??不太清楚
  casesensitive:   輸入字串是否要分大小寫 --> 0:忽略  1:要分大小寫

完整的sample-code主要參考這一篇
 http://stackoverflow.com/questions/21400254/how-to-draw-a-qr-code-with-qt-in-native-c-c

2015年9月15日 星期二

CSAPP閱讀筆記之Linking



Compiler  driver
  比如gcc就是一個compiler  driver,而不僅僅只有編譯功能,它包含了preprocessor, compiler, 
  as- sembler, 以及linker

preprocessor:  gcc  -E  hello.c  -o  hello.i

compilier:         gcc  -S  hello.i  -o  hello.s

as:                     as  hello.s  -o  hello.o

ld:                      ld   *.o

Object Files Format 目的檔格式

  • Relocatable object file:可重定檔
包含了程式碼(code)和資料(data)  ,可被重新Relocate成新的物件檔或可執行檔

  • Executable object file:可執行檔
包含了程式碼(code)和資料(data) ,可以直接載入記憶體並執行

  • Shared object file  : 可共用檔
內容與可重定檔相同,但可以被動態載入至某個正在執行的程式裡運行

Relocatable/Shared 檔會在編譯階段(by Compilers)和組譯(by assemblers )階段產生,而Executable檔則是在連結階段(by Linkers )生成

Static Linking 靜態連結


要產生一執行檔 , Linking必須執行Symbol resolution與Relocation這兩個動作


  • Symbol resolution:
    建立一個symbol reference與一個symbol definition的關連性


  • Relocation:
目的檔之間有會互相引用(呼叫),Relocation要做的就是重新更新這些互相引用的Symbol(函式或變數)的地址,因為目的檔在編譯的期間不會知道其他目的檔的位址,要靠在linking階段進行Relocation才能得到Symbol的真正位址


Relocatable Object Files



ELF header:

    $ : readelf  –h  obj-file


 
                                  Magic:  
                                                                    魔數 ,其中前面4個 7f , 45 = ‘E’ , 4c =’L’ , 46=’F’ 為固定值。
                                                                    後3碼 01=32bit ,01=little-ending , 01= version 。
                                                                    當kernel要載入執行檔前會先檢查魔數是否正確。
                                  Machine: 
                                                                     機器架構(如arm , x86 …) 。
                                  Type:  
                                                                     EXEC 或 REL 或  DYN。
                                  Entry point address :
                                                                    程式載入後,開始執行的入口地址。
 
 

Section header table:


.text :
存放source code經過編譯轉成的二進位機器碼
.data :
存放已初始化的全域變數
.bss :
存放尚未初始化的全域變數
.rodata  :
存放唯讀資料(Read-only),例如printf(“string1”) -->“string1”就是唯讀的


.symtab :
        符號表symbol-table),包含function和全域變數所有的定義(defined)和
參考(referenced),但不包含區域變數   
   
.rel.text :
        程式碼區段的重定位資訊
.rel.data:
        資料區段的重定位資訊
.debug:
A debugging symbol table with entries for local variables and typedefs
defined in the program,global variables defined and referenced in the
program, and the original C source file. It is only present if the compiler
driver is invoked with the -g option.
.line:
C原始碼和已編譯成的機器碼之間的行數對映表.若gcc有下-g選項才會出現
.strtab:
A string table for the symbol tables in the .symtab and .debug sections, and
for the section names in the section headers. A string table is a sequence of
null-terminated character strings.




Symbols and Symbol Tables


- 模組之間的全域變數可互相引用,引用時要加上extern關鍵字
- 宣告為static變數可在單一模組間讓其他區域函式使用,但其他的模組無法引用它
- static 有點類似於物件導向語言的private關鍵字
- static變數會存在.data或.bss段中,並且compiler會在symbol table為它創建一個
   名稱唯一的local linker symbol




如上圖,在同一模組的不同函式中,宣告了同名的static 變數,但它們的local linker symbol是不同的,例如 可能為:  x.1 以及x.2 


ELF symbol table entry


Symbol  Resolution


To be continued   ....