]> git.gir.st - Chiptunes.git/blob - foo.S
cleanup; switch to INT0
[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 ; XXX: move registers down!
13 #define n r21
14 #define s r22
15 #define t r23 //==Ml
16 #define x r24 //==a1==Mh
17 #define _ r25 //==a2
18 #define Xlo r26
19 #define Xhi r27
20 #define one r28
21 ; r29
22 ; r30 Zlo
23 ; r31 Zhi
24 ; aliases:
25 #define Ml t //mod3 vars
26 #define Mh x // -"-
27 #define a1 x //mul_ vars
28 #define a2 _ // -"-
29
30 /* I/O REGISTERS */
31 OCR0AL = 0x26
32 DDRB = 0x01
33 PORTB = 0x02
34 PUEB = 0x03
35 SPL = 0x3D
36 SPH = 0x3E
37 CCP = 0x3C
38 CLKPSR = 0x36
39 OSCCAL = 0x39
40 WDTCSR = 0x31
41 SMCR = 0x3A
42 TCCR0A = 0x2E
43 TCCR0B = 0x2D
44 TIMSK0 = 0x2B
45 TIFR0 = 0x2A
46 EIMSK = 0x13
47 EICRA = 0x15
48 RAMEND = 0x5F
49 FLASHM = 0x4000
50
51 .section .text
52 .org 0x0000 ; RESET interrupt
53 RJMP main
54 .org 0x0002 ; INT0 interrupt
55 CBI EIMSK, 0 ; disable interrupt
56 ;TODO: can move 1 instruction here
57 RJMP wakeup
58 .org 0x0008 ; TIM0_OVF interrupt
59 RJMP sample
60
61 notes:
62 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
63 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
64
65 mod3: ; mod3(Mh.Ml) -> t
66 #define tmp _
67 ADD Ml, Mh
68 CLR Mh
69 ADC Mh, Mh ; store carry in Mh
70 MOV tmp, Ml
71 SWAP tmp
72 ANDI tmp, 0x0f
73 SWAP Mh
74 OR tmp, Mh
75 ANDI Ml, 0x0f
76 ADD Ml, tmp
77 MOV tmp, Ml
78 LSR tmp
79 LSR tmp
80 ANDI Ml, 0x03
81 ADD Ml, tmp
82 MOV tmp, Ml
83 LSR tmp
84 LSR tmp
85 ANDI Ml, 0x03
86 ADD Ml, tmp
87 CPI Ml, 3
88 BRCS skip
89 SUBI Ml, 3
90 skip:
91 RET
92 #undef tmp
93
94 g: ; g(i, t) -> t
95 CLR a1
96
97 #define tmp _
98 #define zero a1
99 ANDI t, 0x07
100 MOV tmp, i2
101 ANDI tmp, 3
102 CPSE tmp, zero
103 SUBI t, -8
104 #undef zero
105 #undef tmp
106
107 LDI Xlo, lo8(notes)
108 ADD Xlo, t
109 LD t, X
110
111 CLR a2
112
113 ; begin of mulitiplication:
114 LSR t
115 BRCC skip1
116 ADD a1, i0
117 ADC a2, i1
118 skip1:
119 LSR a2
120 ROR a1
121 LSR t
122 ; BRCC skip2 -- this bit is always zero
123 ; ADD a1, i0
124 ; ADC a2, i1
125 ;skip2:
126 LSR a2
127 ROR a1
128 LSR t
129 BRCC skip3
130 ADD a1, i0
131 ADC a2, i1
132 skip3:
133 LSR a2
134 ROR a1
135 LSR t
136 BRCC skip4
137 ADD a1, i0
138 ADC a2, i1
139 skip4:
140 LSR a2
141 ROR a1
142 LSR t
143 BRCC skip5
144 ADD a1, i0
145 ADC a2, i1
146 skip5:
147 LSR a2
148 ROR a1
149 LSR t
150 BRCC skip6
151 ADD a1, i0
152 skip6:
153 LSR a1
154 LSR t
155 BRCC skip7
156 ADD a1, i0
157 skip7:
158 LSR a1
159 LSR t
160 BRCC skip8
161 ADD a1, i0
162 skip8:
163 LSR a1
164
165 MOV t, a1 ;;TODO: use a1 in loop: directly
166 RET
167
168 main: ; setup routine
169 CLR i0
170 CLR i1
171 CLR i2
172 CLR acc ; we output a dummy sample before the actual first one
173 LDI Xhi, hi8(FLASHM + notes) ; never changes
174 LDI one, 1 ; mostly for clearing TIM0_OVF bit
175
176 #define zero i0
177 LDI x, RAMEND
178 OUT SPL, x ; init stack ptr
179 OUT SPH, zero ; -"-
180 OUT PUEB, zero ; disable pullups
181 LDI x, 0x03
182 OUT DDRB, x ; PORTB0:pwm, PORTB1:debug (PORTB2:wakeup-input)
183 LDI x, 0xd8
184 OUT CCP, x ; change protected ioregs
185 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
186 LDI x, CAL_MAGIC ; determined by trial-and-error (->PORTB1)
187 OUT OSCCAL, x ; set oscillator calibration
188 OUT WDTCSR, zero; turn off watchdog
189
190 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
191 LDI x, 0x81
192 OUT TCCR0A, x
193 LDI x, 0x09
194 OUT TCCR0B, x
195 OUT TIMSK0, one ; enable tim0_ovf
196 SEI
197 #undef zero
198
199 loop:
200 CPI i2, 0x78 ; 16m23 -- one loop
201 ;cpi i2, 1 ;TODO:removeme
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 OUT TCCR0A, zero ; https://www.avrfreaks.net/forum/oc1a-state-during-pwm-disable
217 OUT TCCR0B, zero ; disable timer to free audio pin for wakeup function
218
219 ;TODO: both of these necessary?
220 SBI PORTB, 0 ; assert high level on pin2, so we can detect a plugged-in state as a low level.
221 SBI PORTB, 2 ; assert high level on pin2, so we can detect a plugged-in state as a low level.
222
223 OUT DDRB, zero ; set all pins as input
224 ;;;OUT PUEB, zero ; disable pullups on all pins (already done @ init/main)
225
226 ;set up INT0 to wake up when a audio sink is connected
227 SBI EIMSK, 0 ; set-bit-0 high => enable interrupt
228 OUT EICRA, zero ; logical low generates INT0
229
230 ;enter power-down-mode
231 LDI x, 0x05 ; sleep mode: power-down, enabled
232 OUT SMCR, x
233 SLEEP
234 ;OUT SMCR, one ; sleep mode: idle, enabled
235 OUT SMCR, zero ; sleep mode: disabled
236
237 RJMP loop
238
239 wakeup:
240 ;;;SBI PCIFR, 1 ; clear interrupt (handled by reti)
241 ;;;OUT PUEB, zero ; remove pullups (already in main)
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