1 ; TODO: melody is still not 100% correct!
11 #define x r24 //==a1==Mh
20 #define Ml t //mod3 vars
22 #define a1 x //mul_ vars
45 .org 0x0000 ; RESET interrupt
50 .org 0x0008 ; TIM0_OVF interrupt
54 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
55 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
57 mod3: ; mod3(Mh.Ml) -> t
61 ADC Mh, Mh ; store carry in Mh
86 ; definitions to mul-tree readable:
87 .macro always _bit ; nop; for when a test() is not necessary (see tree)
89 .macro never _bit ; nop; for when a test() is not necessary (see tree)
91 .macro test _bit,_jmpto
95 .macro i_test _bit,_jmpto ; inverted test (for reordered 0x8_)
103 .macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
106 .macro shift0 ; nop; last shift is common
112 .macro add8 ; ditto with carrying
129 ;TODO: check correctness!
131 ADD Xlo, t ; NOTE: can't overflow, since RAMEND == 0x5F
136 /* decision tree multiplication saves cycles and (hopefully) reduces code size
143 _?000 _?100 _?001 _?101
145 _0000 _1000 _0100 _1100 _1001 _0101 _1101
147 ... ... ... ... ... ... ...
149 B0 58 84 8C 69 75 9D */
166 RJMP end_mul ; calc'd 0xb0
168 m_1000: add16 $ shift16
177 RJMP end_mul ; calc'd 0x58
179 m__100: add16 $ shift16
191 RJMP end_mul ; calc'd 0x8c / 0x84
193 m____1: add16 $ shift16
199 m_1001: add16 $ shift16
208 RJMP end_mul ; calc'd 0x69
210 m__101: add16 $ shift16
221 RJMP end_mul ; calc'd 0x75
223 m_1101: add16 $ shift16
235 LSR a1 ;final shift is a common operation for all
237 MOV t, a1 ;;TODO: use a1 in loop: directly
240 main: ; setup routine
241 ; NOTE: clr i0..i2 moved to .ord 0x0
243 CLR acc ; we output a dummy sample before the actual first one
244 LDI Xhi, hi8(FLASHM + notes) ; never changes
245 LDI one, 1 ; mostly for clearing TIM0_OVF bit
249 OUT SPL, x ; init stack ptr
251 OUT PUEB, zero ; disable pullups
253 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
255 OUT CCP, x ; change protected ioregs
256 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
257 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
258 OUT OSCCAL, x ; set oscillator calibration
259 OUT WDTCSR, zero; turn off watchdog
261 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
266 OUT TIMSK0, one ; enable tim0_ovf
271 SLEEP ; wait for interrupt
275 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
277 SBI PORTB, 2 ; to measure runtime
424 SWAP acc ; acc<<4, to be passed to OCR0AL
432 CBI PORTB, 2 ; end runtime measurement
434 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
435 RETI ; reenables interrupts