second test pcint0 implementation
[Chiptunes.git] / foo.S
1 /* REGISTER NAMES */
2 #define acc r16
3 #define i0 r17
4 #define i1 r18
5 #define i2 r19
6 #define i3 r20
7 #define n r21
8 #define s r22
9 #define t r23 //==Ml
10 #define x r24 //==a1==Mh
11 #define _ r25 //==a2
12 #define Xlo r26
13 #define Xhi r27
14 #define one r28
15 ; r29
16 ; r30 Zlo
17 ; r31 Zhi
18 ; aliases:
19 #define Ml t //mod3 vars
20 #define Mh x // -"-
21 #define a1 x //mul_ vars
22 #define a2 _ // -"-
23
24 /* I/O REGISTERS */
25 OCR0AL = 0x26
26 DDRB = 0x01
27 PORTB = 0x02
28 PUEB = 0x03
29 SPL = 0x3D
30 SPH = 0x3E
31 CCP = 0x3C
32 CLKPSR = 0x36
33 OSCCAL = 0x39
34 WDTCSR = 0x31
35 SMCR = 0x3A
36 TCCR0A = 0x2E
37 TCCR0B = 0x2D
38 TIMSK0 = 0x2B
39 TIFR0 = 0x2A
40 PCMSK = 0x10
41 PCIFR = 0x11
42 PCICR = 0x12
43 PRR = 0x35
44 RAMEND = 0x5F
45 FLASHM = 0x4000
46
47 .section .text
48 .org 0x0000 ; RESET interrupt
49 CLR i0
50 RJMP main
51 .org 0x0004 ; PCINT0 interrupt
52 CBI PCICR, 0 ; disable interrupt
53 RJMP wakeup
54 .org 0x0008 ; TIM0_OVF interrupt
55 RJMP sample
56
57 notes:
58 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
59 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
60
61 mod3: ; mod3(Mh.Ml) -> t
62 #define tmp _
63 ADD Ml, Mh
64 CLR Mh
65 ADC Mh, Mh ; store carry in Mh
66 MOV tmp, Ml
67 SWAP tmp
68 ANDI tmp, 0x0f
69 SWAP Mh
70 OR tmp, Mh
71 ANDI Ml, 0x0f
72 ADD Ml, tmp
73 MOV tmp, Ml
74 LSR tmp
75 LSR tmp
76 ANDI Ml, 0x03
77 ADD Ml, tmp
78 MOV tmp, Ml
79 LSR tmp
80 LSR tmp
81 ANDI Ml, 0x03
82 ADD Ml, tmp
83 CPI Ml, 3
84 BRCS skip
85 SUBI Ml, 3
86 skip:
87 RET
88 #undef tmp
89
90 g: ; g(i, t) -> t
91 CLR a1
92
93 #define tmp _
94 #define zero a1
95 ANDI t, 0x07
96 MOV tmp, i2
97 ANDI tmp, 3
98 CPSE tmp, zero
99 SUBI t, -8
100 #undef zero
101 #undef tmp
102
103 LDI Xlo, lo8(notes)
104 ADD Xlo, t ; NOTE: notes are positioned so that hi8(notes) never changes
105 LD t, X
106
107 CLR a2
108
109 ; begin of mulitiplication:
110 LSR t
111 BRCC skip1
112 ADD a1, i0
113 ADC a2, i1
114 skip1:
115 LSR a2
116 ROR a1
117 LSR t
118 ; BRCC skip2 -- this bit is always zero
119 ; ADD a1, i0
120 ; ADC a2, i1
121 ;skip2:
122 LSR a2
123 ROR a1
124 LSR t
125 BRCC skip3
126 ADD a1, i0
127 ADC a2, i1
128 skip3:
129 LSR a2
130 ROR a1
131 LSR t
132 BRCC skip4
133 ADD a1, i0
134 ADC a2, i1
135 skip4:
136 LSR a2
137 ROR a1
138 LSR t
139 BRCC skip5
140 ADD a1, i0
141 ADC a2, i1
142 skip5:
143 LSR a2
144 ROR a1
145 LSR t
146 BRCC skip6 ;sbrc t, NNN
147 ADD a1, i0
148 skip6:
149 LSR a1
150 LSR t
151 BRCC skip7
152 ADD a1, i0
153 skip7:
154 LSR a1
155 LSR t
156 BRCC skip8
157 ADD a1, i0
158 skip8:
159 LSR a1
160
161 MOV t, a1 ;;TODO: use a1 in loop: directly
162 RET
163
164 main: ; setup routine
165 ; NOTE: clr i0 moved to .ord 0x0
166 CLR i1
167 CLR i2
168 CLR i3
169 CLR acc ; we output a dummy sample before the actual first one
170 LDI Xhi, hi8(FLASHM + notes) ; never changes
171 LDI one, 1 ; mostly for clearing TIM0_OVF bit
172
173 #define zero i0
174 LDI x, RAMEND
175 OUT SPL, x ; init stack ptr
176 OUT SPH, zero ; -"-
177 OUT PUEB, zero ; disable pullups
178 LDI x, 0x05
179 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
180 LDI x, 0xd8
181 OUT CCP, x ; change protected ioregs
182 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
183 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
184 OUT OSCCAL, x ; set oscillator calibration
185 OUT WDTCSR, zero; turn off watchdog
186
187 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
188 LDI x, 0x81
189 OUT TCCR0A, x
190 LDI x, 0x09
191 OUT TCCR0B, x
192 OUT TIMSK0, one ; enable tim0_ovf
193 SEI
194 #undef zero
195
196 loop:
197 CPI i2, 0x78>>5 ; 16m23 -- one loop
198 ;TODO^: s/>>5//
199 BREQ halt
200
201 SLEEP ; wait for interrupt -- XXX: does not work, since we forgot to set sleep_enable bit!
202 RJMP loop
203
204 halt:
205 CLR i2 ; clear halt condition
206
207 #define zero i2
208 ; disable periphials (timer0), then set all pins as input+pullup to conserve battery.
209 LDI x, 0x3 ; could use one-register to save on ROM (would keep adc enabled on attiny5/10)
210 OUT PRR, x
211 OUT DDRB, zero
212 LDI x, 0x0f
213 OUT PUEB, x
214
215 SBI PCMSK, 2 ; listen for pin change on the audio out pin (i.e. wake up when a audio sink is connected)
216 ;TODO^: s/2/0/
217 SBI PCICR, 0 ; enable PCINT0
218
219 ;enter power-down-mode
220 LDI x, 0x05 ; sleep mode: power-down, enabled
221 OUT SMCR, x
222 SLEEP
223 OUT SMCR, one ; sleep mode: idle, enabled
224
225 RJMP loop
226
227 wakeup:
228 SBI PCIFR, 0 ; clear interrupt
229 LDI x, 0x05
230 OUT DDRB, x
231 OUT PUEB, zero
232 LDI x, 0x02
233 OUT PRR, x ; not using zero, so devices with adc keep it disabled
234 RETI
235 #undef zero
236
237 sample:
238 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
239 #ifdef DEBUG
240 SBI PORTB, 2 ; to measure runtime
241 #endif // DEBUG
242
243 MOV n, i2
244 LSL n
245 LSL n
246 #define tmp _
247 MOV tmp, i1
248 SWAP tmp
249 ANDI tmp, 0x0f
250 LSR tmp
251 LSR tmp
252 OR n, tmp
253 #undef tmp
254 MOV s, i3
255 LSR s
256 ROR s
257 ANDI s, 0x80
258 #define tmp _
259 MOV tmp, i2
260 LSR tmp
261 OR s, tmp
262 #undef tmp
263
264 ; voice 1:
265 MOV t, n
266 RCALL g
267 SWAP t
268 ANDI t, 1
269 MOV acc, t
270
271 ; voice 2:
272 #define tmp _
273 MOV tmp, i2
274 LSL tmp
275 LSL tmp
276 LSL tmp
277 MOV t, i1
278 SWAP t
279 ANDI t, 0xf
280 LSR t
281 OR t, tmp
282 #undef tmp
283 EOR t, n
284 RCALL g
285 LSR t
286 LSR t
287 ANDI t, 3
288 AND t, s
289 ADD acc, t
290
291 ; voice 3:
292 MOV Ml, i2
293 SWAP Ml
294 ANDI Ml, 0xf0
295 LSL Ml
296 #define tmp _
297 MOV tmp, i1
298 LSR tmp
299 LSR tmp
300 LSR tmp
301 OR Ml, tmp
302 #undef tmp
303 MOV Mh, i3
304 SWAP Mh
305 ANDI Mh, 0xf0
306 LSL Mh
307 #define tmp _
308 MOV tmp, i2
309 LSR tmp
310 LSR tmp
311 LSR tmp
312 OR Mh, tmp
313 #undef tmp
314 RCALL mod3
315 ADD t, n
316 RCALL g
317 LSR t
318 LSR t
319 ANDI t, 3
320 MOV x, s
321 INC x
322 #define tmp _
323 MOV tmp, x
324 LSR tmp
325 LSR tmp
326 ADD tmp, x
327 ROR tmp
328 LSR tmp
329 ADD tmp, x
330 ROR tmp
331 LSR tmp
332 ADD tmp, x
333 ROR tmp
334 LSR tmp
335 AND t, tmp
336 #undef tmp
337 ADD acc, t
338
339 ; voice 4:
340 MOV Ml, i2
341 SWAP Ml
342 ANDI Ml, 0xf0
343 LSL Ml
344 LSL Ml
345 #define tmp _
346 MOV tmp, i1
347 LSR tmp
348 LSR tmp
349 OR Ml, tmp
350 #undef tmp
351 MOV Mh, i3
352 SWAP Mh
353 ANDI Mh, 0xf0
354 LSL Mh
355 LSL Mh
356 #define tmp _
357 MOV tmp, i2
358 LSR tmp
359 LSR tmp
360 OR Mh, tmp
361 #undef tmp
362 RCALL mod3
363 SUB t, n
364 NEG t
365 SUBI t, -8
366 RCALL g
367 LSR t
368 ANDI t, 3
369 INC s
370 #define tmp _
371 MOV tmp, s
372 LSR tmp
373 ADD tmp, s
374 ROR tmp
375 LSR tmp
376 LSR tmp
377 ADD tmp, s
378 ROR tmp
379 ADD tmp, s
380 ROR tmp
381 LSR tmp
382 LSR tmp
383 AND t, tmp
384 #undef tmp
385 ADD acc, t
386
387 SWAP acc ; acc<<4, to be passed to OCR0AL
388
389 SUBI i0, -1
390 SBCI i1, -1
391 SBCI i2, -1
392 SBCI i3, -1
393
394 #ifdef DEBUG
395 CBI PORTB, 2 ; end runtime measurement
396 #endif // DEBUG
397 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
398 RETI ; reenables interrupts
Imprint / Impressum