X-Git-Url: https://git.gir.st/Chiptunes.git/blobdiff_plain/65aa7cd6239c7ade349d32014e03e4e41884b647..ea40b11f590e27e0fec3b3435007eb2177d85dc1:/foo.S diff --git a/foo.S b/foo.S index 8e76812..55718df 100644 --- a/foo.S +++ b/foo.S @@ -24,11 +24,13 @@ /* I/O REGISTERS */ OCR0AL = 0x26 DDRB = 0x01 +PORTB = 0x02 PUEB = 0x03 SPL = 0x3D SPH = 0x3E CCP = 0x3C CLKPSR = 0x36 +WDTCSR = 0x31 SMCR = 0x3A TCCR0A = 0x2E TCCR0B = 0x2D @@ -36,10 +38,15 @@ TIMSK0 = 0x2B TIFR0 = 0x2A .section .data +data: .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58 .section .text +.org 0x0000 ; RESET interrupt + RJMP main +.org 0x0008 ; TIM0_OVF interrupt + RJMP sample mod3: ; mod3(Mh.Ml) -> t #define tmp _ @@ -71,13 +78,15 @@ mod3: ; mod3(Mh.Ml) -> t #undef tmp ; definitions to mul-tree readable: +#define a1 x +#define a2 _ .macro always _bit ; nop; for when a test() is not necessary (see tree) .endm .macro never _bit ; nop; for when a test() is not necessary (see tree) .endm .macro test _bit,_jmpto - SBRC t, _bit - RJMP _jmpto + SBRC t, \_bit + RJMP \_jmpto .endm .macro shift16 LSR a2 @@ -88,35 +97,32 @@ mod3: ; mod3(Mh.Ml) -> t .endm .macro shift0 ; nop; last shift is common .endm -.macro add_shift16 +.macro add16 ADD a1, i0 ADC a2, i1 - shift16 -.endm -.macro add_shift8 ; ditto with carrying - ADD a1, i0 - shift8 .endm -.macro add_shift0 ; last shift is common +.macro add8 ; ditto with carrying ADD a1, i0 .endm +#undef a2 +#undef a1 g: ; g(i, t) -> t #define tmp _ ANDI t, 0x07 MOV tmp, i2 ANDI tmp, 3 - TST tmp CPSE tmp, zero SUBI t, -8 #undef tmp + ;TODO: check correctness! #define tmp _ MOV tmp, t ; NOTE: must move value away from `t`, as that is also hi(X) - LDI Xhi, hi8(data) ; TODO: can skip if &data < 0xff (it is) + LDI Xhi, hi8(data) ; hi(data) always zero, but still need to clear the register LDI Xlo, lo8(data) ADD Xlo, tmp ;<-- the offset (formerly `t`) into data[] - ADC Xhi, zero ; ditto skip + ;ADC Xhi, zero ; data == 0x40 t <= 0x10, so can never overflow LD tmp, X MOV t, tmp #undef tmp @@ -150,32 +156,32 @@ g: ; g(i, t) -> t test 3, m_1000 m_0000: shift16 always 4 - add_shift16 + add16 $ shift16 always 5 - add_shift8 + add8 $ shift8 never 6 shift8 always 7 - add_shift0 + add8 $ shift0 RJMP end_mul ; calc'd 0xb0 - m_1000: add_shift16 + m_1000: add16 $ shift16 always 4 - add_shift16 + add16 $ shift16 never 5 shift8 always 6 - add_shift8 + add8 $ shift8 never 7 shift0 RJMP end_mul ; calc'd 0x58 - m__100: add_shift16 + m__100: add16 $ shift16 test 3, m_1100 m_0100: shift16 RJMP upper_8 ;'ll calc 0x84 - - m_1100: add_shift16 +;TODO: combine shift16 above with add_shift16 below to save progmem + m_1100: add16 $ shift16 upper_8: ; used twice, so deduplicated never 4 shift16 @@ -184,48 +190,48 @@ g: ; g(i, t) -> t never 6 shift8 always 7 - add_shift0 + add8 $ shift0 RJMP end_mul ; calc'd 0x8c - m____1: add_shift16 + m____1: add16 $ shift16 never 1 m___01: shift16 test 2, m__101 m__001: shift16 always 3 - m_1001: add_shift16 + m_1001: add16 $ shift16 never 4 shift16 always 5 - add_shift8 + add8 $ shift8 always 6 - add_shift8 + add8 $ shift8 never 7 shift0 RJMP end_mul ; calc'd 0x69 - m__101: add_shift16 + m__101: add16 $ shift16 test 3, m_1101 m_0101: shift16 always 4 - add_shift16 + add16 $ shift16 always 5 - add_shift8 + add8 $ shift8 always 6 - add_shift8 + add8 $ shift8 never 7 shift0 RJMP end_mul ; calc'd 0x75 - m_1101: add_shift16 + m_1101: add16 $ shift16 always 4 - add_shift16 + add16 $ shift16 never 5 shift8 never 6 shift8 always 7 - add_shift0 + add8 $ shift0 ; calc'd 0x9d end_mul: @@ -237,15 +243,50 @@ g: ; g(i, t) -> t #undef a2 RET ; TODO: replace CALL/RET with IJMP? -main: +main: ; setup routine CLR zero CLR i0 CLR i1 CLR i2 CLR i3 - ;;TODO: setup stack pointer, portb, clock, sleep mode, timer0 + CLR acc ; we output a dummy sample before the actual first one + + #define one _ + LDI one, 1 + LDI x, 0x5f ; RAMEND + OUT SPL, x ; init stack ptr + OUT SPH, zero ; -"- + OUT PUEB, zero ; disable pullups + LDI x, 0x05 + OUT DDRB, x ; PORTB0:pwm, PORTB2:debug + LDI x, 0xd8 + OUT CCP, x ; change protected ioregs + OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz) + OUT WDTCSR, zero; turn off watchdog ;;TODO: incomplete - see datasheet pg48 + ; OUT SMCR, 2 ; sleep mode 'power down' ('idle' (default) has faster response time) + + ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler + LDI x, 0x81 + OUT TCCR0A, x + LDI x, 0x09 + OUT TCCR0B, x + OUT TIMSK0, one ; enable tim0_ovf + OUT TIFR0, one ; TODO: why? + SEI + #undef one RJMP sample -sample: ;;TODO: this will probably become the timer0 overflow interrupt handler + +loop: + SLEEP ; wait for interrupt + RJMP loop + +sample: + ; potential TODO: softcounter in r25 to only update duty cicle every n iterations + ; potential TODO: save/restore status register (SREG=0x3f) (only if something in mainloop) + + OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime + SBI PORTB, 2 ; to measure runtime + MOV n, i2 LSL n LSL n @@ -390,11 +431,13 @@ sample: ;;TODO: this will probably become the timer0 overflow interrupt handler #undef tmp ADD acc, t - SWAP acc - OUT OCR0AL, acc + SWAP acc ; acc<<4, to be passed to OCR0AL + SUBI i0, -1 SBCI i1, -1 SBCI i2, -1 SBCI i3, -1 - rjmp sample ;;TODO: -> RETI + CBI PORTB, 2 ; end runtime measurement + ;TODO: to reduce jitter: clear pending tim0_ovf (TIFR0[TOV0] <- 1) ? + RETI ; reenables interrupts