1; Delays in CPU clocks, milliseconds, etc. All routines are re-entrant
2; (no global data). No routines touch X or Y during execution.
3; Code generated by macros is relocatable; it contains no JMPs to itself.
4
5zp_byte delay_temp_ ; only written to
6
7; Delays n clocks, from 2 to 16777215
8; Preserved: A, X, Y, flags
9.macro delay n
10    .if (n) < 0 .or (n) = 1 .or (n) > 16777215
11	.error "Delay out of range"
12    .endif
13    delay_ (n)
14.endmacro
15
16
17; Delays n milliseconds (1/1000 second)
18; n can range from 0 to 1100.
19; Preserved: A, X, Y, flags
20.macro delay_msec n
21    .if (n) < 0 .or (n) > 1100
22	.error "time out of range"
23    .endif
24    delay ((n)*CLOCK_RATE+500)/1000
25.endmacro
26
27
28; Delays n microseconds (1/1000000 second).
29; n can range from 0 to 100000.
30; Preserved: A, X, Y, flags
31.macro delay_usec n
32    .if (n) < 0 .or (n) > 100000
33	.error "time out of range"
34    .endif
35    delay ((n)*((CLOCK_RATE+50)/100)+5000)/10000
36.endmacro
37
38.align 64
39
40; Delays A clocks + overhead
41; Preserved: X, Y
42; Time: A+25 clocks (including JSR)
43:       sbc #7          ; carry set by CMP
44delay_a_25_clocks:
45	cmp #7
46	bcs :-          ; do multiples of 7
47	lsr a           ; bit 0
48	bcs :+
49:                       ; A=clocks/2, either 0,1,2,3
50	beq @zero       ; 0: 5
51	lsr a
52	beq :+          ; 1: 7
53	bcc :+          ; 2: 9
54@zero:  bne :+          ; 3: 11
55:       rts             ; (thanks to dclxvi for the algorithm)
56
57
58; Delays A*256 clocks + overhead
59; Preserved: X, Y
60; Time: A*256+16 clocks (including JSR)
61delay_256a_16_clocks:
62	cmp #0
63	bne :+
64	rts
65delay_256a_11_clocks_:
66:       pha
67	lda #256-19-22
68	jsr delay_a_25_clocks
69	pla
70	clc
71	adc #-1
72	bne :-
73	rts
74
75
76; Delays A*65536 clocks + overhead
77; Preserved: X, Y
78; Time: A*65536+16 clocks (including JSR)
79delay_65536a_16_clocks:
80	cmp #0
81	bne :+
82	rts
83delay_65536a_11_clocks_:
84:       pha
85	lda #256-19-22-13
86	jsr delay_a_25_clocks
87	lda #255
88	jsr delay_256a_11_clocks_
89	pla
90	clc
91	adc #-1
92	bne :-
93	rts
94
95max_short_delay = 41
96
97	; delay_short_ macro jumps into these
98	.res (max_short_delay-12)/2,$EA ; NOP
99delay_unrolled_:
100	rts
101
102.macro delay_short_ n
103    .if n < 0 .or n = 1 .or n > max_short_delay
104	.error "Internal delay error"
105    .endif
106    .if n = 0
107    	; nothing
108    .elseif n = 2
109	nop
110    .elseif n = 3
111	sta <delay_temp_
112    .elseif n = 4
113	nop
114	nop
115    .elseif n = 5
116	sta <delay_temp_
117	nop
118    .elseif n = 6
119	nop
120	nop
121	nop
122    .elseif n = 7
123	php
124	plp
125    .elseif n = 8
126	nop
127	nop
128	nop
129	nop
130    .elseif n = 9
131	php
132	plp
133	nop
134    .elseif n = 10
135	sta <delay_temp_
136	php
137	plp
138    .elseif n = 11
139	php
140	plp
141	nop
142	nop
143    .elseif n = 13
144	php
145	plp
146	nop
147	nop
148	nop
149    .elseif n & 1
150	sta <delay_temp_
151	jsr delay_unrolled_-((n-15)/2)
152    .else
153	jsr delay_unrolled_-((n-12)/2)
154    .endif
155.endmacro
156
157.macro delay_nosave_ n
158    ; 65536+17 = maximum delay using delay_256a_11_clocks_
159    ; 255+27   = maximum delay using delay_a_25_clocks
160    ; 27       = minimum delay using delay_a_25_clocks
161    .if n > 65536+17
162	lda #^(n - 15)
163	jsr delay_65536a_11_clocks_
164	; +2 ensures remaining clocks is never 1
165	delay_nosave_ (((n - 15) & $FFFF) + 2)
166    .elseif n > 255+27
167	lda #>(n - 15)
168	jsr delay_256a_11_clocks_
169	; +2 ensures remaining clocks is never 1
170	delay_nosave_ (<(n - 15) + 2)
171    .elseif n >= 27
172	lda #<(n - 27)
173	jsr delay_a_25_clocks
174    .else
175	delay_short_ n
176    .endif
177.endmacro
178
179.macro delay_ n
180    .if n > max_short_delay
181	php
182	pha
183	delay_nosave_ (n - 14)
184	pla
185	plp
186    .else
187	delay_short_ n
188    .endif
189.endmacro
190
191