refactor mul .macros
[Chiptunes.git] / foo.S
diff --git a/foo.S b/foo.S
index 8e76812696dd0fdacb66dc155e153dfc33d67006..55718df70740ef24dfed2b502924b5e8c2f49705 100644 (file)
--- a/foo.S
+++ b/foo.S
 /* 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
Imprint / Impressum