len = readline (CONFIG_SYS_PROMPT);在這個routine裡其實是readline_into_buffer(prompt, console_buffer);所以當我們在bootdelay秒數之前hit any key便會跳到這裡等待輸入,這裡也有個for (;;)無限迴圈,除了按enter外會一直在這個迴圈。當有輸入任何command時便會來到rc = run_command (lastcommand, flag);,這個run_command就是主角了。
2010年7月20日 星期二
2010年7月14日 星期三
部落格文章顯示部分內容,並增加read more連結來閱讀全文
轉載:http://01mistery.blogspot.com/2010/02/web-blogger.html?showComment=1268047957472
另外請參考這一篇:http://easyadsensevn.blogspot.com/2008/09/how-to-add-blogger-read-more-expandable_05.html
裡頭的內容其實就是找出標籤:<>,然後以下列代碼取代:
另外請參考這一篇:http://easyadsensevn.blogspot.com/2008/09/how-to-add-blogger-read-more-expandable_05.html
裡頭的內容其實就是找出標籤:<>,然後以下列代碼取代:
及找出 至 之間加入如下代碼:
summary_noimg = 430;
summary_img = 340;
img_thumb_height = 100;
img_thumb_width = 120;
2010年7月13日 星期二
關於linux/ctype.h
/include/linux/ctype.h此路徑為相對路徑,其絕對路徑依照linux源碼樹為參考:例如我的源碼樹存放在/opt/FriendlyARM/mini2440/linux-2.6.32.2;所以絕對路徑如下:/opt/FriendlyARM/mini2440/linux-2.6.32.2/include/linux/ctype.h
/include/linux/ctype.h代碼如下
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */ /* 大寫字母A-Z*/
#define _L 0x02 /* lower */ /* 小寫字母a-z */
#define _D 0x04 /* digit */ /* 數字0-9 */
#define _C 0x08 /* cntrl */ /* 控制字元 */
#define _P 0x10 /* punct */ /* 標點符號*/
#define _S 0x20 /* white space (space/lf/tab) */ /* 空白字元:空格、\t、\n 等 */
#define _X 0x40 /* hex digit */ /* 十六進位數 */
#define _SP 0x80 /* hard space (0x20) */ /* 空格字元0x20 */
extern unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U∣_L∣_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U∣_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P∣_U∣_L∣_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P∣_U∣_L∣_D∣_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D∣_X)) != 0)
#define isascii(c) (((unsigned char)(c))<=0x7f) #define toascii(c) (((unsigned char)(c))&0x7f)
static inline unsigned char __tolower(unsigned char c) { if (isupper(c)) c -= 'A'-'a'; return c; } static inline unsigned char __toupper(unsigned char c) { if (islower(c)) c -= 'a'-'A'; return c; } #define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)
#endif
以下是/lib/ctype.c
#include
unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
所以由此我們可以來驗證:
大寫S=58h=88 查_ctype得到_U = 0x01
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x01)& (ox01 ∣ 0x02 ∣ 0x04) =1,所以得到true
isalpha("S")=(0x01)& (ox01 ∣ 0x02) =1,所以得到true
iscntrl("S")=(0x01)& (ox08) =0,所以得到false
isdigit("S")=(0x01)& (ox04) =0,所以得到false
♫=0eh=14 查_ctype得到_C = 0x08
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x08)& (ox01 ∣ 0x02 ∣ 0x04) =0,所以得到false
isalpha("S")=(0x08)& (ox01 ∣ 0x02) =0,所以得到false
iscntrl("S")=(0x08)& (ox08) =1,所以得到true
isdigit("S")=(0x08)& (ox04) =0,所以得到false
參考更多特殊字碼:http://cowwu.myweb.hinet.net/note/text/930421a.htm
ASCII code:http://home.educities.edu.tw/wanker742126/index.html
/include/linux/ctype.h代碼如下
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */ /* 大寫字母A-Z*/
#define _L 0x02 /* lower */ /* 小寫字母a-z */
#define _D 0x04 /* digit */ /* 數字0-9 */
#define _C 0x08 /* cntrl */ /* 控制字元 */
#define _P 0x10 /* punct */ /* 標點符號*/
#define _S 0x20 /* white space (space/lf/tab) */ /* 空白字元:空格、\t、\n 等 */
#define _X 0x40 /* hex digit */ /* 十六進位數 */
#define _SP 0x80 /* hard space (0x20) */ /* 空格字元0x20 */
extern unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U∣_L∣_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U∣_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P∣_U∣_L∣_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P∣_U∣_L∣_D∣_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D∣_X)) != 0)
#define isascii(c) (((unsigned char)(c))<=0x7f) #define toascii(c) (((unsigned char)(c))&0x7f)
static inline unsigned char __tolower(unsigned char c) { if (isupper(c)) c -= 'A'-'a'; return c; } static inline unsigned char __toupper(unsigned char c) { if (islower(c)) c -= 'a'-'A'; return c; } #define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)
#endif
以下是/lib/ctype.c
#include
unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C∣_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U∣_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L∣_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S∣_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
所以由此我們可以來驗證:
大寫S=58h=88 查_ctype得到_U = 0x01
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x01)& (ox01 ∣ 0x02 ∣ 0x04) =1,所以得到true
isalpha("S")=(0x01)& (ox01 ∣ 0x02) =1,所以得到true
iscntrl("S")=(0x01)& (ox08) =0,所以得到false
isdigit("S")=(0x01)& (ox04) =0,所以得到false
♫=0eh=14 查_ctype得到_C = 0x08
因此我們以以下幾個巨集來求證:
isalnum("S")=(0x08)& (ox01 ∣ 0x02 ∣ 0x04) =0,所以得到false
isalpha("S")=(0x08)& (ox01 ∣ 0x02) =0,所以得到false
iscntrl("S")=(0x08)& (ox08) =1,所以得到true
isdigit("S")=(0x08)& (ox04) =0,所以得到false
參考更多特殊字碼:http://cowwu.myweb.hinet.net/note/text/930421a.htm
ASCII code:http://home.educities.edu.tw/wanker742126/index.html
2010年7月12日 星期一
特殊符號html表示
由於&無法在blog顯示,以下以%表示&符號
<:%lt >:%gt
& : %amp
":%quot
©:%copy
®:%reg
×:%times
÷:%divide
∣:%#8739
更多特殊字碼表:http://cowwu.myweb.hinet.net/note/text/930421a.htm
<:%lt >:%gt
& : %amp
":%quot
©:%copy
®:%reg
×:%times
÷:%divide
∣:%#8739
更多特殊字碼表:http://cowwu.myweb.hinet.net/note/text/930421a.htm
2010年7月11日 星期日
如何在32bits保護模式下作debug
以下我所論及的主題並非是在os的保護模式底下的debug方式;而是當你有自己的執行系統,這個執行系統是從16bits模式執行後進入32bits保護模式,並且執行自己定義的ap。就類似memtest86這種從booting到run ap都能一手掌控的代碼。然而memtest在保護模式下都是C語言代碼,因此要debug相對容易,所以我們要討論的是以assembly為架構的debug方式。
首先我們知道frame buffer是以為址0xb8000~0xb8fff為vga顯示控制區域;當然其他模式mapping到的位址也不同;但我們討論的是前者。雖然在dos或16bits模式可以使用int 10h來讀寫螢幕,我們也知道int 10h的作法也是去控制frame buffer。然而進入保護模式下傳統的bios及dos中斷已不能調用。但是我們還是可以直接去存取frame buffer;所以我寫了比下代碼以assembly的方式來顯示一些除錯用途的資訊:
以下資訊為如何在保護模式下debug,並利用健盤做單步debug
;清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax
push ecx
push ebx
mov ecx,edi
POS_XY bx,20,23
call sub32_hexprint
pop ebx
pop ecx
;等待8042輸出緩衝器有資料送進來
push eax
WaitOBFLoop:
in al,64h
test al,1
jz WaitOBFLoop
pop eax
;以上這小段完成健盤單步執行判斷,做法是當無按鍵被按下時,便一直執行迴圈
;用法:
;先push ecx和ebx
;將要顯示的資料存到ecx
;POS_XY bx,__x,__y
;call sub32_hexprint
;pop ecx和ebx
sub32_hexprint proc
pushad
mov eax,160
mul bl
add eax,SCREEN_ADR
xchg eax,edx
mov eax,2
mul bh
add edx,eax
mov bx,8 ;count
xor edi,edi
NEXT:
call cl2digital
mov BPTR[edx+edi],al
shr ecx,4
add edi,2
dec bx
jnz NEXT
popad
ret
sub32_hexprint endp
cl2digital proc
xor eax,eax
push ecx
and ecx,0fh
cmp cl,10
jae isA2F
add cl,30h
jmp exit
isA2F:
sub cl,10
add cl,41h
exit:
mov al,cl
pop ecx
ret
cl2digital endp
下面是marco
SCREEN_ADR equ 0b8000h
POS_XY macro r_, x_, y_
mov r_, (((x_) SHL 8) + (y_))
endm
以下為鍵盤控制指令參考:
; ========================================================
; 以下為8042界面函數之內部呼叫函數
; ========================================================
;
Flush8042 PROC
; 清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax
retn
Flush8042 ENDP
;
WaitIBF PROC
; 等待8042輸入緩衝器有空
WaitIBFLoop: push ax
in al,64h
test al,2
pop ax
jnz WaitIBFLoop
retn
WaitIBF ENDP
;
WaitOBF PROC
; 等待8042輸出緩衝器有資料送來
WaitOBFLoop: push ax
in al,64h
test al,1
pop ax
jz WaitOBFLoop
retn
WaitOBF ENDP
;
Read8042Data PROC
; 讀取8042回應資料
; 傳回: AL = 回應資料
call WaitOBF ; 等待資料回庄
in al,60h
retn
Read8042Data ENDP
;
Write8042Data PROC
; 送出資料給8042
; 參數: AL = 8042系統命令或資料
; 備註: 本函數亦為送出系統命令或資料的函數
call WaitIBF ; 等待輸入緩衝區有空
out 60h,al ; 送出資料
call WaitIBF ; 確認8042收到
retn
Write8042Data ENDP
;
RealSend8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
; 備註: 8042命令之參數或傳回值由外界處理
call WaitIBF ; 等待輸入緩衝區有空
out 64h,al ; 送出命令
call WaitIBF ; 確認8042收到
retn
RealSend8042Cmd ENDP
;
RealSend8042Sys PROC
; 送出系統命令碼或參數給8042
; 參數: AL = 8042系統控制命令或參數
; 傳回: AL = 8042回應值
; 備註: 除回音外,其餘命令或參數應檢查是否傳回ACK
call Flush8042
call Write8042Data
call Read8042Data
retn
RealSend8042Sys ENDP
;
; ========================================================
; 以下為8042界面函數,使用前必須使用CLI將岔斷禁能
; ========================================================
;
Send8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
call RealSend8042Cmd
retn
Send8042Cmd ENDP
;
Read8042Cmd PROC
; 送出讀取命令給8042
; 參數: AL = 8042讀取命令
; 傳回: AL = 讀取值
call Flush8042
call RealSend8042Cmd
call Read8042Data
retn
Read8042Cmd ENDP
;
Write8042Cmd PROC
; 送出寫入命令給8042
; 參數: AL = 8042寫入命令
; AH = 寫入資料
; 備註: AX值會被破壞
call RealSend8042Cmd
xchg al,ah
call Write8042Data
retn
Write8042Cmd ENDP
;
Echo8042 PROC
; 送出8042回音命令
; 傳回: AL = EEh
mov al,0EEh ; 回音命令
call RealSend8042Sys
retn
Echo8042 ENDP
首先我們知道frame buffer是以為址0xb8000~0xb8fff為vga顯示控制區域;當然其他模式mapping到的位址也不同;但我們討論的是前者。雖然在dos或16bits模式可以使用int 10h來讀寫螢幕,我們也知道int 10h的作法也是去控制frame buffer。然而進入保護模式下傳統的bios及dos中斷已不能調用。但是我們還是可以直接去存取frame buffer;所以我寫了比下代碼以assembly的方式來顯示一些除錯用途的資訊:
以下資訊為如何在保護模式下debug,並利用健盤做單步debug
;清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax
push ecx
push ebx
mov ecx,edi
POS_XY bx,20,23
call sub32_hexprint
pop ebx
pop ecx
;等待8042輸出緩衝器有資料送進來
push eax
WaitOBFLoop:
in al,64h
test al,1
jz WaitOBFLoop
pop eax
;以上這小段完成健盤單步執行判斷,做法是當無按鍵被按下時,便一直執行迴圈
;用法:
;先push ecx和ebx
;將要顯示的資料存到ecx
;POS_XY bx,__x,__y
;call sub32_hexprint
;pop ecx和ebx
sub32_hexprint proc
pushad
mov eax,160
mul bl
add eax,SCREEN_ADR
xchg eax,edx
mov eax,2
mul bh
add edx,eax
mov bx,8 ;count
xor edi,edi
NEXT:
call cl2digital
mov BPTR[edx+edi],al
shr ecx,4
add edi,2
dec bx
jnz NEXT
popad
ret
sub32_hexprint endp
cl2digital proc
xor eax,eax
push ecx
and ecx,0fh
cmp cl,10
jae isA2F
add cl,30h
jmp exit
isA2F:
sub cl,10
add cl,41h
exit:
mov al,cl
pop ecx
ret
cl2digital endp
下面是marco
SCREEN_ADR equ 0b8000h
POS_XY macro r_, x_, y_
mov r_, (((x_) SHL 8) + (y_))
endm
以下為鍵盤控制指令參考:
; ========================================================
; 以下為8042界面函數之內部呼叫函數
; ========================================================
;
Flush8042 PROC
; 清除所有的輸出緩衝器資料
push ax
FlushOBF: in al,64h
test al,1
jz NotOBF
in al,60h
jmp short FlushOBF
NotOBF: pop ax
retn
Flush8042 ENDP
;
WaitIBF PROC
; 等待8042輸入緩衝器有空
WaitIBFLoop: push ax
in al,64h
test al,2
pop ax
jnz WaitIBFLoop
retn
WaitIBF ENDP
;
WaitOBF PROC
; 等待8042輸出緩衝器有資料送來
WaitOBFLoop: push ax
in al,64h
test al,1
pop ax
jz WaitOBFLoop
retn
WaitOBF ENDP
;
Read8042Data PROC
; 讀取8042回應資料
; 傳回: AL = 回應資料
call WaitOBF ; 等待資料回庄
in al,60h
retn
Read8042Data ENDP
;
Write8042Data PROC
; 送出資料給8042
; 參數: AL = 8042系統命令或資料
; 備註: 本函數亦為送出系統命令或資料的函數
call WaitIBF ; 等待輸入緩衝區有空
out 60h,al ; 送出資料
call WaitIBF ; 確認8042收到
retn
Write8042Data ENDP
;
RealSend8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
; 備註: 8042命令之參數或傳回值由外界處理
call WaitIBF ; 等待輸入緩衝區有空
out 64h,al ; 送出命令
call WaitIBF ; 確認8042收到
retn
RealSend8042Cmd ENDP
;
RealSend8042Sys PROC
; 送出系統命令碼或參數給8042
; 參數: AL = 8042系統控制命令或參數
; 傳回: AL = 8042回應值
; 備註: 除回音外,其餘命令或參數應檢查是否傳回ACK
call Flush8042
call Write8042Data
call Read8042Data
retn
RealSend8042Sys ENDP
;
; ========================================================
; 以下為8042界面函數,使用前必須使用CLI將岔斷禁能
; ========================================================
;
Send8042Cmd PROC
; 送出一般命令碼給8042
; 參數: AL = 8042一般控制命令
call RealSend8042Cmd
retn
Send8042Cmd ENDP
;
Read8042Cmd PROC
; 送出讀取命令給8042
; 參數: AL = 8042讀取命令
; 傳回: AL = 讀取值
call Flush8042
call RealSend8042Cmd
call Read8042Data
retn
Read8042Cmd ENDP
;
Write8042Cmd PROC
; 送出寫入命令給8042
; 參數: AL = 8042寫入命令
; AH = 寫入資料
; 備註: AX值會被破壞
call RealSend8042Cmd
xchg al,ah
call Write8042Data
retn
Write8042Cmd ENDP
;
Echo8042 PROC
; 送出8042回音命令
; 傳回: AL = EEh
mov al,0EEh ; 回音命令
call RealSend8042Sys
retn
Echo8042 ENDP
2010年7月8日 星期四
u-boot 顯示logo,並說明其原理part2
上回我們已經將LCD掛上logo,現在要來探討lcd硬體部分及如何顯示出bmp檔的代碼部分;在board.c中的devices_init→drv_video_init→drv_video_init→video_init→video_hw_init→board_video_init,是否看到都眼花了,函式名稱長的都很像。通常這樣一直往下層呼叫的層數太多的確很難理解,這個時後以圖形來顯示會得到比較好的效果;所以我就來做一張圖吧!
2010年7月6日 星期二
點陣圖(Bitmap)檔案格式
圖一
圖二
圖三
'BM' - Windows 3.1x, 95, NT, ...
'BA' - OS/2 Bitmap Array
'CI' - OS/2 Color Icon
'CP' - OS/2 Color Pointer
'IC' - OS/2 Icon
'PT' - OS/2 Pointer
28h - Windows 3.1x, 95, NT, ...
0Ch - OS/2 1.x
F0h - OS/2 2.x
以目前 Windows 常用的點陣圖來說,此欄位數值通常是 28h。
但因為微軟已經制定出了新的點陣圖格式,其中的 Bitmap Info Header 結構變化較大,長度加長,所以最好不要直接使用常數 28h,而是應該從實際檔案中讀取這個數值,才能確保程式相容性。
【註3】高度可能為負值,負值表示掃瞄方向由上而下。
【註3】高度可能為負值,負值表示掃瞄方向由上而下。
但若高度是負值時,此點陣圖將不能被壓縮!(也就是說 Compression 欄位總是為 0)
【註4】未知的功能...永遠被設為 1。
【註5】16 及 32 位元點陣圖是否使用調色盤必須由 Compression 欄位的數值決定, 請參考 Bitfields 的解說。
【註6】點陣圖壓縮方式有以下四種:BI_RGB,BI_RLE8,BI_RLE4,以及BI_BITFIELDS。
None (BI_RGB)表示此點陣圖資料沒有壓縮,不使用調色盤。
RLE 8bpp (BI_RLE8)每個像素為 8 bit 的 RLE 壓縮編碼(Run-Length Encoding)(總共可使用 256 色)。有「編碼模式」(Encoded Mode)和「絕對模式」(Absolute Mode)兩種方法,可在同一幅圖檔中的任何地方交錯使用。「編碼模式」:由兩個位元組(byte)組成。 第一個位元組指定 "Length"(使用相同顏色的像素數目),第二個位元組指定 "Run"(此像素使用的調色盤索引)。
【註4】未知的功能...永遠被設為 1。
【註5】16 及 32 位元點陣圖是否使用調色盤必須由 Compression 欄位的數值決定, 請參考 Bitfields 的解說。
【註6】點陣圖壓縮方式有以下四種:BI_RGB,BI_RLE8,BI_RLE4,以及BI_BITFIELDS。
None (BI_RGB)表示此點陣圖資料沒有壓縮,不使用調色盤。
RLE 8bpp (BI_RLE8)每個像素為 8 bit 的 RLE 壓縮編碼(Run-Length Encoding)(總共可使用 256 色)。有「編碼模式」(Encoded Mode)和「絕對模式」(Absolute Mode)兩種方法,可在同一幅圖檔中的任何地方交錯使用。「編碼模式」:由兩個位元組(byte)組成。 第一個位元組指定 "Length"(使用相同顏色的像素數目),第二個位元組指定 "Run"(此像素使用的調色盤索引)。
若第一個位元組為零,則表示特殊意義:
0x0000 - 表示此列結束
0x0001 - 表示此點陣圖檔案結束
0x0002 - 表示其後的兩位元組分別表示下個像素位置與目前像素位置的水平/垂直偏移量。
0x000x - 表示絕對模式。「絕對模式」:第一個位元組為 0x00,第二個位元組為0x03 ~ 0xFF 之間的數值。
其中第二個位元組表示後續資料的長度(單位為 byte),後續資料的每個位元組都表示單一像素的調色盤索引值。每一模式的編碼長度都必須與字邊界對齊(word-aligned),也就是 2 的倍數。使用「編碼模式」時,由於每組編碼皆為兩個位元組,所以毋需多加處理;但是使用「絕對模式」時,則必須在最後補上適當的 0x00 以使資料長度對齊 2 的倍數。下面是一個 BI_RLE8 的例子:03 01 05 02 00 03 00 01 02 00 02 01 00 02 05 01 02 03 00 00 09 02 00 01這些資料可解讀為:如圖二
RLE 4bpp (BI_RLE4)每個像素為 4-bit 的 RLE 壓縮編碼(總共可使用 16 色)。同樣也有「編碼模式」與「絕對模式」,且可以在同一圖檔中任何地方使用任一模式。
RLE 4bpp (BI_RLE4)每個像素為 4-bit 的 RLE 壓縮編碼(總共可使用 16 色)。同樣也有「編碼模式」與「絕對模式」,且可以在同一圖檔中任何地方使用任一模式。
「編碼模式」:由兩個位元組組成。
第一個位元組指定像素數目,第二個位元組包含兩個調色盤索引:
第一個像素使用高 4 位元的索引值、第二個像素使用低 4 位元的索引值、第三個像素又使用高 4 位元的索引值,以此類推。
若第一個位元組為零,則表示特殊意義:
0x0000 - 表示此列結束
0x0001 - 表示此點陣圖檔案結束
0x0002 - 表示其後的兩位元組分別表示下個像素位置與目前像素位置的水平/垂直偏移量。
0x000x - 表示絕對模式。「絕對模式」:第一個位元組為 0x00,第二個位元組表示後續資料的長度(單位為 byte)。
後續資料的每個位元組都含有兩個調色盤索引值(高 4 及低 4 位元),每個索引值對應一個像素。每一模式的編碼長度仍然必須與字邊界對齊(word-aligned)。使用「編碼模式」時,由於每組編碼皆為兩個位元組,所以毋需多加處理;但是使用「絕對模式」時,則必須在最後補上適當的 0 以使資料長度對齊 2 的倍數。下面是一個 BI_RLE4 的例子:03 11 05 02 00 05 01 23 10 00 02 22 00 02 05 01 02 13 00 00 09 10 00 01這些資料可解讀為:如圖三
1. Bitfileds (BI_BITFIELDS)只有當「Bit Per Pixel」欄位的數值為 16 或 32 時,才會使用 BI_BITFIELDS 這種格式。使用 BI_BITFIELDS 時,點陣圖檔中原本的調色盤位置會被三個 DWORD 佔據,分別代表 R、G、B 三個顏色分量的遮罩(mask)。例如:
1. Bit_Per_Pixel = 16, Compression = BI_RGB(無壓縮),則每個像素的 16 位元之中:最低 5 位元表示藍色分量,中間 5 位元表示綠色分量,接著的高 5 位元則是紅色分量,最高的 1 位元保留不使用。此格式即為 RGB555 格式。
2. Bit_Per_Pixel = 16, Compression = BI_BITFIELDS,紅、綠、藍的 mask 分別為 0xF800, 0x07E0, 0x001F,則每個像素的 16 位元之中:最低 5 位元表示藍色分量,中間 6 位元表示綠色分量,最高 5 位元則是紅色分量,此格式即為 RGB565 格式。
【註7】若沒有壓縮(Compression 欄位為 0),則此欄數值可設為 0。
1. Bitfileds (BI_BITFIELDS)只有當「Bit Per Pixel」欄位的數值為 16 或 32 時,才會使用 BI_BITFIELDS 這種格式。使用 BI_BITFIELDS 時,點陣圖檔中原本的調色盤位置會被三個 DWORD 佔據,分別代表 R、G、B 三個顏色分量的遮罩(mask)。例如:
1. Bit_Per_Pixel = 16, Compression = BI_RGB(無壓縮),則每個像素的 16 位元之中:最低 5 位元表示藍色分量,中間 5 位元表示綠色分量,接著的高 5 位元則是紅色分量,最高的 1 位元保留不使用。此格式即為 RGB555 格式。
2. Bit_Per_Pixel = 16, Compression = BI_BITFIELDS,紅、綠、藍的 mask 分別為 0xF800, 0x07E0, 0x001F,則每個像素的 16 位元之中:最低 5 位元表示藍色分量,中間 6 位元表示綠色分量,最高 5 位元則是紅色分量,此格式即為 RGB565 格式。
【註7】若沒有壓縮(Compression 欄位為 0),則此欄數值可設為 0。
例如,此欄數值若為 2834 (pixels per meter),則 2834 ÷ 39.37 = 72 (pixels per inch) = 72 dpi
【註9】此欄表示圖檔實際使用的顏色數目,若數值為 0,表示使用所有調色盤顏色。 如果此欄數值並非「可用顏色的最大值」或者「零」,則需注意調色盤尺寸的計算。
【註9】此欄表示圖檔實際使用的顏色數目,若數值為 0,表示使用所有調色盤顏色。 如果此欄數值並非「可用顏色的最大值」或者「零」,則需注意調色盤尺寸的計算。
例如,在 4 bpp bitmap 中,調色盤預設尺寸應是 16*4 bytes,但若 Used Color 欄位數值並非 16 或 0,則調色盤尺寸應是 Used_Color_Number * 4 (bytes)。
【註10】當此欄的值等於「顏色數」或者為 0 時,表示所有顏色都一樣重要。
【註11】緊跟在調色盤之後的就是點陣圖資料陣列。
【註10】當此欄的值等於「顏色數」或者為 0 時,表示所有顏色都一樣重要。
【註11】緊跟在調色盤之後的就是點陣圖資料陣列。
每一掃描列的長度取決於圖檔的寬度及顏色深度(Color Depth),但是每一掃描列的長度必需是 4 byte 的倍數(DWORD-aligned)!
正常的點陣圖掃描列是由底向上儲存的:陣列中的第一個 byte 表示全圖左下角的像素,而最後一個 byte 則表示全圖右上角的像素。但如果是正向掃描(Height 欄位為負值),則掃描方向則是由上而下。
整理 by chiapei@gmail.com
整理 by chiapei@gmail.com
u-boot 顯示logo,並說明其原理part1
jpegtopnm Benson.jpg l ppmquant 31 l ppmtobmp -bpp 8 > Benson-8bit.bmp
紅色l是管線符號,因無法正常顯示所以用小寫L取代
以上這個指令必須先安裝netpbm,其作用是將jpeg檔轉成特定格式的bmp檔。將Benson-8bit.bmp更改檔名為denx.bmp並存到tools\logos,重新compile u-boot,便可完成,如上圖。接著我們來說明其draw logo原理:
在/tools/Makefile:
LOGO_H = $(OBJTREE)/include/bmp_logo.h
及
ifeq ($(LOGO_BMP),)
LOGO_BMP= logos/denx.bmp
endif
ifeq ($(VENDOR),atmel)
LOGO_BMP= logos/atmel.bmp
endif
及
$(LOGO_H):$(obj)bmp_logo $(LOGO_BMP)
$(obj)./bmp_logo $(LOGO_BMP) >$@ #這個$@就是bmp_logo.h
也就是說$(LOGO_H)這個目標的必要條件是bmp_logo 及denx.bmp這兩個檔案,才能產生bmp_logo.h這個主角,它就是denx.bmp的位元圖陣列。
所以在uboot主目錄中的makefile中有這麼一行:@rm -f $(obj)include/bmp_logo.h。在clean 時會將其刪除。
以上資訊若使用Source Insight根本無法搜尋得到,終就還是得到linux使用gerp。像這次我的搜尋指令如下:grep -Hwn "bmp_logo.h" -r ./ 。接著我們來了解一下bmp_logo.c:這是一支單一檔案所完成的獨立執行檔;我先把代碼列出;再來加入註解;另外也必須了解點陣圖的格式,請參考點陣圖(Bitmap)檔案格式
#include (stdio.h)
#include (stdlib.h)
#if defined(__linux__)
#include (stdint.h)
#else
#ifdef __CYGWIN__
#include "elf.h"
#else
#include (inttypes.h)
#endif
#endif
typedef struct bitmap_s { /* bitmap description */
uint16_t width;
uint16_t height;
uint8_t palette[256*3]; //調色盤資料
uint8_t *data; //圖的bit_map資料指標
} bitmap_t;
#define DEFAULT_CMAP_SIZE 16 /* size of default color map */
/* Neutralize little endians. */
uint16_t le_short(uint16_t x) //因為檔案格式是依照LITTLE ENDIAN排列,因此要找出實際數值必須作移位。
{
uint16_t val;
#include (stdlib.h)
#if defined(__linux__)
#include (stdint.h)
#else
#ifdef __CYGWIN__
#include "elf.h"
#else
#include (inttypes.h)
#endif
#endif
typedef struct bitmap_s { /* bitmap description */
uint16_t width;
uint16_t height;
uint8_t palette[256*3]; //調色盤資料
uint8_t *data; //圖的bit_map資料指標
} bitmap_t;
#define DEFAULT_CMAP_SIZE 16 /* size of default color map */
/* Neutralize little endians. */
uint16_t le_short(uint16_t x) //因為檔案格式是依照LITTLE ENDIAN排列,因此要找出實際數值必須作移位。
{
uint16_t val;
uint8_t *p = (uint8_t *)(&x);
val = (*p++ & 0xff) 左移 0;
val = (*p++ & 0xff) 左移 0;
val = (*p & 0xff) 左移 8;
return val;
}
void skip_bytes (FILE *fp, int n)
{
while (n-- > 0) fgetc (fp);
}
int main (int argc, char *argv[])
{
int i, x;
FILE *fp;
bitmap_t bmp;
bitmap_t *b = &bmp;
uint16_t data_offset, n_colors;
if (argc < color="#cc33cc">//判斷參數少於2便顯示fail
fprintf (stderr, "Usage: %s file\n", argv[0]);
exit (EXIT_FAILURE);
}
if ((fp = fopen (argv[1], "rb")) == NULL) {//開啟檔案,若失敗顯示fail
if ((fp = fopen (argv[1], "rb")) == NULL) {//開啟檔案,若失敗顯示fail
perror (argv[1]);
exit (EXIT_FAILURE);
}
if (fgetc (fp) != 'B' fgetc (fp) != 'M') { //判斷檔頭前2個byte是否為"BM",否則顯示錯誤
if (fgetc (fp) != 'B' fgetc (fp) != 'M') { //判斷檔頭前2個byte是否為"BM",否則顯示錯誤
fprintf (stderr, "%s is not a bitmap file.\n", argv[1]);
exit (EXIT_FAILURE);
}
/*
* read width and height of the image, and the number of colors used;
* ignore the rest
*/
skip_bytes (fp, 8);
fread (&data_offset, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
fread (&b->width, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 2);
fread (&b->height, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 22);
fread (&n_colors, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
/*
* read width and height of the image, and the number of colors used;
* ignore the rest
*/
skip_bytes (fp, 8);
fread (&data_offset, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
fread (&b->width, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 2);
fread (&b->height, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 22);
fread (&n_colors, sizeof (uint16_t), 1, fp);
skip_bytes (fp, 6);
/*
* Repair endianess. 求出實際數值,包括data_offset b->width b->height n_colors
*/
data_offset = le_short(data_offset);
b->width = le_short(b->width);
b->height = le_short(b->height);
n_colors = le_short(n_colors);
/* assume we are working with an 8-bit file */
if ((n_colors == 0) or (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
n_colors = 256 - DEFAULT_CMAP_SIZE;
}
//使用printf便可印到bmp_logo.h那是因為$(obj)./bmp_logo $(LOGO_BMP) >$@ 。 這個">"轉向指令。
* Repair endianess. 求出實際數值,包括data_offset b->width b->height n_colors
*/
data_offset = le_short(data_offset);
b->width = le_short(b->width);
b->height = le_short(b->height);
n_colors = le_short(n_colors);
/* assume we are working with an 8-bit file */
if ((n_colors == 0) or (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
n_colors = 256 - DEFAULT_CMAP_SIZE;
}
//使用printf便可印到bmp_logo.h那是因為$(obj)./bmp_logo $(LOGO_BMP) >$@ 。 這個">"轉向指令。
以下的代碼就不用再加註解,只要比對一下產生出來的bmp_logo.h,就知道了
printf ("/*\n"
" * Automatically generated by \"tools/bmp_logo\"\n"
" *\n"
" * DO NOT EDIT\n"
" *\n"
" */\n\n\n"
"#ifndef __BMP_LOGO_H__\n"
"#define __BMP_LOGO_H__\n\n"
"#define BMP_LOGO_WIDTH\t\t%d\n"
"#define BMP_LOGO_HEIGHT\t\t%d\n"
"#define BMP_LOGO_COLORS\t\t%d\n"
"#define BMP_LOGO_OFFSET\t\t%d\n"
"\n",
b->width, b->height, n_colors,
DEFAULT_CMAP_SIZE);
/* allocate memory */
if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) {
fclose (fp);
printf ("Error allocating memory for file %s.\n", argv[1]);
exit (EXIT_FAILURE);
}
/* read and print the palette information */
printf ("unsigned short bmp_logo_palette[] = {\n");
for (i=0; ipalette[(int)(i*3+2)] = fgetc(fp);
b->palette[(int)(i*3+1)] = fgetc(fp);
b->palette[(int)(i*3+0)] = fgetc(fp);
x=fgetc(fp);
printf ("%s0x0%X%X%X,%s",
((i%8) == 0) ? "\t" : " ",
(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
((i%8) == 7) ? "\n" : ""
);
}
/* seek to offset indicated by file header */
fseek(fp, (long)data_offset, SEEK_SET);
/* read the bitmap; leave room for default color map */
printf ("\n");
printf ("};\n");
printf ("\n");
printf ("unsigned char bmp_logo_bitmap[] = {\n");
for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
for (x = 0; x <>width; x++) {
b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) + DEFAULT_CMAP_SIZE;
}
}
fclose (fp);
for (i=0; i<(b->height*b->width); ++i) {
if ((i%8) == 0)
putchar ('\t');
printf ("0x%02X,%c", b->data[i], ((i%8) == 7) ? '\n' : ' ');
}
printf ("\n"
"};\n\n"
"#endif /* __BMP_LOGO_H__ */\n"
);
return (0);
}
printf ("/*\n"
" * Automatically generated by \"tools/bmp_logo\"\n"
" *\n"
" * DO NOT EDIT\n"
" *\n"
" */\n\n\n"
"#ifndef __BMP_LOGO_H__\n"
"#define __BMP_LOGO_H__\n\n"
"#define BMP_LOGO_WIDTH\t\t%d\n"
"#define BMP_LOGO_HEIGHT\t\t%d\n"
"#define BMP_LOGO_COLORS\t\t%d\n"
"#define BMP_LOGO_OFFSET\t\t%d\n"
"\n",
b->width, b->height, n_colors,
DEFAULT_CMAP_SIZE);
/* allocate memory */
if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) {
fclose (fp);
printf ("Error allocating memory for file %s.\n", argv[1]);
exit (EXIT_FAILURE);
}
/* read and print the palette information */
printf ("unsigned short bmp_logo_palette[] = {\n");
for (i=0; i
b->palette[(int)(i*3+1)] = fgetc(fp);
b->palette[(int)(i*3+0)] = fgetc(fp);
x=fgetc(fp);
printf ("%s0x0%X%X%X,%s",
((i%8) == 0) ? "\t" : " ",
(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
((i%8) == 7) ? "\n" : ""
);
}
/* seek to offset indicated by file header */
fseek(fp, (long)data_offset, SEEK_SET);
/* read the bitmap; leave room for default color map */
printf ("\n");
printf ("};\n");
printf ("\n");
printf ("unsigned char bmp_logo_bitmap[] = {\n");
for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
for (x = 0; x <>width; x++) {
b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) + DEFAULT_CMAP_SIZE;
}
}
fclose (fp);
for (i=0; i<(b->height*b->width); ++i) {
if ((i%8) == 0)
putchar ('\t');
printf ("0x%02X,%c", b->data[i], ((i%8) == 7) ? '\n' : ' ');
}
printf ("\n"
"};\n\n"
"#endif /* __BMP_LOGO_H__ */\n"
);
return (0);
}
訂閱:
文章 (Atom)