CPU-Z80-Disassembler
view release on metacpan or search on metacpan
t/data/zx48_benchmark.asm view on Meta::CPAN
PLOT_END:
ld (hl), a ; load byte to the screen.
jp PO_ATTR ; exit to PO-ATTR to set colours for cell.
; ------------------------------
; Put two numbers in BC register
; ------------------------------
;
;
;; STK-TO-BC
STK_TO_BC:
call STK_TO_A ; routine STK-TO-A
ld b, a
push bc
call STK_TO_A ; routine STK-TO-A
ld e, c
pop bc
ld d, c
ld c, a
ret
; -----------------------
; Put stack in A register
; -----------------------
; This routine puts the last value on the calculator stack into the accumulator
; deleting the last value.
;; STK-TO-A
STK_TO_A:
call FP_TO_A ; routine FP-TO-A compresses last value into
; accumulator. e.g. PI would become 3.
; zero flag set if positive.
jp c, REPORT_Bc ; jump forward to REPORT-Bc if >= 255.5.
ld c, $01 ; prepare a positive sign byte.
ret z ; return if FP-TO-BC indicated positive.
ld c, $FF ; prepare negative sign byte and
ret ; return.
; --------------------
; THE 'CIRCLE' COMMAND
; --------------------
; "Goe not Thou about to Square eyther circle" -
; - John Donne, Cambridge educated theologian, 1624
;
; The CIRCLE command draws a circle as a series of straight lines.
; In some ways it can be regarded as a polygon, but the first line is drawn
; as a tangent, taking the radius as its distance from the centre.
;
; Both the CIRCLE algorithm and the ARC drawing algorithm make use of the
; 'ROTATION FORMULA' (see later). It is only necessary to work out where
; the first line will be drawn and how long it is and then the rotation
; formula takes over and calculates all other rotated points.
;
; All Spectrum circles consist of two vertical lines at each side and two
; horizontal lines at the top and bottom. The number of lines is calculated
; from the radius of the circle and is always divisible by 4. For complete
; circles it will range from 4 for a square circle to 32 for a circle of
; radius 87. The Spectrum can attempt larger circles e.g. CIRCLE 0,14,255
; but these will error as they go off-screen after four lines are drawn.
; At the opposite end, CIRCLE 128,88,1.23 will draw a circle as a perfect 3x3
; square using 4 straight lines although very small circles are just drawn as
; a dot on the screen.
;
; The first chord drawn is the vertical chord on the right of the circle.
; The starting point is at the base of this chord which is drawn upwards and
; the circle continues in an anti-clockwise direction. As noted earlier the
; x-coordinate of this point measured from the centre of the circle is the
; radius.
;
; The CIRCLE command makes extensive use of the calculator and as part of
; process of drawing a large circle, free memory is checked 1315 times.
; When drawing a large arc, free memory is checked 928 times.
; A single call to 'sin' involves 63 memory checks and so values of sine
; and cosine are pre-calculated and held in the mem locations. As a
; clever trick 'cos' is derived from 'sin' using simple arithmetic operations
; instead of the more expensive 'cos' function.
;
; Initially, the syntax has been partly checked using the class for the DRAW
; command which stacks the origin of the circle (X,Y).
;; CIRCLE
CIRCLE:
rst $18 ; GET-CHAR x, y.
cp $2C ; Is character the required comma ?
jp nz, REPORT_C ; Jump, if not, to REPORT-C
; 'Nonsense in basic'
rst $20 ; NEXT-CHAR advances the parsed character address.
call EXPT_1NUM ; routine EXPT-1NUM stacks radius in runtime.
call CHECK_END ; routine CHECK-END will return here in runtime
; if nothing follows the command.
; Now make the radius positive and ensure that it is in floating point form
; so that the exponent byte can be accessed for quick testing.
rst $28 ; ; FP-CALC x, y, r.
defb $2A ; ;abs x, y, r.
defb $3D ; ;re-stack x, y, r.
defb $38 ; ;end-calc x, y, r.
ld a, (hl) ; Fetch first, floating-point, exponent byte.
cp $81 ; Compare to one.
jr nc, C_R_GRE_1 ; Forward to C-R-GRE-1
; if circle radius is greater than one.
; The circle is no larger than a single pixel so delete the radius from the
; calculator stack and plot a point at the centre.
rst $28 ; ; FP-CALC x, y, r.
defb $02 ; ;delete x, y.
defb $38 ; ;end-calc x, y.
t/data/zx48_benchmark.asm view on Meta::CPAN
; The ARC will consist of multiple straight lines so call the CIRCLE-DRAW
; PARAMETERS ROUTINE to pre-calculate sine values from the angle (in mem-5)
; and determine also the number of straight lines from that value and the
; 'diameter' which is at the top of the calculator stack.
;; DR-PRMS
DR_PRMS:
call CD_PRMS1 ; routine CD-PRMS1
; mem-0 ; (A)/No. of lines (=a) (step angle)
; mem-1 ; sin(a/2)
; mem-2 ; -
; mem-3 ; cos(a) const
; mem-4 ; sin(a) const
; mem-5 ; Angle of rotation (A) in
; B ; Count of straight lines - max 252.
push bc ; Save the line count on the machine stack.
; Remove the now redundant diameter value D.
rst $28 ; ; FP-CALC x, y, sin(A/2), D.
defb $02 ; ;delete x, y, sin(A/2).
; Dividing the sine of the step angle by the sine of the total angle gives
; the length of the initial chord on a unary circle. This factor f is used
; to scale the coordinates of the first line which still points in the
; direction of the end point and may be larger.
defb $E1 ; ;get-mem-1 x, y, sin(A/2), sin(a/2)
defb $01 ; ;exchange x, y, sin(a/2), sin(A/2)
defb $05 ; ;division x, y, sin(a/2)/sin(A/2)
defb $C1 ; ;st-mem-1 x, y. f.
defb $02 ; ;delete x, y.
; With the factor stored, scale the x coordinate first.
defb $01 ; ;exchange y, x.
defb $31 ; ;duplicate y, x, x.
defb $E1 ; ;get-mem-1 y, x, x, f.
defb $04 ; ;multiply y, x, x*f (=xx)
defb $C2 ; ;st-mem-2 y, x, xx.
defb $02 ; ;delete y. x.
; Now scale the y coordinate.
defb $01 ; ;exchange x, y.
defb $31 ; ;duplicate x, y, y.
defb $E1 ; ;get-mem-1 x, y, y, f
defb $04 ; ;multiply x, y, y*f (=yy)
; Note. 'sin' and 'cos' trash locations mem-0 to mem-2 so fetch mem-2 to the
; calculator stack for safe keeping.
defb $E2 ; ;get-mem-2 x, y, yy, xx.
; Once we get the coordinates of the first straight line then the 'ROTATION
; FORMULA' used in the arc loop will take care of all other points, but we
; now use a variation of that formula to rotate the first arc through (A-a)/2
; radians.
;
; xRotated = y * sin(angle) + x * cos(angle)
; yRotated = y * cos(angle) - x * sin(angle)
;
defb $E5 ; ;get-mem-5 x, y, yy, xx, A.
defb $E0 ; ;get-mem-0 x, y, yy, xx, A, a.
defb $03 ; ;subtract x, y, yy, xx, A-a.
defb $A2 ; ;stk-half x, y, yy, xx, A-a, 1/2.
defb $04 ; ;multiply x, y, yy, xx, (A-a)/2. (=angle)
defb $31 ; ;duplicate x, y, yy, xx, angle, angle.
defb $1F ; ;sin x, y, yy, xx, angle, sin(angle)
defb $C5 ; ;st-mem-5 x, y, yy, xx, angle, sin(angle)
defb $02 ; ;delete x, y, yy, xx, angle
defb $20 ; ;cos x, y, yy, xx, cos(angle).
; Note. mem-0, mem-1 and mem-2 can be used again now...
defb $C0 ; ;st-mem-0 x, y, yy, xx, cos(angle).
defb $02 ; ;delete x, y, yy, xx.
defb $C2 ; ;st-mem-2 x, y, yy, xx.
defb $02 ; ;delete x, y, yy.
defb $C1 ; ;st-mem-1 x, y, yy.
defb $E5 ; ;get-mem-5 x, y, yy, sin(angle)
defb $04 ; ;multiply x, y, yy*sin(angle).
defb $E0 ; ;get-mem-0 x, y, yy*sin(angle), cos(angle)
defb $E2 ; ;get-mem-2 x, y, yy*sin(angle), cos(angle), xx.
defb $04 ; ;multiply x, y, yy*sin(angle), xx*cos(angle).
defb $0F ; ;addition x, y, xRotated.
defb $E1 ; ;get-mem-1 x, y, xRotated, yy.
defb $01 ; ;exchange x, y, yy, xRotated.
defb $C1 ; ;st-mem-1 x, y, yy, xRotated.
defb $02 ; ;delete x, y, yy.
defb $E0 ; ;get-mem-0 x, y, yy, cos(angle).
defb $04 ; ;multiply x, y, yy*cos(angle).
defb $E2 ; ;get-mem-2 x, y, yy*cos(angle), xx.
defb $E5 ; ;get-mem-5 x, y, yy*cos(angle), xx, sin(angle).
defb $04 ; ;multiply x, y, yy*cos(angle), xx*sin(angle).
defb $03 ; ;subtract x, y, yRotated.
defb $C2 ; ;st-mem-2 x, y, yRotated.
; Now the initial x and y coordinates are made positive and summed to see
; if they measure up to anything significant.
defb $2A ; ;abs x, y, yRotated'.
defb $E1 ; ;get-mem-1 x, y, yRotated', xRotated.
defb $2A ; ;abs x, y, yRotated', xRotated'.
defb $0F ; ;addition x, y, yRotated+xRotated.
defb $02 ; ;delete x, y.
defb $38 ; ;end-calc x, y.
; Although the test value has been deleted it is still above the calculator
; stack in memory and conveniently DE which points to the first free byte
; addresses the exponent of the test value.
t/data/zx48_benchmark.asm view on Meta::CPAN
defb $01 ; ;exchange tx, y.
defb $38 ; ;end-calc tx, y.
ld a, (COORDS_hi) ; Fetch System Variable COORDS-y
call STACK_A ; routine STACK-A
rst $28 ; ; FP-CALC tx, y, last-y.
; Store the last point plotted to initialize the moving ay value.
defb $C5 ; ;st-mem-5 tx, y, last-y.
defb $0F ; ;addition tx, ty.
; Fetch the moving ax and ay to the calculator stack.
defb $E0 ; ;get-mem-0 tx, ty, ax.
defb $E5 ; ;get-mem-5 tx, ty, ax, ay.
defb $38 ; ;end-calc tx, ty, ax, ay.
pop bc ; Restore the straight line count.
; -----------------------------------
; THE 'CIRCLE/DRAW CONVERGENCE POINT'
; -----------------------------------
; The CIRCLE and ARC-DRAW commands converge here.
;
; Note. for both the CIRCLE and ARC commands the minimum initial line count
; is 4 (as set up by the CD_PARAMS routine) and so the zero flag will never
; be set and the loop is always entered. The first test is superfluous and
; the jump will always be made to ARC-START.
;; DRW-STEPS
DRW_STEPS:
dec b ; decrement the arc count (4,8,12,16...).
jr z, ARC_END ; forward, if zero (not possible), to ARC-END
jr ARC_START ; forward to ARC-START
; --------------
; THE 'ARC LOOP'
; --------------
;
; The arc drawing loop will draw up to 31 straight lines for a circle and up
; 251 straight lines for an arc between two points. In both cases the final
; closing straight line is drawn at ARC_END, but it otherwise loops back to
; here to calculate the next coordinate using the ROTATION FORMULA where (a)
; is the previously calculated, constant CENTRAL ANGLE of the arcs.
;
; Xrotated = x * cos(a) - y * sin(a)
; Yrotated = x * sin(a) + y * cos(a)
;
; The values cos(a) and sin(a) are pre-calculated and held in mem-3 and mem-4
; for the duration of the routine.
; Memory location mem-1 holds the last relative x value (rx) and mem-2 holds
; the last relative y value (ry) used by DRAW.
;
; Note. that this is a very clever twist on what is after all a very clever,
; well-used formula. Normally the rotation formula is used with the x and y
; coordinates from the centre of the circle (or arc) and a supplied angle to
; produce two new x and y coordinates in an anticlockwise direction on the
; circumference of the circle.
; What is being used here, instead, is the relative X and Y parameters from
; the last point plotted that are required to get to the current point and
; the formula returns the next relative coordinates to use.
;; ARC-LOOP
ARC_LOOP:
rst $28 ; ; FP-CALC
defb $E1 ; ;get-mem-1 rx.
defb $31 ; ;duplicate rx, rx.
defb $E3 ; ;get-mem-3 cos(a)
defb $04 ; ;multiply rx, rx*cos(a).
defb $E2 ; ;get-mem-2 rx, rx*cos(a), ry.
defb $E4 ; ;get-mem-4 rx, rx*cos(a), ry, sin(a).
defb $04 ; ;multiply rx, rx*cos(a), ry*sin(a).
defb $03 ; ;subtract rx, rx*cos(a) - ry*sin(a)
defb $C1 ; ;st-mem-1 rx, new relative x rotated.
defb $02 ; ;delete rx.
defb $E4 ; ;get-mem-4 rx, sin(a).
defb $04 ; ;multiply rx*sin(a)
defb $E2 ; ;get-mem-2 rx*sin(a), ry.
defb $E3 ; ;get-mem-3 rx*sin(a), ry, cos(a).
defb $04 ; ;multiply rx*sin(a), ry*cos(a).
defb $0F ; ;addition rx*sin(a) + ry*cos(a).
defb $C2 ; ;st-mem-2 new relative y rotated.
defb $02 ; ;delete .
defb $38 ; ;end-calc .
; Note. the calculator stack actually holds tx, ty, ax, ay
; and the last absolute values of x and y
; are now brought into play.
;
; Magically, the two new rotated coordinates rx and ry are all that we would
; require to draw a circle or arc - on paper!
; The Spectrum DRAW routine draws to the rounded x and y coordinate and so
; repetitions of values like 3.49 would mean that the fractional parts
; would be lost until eventually the draw coordinates might differ from the
; floating point values used above by several pixels.
; For this reason the accurate offsets calculated above are added to the
; accurate, absolute coordinates maintained in ax and ay and these new
; coordinates have the integer coordinates of the last plot position
; ( from System Variable COORDS ) subtracted from them to give the relative
; coordinates required by the DRAW routine.
; The mid entry point.
;; ARC-START
ARC_START:
push bc ; Preserve the arc counter on the machine stack.
; Store the absolute ay in temporary variable mem-0 for the moment.
rst $28 ; ; FP-CALC ax, ay.
defb $C0 ; ;st-mem-0 ax, ay.
defb $02 ; ;delete ax.
; Now add the fractional relative x coordinate to the fractional absolute
; x coordinate to obtain a new fractional x-coordinate.
defb $E1 ; ;get-mem-1 ax, xr.
defb $0F ; ;addition ax+xr (= new ax).
t/data/zx48_benchmark.asm view on Meta::CPAN
; stored in the 'mem' locations. Some are not relevant for the circle.
;; DRAW-SAVE
DRAW_SAVE:
push af ; Save the line count (A) on the machine stack.
call STACK_A ; Routine STACK-A stacks the modified count(A).
rst $28 ; ; FP-CALC z, A.
defb $E5 ; ;get-mem-5 z, A, ANGLE.
defb $01 ; ;exchange z, ANGLE, A.
defb $05 ; ;division z, ANGLE/A. (Angle/count = a)
defb $31 ; ;duplicate z, a, a.
; Note. that cos (a) could be formed here directly using 'cos' and stored in
; mem-3 but that would spoil a good story and be slightly slower, as also
; would using square roots to form cos (a) from sin (a).
defb $1F ; ;sin z, a, sin(a)
defb $C4 ; ;st-mem-4 z, a, sin(a)
defb $02 ; ;delete z, a.
defb $31 ; ;duplicate z, a, a.
defb $A2 ; ;stk-half z, a, a, 1/2.
defb $04 ; ;multiply z, a, a/2.
defb $1F ; ;sin z, a, sin(a/2).
; Note. after second sin, mem-0 and mem-1 become free.
defb $C1 ; ;st-mem-1 z, a, sin(a/2).
defb $01 ; ;exchange z, sin(a/2), a.
defb $C0 ; ;st-mem-0 z, sin(a/2), a. (for arc only)
; Now form cos(a) from sin(a/2) using the 'DOUBLE ANGLE FORMULA'.
defb $02 ; ;delete z, sin(a/2).
defb $31 ; ;duplicate z, sin(a/2), sin(a/2).
defb $04 ; ;multiply z, sin(a/2)*sin(a/2).
defb $31 ; ;duplicate z, sin(a/2)*sin(a/2),
; ; sin(a/2)*sin(a/2).
defb $0F ; ;addition z, 2*sin(a/2)*sin(a/2).
defb $A1 ; ;stk-one z, 2*sin(a/2)*sin(a/2), 1.
defb $03 ; ;subtract z, 2*sin(a/2)*sin(a/2)-1.
defb $1B ; ;negate z, 1-2*sin(a/2)*sin(a/2).
defb $C3 ; ;st-mem-3 z, cos(a).
defb $02 ; ;delete z.
defb $38 ; ;end-calc z.
; The radius/diameter is left on the calculator stack.
pop bc ; Restore the line count to the B register.
ret ; Return.
; --------------------------
; THE 'DOUBLE ANGLE FORMULA'
; --------------------------
; This formula forms cos(a) from sin(a/2) using simple arithmetic.
;
; THE GEOMETRIC PROOF OF FORMULA cos (a) = 1 - 2 * sin(a/2) * sin(a/2)
;
;
; A
;
; . /|\
; . / | \
; . / | \
; . / |a/2\
; . / | \
; . 1 / | \
; . / | \
; . / | \
; . / | \
; . a/2 D / a E|-+ \
; B ---------------------/----------+-+--------\ C
; <- 1 -><- 1 ->
;
; cos a = 1 - 2 * sin(a/2) * sin(a/2)
;
; The figure shows a right triangle that inscribes a circle of radius 1 with
; centre, or origin, D. Line BC is the diameter of length 2 and A is a point
; on the circle. The periphery angle BAC is therefore a right angle by the
; Rule of Thales.
; Line AC is a chord touching two points on the circle and the angle at the
; centre is (a).
; Since the vertex of the largest triangle B touches the circle, the
; inscribed angle (a/2) is half the central angle (a).
; The cosine of (a) is the length DE as the hypotenuse is of length 1.
; This can also be expressed as 1-length CE. Examining the triangle at the
; right, the top angle is also (a/2) as angle BAE and EBA add to give a right
; angle as do BAE and EAC.
; So cos (a) = 1 - AC * sin(a/2)
; Looking at the largest triangle, side AC can be expressed as
; AC = 2 * sin(a/2) and so combining these we get
; cos (a) = 1 - 2 * sin(a/2) * sin(a/2).
;
; "I will be sufficiently rewarded if when telling it to others, you will
; not claim the discovery as your own, but will say it is mine."
; - Thales, 640 - 546 B.C.
;
; --------------------------
; THE 'LINE DRAWING' ROUTINE
; --------------------------
;
;
;; DRAW-LINE
DRAW_LINE:
call STK_TO_BC ; routine STK-TO-BC
ld a, c
cp b
jr nc, DL_X_GE_Y ; to DL-X-GE-Y
ld l, c
push de
xor a
ld e, a
t/data/zx48_benchmark.asm view on Meta::CPAN
; ---
; ->
;; S-FN
S_FN:
jp S_FN_SBRN ; jump forward to S-FN-SBRN.
; --------------------------------------------------------------------
;
; RANDOM THEORY from the ZX81 manual by Steven Vickers
;
; (same algorithm as the ZX Spectrum).
;
; Chapter 5. Exercise 6. (For mathematicians only.)
;
; Let p be a [large] prime, & let a be a primitive root modulo p.
; Then if b_i is the residue of a^i modulo p (1<=b_i<p-1), the
; sequence
;
; (b_i-1)/(p-1)
;
; is a cyclical sequence of p-1 distinct numbers in the range 0 to 1
; (excluding 1). By choosing a suitably, these can be made to look
; fairly random.
;
; 65537 is a Mersenne prime 2^16-1. Note.
;
; Use this, & Gauss' law of quadratic reciprocity, to show that 75
; is a primitive root modulo 65537.
;
; The ZX81 uses p=65537 & a=75, & stores some b_i-1 in memory.
; The function RND involves replacing b_i-1 in memory by b_(i+1)-1,
; & yielding the result (b_(i+1)-1)/(p-1). RAND n (with 1<=n<=65535)
; makes b_i equal to n+1.
;
; --------------------------------------------------------------------
;
; Steven Vickers writing in comp.sys.sinclair on 20-DEC-1993
;
; Note. (Of course, 65537 is 2^16 + 1, not -1.)
;
; Consider arithmetic modulo a prime p. There are p residue classes, and the
; non-zero ones are all invertible. Hence under multiplication they form a
; group (Fp*, say) of order p-1; moreover (and not so obvious) Fp* is cyclic.
; Its generators are the "primitive roots". The "quadratic residues modulo p"
; are the squares in Fp*, and the "Legendre symbol" (d/p) is defined (when p
; does not divide d) as +1 or -1, according as d is or is not a quadratic
; residue mod p.
;
; In the case when p = 65537, we can show that d is a primitive root if and
; only if it's not a quadratic residue. For let w be a primitive root, d
; congruent to w^r (mod p). If d is not primitive, then its order is a proper
; factor of 65536: hence w^{32768*r} = 1 (mod p), so 65536 divides 32768*r,
; and hence r is even and d is a square (mod p). Conversely, the squares in
; Fp* form a subgroup of (Fp*)^2 of index 2, and so cannot be generators.
;
; Hence to check whether 75 is primitive mod 65537, we want to calculate that
; (75/65537) = -1. There is a multiplicative formula (ab/p) = (a/p)(b/p) (mod
; p), so (75/65537) = (5/65537)^2 * (3/65537) = (3/65537). Now the law of
; quadratic reciprocity says that if p and q are distinct odd primes, then
;
; (p/q)(q/p) = (-1)^{(p-1)(q-1)/4}
;
; Hence (3/65537) = (65537/3) * (-1)^{65536*2/4} = (65537/3)
; = (2/3) (because 65537 = 2 mod 3)
; = -1
;
; (I referred to Pierre Samuel's "Algebraic Theory of Numbers".)
;
; ->
;; S-RND
S_RND:
call SYNTAX_Z ; routine SYNTAX-Z
jr z, S_RND_END ; forward to S-RND-END if checking syntax.
ld bc, (SEED) ; fetch system variable SEED
call STACK_BC ; routine STACK-BC places on calculator stack
rst $28 ; ; FP-CALC ;s.
defb $A1 ; ;stk-one ;s,1.
defb $0F ; ;addition ;s+1.
defb $34 ; ;stk-data ;
defb $37 ; ;Exponent: $87,
; ;Bytes: 1
defb $16 ; ;(+00,+00,+00) ;s+1,75.
defb $04 ; ;multiply ;(s+1)*75 = v
defb $34 ; ;stk-data ;v.
defb $80 ; ;Bytes: 3
defb $41, $00, $00, $80 ; ;Exponent $91
; ;(+00) ;v,65537.
defb $32 ; ;n-mod-m ;remainder, result.
defb $02 ; ;delete ;remainder.
defb $A1 ; ;stk-one ;remainder, 1.
defb $03 ; ;subtract ;remainder - 1. = rnd
defb $31 ; ;duplicate ;rnd,rnd.
defb $38 ; ;end-calc
call FP_TO_BC ; routine FP-TO-BC
ld (SEED), bc ; store in SEED for next starting point.
ld a, (hl) ; fetch exponent
and a ; is it zero ?
jr z, S_RND_END ; forward if so to S-RND-END
sub $10 ; reduce exponent by 2^16
ld (hl), a ; place back
;; S-RND-END
S_RND_END:
jr S_PI_END ; forward to S-PI-END
; ---
; the number PI 3.14159...
t/data/zx48_benchmark.asm view on Meta::CPAN
defb $33 ; ;jump
defb $03 ; ;to L37FA, CASES
;; SMALL
SMALL:
rst $28 ; ; FP-CALC
defb $A0 ; ;stk-zero
;; CASES
CASES:
defb $01 ; ;exchange
defb $31 ; ;duplicate
defb $31 ; ;duplicate
defb $04 ; ;multiply
defb $31 ; ;duplicate
defb $0F ; ;addition
defb $A1 ; ;stk-one
defb $03 ; ;subtract
defb $8C ; ;series-0C
defb $10 ; ;Exponent: $60, Bytes: 1
defb $B2 ; ;(+00,+00,+00)
defb $13 ; ;Exponent: $63, Bytes: 1
defb $0E ; ;(+00,+00,+00)
defb $55 ; ;Exponent: $65, Bytes: 2
defb $E4, $8D ; ;(+00,+00)
defb $58 ; ;Exponent: $68, Bytes: 2
defb $39, $BC ; ;(+00,+00)
defb $5B ; ;Exponent: $6B, Bytes: 2
defb $98, $FD ; ;(+00,+00)
defb $9E ; ;Exponent: $6E, Bytes: 3
defb $00, $36, $75 ; ;(+00)
defb $A0 ; ;Exponent: $70, Bytes: 3
defb $DB, $E8, $B4 ; ;(+00)
defb $63 ; ;Exponent: $73, Bytes: 2
defb $42, $C4 ; ;(+00,+00)
defb $E6 ; ;Exponent: $76, Bytes: 4
defb $B5, $09, $36, $BE ; ;
defb $E9 ; ;Exponent: $79, Bytes: 4
defb $36, $73, $1B, $5D ; ;
defb $EC ; ;Exponent: $7C, Bytes: 4
defb $D8, $DE, $63, $BE ; ;
defb $F0 ; ;Exponent: $80, Bytes: 4
defb $61, $A1, $B3, $0C ; ;
defb $04 ; ;multiply
defb $0F ; ;addition
defb $38 ; ;end-calc
ret ; return.
; ---------------------
; THE 'ARCSIN' FUNCTION
; ---------------------
; (Offset $22: 'asn')
; The inverse sine function with result in radians.
; Derived from arctan function above.
; Error A unless the argument is between -1 and +1 inclusive.
; Uses an adaptation of the formula asn(x) = atn(x/sqr(1-x*x))
;
;
; /|
; / |
; 1/ |x
; /a |
; /----|
; y
;
; e.g. We know the opposite side (x) and hypotenuse (1)
; and we wish to find angle a in radians.
; We can derive length y by Pythagoras and then use ATN instead.
; Since y*y + x*x = 1*1 (Pythagoras Theorem) then
; y=sqr(1-x*x) - no need to multiply 1 by itself.
; So, asn(a) = atn(x/y)
; or more fully,
; asn(a) = atn(x/sqr(1-x*x))
; Close but no cigar.
; While PRINT ATN (x/SQR (1-x*x)) gives the same results as PRINT ASN x,
; it leads to division by zero when x is 1 or -1.
; To overcome this, 1 is added to y giving half the required angle and the
; result is then doubled.
; That is, PRINT ATN (x/(SQR (1-x*x) +1)) *2
;
; GEOMETRIC PROOF.
;
;
; . /|
; . c/ |
; . /1 |x
; . c b /a |
; ---------/----|
; 1 y
;
; By creating an isosceles triangle with two equal sides of 1, angles c and
; c are also equal. If b+c+c = 180 degrees and b+a = 180 degrees then c=a/2.
;
; A value higher than 1 gives the required error as attempting to find the
; square root of a negative number generates an error in Sinclair BASIC.
;; asn
asn:
rst $28 ; ; FP-CALC x.
defb $31 ; ;duplicate x, x.
defb $31 ; ;duplicate x, x, x.
defb $04 ; ;multiply x, x*x.
defb $A1 ; ;stk-one x, x*x, 1.
defb $03 ; ;subtract x, x*x-1.
defb $1B ; ;negate x, 1-x*x.
defb $28 ; ;sqr x, sqr(1-x*x) = y
defb $A1 ; ;stk-one x, y, 1.
defb $0F ; ;addition x, y+1.
defb $05 ; ;division x/y+1.
defb $24 ; ;atn a/2 (half the angle)
defb $31 ; ;duplicate a/2, a/2.
defb $0F ; ;addition a.
defb $38 ; ;end-calc a.
( run in 1.916 second using v1.01-cache-2.11-cpan-39bf76dae61 )