CPU-Z80-Disassembler
view release on metacpan or search on metacpan
t/data/zx48.asm view on Meta::CPAN
;; PL-TST-IN
L22FD: BIT 2,C ; is it inverse 1 ?
JR NZ,L2303 ; to PLOT-END if so.
XOR B ; switch the pixel
CPL ; restore other 7 bits
;; PLOT-END
L2303: LD (HL),A ; load byte to the screen.
JP L0BDB ; exit to PO-ATTR to set colours for cell.
; ------------------------------
; Put two numbers in BC register
; ------------------------------
;
;
;; STK-TO-BC
L2307: CALL L2314 ; routine STK-TO-A
LD B,A ;
PUSH BC ;
CALL L2314 ; 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
L2314: CALL L2DD5 ; routine FP-TO-A compresses last value into
; accumulator. e.g. PI would become 3.
; zero flag set if positive.
JP C,L24F9 ; 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
L2320: RST 18H ; GET-CHAR x, y.
CP $2C ; Is character the required comma ?
JP NZ,L1C8A ; Jump, if not, to REPORT-C
; 'Nonsense in basic'
RST 20H ; NEXT-CHAR advances the parsed character address.
CALL L1C82 ; routine EXPT-1NUM stacks radius in runtime.
CALL L1BEE ; 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 28H ;; 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,L233B ; 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 28H ;; FP-CALC x, y, r.
DEFB $02 ;;delete x, y.
DEFB $38 ;;end-calc x, y.
JR L22DC ; back to PLOT routine to just plot x,y.
t/data/zx48.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
L23C1: CALL L247D ; 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 28H ;; 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.asm view on Meta::CPAN
DEFB $C0 ;;st-mem-0 y, x, last-x.
DEFB $0F ;;addition y, absolute x.
DEFB $01 ;;exchange tx, y.
DEFB $38 ;;end-calc tx, y.
LD A,($5C7E) ; Fetch System Variable COORDS-y
CALL L2D28 ; routine STACK-A
RST 28H ;; 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
L2420: DEC B ; decrement the arc count (4,8,12,16...).
JR Z,L245F ; forward, if zero (not possible), to ARC-END
JR L2439 ; 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
L2425: RST 28H ;; 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
L2439: PUSH BC ; Preserve the arc counter on the machine stack.
; Store the absolute ay in temporary variable mem-0 for the moment.
RST 28H ;; 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).
DEFB $31 ;;duplicate ax, ax.
DEFB $38 ;;end-calc ax, ax.
LD A,($5C7D) ; COORDS-x last x (integer ix 0-255)
t/data/zx48.asm view on Meta::CPAN
; For both arcs and circles, constants derived from the central angle are
; stored in the 'mem' locations. Some are not relevant for the circle.
;; DRAW-SAVE
L2497: PUSH AF ; Save the line count (A) on the machine stack.
CALL L2D28 ; Routine STACK-A stacks the modified count(A).
RST 28H ;; 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
L24B7: CALL L2307 ; routine STK-TO-BC
LD A,C ;
CP B ;
JR NC,L24C4 ; to DL-X-GE-Y
LD L,C ;
PUSH DE ;
XOR A ;
LD E,A ;
JR L24CB ; to DL-LARGER
t/data/zx48.asm view on Meta::CPAN
RST 20H ; NEXT-CHAR
JP L2712 ; jump forward to S-CONT-2 ===>
; ---
; ->
;; S-FN
L25F5: JP L27BD ; 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
L25F8: CALL L2530 ; routine SYNTAX-Z
JR Z,L2625 ; forward to S-RND-END if checking syntax.
LD BC,($5C76) ; fetch system variable SEED
CALL L2D2B ; routine STACK-BC places on calculator stack
RST 28H ;; 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 ;;Exponent $91
DEFB $00,$00,$80 ;;(+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 L2DA2 ; routine FP-TO-BC
LD ($5C76),BC ; store in SEED for next starting point.
LD A,(HL) ; fetch exponent
AND A ; is it zero ?
JR Z,L2625 ; forward if so to S-RND-END
SUB $10 ; reduce exponent by 2^16
LD (HL),A ; place back
;; S-RND-END
L2625: JR L2630 ; forward to S-PI-END
; ---
; the number PI 3.14159...
; ->
;; S-PI
L2627: CALL L2530 ; routine SYNTAX-Z
JR Z,L2630 ; to S-PI-END if checking syntax.
t/data/zx48.asm view on Meta::CPAN
DEFB $01 ;;exchange
DEFB $00 ;;jump-true
DEFB $06 ;;to L37FA, CASES
DEFB $1B ;;negate
DEFB $33 ;;jump
DEFB $03 ;;to L37FA, CASES
;; SMALL
L37F8: RST 28H ;; FP-CALC
DEFB $A0 ;;stk-zero
;; CASES
L37FA: 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
L3833: RST 28H ;; 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.
RET ; return.
( run in 1.921 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )