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