程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 嵌入式系統中的代碼壓縮

嵌入式系統中的代碼壓縮

編輯:C++入門知識

    在我們的某一個POWERPC系統中,通過總線掛接一片FPGA,和NorFlash等外設。以前我們一直是通過jtag燒寫NorFlash的,速度很慢,操作也比較麻煩。現在有了PGA,tpu決定在裡面放4k的代碼,用於通過串口下載bootloader,並燒寫到NorFlash中。這樣生產時只要FPGA燒寫工具就行了。     後來,在實現時發現,4k的代碼空間,放上各種功能後,已經不夠了。只好把各種功能打個折,勉強塞了進去。現在,可以用xmodem協議下載bootloader,但只能直接執行,沒有足夠的代碼空間寫NorFlash了。其實,如果把4k的二進制文件,用zip等工具壓縮,能壓到原來的一半大小。我們也可以仿照lzss等算法,實現一個自己的壓縮功能。       首先,我們定義好我們的壓縮方案:     用一到兩個bit做標志,描述數據流。標志湊齊一個字節就輸出到數據流。         比如:  flag data data ...... data flag data ...... data     標志1 : 數據流中下一個字節是未壓縮數據,直接輸出。     標志00: 表示一個短的前向匹配。下一個字節包含距離和長度:             高2位是匹配長度,0-3對應2-5的匹配長度。             低6位是匹配距離,0-63對應1-64的匹配位置。     標志01: 表示一個長的前向匹配。下面兩個字節包含距離和長度:             高4位是匹配長度,0-15對應3-18的匹配長度。             低4位和下一個字節是匹配距離,0-4095對應1-4096的匹配位置。     根據這個方案,就可以開始寫解壓與壓縮的實現了。實際測試發現,這個壓縮方案,可以把PowerPC的代碼,壓縮到原來的65%左右。基本的硬件初始化和解壓代碼,大概用了512字節,剩余的3.5k空間,大概可以放5.3k的代碼。這樣以來,最初的設想完全可以實現了,而且很有很多的剩余空間備用。         C語言實現的壓縮代碼:   [cpp]  static u8 *dst, *src;   static int dp, sp, fp;   static int flag, bits;      void put_flag(int bit)   {       if(bits==8){           if(c_debug) printf("flag %02x at %04x\n", flag, fp);           dst[fp] = flag;           fp = dp;           dp += 1;           bits = 0;           flag = 0;       }          flag >>= 1;       if(bit)           flag |= 0x80;       bits += 1;   }      int tlz_compress(u8 *dst_buf, u8 *src_buf, int src_len)   {       int i, j, pp;       int match_len, match_pos;          dst = dst_buf;       src = src_buf;       sp = 0;       fp = 0;       dp = 1;       bits = 0;       flag = 0;             while(sp<src_len){           /* find match           * max windows: 1-4095 1-63           * max length: 3-18/2-5           */           match_len = 1;           match_pos = 1;           pp = sp-4095;           if(pp<0)               pp = 0;           for(i=pp; i<sp; i++){               for(j=0; (j<18 && sp+j<src_len); j++){                   if(src[i+j]!=src[sp+j])                       break;               }               if(j>=match_len){                   match_len = j;                   match_pos = sp-i;               }           }              if(match_len==1 || (match_len==2 && match_pos>63)){               /* raw byte */               put_flag(1);               if(c_debug) printf("%04x raw: %02x\n", sp, src[sp]);               dst[dp++] = src[sp++];           }else{               put_flag(0);                  if(match_len<6 && match_pos<64){                   /* short match */                   put_flag(0);                      if(c_debug) printf("%04x short: pos=%4d len=%2d\n", sp, match_pos, match_len);                   sp += match_len;                      match_pos -= 1;                   match_len -= 2;                   match_pos |= (match_len<<6);                      dst[dp++] = match_pos;                  }else{                   /* long match */                   put_flag(1);                      if(c_debug) printf("%04x  long: pos=%4d len=%2d\n", sp, match_pos, match_len);                   sp += match_len;                      match_pos -= 1;                   match_len -= 3;                   match_pos |= (match_len<<12);                      dst[dp++] = (match_pos>>8);                   dst[dp++] = (match_pos&0xff);               }           }          }          /* end of stream */       put_flag(0);       put_flag(0);       dst[dp++] = 0xff;          if(bits){           flag >>= (8-bits);           if(c_debug) printf("flag %02x at %04x\n", flag, fp);           dst[fp] = flag;       }          return dp;   }         C語言實現的解壓代碼: [cpp]   int tlz_decompress(u8 *dst, u8 *src)   {       int i, sp, dp;       int flag, offset, len;       u8 *pbuf;          sp = 0;       dp = 0;       flag = 0x0100;          while(1){           if(flag&0x0100){               flag = src[sp++];               if(d_debug) printf("flag %02x at %04x\n", flag, sp-1);               flag |= 0x00010000;           }              if(flag&1){               /* raw byte */               if(d_debug) printf("%04x raw: %02x\n", dp, src[sp]);               dst[dp++] = src[sp++];               flag >>= 1;           }else{               flag >>= 1;               if(flag&0x0100){                   flag = src[sp++];                   if(d_debug) printf("flag %02x at %04x\n", flag, sp-1);                   flag |= 0x00010000;               }               offset = src[sp++];               if(flag&1){                   /* 01: long format */                   len = offset>>4;                   len += 3;                   offset <<= 8;                   offset |= src[sp++];                   offset &= 0x0fff;                   if(d_debug) printf("%04x  long: pos=%4d len=%2d\n", dp, offset+1, len);               }else{                   /* 00: short format */                   if(offset==0xff)                       break;                   len = (offset>>6);                   len += 2;                   offset &= 0x3f;                   if(d_debug) printf("%04x short: pos=%4d len=%2d\n", dp, offset+1, len);               }               flag >>= 1;               pbuf = &dst[dp-offset-1];               for(i=0; i<len; i++){                   dst[dp++] = pbuf[i];               }           }       }          return dp;   }           PowerPC匯編實現的解壓代碼:   [html]  /*        int tlz_decomp(u8 *dst, u8 *src);          r3: dst-1       r4: src-1       r5: flag       r8: match offset       r7: match len      */      tlz_decomp:       li  r5, 0x0100      _main_loop:       andi.   r0, r5, 0x0100       beq 1f       lbzu    r5, 1(r4)       oris    r5, r5, 0x0001   1:       andi.   r0, r5, 0x01       srawi   r5, r5, 1       beq _match   _raw_byte:       lbzu    r6, 1(r4)       stbu    r6, 1(r3)       b   _main_loop      _match:       andi.   r0, r5, 0x0100       beq 1f       lbzu    r5, 1(r4)       oris    r5, r5, 0x0001   1:       lbzu    r6, 1(r4)       andi.   r0, r5, 0x01       beq _short_match   _long_match:       srawi   r7, r6, 4       addi    r7, r7, 3       lbzu    r8, 1(r4)       rlwimi  r8, r6, 8, 20, 23       b   _copy   _short_match:       cmpwi   r6, 0xff       beqlr       srawi   r7, r6, 6       addi    r7, r7, 2       andi.   r8, r6, 0x3f   _copy:       srawi   r5, r5, 1       sub r8, r3, r8       subi    r8, r8, 1       mtctr   r7   1:       lbzu    r6, 1(r8)       stbu    r6, 1(r3)       bdnz    1b          b   _main_loop       這裡與C實現不一樣的是,入口參數都要減一。這是為了充分利用PPC的指令特點,可以節省兩條指令。這段代碼占144字節空間。  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved