最後的 table : rb_clip_dummy, rb_clip, 還有 g_clip_dummy, g_clip。
dummy 都是0,然後兩個加起來, rb 是 16 x 8, g 是16 x 16。
這個大概是跟 paper 講的一樣,用 table 取代 saturation 判斷。
0 的部份就是 負 值的部份。
所以 整個 assembly code 中沒有 compare jmp 指令 (除了最後的 line end 判斷)。
YUV 計算部份直接用 mla ( x +),沒有使用 table -- 大概是因為 ARM 作 16x16 只要1 個 clock,所以沒必要。
一樣是作 w (寬度),然後 line.. 一次(loop) 4 pixel。
因為先作 bit shift (5-6-5)再做查表,所以table[]不用太大。
code 沒有避免使用 mul (mla),反而大量使用,避免不需要的 ldr 動作 (大概是 ldr 和 mla 都是一個 clk 吧)。其中:
- r8 : multy 0x00012A15
- r9 : (Y-16)
- r6 : Coef *(V-128) + 32768
- r5 : Coef*(U-128) + 32768
- r4 : -Coef *(U-128) - Coef*(V-128) + 32768
剩下的就..
原來 eVC 的 ARMASM 最佳 example code 就是 OS bsp 下所有的 .s file。
所以語法參考 BSP 就可以了。
MSDN : CE .NET 4.2 ASM大概要改的是:
- MS armasm 規定只有 label 可以從一行的第一格開始,所以所有其他的 instruction, directive 都要先空
- comment 是以 ; 開頭
- label 不可以加 : 號
- .byte 改為 DCB
- .word 改為 DCD
- .text 宣告要改為 AREA |.text|,CODE, ARM
- .global 要改 EXPORT
reference
http://checko.blogspot.com/2006/09/writting-arm-assembly-in-embedded-vc_28.html :
Q_Q ,, argument passing type 不一樣...
這個 assembly code 有"適當安排過". 可以看到:
有 memory access 的 instruction,接著的會是 register-only 的 operation。
這樣instruction pipeline 就可以沒有阻礙的run 下去 (如果一個 load 下一個 store, pipe line 要等 cache/memory 的同步?)
作法是:要使用之前,在 n 個 instruction 前就 load...
所以下面是重新安排後的 code,變得比較容易看....
;
; void convert_yuv420_rgb565(AVPicture *picture, unsigned char *results, int w, int h) ;
;
AREA |.text|,CODE,ARM
EXPORT convert_yuv420_rgb565
convert_yuv420_rgb565
stmdb sp!, { r4 - r12, lr } ; all callee saved regs
ldr r7, [r0, #0] ; Y ptr
ldr r9, [r0, #4] ; U ptr
ldr r10, [r0, #8] ; V ptr
subs r10, r10, r9 ; V ptr - U ptr
ldr r8, [r0, #12]
add r8, r8, r7 ; Y + stride_Y
ldr r4, [r0, #12] ; Stride_Y
mov r4, r4, lsl #1
sub r4, r4, r2 ; (2 * Stride_Y) - width
ldr r5, [r0, #16] ; Stride_U
sub r5, r5, r2, lsr #1 ; Stride_U - (width / 2)
ldr r6, [r0, #20] ; Stride_V
sub r6, r6, r2, lsr #1 ; Stride_V - (width / 2)
add r0, r1, r2, lsl #1 ; RGB + 1
stmdb sp!, { r0-r10 }
; Stack description :
; (sp+ 0) RGB + one line
; (sp+ 4) RGB
; (sp+ 8) width (save)
; (sp+12) height
; (sp+16) (2 * stride_Y) - width
; (sp+20) stride_U - (width / 2)
; (sp+24) stride_V - (width / 2) !!! UNUSED !!!
; (sp+28) Y ptr
; (sp+32) Y ptr + one line
; (sp+36) U ptr
; (sp+40) V - U
mov lr, r2 ; Initialize the width counter
add r0, pc, #(const_storage-.-8) ; r0 = base pointer to the constants array
ldr r8, [r0, #(4*4)] ; r8 = multy
yuv_loop
ldr r10, [sp, #28] ; r10 = Y
ldrb r9, [r10, #0] ; r9 = *Y
add r10, r10, #2 ; r10 = Y + 2
str r10, [sp, #28] ; save Y + 2
ldr r1, [sp, #36] ; r1 = U
ldrb r11, [r1] ; r11 = *U
add r1, r1, #1 ;; r1 = U++
str r1, [sp, #36] ; store U++
ldr r2, [sp, #40] ; r2 = V - U
add r2, r1, r2 ; r2 = V+1
ldrb r12, [r2, #-1] ; r12 = *V
sub r11, r11, #128 ; r11 = *U - 128
sub r12, r12, #128 ; r12 = *V - 128
mov r7, #32768 ; r7 = 32768 (for additions in MLA)
add r0, pc, #(const_storage-.-8) ; r0 = base pointer to the constants array
ldr r1, [r0, #(4*0)] ; r1 = crv
mla r6, r1, r12, r7 ; r6 = nonyc_r = crv * (*V - 128) + 32768
ldr r2, [r0, #(4*3)] ; r2 = -cgv
mla r4, r2, r12, r7 ; r4 = - cgv * (*V - 128) + 32768
ldr r3, [r0, #(4*1)] ; r3 = cbu
mla r5, r3, r11, r7 ; r5 = nonyc_b = cbu * (*U - 128) + 32768
sub r9, r9, #16 ; r9 = *Y - 16
mla r7, r8, r9, r6 ; r7 = (*Y - 16) * multy + nonyc_r
ldr r0, [r0, #(4*2)] ; r0 = -cgu
mla r4, r0, r11, r4 ; r4 = nonyc_g = - cgu * (*U - 128) + r4 = - cgu * (*U - 128) - cgv * (*V - 128) + 32768
add r0, pc, #(rb_clip-.-8) ; r0 contains the pointer to the R and B clipping array
ldrb r7, [r0, r7, asr #(16+3)] ; r7 = R composant
mla r12, r8, r9, r5 ; r12 = (*Y - 16) * multy + nonyc_b
mla r1, r8, r9, r4 ; r1 = (*Y - 16) * multy + nonyc_g
ldrb r12, [r0, r12, asr #(16+3)] ; r12 = B composant (and the start of the RGB word)
add r12, r12, r7, lsl #11 ; r12 = .GB ...
add r11, pc, #(g_clip-.-8) ; r11 now contains the pointer to the G clipping array
ldrb r1, [r11, r1, asr #(16+2)] ; r1 contains the G part of the RGB triplet
add r12, r12, r1, lsl #5 ; r12 = RGB ... (ie the first pixel (half-word) is done)
; --- next pixel
ldrb r9, [r10, #-1] ; r9 = *(Y+1)
sub r9, r9, #16 ; r9 = *(Y+1) - 16
mla r10, r8, r9, r6 ; r10 is the Red part of the RGB triplet
mla r7, r8, r9, r5 ; r7 is the Blue part of the RGB triplet
mla r2, r8, r9, r4 ; r2 is the Green part of the RGB triplet
ldrb r2, [r11, r2, asr #(16+2)] ; r2 = G composant
add r12, r12, r2, lsl #(5+16) ; r12 = RGB .G.
ldrb r7, [r0, r7, asr #(16+3)] ; r7 = B composant
add r12, r12, r7, lsl #(0+16) ; r12 = RGB .GB
ldrb r10, [r0, r10, asr #(16+3)] ; r10 = R composant
add r12, r12, r10, lsl #(11+16) ; r12 = RGB RGB
;---- do store ----
ldr r3, [sp, #4] ; r3 = RGB
add r3, r3, #4 ; r3 = RGB++ (ie next double-pixel)
str r3, [sp, #4] ; store the RGB pointer
str r12, [r3] ; store the rgb pixel at *RGB
;---- next line ----
ldr r1, [sp, #32] ; r1 = Ynext
ldrb r9, [r1] ; r9 = *Ynext
sub r9, r9, #16 ; r9 = *Ynext - 16
mla r2, r8, r9, r4 ; r2 is the Green part of the RGB triplet
mla r7, r8, r9, r5 ; r7 is the Blue part of the RGB triplet
mla r10, r8, r9, r6 ; r10 is the Red part of the RGB triplet
ldrb r12, [r0, r7, asr #(16+3)] ; r12 = ..B ...
ldrb r10, [r0, r10, asr #(16+3)] ; r10 = B composant
add r12, r12, r10, lsl #11 ; r12 = R.B ...
ldrb r2, [r11, r2, asr #(16+2)] ; r2 = G composant
add r12, r12, r2, lsl #5 ; r12 = RGB ...
;---- next pixel
ldrb r9, [r1, #1] ; r9 = *(Ynext+1)
sub r9, r9, #16 ; r9 = *(Ynext+1) - 16
add r1, r1, #2 ; r1 = Ynext + 2
str r1, [sp, #32] ; store the increased Ynext pointer
mla r7, r8, r9, r5 ; r7 is the Blue part of the RGB triplet
mla r10, r8, r9, r6 ; r10 is the Red part of the RGB triplet
mla r2, r8, r9, r4 ; r2 is the Green part of the RGB triplet
ldrb r7, [r0, r7, asr #(16+3)] ; r7 = B composant
add r12, r12, r7, lsl #(16+0) ; r12 = RGB ..B
ldrb r10, [r0, r10, asr #(16+3)] ; r10 = R composant
add r12, r12, r10, lsl #(16+11) ; r12 = RGB R.B
ldrb r2, [r11, r2, asr #(16+2)] ; r2 = G composant
add r12, r12, r2, lsl #(16+5) ; r12 = RGB RGB
;---- do store
ldr r3, [sp, #0] ; r3 = RGBnext pointer
add r3, r3, #4 ; r3 = next pixel on the RGBnext line
str r12, [r3, #-4] ; store the next pixel
str r3, [sp, #0] ; store the increased 'next line' pixel pointer
;-- complete, do loop --
subs lr, lr, #2 ; decrement the line counter
bne yuv_loop ; and restart if not at the end of the line
ldr r0, [sp, #8] ; r0 = saved width
ldr r1, [sp, #0] ; r1 = RGBnext pointer
mov lr, r0 ; lr = saved width (to restart the line counter)
str r1, [sp, #4] ; current RGBnext pointer is next iteration RGB pointer
add r1, r1, r0, lsl #1 ; r1 = update RGBnext to next line
str r1, [sp, #0] ; store updated RGBnext pointer
ldr r3, [sp, #16] ; r3 = (2 * stride_Y) - width
ldr r4, [sp, #28] ; r4 = Y ptr
ldr r5, [sp, #32] ; r5 = Ynext ptr
add r4, r4, r3 ; r4 = Y ptr for the next two lines
add r5, r5, r3 ; r5 = Ynext ptr for the next two lines
str r4, [sp, #28] ; store updated Y pointer
str r5, [sp, #32] ; store update Ynext pointer
ldr r1, [sp, #20] ; r1 = stride_U - (width / 2)
ldr r2, [sp, #36] ; r2 = U ptr
ldr r6, [sp, #12] ; get height counter
add r2, r2, r1 ; update U ptr
str r2, [sp, #36] ; store updated U ptr (and update 'V' at the same time :-) )
subs r6, r6, #2
str r6, [sp, #12]
bne yuv_loop
; Exit cleanly :-)
add sp, sp, #(11*4) ; remove all custom things from stack
ldmia sp!, { r4 - r12, pc } ; restore callee saved regs and return
const_storage
; In order : crv, cbu, - cgu, - cgv, multy
DCD 0x00019895, 0x00020469, 0xffff9bb5, 0xffff2fe1, 0x00012A15
rb_clip_dummy
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
rb_clip
DCB 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
DCB 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
DCB 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f
DCB 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f
DCB 0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f
g_clip_dummy
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
DCB 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
g_clip
DCB 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
DCB 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
DCB 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
DCB 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
DCB 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f
END