?? ad_pcm.asm
字號:
******************************************************************************
******************************************************************************
**** TMS320C54x用ADPCM編解碼程序V0.1 ****
**** All right reserved ****
**** 版權所有 ****
**** 程序設計:羅茂才 ****
**** E-mail: luomc@neusoft.com ****
**** luomao2000@163.net ****
**** luomao1977@sina.com ****
**** ****
**** 本程序參照Stichting Mathematisch Centrum, Amsterdam,The Netherlands ****
**** 所寫的C語言ADPCM編解碼程序設計,作者不承擔任何可能侵犯版權的后果。 ****
**** ****
**** 允許自由使用、復制、修改、傳播該程序,可免費用于商業(yè)用途,但不得以 ****
**** 該程序作為主體獲得利益。無論在什么情況下使用,都請保留該版權信息。 ****
**** 作者不保證該程序能完全正確按照你的要求運行,所有由于使用該程序 ****
**** 造成的損失,后果自負(呵呵,我可沒有特意留下什么隱患?。?。 ****
**** 如果你利用了該程序,請告訴一聲(我想知道有多少人會使用這個程序)。 ****
**** 如果你對該程序有任何建議、錯誤信息反饋等,敬請與作者聯(lián)系 ****
**** (請采用Algebraic assembly方式匯編該文件) ****
**** ****
**** 感謝我的老婆給予我的愛、關心以及支持。 ****
**** 2003年7月31日 ****
******************************************************************************
******************************************************************************
*
* 編碼函數(shù)C語言聲明
* extern void AdpcmEncoder(int* pBufferIn, int* pBufferOut,
* int* pPrevValue,int* pPrevIndex, int Length);
* 解碼函數(shù)C語言聲明(解碼長度為實際解碼后長度的1/4)
* extern void AdpcmDecoder(int* pBufferIn, int* pBufferOut,
* int* pPrevValue,int* pPrevIndex, int Length);
*
* 編解碼后的PrevValue和PrevIndex都被修改,在后續(xù)的編解碼中將繼續(xù)被使用
*
* CCS2.1下測試通過
.title "Intel/DVI ADPCM coder/decoder"
.def _AdpcmEncoder
.def _AdpcmDecoder
.mmregs
;索引表
.data
IndexTable: ; 實際上只用了15個,考慮到速度問題,有一個舍棄了
.word -8, -5, -3, -1, 1, 3, 5, 8
.word 8, 5, 3, 1, -1,-3,-5,-8
;步進量
StepSizeTable: ; 共84個
.word 4, 5, 6, 7, 8, 9, 10, 11, 12, 14
.word 16, 18, 20, 22, 25, 28, 32, 36, 42, 49
.word 57, 67, 78, 90, 103, 118, 134, 152, 170, 189
.word 209, 230, 253, 279, 307, 337, 371, 408, 449, 494
.word 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282
.word 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327
.word 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630
.word 9493, 10442, 11487, 12635,13899, 15289,16818, 18500, 20350, 22385
.word 24623, 27086, 29794, 32767
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 寄存器使用規(guī)則(調(diào)用時不設置)
; AR0: 臨時變量
; AR2: 輸入緩沖區(qū)指針
; AR3: 輸出緩沖區(qū)指針
; AR4: 步進量地址指針
; AR5: 當前輸出數(shù)據(jù)計數(shù)器(0--3: 16位長度可保存4個編碼數(shù)據(jù))
.asg *SP(3), pBufferOut
.asg *SP(4), pPrevValue
.asg *SP(5), pPrevIndex
.asg *SP(6), Length
.asg *SP(0), PrevValue ; 占用了這兩個堆棧位置,存放臨時數(shù)據(jù)
.asg *SP(1), PrevIndex ;
.text
_AdpcmEncoder:
TC = (*SP(4) == #0) ; 首先檢測緩沖區(qū)長度是否為0,為0則結束
if(TC) dgoto EncoderEnd
AR5 = #4 ; 設置計數(shù)器初值
SP += -2 ; 調(diào)整堆棧指針,以便利用其中的兩個子
AR2 = A ; 讀取輸入緩沖區(qū)地址
B = pBufferOut ; 讀入輸出緩沖區(qū)地址
AR3 = B
B = pPrevValue ; 讀入上次轉(zhuǎn)換值地址
AR0 = B
ASM = #0
SXM = 1 ; 設置符號位擴展
Length -= 1 ; 長度減1
A = pPrevIndex ; 讀取上次轉(zhuǎn)換的索引
B = *AR0
AR0 = A
PrevValue = B ; 讀取上次轉(zhuǎn)換值
FRCT = 0
A = *AR0
PrevIndex = A ; 保存上次轉(zhuǎn)換索引
A = Length ; 讀取轉(zhuǎn)換長度
BRC = A ; 設置塊循環(huán)計數(shù)器
A = PrevIndex
DBLOCKREPEAT(EncoderLoopEnd-1) ; 啟動塊循環(huán)(根據(jù)循環(huán)最后一條指令確定是1還是2)
*AR3 = #0 ; 輸出緩沖區(qū)第一個字清零
EncoderLoop:
A += #StepSizeTable ; 偏移
AR4 = A ; 取得步進基地址 + 偏移
B = *AR2+ ; 取得輸入緩沖區(qū)的值(沒有必要規(guī)范到-32768...+32767)
B -= PrevValue ; 獲得當前值與上次計算值之間的差值
A = |B| ; 計算delta=diff/step,并將商規(guī)范到-8...+7
REPEAT(#16) ; 循環(huán)減(做除法)多除了一次,相當于商×2
SUBC(*AR4, A)
A += #1 ; 調(diào)整0.5的差值
A &= #0FFFFh ; (清除高位無效數(shù)據(jù))
A = A >> 1
if(BGEQ) DGOTO EncoderSetDelta ; 檢測是否是負數(shù)
B = #7 ; 將Delta數(shù)據(jù)規(guī)范到-8...+7
A = MIN(A, B)
A = -A ; 是負數(shù),商取負
EncoderSetDelta:
;B = #-8 ; 已經(jīng)規(guī)范到0--7了,取負數(shù)后也沒有關系
;A =MAX(A, B)
T = A
; 計算PrevValue值,并將其規(guī)范到(-32768)--(+32767)
B = T*(*AR4) ; 獲得Delta*Step的值,保存在B寄存器中
B += PrevValue ; 計算上次值與這次差值的和
;B += *AR4 >> 1
B = B <<C 8 ; 只有32位的飽和運算
B = B <<C 8 ; 移位操作比用max/min指令要快
saturate(B) ; 飽和成32位的數(shù)據(jù)
; 檢測是否需要將輸出指針移動到下一個字
if(*AR5- != 0) DGOTO EncoderNoInc
A &= #0Fh ; 保留低4位
AR5 = #3 ; 重新設置計數(shù)器
*+AR3 = #0 ; 輸出緩沖區(qū)清零
EncoderNoInc:
PrevValue = hi(B) ; 保存當前轉(zhuǎn)換結果
B = A + *AR3 << 4 ; 將輸出緩沖區(qū)當前字左移4位,然后加上當前值
*AR3 = B ;
AR0 = A ; 取得更新后的索引
B = #0
A = PrevIndex
A += *AR0(IndexTable) ; 基地址 + 偏移
A = MAX(A, B) ; 將PrevIndex規(guī)范到0-83
B = #83
A = MIN(A, B)
PrevIndex = A
EncoderLoopEnd:
B = pPrevValue ; 設置轉(zhuǎn)換后的PrevIndex和PrevValue
AR0 = B
A = pPrevIndex
AR2 = A
A = PrevIndex
B = PrevValue
*AR2 = A
SP += 2 ; 將堆棧指針調(diào)整回原來的值
*AR0 = B
NOP ; 避免沖突用的
EncoderEnd:
RETURN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 寄存器使用規(guī)則(調(diào)用時不設置)
; AR0: 臨時變量
; AR1: 當前轉(zhuǎn)換值
; AR2: 輸入緩沖區(qū)指針
; AR3: 輸出緩沖區(qū)指針
; AR4: 步進量地址指針
; AR5: 當前輸出數(shù)據(jù)計數(shù)器(0--3: 16位長度可保存4個編碼數(shù)據(jù))
.asg *SP(3), StepValue ; 臨時變量,存放當前的輸入處理值(不斷左移4位)
_AdpcmDecoder:
TC = (*SP(4) == #0)
if(TC) DGOTO DecoderEnd ; 如果長度為0,退出
AR5 = #3 ; 設置循環(huán)計數(shù)器
SP -= 2 ; 調(diào)整堆棧指針,以便有多余的兩個字可供臨時使用
AR2 = A ; 取輸入緩沖區(qū)地址
A = pBufferOut ; 取輸出緩沖區(qū)地址
B = pPrevValue ; 取存放上次轉(zhuǎn)換值變量的地址
AR0 = B
ASM = #0 ; (好像沒有用)
SXM = 1 ; 設置符號位擴展
AR3 = A ; 取得輸出緩沖區(qū)
B= *AR0 ; 取得PrevValue
A = pPrevIndex ; 取PrevIndex的地址
AR0 = A ; 臨時存放地址(直接存會出錯(編譯得就不對))
PrevValue = B ; 呵呵,終于取出來了
OVM = 1 ; 溢出吧,我的兄弟,就等你了
A = *AR0 ; 讀取PrevIndex的值
PrevIndex = A
A = Length<<2 ; 因為是16位操作,可存放4個轉(zhuǎn)換值,乘以4
A -= #1 ; 減去1,循環(huán)次數(shù)要比實際次數(shù)少1
BRC = A ; 設置塊循環(huán)計數(shù)器
A = *AR2+ ; 取輸入緩沖區(qū)的值
DBLOCKREPEAT(DecoderLoopEnd-1) ; 運轉(zhuǎn)起來吧,要不然飯都涼了
StepValue = A ; 獲得當前處理值
A = PrevIndex ; 取得當前index所對應的值
DecoderLoop:
A += #StepSizeTable
AR4 = A
A = StepValue << 4 ; 取當前轉(zhuǎn)換值,獲得delta值(利用了符號擴展功能)
StepValue = A
B = PrevValue
B = B + hi(A)*(*AR4) ; 獲得計算的差值
;B += *AR4 >> 1
B = B <<C 8 ; 因為只能進行32位的飽和運算,沒有辦法啦
B = B <<C 8 ; 將數(shù)據(jù)規(guī)范到-32768...+32767
saturate(B)
if(*AR5- != 0) DGOTO DecoderNoInc
*AR3+ = hi(B)
PrevValue = hi(B)
AR5 = #3 ; 重新設置計數(shù)器
B = *AR2+
StepValue = B
DecoderNoInc:
A = A >> 16 ; 調(diào)整PrevIndex的值
A &= #0Fh ; 并將其調(diào)整在0...83之間
AR0 = A
B = #0
A = PrevIndex
A += *AR0(IndexTable)
A = MAX(A, B)
B = #83
A = MIN(A, B)
PrevIndex = A
DecoderLoopEnd:
B = pPrevValue ; 設置PrevValue和PrevIndex
AR0 = B
B = PrevValue
A = pPrevIndex
AR2 = A
A = PrevIndex
*AR0 = B
*AR2 = A
SP += 2 ; 將堆棧指針調(diào)整回原來的值
NOP ; 避免沖突用的
DecoderEnd:
RETURN
.end
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -