/
sincos.s
162 lines (122 loc) · 3.87 KB
/
sincos.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
;
; Fixed point cosine/sine functions.
;
; int __fastcall__ _sin (unsigned x);
; int __fastcall__ _cos (unsigned x);
;
; Returns the cosine/sine for the given argument as angular degree.
; Valid argument range is 0..360 for both functions. They will return
; garbage if the argument is not in a valid range. Result is in 8.8 fixed
; point format, so $100 is 1.0 and $FF00 is -1.0.
;
;
; Ullrich von Bassewitz, 2009-10-29
;
.export __cos, __sin
; ---------------------------------------------------------------------------
; Sinus table covering values from 0..86° as 0.8 fixed point values. Values
; for 87..90° are actually 1.0 (= $100), will therefore not fit in the table
; and are covered specially in the code below.
.rodata
_sintab:
.byte $00, $04, $09, $0D, $12, $16, $1B, $1F, $24, $28
.byte $2C, $31, $35, $3A, $3E, $42, $47, $4B, $4F, $53
.byte $58, $5C, $60, $64, $68, $6C, $70, $74, $78, $7C
.byte $80, $84, $88, $8B, $8F, $93, $96, $9A, $9E, $A1
.byte $A5, $A8, $AB, $AF, $B2, $B5, $B8, $BB, $BE, $C1
.byte $C4, $C7, $CA, $CC, $CF, $D2, $D4, $D7, $D9, $DB
.byte $DE, $E0, $E2, $E4, $E6, $E8, $EA, $EC, $ED, $EF
.byte $F1, $F2, $F3, $F5, $F6, $F7, $F8, $F9, $FA, $FB
.byte $FC, $FD, $FE, $FE, $FF, $FF, $FF
; ---------------------------------------------------------------------------
; Cosine function. Is actually implemented as _cos(x) = _sin(x+90)
.code
__cos:
; _cos(x) = _sin(x+90)
clc
adc #90
bcc @L1
inx
; If x is now larger than 360, we need to subtract 360.
@L1: cpx #>360
bne @L2
cmp #<360
@L2: bcc __sin
sbc #<360
bcs @L3
dex
@L3: dex
; ---------------------------------------------------------------------------
; Sine function. Uses
;
; table lookup for 0..89°
; _sin(x) = _sin(180-x) for 90°..179°
; _sin(x) = -_sin(x-180) for 180..360°
;
; Plus special handling for the values missing in the table.
__sin:
; If the high byte is non zero, argument is > 255
cpx #0
bne L3
cmp #180
bcs L4
; 0..179°
cmp #90
bcc L1
; 90..179°. Value is identical to _sin(180-val). Carry is set on entry.
;
; 180-val := -val + 180.
; With
; -val := (val ^ $FF) + 1
; we get
; 180-val = (val ^ $FF) + 1 + 180
; Since carry is set, we can drop the "+ 1".
;
eor #$FF
adc #180 ; 180-val
; 0..89°. Values for 87..90° are actually 1.0. Since this format doesn't fit
; into the table, we have to check for it manually.
L1: cmp #87
bcc L2
; The value is 1.0
ldx #>(1 << 8)
lda #<(1 << 8)
rts
; 0..86°. Read the value from the table.
L2: tay
ldx #0
lda _sintab,y
rts
; 180..360°. _sin(x) = -_sin(x-180). Since the argument is in range 0..180
; after the subtraction, we don't need to handle the high byte.
L3: sec
L4: sbc #180
cmp #90
bcc L5
; 270..360°. Value is identical to -_sin(180-val). Carry is set on entry.
;
; 180-val := -val + 180.
; With
; -val := (val ^ $FF) + 1
; we get
; 180-val = (val ^ $FF) + 1 + 180
; Since carry is set, we can drop the "+ 1".
;
eor #$FF
adc #180 ; 180-val
; 180..269°. Values for 267..269° are actually -1.0. Since this format doesn't
; fit into the table, we have to check for it manually.
L5: ldx #$FF
cmp #87
bcc L6
; The value is -1.0
lda #<(-1 << 8)
rts
; 180..266°. Read the value from the table. Carry is clear on entry.
L6: tay
txa ; A = $FF
eor _sintab,y
adc #1
bcc L7
inx
L7: rts