mirror of
https://github.com/HEYAHONG/emu8051.git
synced 2025-05-08 13:43:42 +08:00
Add square root regression test
This commit is contained in:
parent
b470088f1c
commit
e8c456321e
@ -11,9 +11,10 @@ SUFFIXES = .hex .asm .sh
|
||||
ASM_SRC = \
|
||||
add.asm \
|
||||
mul1.asm mul2.asm \
|
||||
div.asm \
|
||||
div.asm div32u.asm \
|
||||
orl.asm anl.asm \
|
||||
mov.asm \
|
||||
sqroot.asm \
|
||||
timer0.asm timer1.asm timer2.asm
|
||||
|
||||
if RUN_TESTS
|
||||
@ -21,9 +22,10 @@ if RUN_TESTS
|
||||
TESTS = \
|
||||
add.sh \
|
||||
mul1.sh mul2.sh \
|
||||
div.sh \
|
||||
div.sh div32u.sh \
|
||||
orl.sh anl.sh \
|
||||
mov.sh \
|
||||
sqroot.sh \
|
||||
timer0.sh timer1.sh timer2.sh
|
||||
|
||||
# Tell make how to generate a .sh file after a .hex file is generated:
|
||||
|
250
tests/div32u.asm
Normal file
250
tests/div32u.asm
Normal file
@ -0,0 +1,250 @@
|
||||
; Test program to verify correct emu8051 operation
|
||||
; Taken from http://www.vzsite.us/8051/
|
||||
;
|
||||
; Test desc: 32-bit division
|
||||
; Test output: PC = $FFF0
|
||||
; Test output: SP = $60
|
||||
; Test output: R0 = $E6
|
||||
; Test output: R1 = $55
|
||||
; Test output: R2 = $00
|
||||
; Test output: R3 = $00
|
||||
; Test output: R4 = $20
|
||||
; Test output: R5 = $1B
|
||||
; Test output: PSW = $05
|
||||
|
||||
;26 Oct 00 added code to zero remainder when dividend is zero
|
||||
;19 Dec 99 corrected comments, removed unnecessary instruction
|
||||
;16 May 99 8051 source code
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
;DIV32U is called to divide (unsigned) a 32-bit dividend using a
|
||||
; 16-bit divisor.
|
||||
;
|
||||
;DIV32U solves for quotient and remainder the equation:
|
||||
;
|
||||
; dividend = divisor*quotient + remainder
|
||||
;
|
||||
;Call:
|
||||
; r7,r6,r5,r4 = dividend
|
||||
; r1,r0 = divisor
|
||||
; lcall DIV32U
|
||||
;
|
||||
;Return:
|
||||
; r5,r4 = quotient
|
||||
; r7,r6 = remainder
|
||||
; c flag set to 1 if overflow occured
|
||||
; All registers, acc, b and two caller-assigned direct memory bytes
|
||||
; (q0 and q1)have been changed.
|
||||
; Data pointer has not been disturbed
|
||||
;
|
||||
;Note:
|
||||
; (1)Overflow is a divide by zero or any value that will cause
|
||||
; the quotient to be greater than 16 bits.
|
||||
; (2)Most significant (ms) register always listed first when comma separates
|
||||
; two in a comment. Example: r3,r2 (r3 contains the ms bits)
|
||||
; (3) The algorithm used in this code borrows heavily from work posted
|
||||
; by John C. Wren who said he got it from a C complier.
|
||||
;
|
||||
;Original author: John Veazey, Ridgecrest, CA, 18 APR 99
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
q0 EQU 70h
|
||||
q1 EQU 71h
|
||||
TOS EQU 60h ; Adresse du dessus de la pile.
|
||||
|
||||
ORG 0000h ; Reset vector
|
||||
MOV SP,#TOS ; Init stack pointer
|
||||
|
||||
;; Set dividend
|
||||
MOV R7,#012h
|
||||
MOV R6,#034h
|
||||
MOV R5,#056h
|
||||
MOV R4,#078h
|
||||
|
||||
;; Set divisor
|
||||
MOV R1,#0ABh
|
||||
MOV R0,#0CDh
|
||||
|
||||
LCALL DIV32U
|
||||
LJMP 0FFF0h
|
||||
|
||||
DIV32U:
|
||||
;
|
||||
;Clear the working quotient
|
||||
;
|
||||
clr a
|
||||
mov q1,a
|
||||
mov q0,a
|
||||
;
|
||||
;Clear the msb's of a 32-bit working divisor (r3,r2,r1,r0)
|
||||
;
|
||||
mov r3,a
|
||||
mov r2,a
|
||||
;
|
||||
;b counts the number of places+1 the divisor was initially
|
||||
; shifted left to align its ms bit set with the ms bit set
|
||||
; in the dividend
|
||||
;
|
||||
mov b,#1
|
||||
;
|
||||
;Make an error return if trying to divide by zero
|
||||
;
|
||||
mov a,r1
|
||||
orl a,r0
|
||||
jnz du100
|
||||
ljmp du920 ;Make the error return
|
||||
;
|
||||
;Just return with quotient and remainder zero if dividend is zero
|
||||
;
|
||||
du100:
|
||||
mov a,r7
|
||||
orl a,r6
|
||||
orl a,r5
|
||||
orl a,r4
|
||||
jnz du200
|
||||
mov r7,a
|
||||
mov r6,a
|
||||
ljmp du910 ;Make a normal return
|
||||
;
|
||||
;Align the msb set in the demoninator with the msb set in the
|
||||
; numerator. Increment the shift count in b each time a shift left
|
||||
; is performed.
|
||||
;
|
||||
du200:
|
||||
mov a,r3 ;Stop if msb set
|
||||
clr c
|
||||
rlc a
|
||||
jc du600
|
||||
subb a,r7 ;Compare r3 & r7, (c clear)
|
||||
jz du210 ; jump if r3=r7
|
||||
jnc du600 ; jump if r3>r7
|
||||
sjmp du240 ; r3<r7
|
||||
du210:
|
||||
mov a,r6 ;r3=r7, so compare r2 & r6
|
||||
subb a,r2
|
||||
jc du600 ; jump if r2>r6
|
||||
jnz du240 ; jump if r2<r6
|
||||
mov a,r5 ;r2=r6, so compare r1 & r5
|
||||
subb a,r1
|
||||
jc du600 ; jump if r1>r5
|
||||
jnz du240 ; jump if r1<r5
|
||||
mov a,r4 ;r1=r5, so compare r0 & r4
|
||||
subb a,r0
|
||||
jc du600 ; jump if r0>r4
|
||||
du240:
|
||||
clr c ;Now shift the denominator
|
||||
mov a,r0 ; left 1 bit position
|
||||
rlc a
|
||||
mov r0,a
|
||||
mov a,r1
|
||||
rlc a
|
||||
mov r1,a
|
||||
mov a,r2
|
||||
rlc a
|
||||
mov r2,a
|
||||
mov a,r3
|
||||
rlc a
|
||||
mov r3,a
|
||||
inc b ;Increment b counter and
|
||||
sjmp du200 ; continue
|
||||
;
|
||||
;Compare the shifted divisor with the remainder (what's
|
||||
; left of the dividend)
|
||||
;
|
||||
du600:
|
||||
mov a,r7
|
||||
clr c
|
||||
subb a,r3
|
||||
jc du720 ;jump if r3>r7
|
||||
jnz du700 ;jump if r3<r7
|
||||
mov a,r6
|
||||
subb a,r2
|
||||
jc du720 ;jump if r2>r6
|
||||
jnz du700 ;jump if r2<r6
|
||||
mov a,r5
|
||||
subb a,r1
|
||||
jc du720 ;jump if r1>r5
|
||||
jnz du700 ;jump if r1<r5
|
||||
mov a,r4
|
||||
subb a,r0
|
||||
jc du720 ;jump if r0>r4
|
||||
;
|
||||
;Divisor is equal or smaller, so subtract it off and
|
||||
; get a 1 for the quotient
|
||||
;
|
||||
du700:
|
||||
mov a,r4
|
||||
clr c
|
||||
subb a,r0
|
||||
mov r4,a
|
||||
mov a,r5
|
||||
subb a,r1
|
||||
mov r5,a
|
||||
mov a,r6
|
||||
subb a,r2
|
||||
mov r6,a
|
||||
mov a,r7
|
||||
subb a,r3
|
||||
mov r7,a
|
||||
clr c
|
||||
cpl c ;Get a 1 for the quotient
|
||||
sjmp du730
|
||||
;
|
||||
;Divisor is greater, get a 0 for the quotient
|
||||
;
|
||||
du720:
|
||||
clr c
|
||||
;
|
||||
;Shift 0 or 1 into quotient
|
||||
;
|
||||
du730:
|
||||
mov a,q0
|
||||
rlc a
|
||||
mov q0,a
|
||||
mov a,q1
|
||||
rlc a
|
||||
mov q1,a
|
||||
jc du920 ;overflow - make the error return
|
||||
;
|
||||
;Now shift the denominator right 1, decrement the counter
|
||||
; in b until b = 0
|
||||
;
|
||||
du740:
|
||||
clr c
|
||||
mov a,r3
|
||||
rrc a
|
||||
mov r3,a
|
||||
mov a,r2
|
||||
rrc a
|
||||
mov r2,a
|
||||
mov a,r1
|
||||
rrc a
|
||||
mov r1,a
|
||||
mov a,r0
|
||||
rrc a
|
||||
mov r0,a
|
||||
djnz b,du600
|
||||
;
|
||||
;Move quotient and remainder
|
||||
;
|
||||
mov a,r5
|
||||
mov r7,a
|
||||
mov a,r4
|
||||
mov r6,a
|
||||
mov a,q1
|
||||
mov r5,a
|
||||
mov a,q0
|
||||
mov r4,a
|
||||
;
|
||||
;Make the normal return
|
||||
;
|
||||
du910:
|
||||
clr c
|
||||
ret
|
||||
;
|
||||
;Make the error return
|
||||
;
|
||||
du920:
|
||||
clr c
|
||||
cpl c
|
||||
ret
|
374
tests/sqroot.asm
Normal file
374
tests/sqroot.asm
Normal file
@ -0,0 +1,374 @@
|
||||
; Test program to verify correct emu8051 operation
|
||||
; Taken from http://www.vzsite.us/8051/
|
||||
;
|
||||
; Test desc: 32-bit division
|
||||
; Test output: PC = $FFF0
|
||||
; Test output: SP = $30
|
||||
; Test output: PSW = $04
|
||||
; Test output: A = $44
|
||||
; Test output: B = $44
|
||||
|
||||
;17 Jan 00 re-written for consistency with assembler/compiler byte order
|
||||
;21 May 99 8051 source code
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
;SQROOT1 is called to calculate the square root of a 32-bit number.
|
||||
;
|
||||
;Call:
|
||||
;
|
||||
; r0 => MSB of 32-bit input
|
||||
; lcall SQROOT1
|
||||
;
|
||||
;Return:
|
||||
;
|
||||
; computed square root is in acc(LSB's) and b(MSB's)
|
||||
; (root is also in est(MSB's) and est+1(LSB's))
|
||||
;
|
||||
;SQROOT1 uses the formula
|
||||
;
|
||||
; estimate = (last_estimate + input/last_estimate)/2
|
||||
;
|
||||
;Method is described as Newton's, Newton-Raphson, and Babylonian method.
|
||||
;DIV32U is called to do the 32/16-bit division.
|
||||
;SQROOT1 perfoms a fixed number of iterations to converge to the root.
|
||||
;
|
||||
;SQROOT1 will destroy all registers except r0, dptr.
|
||||
;
|
||||
;Original Author: John Veazey, Ridgecrest, CA, 18 Apr 99
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
q0 EQU 70h
|
||||
q1 EQU 71h
|
||||
est EQU 72h ; 2 bytes: The estimated value being developed
|
||||
sqrcnt EQU 74h ; Counts iterations
|
||||
square EQU 75h
|
||||
TOS EQU 30h ; Adresse du dessus de la pile.
|
||||
|
||||
ORG 0000h ; Reset vector
|
||||
MOV SP,#TOS ; Init stack pointer
|
||||
|
||||
;; Set 32-bit input value
|
||||
MOV square+0,#012h
|
||||
MOV square+1,#034h
|
||||
MOV square+2,#032h
|
||||
MOV square+3,#010h
|
||||
|
||||
;; Set pointer to square
|
||||
mov r0,#square
|
||||
|
||||
LCALL SQROOT
|
||||
LJMP 0FFF0h
|
||||
|
||||
SQROOT:
|
||||
;
|
||||
;Save r0 on the stack
|
||||
;
|
||||
mov a,r0
|
||||
push acc
|
||||
;
|
||||
;Initialize the iteration counter
|
||||
;
|
||||
mov sqrcnt,#7 ;There will be seven calculations
|
||||
;
|
||||
;Find the MSB set in input, call it n as in 2**n. Calculate
|
||||
; r = ceiling(n+1)/2, then set up the first estimate to
|
||||
; be (2**r)-1.
|
||||
;
|
||||
mov a,@r0 ;Is MS byte of input not-zero?
|
||||
jz sqr112
|
||||
mov r1,#33 ; Yes, set r1 to the bit number+2
|
||||
sjmp sqr140
|
||||
sqr112:
|
||||
inc r0 ; No,
|
||||
mov a,@r0 ;Is 2nd MS byte of input not-zero?
|
||||
jz sqr114
|
||||
mov r1,#25 ; Yes
|
||||
sjmp sqr140
|
||||
sqr114:
|
||||
inc r0
|
||||
mov a,@r0 ;Is 3rd MS byte of input not-zero?
|
||||
jz sqr116
|
||||
mov r1,#17 ; Yes
|
||||
sjmp sqr140
|
||||
sqr116:
|
||||
inc r0
|
||||
mov est,#0
|
||||
mov a,@r0 ;Is LS byte of input zero?
|
||||
jnz sqr122
|
||||
mov est+1,#0 ; Yes, return with a zero
|
||||
ljmp sqr900 ; because input is zero
|
||||
sqr122:
|
||||
mov est+1,#1
|
||||
dec a ;Is LS byte of input = 1?
|
||||
jz sqr900 ; Yes, return with a one
|
||||
inc a ; No
|
||||
mov r1,#9
|
||||
sqr140:
|
||||
dec r1
|
||||
rlc a
|
||||
jnc sqr140
|
||||
mov a,r1 ;Form ceiling[(n+1)/2]
|
||||
clr c
|
||||
rrc a ; (divide by 2, add remainder)
|
||||
jnc sqr142
|
||||
inc a
|
||||
sqr142:
|
||||
mov r1,a
|
||||
clr a
|
||||
mov est,a
|
||||
sqr144:
|
||||
setb c ;Get the 1 to shift in
|
||||
rlc a
|
||||
mov b,a
|
||||
mov a,est
|
||||
rlc a
|
||||
mov est,a
|
||||
mov a,b
|
||||
dec r1
|
||||
cjne r1,#0,sqr144
|
||||
mov est+1,a
|
||||
;
|
||||
;Load input into DIV32U dividend register
|
||||
;
|
||||
sqr200:
|
||||
pop acc
|
||||
push acc
|
||||
mov r0,a
|
||||
mov a,@r0 ;Set MSB's
|
||||
mov r7,a
|
||||
inc r0
|
||||
mov a,@r0
|
||||
mov r6,a
|
||||
inc r0
|
||||
mov a,@r0
|
||||
mov r5,a
|
||||
inc r0
|
||||
mov a,@r0
|
||||
mov r4,a
|
||||
;
|
||||
;Load last estimate into DIV32U divisor registers
|
||||
;
|
||||
mov a,est+1 ;Set LSB's
|
||||
mov r0,a
|
||||
mov a,est ;Set MSB's
|
||||
mov r1,a
|
||||
;
|
||||
;Call DIV32U to do the 32/16-bit division (input/est)
|
||||
;
|
||||
lcall DIV32U ;(r7,r6,r5,r4)/(r1,r0) = (r5,r4)
|
||||
jnc sqr310 ;If overflow, set to maximum number
|
||||
mov r4,#-1
|
||||
mov r5,#-1
|
||||
;
|
||||
;Add the last estimate to the quotient
|
||||
;
|
||||
sqr310:
|
||||
mov a,r4
|
||||
add a,est+1 ;sets c
|
||||
mov est+1,a
|
||||
mov a,est
|
||||
addc a,r5 ;sets c
|
||||
;
|
||||
;Divide sum by 2 and save as new estimate
|
||||
;
|
||||
rrc a ;sets c
|
||||
mov est,a
|
||||
mov a,est+1
|
||||
rrc a ;c discarded
|
||||
mov est+1,a
|
||||
;
|
||||
;Decrement the iteration counter and repeat if not zero
|
||||
;
|
||||
djnz sqrcnt,sqr200
|
||||
;
|
||||
;Make the normal return
|
||||
;
|
||||
sqr900:
|
||||
pop acc ;Restore caller's pointer
|
||||
mov r0,a
|
||||
mov b,est ;Get answer in (b,a)
|
||||
mov a,est+1
|
||||
ret
|
||||
|
||||
|
||||
DIV32U:
|
||||
;
|
||||
;Clear the working quotient
|
||||
;
|
||||
clr a
|
||||
mov q1,a
|
||||
mov q0,a
|
||||
;
|
||||
;Clear the msb's of a 32-bit working divisor (r3,r2,r1,r0)
|
||||
;
|
||||
mov r3,a
|
||||
mov r2,a
|
||||
;
|
||||
;b counts the number of places+1 the divisor was initially
|
||||
; shifted left to align its ms bit set with the ms bit set
|
||||
; in the dividend
|
||||
;
|
||||
mov b,#1
|
||||
;
|
||||
;Make an error return if trying to divide by zero
|
||||
;
|
||||
mov a,r1
|
||||
orl a,r0
|
||||
jnz du100
|
||||
ljmp du920 ;Make the error return
|
||||
;
|
||||
;Just return with quotient and remainder zero if dividend is zero
|
||||
;
|
||||
du100:
|
||||
mov a,r7
|
||||
orl a,r6
|
||||
orl a,r5
|
||||
orl a,r4
|
||||
jnz du200
|
||||
mov r7,a
|
||||
mov r6,a
|
||||
ljmp du910 ;Make a normal return
|
||||
;
|
||||
;Align the msb set in the demoninator with the msb set in the
|
||||
; numerator. Increment the shift count in b each time a shift left
|
||||
; is performed.
|
||||
;
|
||||
du200:
|
||||
mov a,r3 ;Stop if msb set
|
||||
clr c
|
||||
rlc a
|
||||
jc du600
|
||||
subb a,r7 ;Compare r3 & r7, (c clear)
|
||||
jz du210 ; jump if r3=r7
|
||||
jnc du600 ; jump if r3>r7
|
||||
sjmp du240 ; r3<r7
|
||||
du210:
|
||||
mov a,r6 ;r3=r7, so compare r2 & r6
|
||||
subb a,r2
|
||||
jc du600 ; jump if r2>r6
|
||||
jnz du240 ; jump if r2<r6
|
||||
mov a,r5 ;r2=r6, so compare r1 & r5
|
||||
subb a,r1
|
||||
jc du600 ; jump if r1>r5
|
||||
jnz du240 ; jump if r1<r5
|
||||
mov a,r4 ;r1=r5, so compare r0 & r4
|
||||
subb a,r0
|
||||
jc du600 ; jump if r0>r4
|
||||
du240:
|
||||
clr c ;Now shift the denominator
|
||||
mov a,r0 ; left 1 bit position
|
||||
rlc a
|
||||
mov r0,a
|
||||
mov a,r1
|
||||
rlc a
|
||||
mov r1,a
|
||||
mov a,r2
|
||||
rlc a
|
||||
mov r2,a
|
||||
mov a,r3
|
||||
rlc a
|
||||
mov r3,a
|
||||
inc b ;Increment b counter and
|
||||
sjmp du200 ; continue
|
||||
;
|
||||
;Compare the shifted divisor with the remainder (what's
|
||||
; left of the dividend)
|
||||
;
|
||||
du600:
|
||||
mov a,r7
|
||||
clr c
|
||||
subb a,r3
|
||||
jc du720 ;jump if r3>r7
|
||||
jnz du700 ;jump if r3<r7
|
||||
mov a,r6
|
||||
subb a,r2
|
||||
jc du720 ;jump if r2>r6
|
||||
jnz du700 ;jump if r2<r6
|
||||
mov a,r5
|
||||
subb a,r1
|
||||
jc du720 ;jump if r1>r5
|
||||
jnz du700 ;jump if r1<r5
|
||||
mov a,r4
|
||||
subb a,r0
|
||||
jc du720 ;jump if r0>r4
|
||||
;
|
||||
;Divisor is equal or smaller, so subtract it off and
|
||||
; get a 1 for the quotient
|
||||
;
|
||||
du700:
|
||||
mov a,r4
|
||||
clr c
|
||||
subb a,r0
|
||||
mov r4,a
|
||||
mov a,r5
|
||||
subb a,r1
|
||||
mov r5,a
|
||||
mov a,r6
|
||||
subb a,r2
|
||||
mov r6,a
|
||||
mov a,r7
|
||||
subb a,r3
|
||||
mov r7,a
|
||||
clr c
|
||||
cpl c ;Get a 1 for the quotient
|
||||
sjmp du730
|
||||
;
|
||||
;Divisor is greater, get a 0 for the quotient
|
||||
;
|
||||
du720:
|
||||
clr c
|
||||
;
|
||||
;Shift 0 or 1 into quotient
|
||||
;
|
||||
du730:
|
||||
mov a,q0
|
||||
rlc a
|
||||
mov q0,a
|
||||
mov a,q1
|
||||
rlc a
|
||||
mov q1,a
|
||||
jc du920 ;overflow - make the error return
|
||||
;
|
||||
;Now shift the denominator right 1, decrement the counter
|
||||
; in b until b = 0
|
||||
;
|
||||
du740:
|
||||
clr c
|
||||
mov a,r3
|
||||
rrc a
|
||||
mov r3,a
|
||||
mov a,r2
|
||||
rrc a
|
||||
mov r2,a
|
||||
mov a,r1
|
||||
rrc a
|
||||
mov r1,a
|
||||
mov a,r0
|
||||
rrc a
|
||||
mov r0,a
|
||||
djnz b,du600
|
||||
;
|
||||
;Move quotient and remainder
|
||||
;
|
||||
mov a,r5
|
||||
mov r7,a
|
||||
mov a,r4
|
||||
mov r6,a
|
||||
mov a,q1
|
||||
mov r5,a
|
||||
mov a,q0
|
||||
mov r4,a
|
||||
;
|
||||
;Make the normal return
|
||||
;
|
||||
du910:
|
||||
clr c
|
||||
ret
|
||||
;
|
||||
;Make the error return
|
||||
;
|
||||
du920:
|
||||
clr c
|
||||
cpl c
|
||||
ret
|
||||
|
Loading…
x
Reference in New Issue
Block a user