cleanup some TODOs, #defines
[Chiptunes.git] / foo.S
CommitLineData
ce618731 1; TODO: melody is still not 100% correct!
f180febe 2/* REGISTER NAMES */
6d672b87
TG
3#define acc r16
4#define i0 r17
5#define i1 r18
6#define i2 r19
7#define i3 r20
8#define n r21
9#define s r22
10#define t r23 //==Ml
f99fd6f3
TG
11#define x r24 //==a1==Mh
12#define _ r25 //==a2
13#define Xlo r26
14#define Xhi r27
ce618731 15#define one r28
f180febe
TG
16; r29
17; r30 Zlo
18; r31 Zhi
19; aliases:
ce618731
TG
20#define Ml t //mod3 vars
21#define Mh x // -"-
22#define a1 x //mul_ vars
23#define a2 _ // -"-
da32ed67 24
f180febe
TG
25/* I/O REGISTERS */
26OCR0AL = 0x26
27DDRB = 0x01
34fa6d04 28PORTB = 0x02
f180febe
TG
29PUEB = 0x03
30SPL = 0x3D
31SPH = 0x3E
32CCP = 0x3C
33CLKPSR = 0x36
2af726bc 34OSCCAL = 0x39
19e320a6 35WDTCSR = 0x31
f180febe
TG
36SMCR = 0x3A
37TCCR0A = 0x2E
38TCCR0B = 0x2D
39TIMSK0 = 0x2B
40TIFR0 = 0x2A
f99fd6f3
TG
41RAMEND = 0x5F
42FLASHM = 0x4000
4466dd8b 43
f180febe 44.section .text
19e320a6 45.org 0x0000 ; RESET interrupt
cf36b4c3
TG
46 CLR i0
47 CLR i1
48 CLR i2
19e320a6
TG
49 RJMP main
50.org 0x0008 ; TIM0_OVF interrupt
51 RJMP sample
4466dd8b 52
f99fd6f3
TG
53notes:
54 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
55 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
56
f180febe 57mod3: ; mod3(Mh.Ml) -> t
8d8c00e4 58 #define tmp _
65aa7cd6
TG
59 ADD Ml, Mh
60 CLR Mh
6d672b87 61 ADC Mh, Mh ; store carry in Mh
65aa7cd6
TG
62 MOV tmp, Ml
63 SWAP tmp
64 ANDI tmp, 0x0f
65 SWAP Mh
66 OR tmp, Mh
67 ANDI Ml, 0x0f
68 ADD Ml, tmp
69 MOV tmp, Ml
70 LSR tmp
71 LSR tmp
72 ANDI Ml, 0x03
73 ADD Ml, tmp
74 MOV tmp, Ml
75 LSR tmp
76 LSR tmp
77 ANDI Ml, 0x03
78 ADD Ml, tmp
79 CPI Ml, 3
80 BRPL skip
81 SUBI Ml, 3
82 skip:
4283632d 83 RET
8d8c00e4 84 #undef tmp
f180febe
TG
85
86; definitions to mul-tree readable:
87.macro always _bit ; nop; for when a test() is not necessary (see tree)
88.endm
89.macro never _bit ; nop; for when a test() is not necessary (see tree)
90.endm
91.macro test _bit,_jmpto
65958d9d
TG
92 SBRC t, \_bit
93 RJMP \_jmpto
f180febe 94.endm
f8861a90
TG
95.macro i_test _bit,_jmpto ; inverted test (for reordered 0x8_)
96 SBRS t, \_bit
97 RJMP \_jmpto
98.endm
f180febe
TG
99.macro shift16
100 LSR a2
101 ROR a1
102.endm
103.macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
104 LSR a1
105.endm
106.macro shift0 ; nop; last shift is common
107.endm
ea40b11f 108.macro add16
f180febe
TG
109 ADD a1, i0
110 ADC a2, i1
f180febe 111.endm
ea40b11f 112.macro add8 ; ditto with carrying
f180febe
TG
113 ADD a1, i0
114.endm
115
116g: ; g(i, t) -> t
6d672b87
TG
117 CLR a1
118
d35c3d70 119 #define tmp _
6d672b87 120 #define zero a1
65aa7cd6
TG
121 ANDI t, 0x07
122 MOV tmp, i2
123 ANDI tmp, 3
65aa7cd6
TG
124 CPSE tmp, zero
125 SUBI t, -8
6d672b87 126 #undef zero
02f61e33 127 #undef tmp
4466dd8b 128
34fa6d04 129 ;TODO: check correctness!
d44d4b47
TG
130 LDI Xlo, lo8(notes)
131 ADD Xlo, t ; NOTE: can't overflow, since RAMEND == 0x5F
132 LD t, X
4466dd8b 133
986f12ae
TG
134 CLR a2
135
4466dd8b
TG
136 /* decision tree multiplication saves cycles and (hopefully) reduces code size
137 _xxx?
138 / \
139 _xx?0 _xx1?
140 | |
141 _x?00 _x?01
142 / \ / \
143 _?000 _?100 _?001 _?101
144 / \ / \ | / \
145 _0000 _1000 _0100 _1100 _1001 _0101 _1101
146 | | | | | | |
147 ... ... ... ... ... ... ...
148 | | | | | | |
149 B0 58 84 8C 69 75 9D */
65aa7cd6 150 test 0, m____1
4466dd8b 151 m____0: shift16
65aa7cd6 152 never 1
4466dd8b 153 m___00: shift16
65aa7cd6 154 test 2, m__100
4466dd8b 155 m__000: shift16
65aa7cd6 156 test 3, m_1000
4466dd8b 157 m_0000: shift16
65aa7cd6 158 always 4
ea40b11f 159 add16 $ shift16
65aa7cd6 160 always 5
ea40b11f 161 add8 $ shift8
65aa7cd6 162 never 6
4466dd8b 163 shift8
65aa7cd6 164 always 7
ea40b11f 165 add8 $ shift0
65aa7cd6 166 RJMP end_mul ; calc'd 0xb0
d0324785 167
ea40b11f 168 m_1000: add16 $ shift16
65aa7cd6 169 always 4
ea40b11f 170 add16 $ shift16
65aa7cd6 171 never 5
4466dd8b 172 shift8
65aa7cd6 173 always 6
ea40b11f 174 add8 $ shift8
65aa7cd6 175 never 7
4466dd8b 176 shift0
65aa7cd6 177 RJMP end_mul ; calc'd 0x58
d0324785 178
ea40b11f 179 m__100: add16 $ shift16
f8861a90
TG
180 i_test 3, m_0100
181 m_1100: add16
4466dd8b 182 m_0100: shift16
65aa7cd6 183 never 4
4466dd8b 184 shift16
65aa7cd6 185 never 5
4466dd8b 186 shift8
65aa7cd6 187 never 6
4466dd8b 188 shift8
65aa7cd6 189 always 7
ea40b11f 190 add8 $ shift0
f8861a90 191 RJMP end_mul ; calc'd 0x8c / 0x84
d0324785 192
ea40b11f 193 m____1: add16 $ shift16
65aa7cd6 194 never 1
4466dd8b 195 m___01: shift16
65aa7cd6 196 test 2, m__101
4466dd8b 197 m__001: shift16
65aa7cd6 198 always 3
ea40b11f 199 m_1001: add16 $ shift16
65aa7cd6 200 never 4
4466dd8b 201 shift16
65aa7cd6 202 always 5
ea40b11f 203 add8 $ shift8
65aa7cd6 204 always 6
ea40b11f 205 add8 $ shift8
65aa7cd6 206 never 7
4466dd8b 207 shift0
65aa7cd6 208 RJMP end_mul ; calc'd 0x69
d0324785 209
ea40b11f 210 m__101: add16 $ shift16
65aa7cd6 211 test 3, m_1101
4466dd8b 212 m_0101: shift16
65aa7cd6 213 always 4
ea40b11f 214 add16 $ shift16
65aa7cd6 215 always 5
ea40b11f 216 add8 $ shift8
65aa7cd6 217 always 6
ea40b11f 218 add8 $ shift8
65aa7cd6 219 never 7
4466dd8b 220 shift0
65aa7cd6 221 RJMP end_mul ; calc'd 0x75
d0324785 222
ea40b11f 223 m_1101: add16 $ shift16
65aa7cd6 224 always 4
ea40b11f 225 add16 $ shift16
65aa7cd6 226 never 5
4466dd8b 227 shift8
65aa7cd6 228 never 6
4466dd8b 229 shift8
65aa7cd6 230 always 7
ea40b11f 231 add8 $ shift0
65aa7cd6 232 ; calc'd 0x9d
d0324785 233
4466dd8b 234 end_mul:
65aa7cd6 235 LSR a1 ;final shift is a common operation for all
4466dd8b 236
2af726bc 237 MOV t, a1 ;;TODO: use a1 in loop: directly
ce618731 238 RET
61fab018 239
19e320a6 240main: ; setup routine
cf36b4c3 241 ; NOTE: clr i0..i2 moved to .ord 0x0
65aa7cd6 242 CLR i3
19e320a6 243 CLR acc ; we output a dummy sample before the actual first one
f99fd6f3 244 LDI Xhi, hi8(FLASHM + notes) ; never changes
ce618731 245 LDI one, 1 ; mostly for clearing TIM0_OVF bit
19e320a6 246
6d672b87 247 #define zero i0
f99fd6f3 248 LDI x, RAMEND
19e320a6
TG
249 OUT SPL, x ; init stack ptr
250 OUT SPH, zero ; -"-
251 OUT PUEB, zero ; disable pullups
ea40b11f
TG
252 LDI x, 0x05
253 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
19e320a6
TG
254 LDI x, 0xd8
255 OUT CCP, x ; change protected ioregs
256 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
2af726bc
TG
257 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
258 OUT OSCCAL, x ; set oscillator calibration
ce618731 259 OUT WDTCSR, zero; turn off watchdog
19e320a6
TG
260
261 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
262 LDI x, 0x81
263 OUT TCCR0A, x
264 LDI x, 0x09
265 OUT TCCR0B, x
266 OUT TIMSK0, one ; enable tim0_ovf
19e320a6 267 SEI
6d672b87 268 #undef zero
19e320a6
TG
269
270loop:
271 SLEEP ; wait for interrupt
272 RJMP loop
273
274sample:
19e320a6 275 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
ce618731 276#ifdef DEBUG
34fa6d04 277 SBI PORTB, 2 ; to measure runtime
ce618731 278#endif // DEBUG
19e320a6 279
65aa7cd6
TG
280 MOV n, i2
281 LSL n
282 LSL n
f6ef1520 283 #define tmp _
65aa7cd6
TG
284 MOV tmp, i1
285 SWAP tmp
286 ANDI tmp, 0x0f
287 LSR tmp
288 LSR tmp
289 OR n, tmp
f6ef1520 290 #undef tmp
65aa7cd6
TG
291 MOV s, i3
292 LSR s
293 ROR s
294 ANDI s, 0x80
f6ef1520 295 #define tmp _
65aa7cd6
TG
296 MOV tmp, i2
297 LSR tmp
298 OR s, tmp
f6ef1520 299 #undef tmp
3b86ca43 300
65aa7cd6
TG
301 ; voice 1:
302 MOV t, n
303 RCALL g
304 SWAP t
305 ANDI t, 1
306 MOV acc, t
3b86ca43 307
65aa7cd6 308 ; voice 2:
f6ef1520 309 #define tmp _
65aa7cd6
TG
310 MOV tmp, i2
311 LSL tmp
312 LSL tmp
313 LSL tmp
314 MOV t, i1
315 SWAP t
316 ANDI t, 0xf
317 LSR t
318 OR t, tmp
f6ef1520 319 #undef tmp
65aa7cd6
TG
320 EOR t, n
321 RCALL g
322 LSR t
323 LSR t
324 ANDI t, 3
325 AND t, s
326 ADD acc, t
3b86ca43 327
65aa7cd6
TG
328 ; voice 3:
329 MOV Ml, i2
330 SWAP Ml
331 ANDI Ml, 0xf0
332 LSL Ml
f6ef1520 333 #define tmp _
65aa7cd6
TG
334 MOV tmp, i1
335 LSR tmp
336 LSR tmp
337 LSR tmp
338 OR Ml, tmp
f6ef1520 339 #undef tmp
65aa7cd6
TG
340 MOV Mh, i3
341 SWAP Mh
342 ANDI Mh, 0xf0
343 LSL Mh
f6ef1520 344 #define tmp _
65aa7cd6
TG
345 MOV tmp, i2
346 LSR tmp
347 LSR tmp
348 LSR tmp
349 OR Mh, tmp
f6ef1520 350 #undef tmp
65aa7cd6
TG
351 RCALL mod3
352 ADD t, n
353 RCALL g
354 LSR t
355 LSR t
356 ANDI t, 3
357 MOV x, s
358 INC x
f6ef1520 359 #define tmp _
65aa7cd6
TG
360 MOV tmp, x
361 LSR tmp
362 LSR tmp
363 ADD tmp, x
364 ROR tmp
365 LSR tmp
366 ADD tmp, x
367 ROR tmp
368 LSR tmp
369 ADD tmp, x
370 ROR tmp
371 LSR tmp
372 AND t, tmp
f6ef1520 373 #undef tmp
65aa7cd6 374 ADD acc, t
f6ef1520 375
65aa7cd6
TG
376 ; voice 4:
377 MOV Ml, i2
378 SWAP Ml
379 ANDI Ml, 0xf0
380 LSL Ml
381 LSL Ml
f6ef1520 382 #define tmp _
65aa7cd6
TG
383 MOV tmp, i1
384 LSR tmp
385 LSR tmp
386 OR Ml, tmp
f6ef1520 387 #undef tmp
65aa7cd6
TG
388 MOV Mh, i3
389 SWAP Mh
390 ANDI Mh, 0xf0
391 LSL Mh
392 LSL Mh
f6ef1520 393 #define tmp _
65aa7cd6
TG
394 MOV tmp, i2
395 LSR tmp
396 LSR tmp
397 OR Mh, tmp
f6ef1520 398 #undef tmp
65aa7cd6
TG
399 RCALL mod3
400 SUB t, n
401 NEG t
402 SUBI t, -8
403 RCALL g
404 LSR t
405 ANDI t, 3
406 INC s
f6ef1520 407 #define tmp _
65aa7cd6
TG
408 MOV tmp, s
409 LSR tmp
410 ADD tmp, s
411 ROR tmp
412 LSR tmp
413 LSR tmp
414 ADD tmp, s
415 ROR tmp
416 ADD tmp, s
417 ROR tmp
418 LSR tmp
419 LSR tmp
420 AND t, tmp
f6ef1520 421 #undef tmp
65aa7cd6 422 ADD acc, t
3b86ca43 423
19e320a6
TG
424 SWAP acc ; acc<<4, to be passed to OCR0AL
425
f6ef1520
TG
426 SUBI i0, -1
427 SBCI i1, -1
428 SBCI i2, -1
429 SBCI i3, -1
bfce2f8c 430
ce618731
TG
431#ifdef DEBUG
432 CBI PORTB, 2 ; end runtime measurement
433#endif // DEBUG
434 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
19e320a6 435 RETI ; reenables interrupts
Imprint / Impressum