8.10.2010

Build Assembly code in VS2005

這是參考 tcpmp 的 project 檔。

大概也跟 eVC 一樣,就是為 assembly.asm 加上 custom build command.
  1. 先把 assembly code 的 source file 寫好
  2. 開啟 VS2005,把 assembly file 加到 source folder 中
  3. 在 assembly file 按右鍵,選 properties
  4. Custom Build Step -- General --Command Line,, 寫armasm.exe -cpu xscale "$(InputPath)" "$(IntDir)/$(InputName).obj"
  5. Output 寫$(IntDir)/$(InputName).obj

8.09.2010

CpuId - 紀錄一下

因為 CE 6.0 沒有辦法 SetKMode,所以只好... 寫一個 driver,然後 load 進去..,

這就是 copy 自 tcpmp getcpuid 的 code 後,run 起來:
  • 我們的: 4117B362,1D152152,0,0
  • 測試的: 410FB764,1D992992,0,0
第一個,cpu id

4117B362:ref(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CACEDHJG.html)
所以是 ARM1136, rev2

410FB764: ref (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CACEDHJG.html)
所以是 ARM1176 , rev 4

第二個,cache type register

ref : http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/I67616.html

  • [31:29] : always 0
  • [28:25] : ctype - cache type b1110 means "write back","register 7 operation","format C"
  • [24] : separate D and I cache
  • [23:12] : D cache size
  • [11:0] : I cache size
其中 D 和 I cache size encoding format:
  • [11] : P
  • [10:9] : always 0
  • [8:6] : size
  • [5:3] : association (way)
  • [2] : M
  • [1:0] Length
所以
1D152152 : 16K, 4 way, len=32 bytes.
1D992992: 32K, 4 way, len=32 bytes.


driver code

GETID.C:
#include <windows.h>
#include <drvlib.h>


//----- Code Control -----
#define GID_DEBUG

#ifdef DEBUG
DBGPARAM dpCurSettings = { TEXT("Getid"), {
TEXT("Verbose"), TEXT(""), TEXT(""), TEXT(""),
TEXT(""), TEXT(""), TEXT(""), TEXT(""),
TEXT(""), TEXT(""), TEXT(""), TEXT(""),
TEXT(""), TEXT(""), TEXT(""), TEXT("")},
0x00000000
};
#endif

extern void GetCpuId(int,DWORD*);

void SafeGetCpuId(int Id, DWORD* p)
{
memset(p,0,4*sizeof(DWORD));
GetCpuId(Id,p);
}


//--- GID_Init
DWORD GID_Init(DWORD dwContext)
{
DWORD CpuId[4];
DWORD dwErr;
TCHAR outmsg[60];

RETAILMSG(1, (TEXT("[GID] GID_Init+\r\n")));

SafeGetCpuId(0,CpuId);
RETAILMSG(1,(TEXT("%X,%X,%X,%X\r\n"),CpuId[0],CpuId[1],CpuId[2],CpuId[3]));
swprintf(outmsg,TEXT("%X,%X,%X,%X"),CpuId[0],CpuId[1],CpuId[2],CpuId[3]);

MessageBox(NULL,outmsg,TEXT("GID"),MB_OK);


RETAILMSG(1, (TEXT("[GID] GID_Init OK \r\n")));
return TRUE;

}



//--- GID_Deinit
BOOL GID_Deinit(DWORD dwContext)
{
RETAILMSG(1, (TEXT("[GID] GID_Deinit+\r\n")));


return TRUE;
}



//--- GID_Open
DWORD GID_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode)
{
RETAILMSG(1, (TEXT("[GID] GID_Open+\r\n")));

return dwData;
}



//--- GID_Close
BOOL GID_Close(DWORD Handle)
{
RETAILMSG(1, (TEXT("[GID] GID_Close+\r\n")));

return TRUE;
}



