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