12 #define x r26 //==Xlo==Mh
13 #define t r27 //==Xhi==Ml
21 #define Mh r26 //mod3 vars
41 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
42 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
45 .org 0x0000 ; RESET interrupt
47 .org 0x0008 ; TIM0_OVF interrupt
50 mod3: ; mod3(Mh.Ml) -> t
79 ; definitions to mul-tree readable:
82 .macro always _bit ; nop; for when a test() is not necessary (see tree)
84 .macro never _bit ; nop; for when a test() is not necessary (see tree)
86 .macro test _bit,_jmpto
94 .macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
97 .macro shift0 ; nop; last shift is common
104 .macro add_shift8 ; ditto with carrying
108 .macro add_shift0 ; last shift is common
125 MOV tmp, t ; NOTE: must move value away from `t`, as that is also hi(X)
126 LDI Xhi, hi8(data) ; TODO: can skip if &data < 0xff (it is)
128 ADD Xlo, tmp ;<-- the offset (formerly `t`) into data[]
129 ADC Xhi, zero ; ditto skip
140 /* decision tree multiplication saves cycles and (hopefully) reduces code size
147 _?000 _?100 _?001 _?101
149 _0000 _1000 _0100 _1100 _1001 _0101 _1101
151 ... ... ... ... ... ... ...
153 B0 58 84 8C 69 75 9D */
170 RJMP end_mul ; calc'd 0xb0
181 RJMP end_mul ; calc'd 0x58
186 RJMP upper_8 ;'ll calc 0x84
189 upper_8: ; used twice, so deduplicated
198 RJMP end_mul ; calc'd 0x8c
215 RJMP end_mul ; calc'd 0x69
228 RJMP end_mul ; calc'd 0x75
242 LSR a1 ;final shift is a common operation for all
244 MOV t, a1 ;;TODO: use a1 in main() directly
248 RET ; TODO: replace CALL/RET with IJMP?
250 main: ; setup routine
256 CLR acc ; we output a dummy sample before the actual first one
261 OUT SPL, x ; init stack ptr
263 OUT PUEB, zero ; disable pullups
264 OUT DDRB, one ; PORTB[0] as output
266 OUT CCP, x ; change protected ioregs
267 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
268 OUT WDTCSR, zero; turn off watchdog ;;TODO: incomplete - see datasheet pg48
269 ; OUT SMCR, 2 ; sleep mode 'power down' ('idle' (default) has faster response time)
271 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
276 OUT TIMSK0, one ; enable tim0_ovf
277 OUT TIFR0, one ; TODO: why?
283 SLEEP ; wait for interrupt
287 ; potential TODO: softcounter in r28 to only update duty cicle every n iterations
288 ; potential TODO: save/restore status register (SREG=0x3f)
289 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
435 SWAP acc ; acc<<4, to be passed to OCR0AL
442 RETI ; reenables interrupts