//--- GID_Read
DWORD GID_Read(DWORD Handle, LPVOID pBuffer, DWORD dwNumBytes)
{
RETAILMSG(1, (TEXT("[GID] GID_Read+\r\n")));
return 0;
}



//--- GID_Write
DWORD GID_Write(DWORD Handle, LPCVOID pBuffer, DWORD dwNumBytes)
{
RETAILMSG(1, (TEXT("[GID] GID_Write+\r\n")));


return 0;
}



//--- GID_Seek
DWORD GID_Seek(DWORD Handle, long lDistance, DWORD dwMoveMethod)
{
RETAILMSG(1, (TEXT("[GID] GID_Seek+\r\n")));

return (DWORD) -1;
}



//--- GID_IOControl
BOOL GID_IOControl(
DWORD Handle,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
)
{

RETAILMSG(1, (TEXT("[GID] GID_IOControl+\r\n")));
return (FALSE);
}

BOOL
GID_DllEntry(
HINSTANCE hinstDll, /*@parm Instance pointer. */
DWORD dwReason, /*@parm Reason routine is called. */
LPVOID lpReserved /*@parm system parameter. */
)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls((HMODULE) hinstDll);
}


return (TRUE);
}


arm.s
INCLUDE kxarm.h

EXPORT GetCpuId

TEXTAREA

LEAF_ENTRY GetCpuId
export GetCpuId
mrs r0,cpsr

