📄 ldiv16.asm
字号:
;***********************************************************
; Version 2.20.01
;***********************************************************
;****************************************************************
; Function: ldiv16.asm
; Description: divide Q31 by Q15 yielding Q15 result
;
;
; Copyright Texas instruments Inc, 1998
;----------------------------------------------------------------
; Revision History:
; 1.00Beta - K. Baldwin. Original Beta Release 8/31/98
;****************************************************************
.mmregs
.def _ldiv16
_ldiv16:
;
; Far_mode adjustment
;---------------------------------------------------------------
;
.if __far_mode
.asg 1, OFFSET
.else
.asg 0, OFFSET
.endif
;
; Set size of space on stack for preserving save on entry registers
;---------------------------------------------------------------
;
REG_SAVE_SZ .set 4
;-------------------------------------------------------------------------
; Command-line stack arguments
;-------------------------------------------------------------------------
ARG_Y .set 1 + OFFSET + REG_SAVE_SZ
ARG_Z .set 2 + OFFSET + REG_SAVE_SZ
ARG_ZEXP .set 3 + OFFSET + REG_SAVE_SZ
ARG_N .set 4 + OFFSET + REG_SAVE_SZ
;-------------------------------------------------------------------------
; ARXY_ means Xmem/Ymem register
;-------------------------------------------------------------------------
AR_Y .set ar0 ; Points to SP_INDEX
AR_N .set ar1
AR_Z .set ar2
AR_X .set ar3
AR_PROD .set ar4
AR_ZEXP .set ar5
AR_TABLE .set ar7
;-------------------------------------------------------------------------
; Stack local variables
;-------------------------------------------------------------------------
SP_PROD_H .set 0
SP_PROD_L .set 1
SP_XNORM .set 2
SP_TEMP .set 3
SP_EXP .set 4
SP_SIGN .set 5
SP_MAX_EXP .set 6
FSZ .set 7 ; # of local variables
;-------------------------------------------------------------------------
; Preserve contents registers that will be used by this function
;-------------------------------------------------------------------------
pshm ar1 ; 1 cycle
pshm ar7 ; 1 cycle
PSHM ST0 ; 1 cycle
PSHM ST1 ; 1 cycle
RSBX OVA ; 1 cycle
RSBX OVB ; 1 cycle
;-------------------------------------------------------------------------
; Process command-line arguments
;-------------------------------------------------------------------------
stl a,*(AR_X) ; 1 cycle
mvdk *sp(ARG_Y), AR_Y ; 2 cycles
mvdk *sp(ARG_Z),AR_Z ; 2 cycles
mvdk *sp(ARG_ZEXP),AR_ZEXP ; 2 cycles
;-------------------------------------------------------------------------
; N=N-1
;-------------------------------------------------------------------------
ld *sp(ARG_N),a ; 1 cycle
sub #1,a ; 2 cycles
stlm a,AR_N ; 1 cycle
;-------------------------------------------------------------------------
; Can't access local variables before this instruction
; Can't access command-line arguments after this instruction
;-------------------------------------------------------------------------
frame #-FSZ ; 1 cycle
;-------------------------------------------------------------------------
; Initialize constants and set arithmetic modes
;-------------------------------------------------------------------------
ssbx SXM ; 1 cycle
ssbx OVM ; 1 cycle
ldm sp, a ; 1 cycle
add #SP_PROD_H, a ; 2 cycles
stlm a, AR_PROD ; 1 cycle
LOOP:
;-------------------------------------------------------------------------
; Treat all values as positive, preserve sign for inclusion in final result
; Normalize input value to determine initial exponent.
;-------------------------------------------------------------------------
ld *AR_Y+,16,a ; 1 cycle
exp a ; 1 cycle
nop ; 1 cycle
nop ; 1 cycle
norm a ; 1 cycle
ldm t, b ; 1 cycle
add #1, b ; 2 cycles
stl b, *AR_ZEXP ; 1 cycle
sth a,*sp(SP_XNORM) ; 1 cycle
;---------------------------------------------------------------------------
; The algorithm used in calculating the quotient is to invert the denominator
; and multiply by numerator. The reciprocal of the Q15 number is found by an
; approximation method.
;
; Ym = 2 * Ym - Ym^2 * X
; where, Ym is the best approximation and X is the normalize value of the
; denominator. The reciprocal converges to 15 bit accuaracy in 3 iterations.
; First approximation is obtained by shifting right by 1.
;---------------------------------------------------------------------------
sfta a,-1 ; 1 cycle
sth a,*AR_Z ; 1 cycle
;---------------------------------------------------------------------------
; First two iterations:
;---------------------------------------------------------------------------
.loop 2
ld *AR_Z,15,a ; 1 cycle
ld *AR_Z,t ; 1 cycle
mpy *sp(SP_XNORM),b ; 1 cycle
sth b,1,*AR_Z ; 1 cycle
mpy *AR_Z,b ; 1 cycle
sub b,1,a ; 1 cycle
sth a,2,*AR_Z ; 1 cycle
.endloop
;-------------------------------------------------------------------------
; Final iteration: - this code is same as above loop, except
; last instruction omitted
;-------------------------------------------------------------------------
ld *AR_Z,15,a ; 1 cycle
ld *AR_Z,t ; 1 cycle
mpy *sp(SP_XNORM),b ; 1 cycle
sth b,1,*AR_Z ; 1 cycle
mpy *AR_Z,b ; 1 cycle
sub b,1,a ; 1 cycle
;-------------------------------------------------------------------------
; Make sure vlaue is in range 8000h <= Ym <= 7fffh
;-------------------------------------------------------------------------
st #07000h,*AR_Z ; 2 cycles
add *AR_Z,16,a ; 1 cycle
sub *AR_Z,16,a ; 1 cycle
sub *AR_Z,16,a ; 1 cycle
add *AR_Z,16,a ; 1 cycle
;-------------------------------------------------------------------------
; Adjust sign of result
;-------------------------------------------------------------------------
sth a, #3, *AR_Z ; 1 cycle
nop
nop
nop
nop
nop
nop
;-------------------------------------------------------------------------
; Multiply numerator by reciprocal of denominator
;-------------------------------------------------------------------------
ld #0, b ; 1 cycle
mpy *AR_Z, *AR_X+, a ; 1 cycle ; Numerator high * denominator high
macsu *AR_X+, *AR_Z, b ; 1 cycle ; Denominator low * numerator high
rsbx sxm ; 1 cycle
add b, -16, a ; 1 cycle ; add H + L
sfta a, #1, a ; 1 cycle
ssbx sxm ; 1 cycle
add #08000h, a ; 2 cycles
nop
nop
nop
nop
exp a ; 1 cycle
ld #0, b ; 1 cycle
nop ; 1 cycle
nop
nop
nop
nop
nop
nop
ldm t, b ; 1 cycle
neg b
nop
nop
nop
nop
add *AR_ZEXP, b, b ; 1 cycle
nop
nop
nop
nop
nop
norm a ; 1 cycle
bcd L1, BGT ; 3 cycles
stlm b, T ; 1 cycle - delay slot
nop ; 1 cycle - delay slot
ld *(AH), TS, a ; 1 cycle
ld #1, b ; 1 cycle
bd L2 ; 2 cycles
ld *(AL), 16, a ; 1 cycle - delay slot
nop ; 1 cycle - delay slot
nop
L1:
ld #1, b ; 1 cycle
ld *(BL),TS,b ; 1 cycle
L2:
stl b, *AR_ZEXP ; 1 cycle
sth a, *AR_Z+ ; 1 cycle
;-------------------------------------------------------------------------
; Check for MAX exponent
;-------------------------------------------------------------------------
sub *sp(SP_MAX_EXP), b, a ; 1 cycle
mar *AR_ZEXP+ ; 1 cycle
xc 1, AGT ; 1 cycle
stl b, *sp(SP_MAX_EXP) ; 1 cycle
banz LOOP,*AR_N- ; 4 cycles
;-------------------------------------------------------------------------
; Return to calling program, place MAX exponent value in accumulator A
;-------------------------------------------------------------------------
DONE:
ld *sp(SP_MAX_EXP), a ; 1 cycle
frame #FSZ ; 1 cycle
POPM ST1
POPM ST0
popm ar7 ; 1 cycle
popm ar1 ; 1 cycle
.if __far_mode
fretd ; 4 cycles
.else
retd ; 3 cycles
.endif
nop
nop
;end of file. please do not remove. it is left here to ensure that no lines of code are removed by any editor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -