I2S emulation and DDS implementation with interrupt latency align and interpolation to 16-bit resolution - this is the most interesting in this project.
;4 address store
DDS: lds ZL,TCNT1L ;2 TCNT1L = 5..8
ldi ZH,high(JmpTab) ;1
ijmp ;2
.org (PC + 0x100) & 0xFF00 ;align to page
JmpTab: nop ; dummy
nop ; dummy
nop ; dummy
nop ; dummy
nop ; dummy
nop ;0/1 TCNT1L = 5
nop ;0/1 TCNT1L = 6
nop ;0/1 TCNT1L = 7
; TCNT1L = 8
in tsreg,SREG ;10/13 save status register
out SPDR,SinH ;1 ---> load DAC L high byte
add APhaseK,AFreqK ;1 Phase(0..33) = Phase(0..33) + Freq(0..31)
adc APhaseL,AFreqL ;1
adc APhaseM,AFreqM ;1
adc APhaseN,AFreqN ;1
adc APhaseP,zero ;1
mov ZL,APhaseN ;1 ZL = wa (word address)
mov r0,APhaseM ;1 r0 = dx
sbrc APhaseP,0 ;2/1 if(Phase.24 == 0)
com ZL ;0/1 wa = !wa
sbrc APhaseP,0 ;2/1 if(Phase.24 == 0)
com r0 ;0/1 dx = !dx
ldi ZH,high(LUT) ;1 ZH = table base (low(LUT) = 0)
add ZL,ZL ;1 offset * 2 (word offset)
adc ZH,zero ;1
ldi SinH,44 ;1
sts OCR1BL,SinH ;2
out SPDR,SinL ;19 ---> load DAC L low byte
ld SinL,Z+ ;2 SinL = lo sin[x]
ld SinH,Z+ ;2 SinH = hi sin[x]
ld r1,Z ;2 r1 = lo sin[x + 1]
sub r1,SinL ;1 r1 = dA
mul r1,r0 ;2 r1,r0 = dA * dx
rol r0 ;1 C = 1 if r0.7 == 1
adc SinL,r1 ;1 SinH:SinL = sin[x] + round(r1:r0 / 256)
adc SinH,zero ;1 SinH:SinL = A
sbrs APhaseP,1 ;2/1
rjmp ph_cd1 ;0/2 jump if Phase.25 == 0
ph_ab1: com SinL ;1/0 SIN > 0, data line has NOT gate,
com SinH ;1/0 SinH:SinL = !SinH:SinL
rjmp ph_ad1 ;2/0
ph_cd1: sec ;0/1
sbc SinL,zero ;0/1 SIN < 0, data line has NOT gate,
sbc SinH,zero ;0/1 SinH:SinL = SinH:SinL - 1
ph_ad1: out SPDR,SinH ;38 ---> load DAC R high byte
add BPhaseK,BFreqK ;1 Phase(0..33) = Phase(0..33) + Freq(0..31)
adc BPhaseL,BFreqL ;1
adc BPhaseM,BFreqM ;1
adc BPhaseN,BFreqN ;1
adc BPhaseP,zero ;1
mov ZL,BPhaseN ;1 ZL = wa (word address)
mov r0,BPhaseM ;1 r0 = dx
sbrc BPhaseP,0 ;2/1 if(Phase.24 == 0)
com ZL ;0/1 wa = !wa
sbrc BPhaseP,0 ;2/1 if(Phase.24 == 0)
com r0 ;0/1 dx = !dx
ldi ZH,high(LUT) ;1 ZH = table base (low(LUT) = 0)
add ZL,ZL ;1 offset * 2 (word offset)
adc ZH,zero ;1
ldi SinH,81 ;1
sts OCR1BL,SinH ;2
out SPDR,SinL ;56 ---> load DAC R low byte
ld SinL,Z+ ;2 SinL = lo sin[x]
ld SinH,Z+ ;2 SinH = hi sin[x]
ld r1,Z ;2 r1 = lo sin[x + 1]
sub r1,SinL ;1 r1 = dA
mul r1,r0 ;2 r1,r0 = dA * dx
rol r0 ;1 C = 1 if r0.7 == 1
adc SinL,r1 ;1 SinH:SinL = sin[x] + round(r1:r0 / 256)
adc SinH,zero ;1 SinH:SinL = A
sbrs BPhaseP,1 ;2/1
rjmp ph_cd2 ;0/2 jump if Phase.25 == 0
ph_ab2: com SinL ;1/0 SIN > 0, data line has NOT gate,
com SinH ;1/0 SinH:SinL = !SinH:SinL
rjmp ph_ad2 ;2/0
ph_cd2: sec ;0/1
sbc SinL,zero ;0/1 SIN < 0, data line has NOT gate,
sbc SinH,zero ;0/1 SinH:SinL = SinH:SinL - 1
ph_ad2: out SREG,tsreg ;1 restore status register
reti ;4
;89/92 total