remove i3
[Chiptunes.git] / foo.S
CommitLineData
f180febe 1/* REGISTER NAMES */
6d672b87
TG
2#define acc r16
3#define i0 r17
4#define i1 r18
5#define i2 r19
6d672b87
TG
6#define n r21
7#define s r22
8#define t r23 //==Ml
f99fd6f3
TG
9#define x r24 //==a1==Mh
10#define _ r25 //==a2
11#define Xlo r26
12#define Xhi r27
ce618731 13#define one r28
f180febe
TG
14; r29
15; r30 Zlo
16; r31 Zhi
17; aliases:
ce618731
TG
18#define Ml t //mod3 vars
19#define Mh x // -"-
20#define a1 x //mul_ vars
21#define a2 _ // -"-
da32ed67 22
f180febe
TG
23/* I/O REGISTERS */
24OCR0AL = 0x26
25DDRB = 0x01
34fa6d04 26PORTB = 0x02
f180febe
TG
27PUEB = 0x03
28SPL = 0x3D
29SPH = 0x3E
30CCP = 0x3C
31CLKPSR = 0x36
2af726bc 32OSCCAL = 0x39
19e320a6 33WDTCSR = 0x31
f180febe
TG
34SMCR = 0x3A
35TCCR0A = 0x2E
36TCCR0B = 0x2D
37TIMSK0 = 0x2B
38TIFR0 = 0x2A
95d26108
TG
39PCMSK = 0x10
40PCIFR = 0x11
41PCICR = 0x12
42PRR = 0x35
f99fd6f3
TG
43RAMEND = 0x5F
44FLASHM = 0x4000
4466dd8b 45
f180febe 46.section .text
19e320a6 47.org 0x0000 ; RESET interrupt
cf36b4c3 48 CLR i0
19e320a6 49 RJMP main
95d26108
TG
50.org 0x0004 ; PCINT0 interrupt
51 CBI PCICR, 0 ; disable interrupt
8d6ea016 52 RJMP wakeup
19e320a6
TG
53.org 0x0008 ; TIM0_OVF interrupt
54 RJMP sample
4466dd8b 55
f99fd6f3
TG
56notes:
57 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
58 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
59
f180febe 60mod3: ; mod3(Mh.Ml) -> t
8d8c00e4 61 #define tmp _
65aa7cd6
TG
62 ADD Ml, Mh
63 CLR Mh
6d672b87 64 ADC Mh, Mh ; store carry in Mh
65aa7cd6
TG
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
26799bab 83 BRCS skip
65aa7cd6
TG
84 SUBI Ml, 3
85 skip:
4283632d 86 RET
8d8c00e4 87 #undef tmp
f180febe 88
f180febe 89g: ; g(i, t) -> t
6d672b87
TG
90 CLR a1
91
d35c3d70 92 #define tmp _
6d672b87 93 #define zero a1
65aa7cd6
TG
94 ANDI t, 0x07
95 MOV tmp, i2
96 ANDI tmp, 3
65aa7cd6
TG
97 CPSE tmp, zero
98 SUBI t, -8
6d672b87 99 #undef zero
02f61e33 100 #undef tmp
4466dd8b 101
d44d4b47 102 LDI Xlo, lo8(notes)
95d26108 103 ADD Xlo, t ; NOTE: notes are positioned so that hi8(notes) never changes
d44d4b47 104 LD t, X
4466dd8b 105
986f12ae
TG
106 CLR a2
107
dd3193ab
TG
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
4466dd8b 159
2af726bc 160 MOV t, a1 ;;TODO: use a1 in loop: directly
ce618731 161 RET
61fab018 162
19e320a6 163main: ; setup routine
95d26108
TG
164 ; NOTE: clr i0 moved to .ord 0x0
165 CLR i1
166 CLR i2
19e320a6 167 CLR acc ; we output a dummy sample before the actual first one
f99fd6f3 168 LDI Xhi, hi8(FLASHM + notes) ; never changes
ce618731 169 LDI one, 1 ; mostly for clearing TIM0_OVF bit
19e320a6 170
6d672b87 171 #define zero i0
f99fd6f3 172 LDI x, RAMEND
19e320a6
TG
173 OUT SPL, x ; init stack ptr
174 OUT SPH, zero ; -"-
175 OUT PUEB, zero ; disable pullups
ea40b11f
TG
176 LDI x, 0x05
177 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
19e320a6
TG
178 LDI x, 0xd8
179 OUT CCP, x ; change protected ioregs
180 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
2af726bc
TG
181 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
182 OUT OSCCAL, x ; set oscillator calibration
ce618731 183 OUT WDTCSR, zero; turn off watchdog
19e320a6
TG
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
19e320a6 191 SEI
6d672b87 192 #undef zero
19e320a6
TG
193
194loop:
8d6ea016
TG
195 CPI i2, 0x78>>5 ; 16m23 -- one loop
196;TODO^: s/>>5//
197 BREQ halt
198
899e1656 199 SLEEP
19e320a6
TG
200 RJMP loop
201
8d6ea016
TG
202halt:
203 CLR i2 ; clear halt condition
204
205 #define zero i2
899e1656
TG
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
212sbi PORTB, 0 ; force pin high, so pcint triggers on connect to ground --- XXX TODO: this does not work reliably for PORTB0
213sbi PORTB, 2 ; force pin high, so pcint triggers on connect to ground (works reliably for portb2)
214
215
8d6ea016
TG
216 OUT DDRB, zero
217 LDI x, 0x0f
218 OUT PUEB, x
219
899e1656
TG
220
221
8d6ea016
TG
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/
899e1656 224 OUT PCICR, one ; enable PCINT0
8d6ea016
TG
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
234wakeup:
235 SBI PCIFR, 0 ; clear interrupt
899e1656
TG
236 OUT PUEB, zero ; remove pullups
237 LDI x, 0x05 ; restore output pins
8d6ea016 238 OUT DDRB, x
899e1656
TG
239 ;OUT PRR, zero ; reenable periphials
240 LDI x, 0x09
241 OUT TCCR0B, x ; reenable timer0
8d6ea016
TG
242 RETI
243 #undef zero
244
19e320a6 245sample:
19e320a6 246 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
ce618731 247#ifdef DEBUG
34fa6d04 248 SBI PORTB, 2 ; to measure runtime
ce618731 249#endif // DEBUG
19e320a6 250
65aa7cd6
TG
251 MOV n, i2
252 LSL n
253 LSL n
f6ef1520 254 #define tmp _
65aa7cd6
TG
255 MOV tmp, i1
256 SWAP tmp
257 ANDI tmp, 0x0f
258 LSR tmp
259 LSR tmp
260 OR n, tmp
f6ef1520 261 #undef tmp
5e5a35c0 262 MOV s, i2
65aa7cd6 263 LSR s
3b86ca43 264
65aa7cd6
TG
265 ; voice 1:
266 MOV t, n
267 RCALL g
268 SWAP t
269 ANDI t, 1
270 MOV acc, t
3b86ca43 271
65aa7cd6 272 ; voice 2:
f6ef1520 273 #define tmp _
65aa7cd6
TG
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
f6ef1520 283 #undef tmp
65aa7cd6
TG
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
3b86ca43 291
65aa7cd6
TG
292 ; voice 3:
293 MOV Ml, i2
294 SWAP Ml
295 ANDI Ml, 0xf0
296 LSL Ml
f6ef1520 297 #define tmp _
65aa7cd6
TG
298 MOV tmp, i1
299 LSR tmp
300 LSR tmp
301 LSR tmp
302 OR Ml, tmp
f6ef1520 303 #undef tmp
5e5a35c0
TG
304 MOV Mh, i2
305 LSR Mh
306 LSR Mh
307 LSR Mh
65aa7cd6
TG
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
f6ef1520 316 #define tmp _
65aa7cd6
TG
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
f6ef1520 330 #undef tmp
65aa7cd6 331 ADD acc, t
f6ef1520 332
65aa7cd6
TG
333 ; voice 4:
334 MOV Ml, i2
335 SWAP Ml
336 ANDI Ml, 0xf0
337 LSL Ml
338 LSL Ml
f6ef1520 339 #define tmp _
65aa7cd6
TG
340 MOV tmp, i1
341 LSR tmp
342 LSR tmp
343 OR Ml, tmp
f6ef1520 344 #undef tmp
5e5a35c0
TG
345 MOV Mh, i2
346 LSR Mh
347 LSR Mh
65aa7cd6
TG
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
f6ef1520 356 #define tmp _
65aa7cd6
TG
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
f6ef1520 370 #undef tmp
65aa7cd6 371 ADD acc, t
3b86ca43 372
19e320a6
TG
373 SWAP acc ; acc<<4, to be passed to OCR0AL
374
f6ef1520
TG
375 SUBI i0, -1
376 SBCI i1, -1
377 SBCI i2, -1
bfce2f8c 378
ce618731
TG
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)
19e320a6 383 RETI ; reenables interrupts
Imprint / Impressum