12 #define x r26 //==Xlo==Mh==a1
13 #define _ r27 //==Xhi==a2
21 #define Ml r23 //mod3 vars
43 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
44 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
47 .org 0x0000 ; RESET interrupt
49 .org 0x0008 ; TIM0_OVF interrupt
52 mod3: ; mod3(Mh.Ml) -> t
56 ADC Mh, Mh ; store carry in Mh
81 ; definitions to mul-tree readable:
84 .macro always _bit ; nop; for when a test() is not necessary (see tree)
86 .macro never _bit ; nop; for when a test() is not necessary (see tree)
88 .macro test _bit,_jmpto
92 .macro i_test _bit,_jmpto ; inverted test (for reordered 0x8_)
100 .macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
103 .macro shift0 ; nop; last shift is common
109 .macro add8 ; ditto with carrying
130 ;TODO: check correctness!
131 LDI Xhi, hi8(notes) ; hi(notes) always zero, but still need to clear the register
133 ADD Xlo, t ; NOTE: can't overflow, since RAMEND == 0x5F
138 /* decision tree multiplication saves cycles and (hopefully) reduces code size
145 _?000 _?100 _?001 _?101
147 _0000 _1000 _0100 _1100 _1001 _0101 _1101
149 ... ... ... ... ... ... ...
151 B0 58 84 8C 69 75 9D */
168 RJMP end_mul ; calc'd 0xb0
170 m_1000: add16 $ shift16
179 RJMP end_mul ; calc'd 0x58
181 m__100: add16 $ shift16
193 RJMP end_mul ; calc'd 0x8c / 0x84
195 m____1: add16 $ shift16
201 m_1001: add16 $ shift16
210 RJMP end_mul ; calc'd 0x69
212 m__101: add16 $ shift16
223 RJMP end_mul ; calc'd 0x75
225 m_1101: add16 $ shift16
237 LSR a1 ;final shift is a common operation for all
239 MOV t, a1 ;;TODO: use a1 in loop: directly
242 RET ; TODO: replace CALL/RET with IJMP?
244 main: ; setup routine
249 CLR acc ; we output a dummy sample before the actual first one
255 OUT SPL, x ; init stack ptr
257 OUT PUEB, zero ; disable pullups
259 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
261 OUT CCP, x ; change protected ioregs
262 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
263 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
264 OUT OSCCAL, x ; set oscillator calibration
265 OUT WDTCSR, zero; turn off watchdog ;;TODO: incomplete - see datasheet pg48
266 ; OUT SMCR, 2 ; sleep mode 'power down' ('idle' (default) has faster response time)
268 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
273 OUT TIMSK0, one ; enable tim0_ovf
279 SLEEP ; wait for interrupt
283 ; potential TODO: softcounter in r25 to only update duty cicle every n iterations
284 ; potential TODO: save/restore status register (SREG=0x3f) (only if something in mainloop)
286 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
287 SBI PORTB, 2 ; to measure runtime
433 SWAP acc ; acc<<4, to be passed to OCR0AL
440 CBI PORTB, 2 ; end runtime measurement
441 LDI _, 1 ; NOTE: could use own register for speed
442 OUT TIFR0, _ ; clear pending interrupt (routine takes two intr.cycles)
443 RETI ; reenables interrupts