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