and r0,r0,#15
cmp r0,#15
bne UserMode
mrc p15,0,r0,c0,c0,0
nop
nop
mrc p15,0,r2,c0,c0,1
nop
nop
str r0,[r1,#0]
str r2,[r1,#4]
UserMode
mov pc,lr

ref (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CACEDHJG.html) CpuID 取的是 opcode2 = 0 和 1 : cpu id 跟 cache type.
GETID.DEF
LIBRARY getid

EXPORTS
GID_Init
GID_Deinit
GID_Open
GID_Close
GID_Read
GID_Write
GID_IOControl

sources

TARGETNAME=getid
TARGETTYPE=DYNLINK
RELEASETYPE=PLATFORM

DLLENTRY=GID_DllEntry
DEFFILE=$(_TARGETPLATROOT)\SRC\DRIVERS\getid\getid.def

PREPROCESSDEFFILE=1
SYNCHRONIZE_DRAIN=1
WINCEREL=1

TARGETLIBS= \
$(_COMMONSDKROOT)\LIB\$(_CPUINDPATH)\coredll.lib \

SOURCELIBS= \

SOURCES= \
getid.c \
arm.s


load driver 的程式就是以前哪個 activedriverex( ). 改一下 dll name 就可以


ref http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/I67616.html
用

c0, Core feature ID registers

好像可以得到更多 cpu feature

8.07.2010

to replace t3

t3
  • 500萬 1/2.4" CCD
  • 3x optical zoom
  • 38 - 114 mm
  • F3.5 - F4.4
  • 640 x 480, 30 fps m jpg
  • 2.5" lcd
COOLPIX S620 nt 5980
  • 1,220 萬 1/2.33 英寸 CCD
  • 4倍變焦 28-112mm
  • F2.7-5.8
  • 640 x 480@30fps mjpeg
  • 2.7" lcd
  • VR 光學防震
OLYMPUS FE-4030 nt 5900
  • 1400 萬像素
  • 4X 26 mm 至 105 mm
  • 2.6 (wide) – 5.9 (tele)
  • 640 x 480 @ 30/15 fps mjpeg
  • 2.7" lcd
OLYMPUS μ1070 nt 4999 (costco)
  • 1,200萬
  • 38mm~114mm
  • F3.5(W)~F5.0(T)
  • 640 x 480 @ 30/15 fps mjpeg
  • 2.7" lcd
  • CCD移動式手震校正
FUJI F72EXR nt 5990

8.05.2010

pipeline bubble

利用 assembly 來optimize speed 時,要注意,並不是 instruction line 短就夠了。
還要注意 pipline 的特性。

pipeline 將指令分成幾個 stage:
  • fetch,
  • decode/register read,
  • alu,
  • memory write,
  • register update.
如果這樣個 assembly codes:
ldr r0,#1
add r3,r0,r1
第二行指令在 decode/register read 時,r0 還沒update,因為上一行才執行到alu operation。所以在pipeline中的第二行指令就要停下來,等兩個clock,等上一行指令執行到register update後,才可以繼續。
這樣,就白白浪費 2 個 clock 了。

為了避免這樣的情況,寫 assembly 的時候,就可以在中間插入下面要作的 assembly code,不要白白浪費這兩個clock

在 (很久)前面的文章:yuv - rgb color space convert 的 assembly code 可以看到。最後一個作者的assembly code 就有做到這個(所以整個 code 的 flow 變得不好trace)。實測的結果,也是最快的。

在 Wiki 里也有說明:
instruction scheduling
Instruction scheduling is an important optimization for modern pipelined processors, which avoids stalls or bubbles in the pipeline by clustering instructions with no dependencies together, while being careful to preserve the original semantics.

8.04.2010

OEM 自訂 cache mode --- CE 6.0

這一篇 ( http://support.microsoft.com/kb/977855/ ) 超新的... An update that enables the Windows Embedded CE 6.0 kernel to support different cache mode bits is available

是 Microsoft as Windows Embedded CE 6.0 Platform Builder Monthly Update (June 2010). 才支援。

就是在 5.0 以前都有 support 的 OEMARMCacheMode( ) 回報 .

cache

cache 是一小塊和cpu時脈一樣的記憶體,作為 cpu 與 主記憶體間的 buffer。
當 cpu 要讀取 memory 時, cache 先把 memory 的資料讀進 cache 中,然後再讓 cpu 讀取。

cpu 每次讀取的單位是 int (32bit),但是 cache 為求效能,會一次讀入比 int 還多的資料。
cache 每次讀入的資料大小叫 line size,每次讀入的資料放入 一個 line。

cache 就是利用這樣預先讀取的能力,讓cpu 下次需要讀取記憶體時,可以直接由 cache 拿,不需要再向 主記憶體 讀取。


由於 cache 只有小小一塊,所以必須要有一個機制知道 cpu 需要存取記憶體時,那個 address的內容是不是已經在cache 里,如果在,是在 cache 的那一條 line ...

最直覺的方法就是去找每一個 cache line 的 address,看看那一個 line 所以 cache 的 記憶體位址是不是 cpu 現在要的。

這樣個 cache 叫 associative cache.

但是這樣作很耗空間(電路),因為每一個 line 都要作一個 address比較電路。
所以就有比較便宜的作法.. 把 把 address 分成兩部份:

tag, index

以 32 bit 的 address line 為例,可以分成:
  • tag : 31~20
  • index : 19~0
這樣要找cache 時就可以反過來用,用 address的 0~19作 index,找到那個 cache index line 的 tag,然後跟 31~20比較就可以。


後來又有折衷的辦法,就是...每個 index 可以有兩個 tag欄位和lines,這樣,每20 條位址線,就可以共用兩條 cache line。 -- 這就叫 2 way cache.
=>這樣就是:拿 index 找到對應的 2 個 tag ,比較和 address bit 31-20 一步一樣。

一此類推,可以有 4 way cache。

這一篇 (http://www.mirabilisdesign.com/Pages/Demonstrations/systemarchitecture/Cache_System/Functional_Cache_Model_Overview.html)雖然是 sim software 的說明,但是可以看到 ARM11 cache 的 impelement 圖例

cache line size 是 16 words (address 0~3), index size 是 4096 (address 4~15), tag filed 是 address 16~31,




所以 cache index size x byte size x way = cache size

8.02.2010

這個網站很不錯,範圍很廣,軟體與實際的應用.. http://yukuan.blogspot.com/