cleanup a bit
[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 RJMP wakeup
57 .org 0x0008 ; TIM0_OVF interrupt
58 RJMP sample
59
60 notes:
61 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
62 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
63
64 mod3: ; mod3(Mh.Ml) -> t
65 #define tmp _
66 ADD Ml, Mh
67 CLR Mh
68 ADC Mh, Mh ; store carry in Mh
69 MOV tmp, Ml
70 SWAP tmp
71 ANDI tmp, 0x0f
72 SWAP Mh
73 OR tmp, Mh
74 ANDI Ml, 0x0f
75 ADD Ml, tmp
76 MOV tmp, Ml
77 LSR tmp
78 LSR tmp
79 ANDI Ml, 0x03
80 ADD Ml, tmp
81 MOV tmp, Ml
82 LSR tmp
83 LSR tmp
84 ANDI Ml, 0x03
85 ADD Ml, tmp
86 CPI Ml, 3
87 BRCS skip
88 SUBI Ml, 3
89 skip:
90 RET
91 #undef tmp
92
93 g: ; g(i, t) -> t
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 RET
166
167 main: ; setup routine
168 CLR i0
169 CLR i1
170 CLR i2
171 CLR acc ; we output a dummy sample before the actual first one
172 LDI Xhi, hi8(FLASHM + notes) ; never changes
173 LDI one, 1 ; mostly for clearing TIM0_OVF bit
174
175 #define zero i0
176 LDI x, RAMEND
177 OUT SPL, x ; init stack ptr
178 OUT SPH, zero ; -"-
179 OUT PUEB, zero ; disable pullups
180 LDI x, 0x03
181 OUT DDRB, x ; PORTB0:pwm, PORTB1:debug (PORTB2:wakeup-input)
182 LDI x, 0xd8
183 OUT CCP, x ; change protected ioregs
184 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
185 LDI x, CAL_MAGIC ; determined by trial-and-error (->PORTB1)
186 OUT OSCCAL, x ; set oscillator calibration
187 OUT WDTCSR, zero; turn off watchdog
188
189 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
190 LDI x, 0x81
191 OUT TCCR0A, x
192 LDI x, 0x09
193 OUT TCCR0B, x
194 OUT TIMSK0, one ; enable tim0_ovf
195 SEI
196 #undef zero
197
198 loop:
199 CPI i2, 0x78 ; 16m23 -- one loop
200 BREQ halt
201
202 SLEEP
203 RJMP loop
204
205 //we use an external pullup(>= 1kohm), as line-input usually has an impedance
206 //between 20-100kohm, while the attiny's internal pullups are "only" 20-50kohm
207 //(which is too strong)
208 halt:
209 ;stop the music, and check whether PINB0 is plugged into an audio
210 ;sink. Until then, conserve as much battery as possible.
211 CLR i2 ; clear halt condition
212
213 #define zero i2
214 ; disable timer to free audio pin for wakeup function:
215 OUT TCCR0A, zero
216 OUT TCCR0B, zero
217
218 #define five x
219 LDI x, 0x05
220
221 ;assert high level on pullup pins to avoid accidentally triggering INT0:
222 OUT PORTB, five
223
224 OUT DDRB, zero ; set all pins as input
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 OUT SMCR, five ; sleep mode: power-down, enabled
232 SLEEP
233 ;OUT SMCR, one ; sleep mode: idle, enabled
234 OUT SMCR, zero ; sleep mode: disabled
235 #undef five
236
237 RJMP loop
238
239 wakeup:
240 LDI x, 0x03 ; restore output pins
241 OUT DDRB, x
242 LDI x, 0x81
243 OUT TCCR0A, x ; reenable COMA bits
244 LDI x, 0x09
245 OUT TCCR0B, x ; reenable timer0
246 RETI
247 #undef zero
248
249 sample:
250 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
251 #ifdef DEBUG
252 SBI PORTB, 1 ; to measure runtime
253 #endif // DEBUG
254
255 MOV n, i2
256 LSL n
257 LSL n
258 #define tmp _
259 MOV tmp, i1
260 SWAP tmp
261 ANDI tmp, 0x0f
262 LSR tmp
263 LSR tmp
264 OR n, tmp
265 #undef tmp
266 MOV s, i2
267 LSR s
268
269 ; voice 1:
270 MOV t, n
271 RCALL g
272 SWAP t
273 ANDI t, 1
274 MOV acc, t
275
276 ; voice 2:
277 #define tmp _
278 MOV tmp, i2
279 LSL tmp
280 LSL tmp
281 LSL tmp
282 MOV t, i1
283 SWAP t
284 ANDI t, 0xf
285 LSR t
286 OR t, tmp
287 #undef tmp
288 EOR t, n
289 RCALL g
290 LSR t
291 LSR t
292 ANDI t, 3
293 AND t, s
294 ADD acc, t
295
296 ; voice 3:
297 MOV Ml, i2
298 SWAP Ml
299 ANDI Ml, 0xf0
300 LSL Ml
301 #define tmp _
302 MOV tmp, i1
303 LSR tmp
304 LSR tmp
305 LSR tmp
306 OR Ml, tmp
307 #undef tmp
308 MOV Mh, i2
309 LSR Mh
310 LSR Mh
311 LSR Mh
312 RCALL mod3
313 ADD t, n
314 RCALL g
315 LSR t
316 LSR t
317 ANDI t, 3
318 MOV x, s
319 INC x
320 #define tmp _
321 MOV tmp, x
322 LSR tmp
323 LSR tmp
324 ADD tmp, x
325 ROR 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 AND t, tmp
334 #undef tmp
335 ADD acc, t
336
337 ; voice 4:
338 MOV Ml, i2
339 SWAP Ml
340 ANDI Ml, 0xf0
341 LSL Ml
342 LSL Ml
343 #define tmp _
344 MOV tmp, i1
345 LSR tmp
346 LSR tmp
347 OR Ml, tmp
348 #undef tmp
349 MOV Mh, i2
350 LSR Mh
351 LSR Mh
352 RCALL mod3
353 SUB t, n
354 NEG t
355 SUBI t, -8
356 RCALL g
357 LSR t
358 ANDI t, 3
359 INC s
360 #define tmp _
361 MOV tmp, s
362 LSR tmp
363 ADD tmp, s
364 ROR tmp
365 LSR tmp
366 LSR tmp
367 ADD tmp, s
368 ROR tmp
369 ADD tmp, s
370 ROR tmp
371 LSR tmp
372 LSR tmp
373 AND t, tmp
374 #undef tmp
375 ADD acc, t
376
377 SWAP acc ; acc<<4, to be passed to OCR0AL
378
379 SUBI i0, -1
380 SBCI i1, -1
381 SBCI i2, -1
382
383 #ifdef DEBUG
384 CBI PORTB, 1 ; end runtime measurement
385 #endif // DEBUG
386 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
387 RETI ; reenables interrupts
Imprint / Impressum