optimize multiplication for space
[Chiptunes.git] / foo.S
CommitLineData
f180febe 1/* REGISTER NAMES */
6d672b87
TG
2#define acc r16
3#define i0 r17
4#define i1 r18
5#define i2 r19
6#define i3 r20
7#define n r21
8#define s r22
9#define t r23 //==Ml
f99fd6f3
TG
10#define x r24 //==a1==Mh
11#define _ r25 //==a2
12#define Xlo r26
13#define Xhi r27
ce618731 14#define one r28
f180febe
TG
15; r29
16; r30 Zlo
17; r31 Zhi
18; aliases:
ce618731
TG
19#define Ml t //mod3 vars
20#define Mh x // -"-
21#define a1 x //mul_ vars
22#define a2 _ // -"-
da32ed67 23
f180febe
TG
24/* I/O REGISTERS */
25OCR0AL = 0x26
26DDRB = 0x01
34fa6d04 27PORTB = 0x02
f180febe
TG
28PUEB = 0x03
29SPL = 0x3D
30SPH = 0x3E
31CCP = 0x3C
32CLKPSR = 0x36
2af726bc 33OSCCAL = 0x39
19e320a6 34WDTCSR = 0x31
f180febe
TG
35SMCR = 0x3A
36TCCR0A = 0x2E
37TCCR0B = 0x2D
38TIMSK0 = 0x2B
39TIFR0 = 0x2A
f99fd6f3
TG
40RAMEND = 0x5F
41FLASHM = 0x4000
4466dd8b 42
f180febe 43.section .text
19e320a6 44.org 0x0000 ; RESET interrupt
cf36b4c3
TG
45 CLR i0
46 CLR i1
47 CLR i2
19e320a6
TG
48 RJMP main
49.org 0x0008 ; TIM0_OVF interrupt
50 RJMP sample
4466dd8b 51
f99fd6f3
TG
52notes:
53 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
54 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
55
f180febe 56mod3: ; mod3(Mh.Ml) -> t
8d8c00e4 57 #define tmp _
65aa7cd6
TG
58 ADD Ml, Mh
59 CLR Mh
6d672b87 60 ADC Mh, Mh ; store carry in Mh
65aa7cd6
TG
61 MOV tmp, Ml
62 SWAP tmp
63 ANDI tmp, 0x0f
64 SWAP Mh
65 OR tmp, Mh
66 ANDI Ml, 0x0f
67 ADD Ml, tmp
68 MOV tmp, Ml
69 LSR tmp
70 LSR tmp
71 ANDI Ml, 0x03
72 ADD Ml, tmp
73 MOV tmp, Ml
74 LSR tmp
75 LSR tmp
76 ANDI Ml, 0x03
77 ADD Ml, tmp
78 CPI Ml, 3
26799bab 79 BRCS skip
65aa7cd6
TG
80 SUBI Ml, 3
81 skip:
4283632d 82 RET
8d8c00e4 83 #undef tmp
f180febe 84
f180febe 85g: ; g(i, t) -> t
6d672b87
TG
86 CLR a1
87
d35c3d70 88 #define tmp _
6d672b87 89 #define zero a1
65aa7cd6
TG
90 ANDI t, 0x07
91 MOV tmp, i2
92 ANDI tmp, 3
65aa7cd6
TG
93 CPSE tmp, zero
94 SUBI t, -8
6d672b87 95 #undef zero
02f61e33 96 #undef tmp
4466dd8b 97
d44d4b47
TG
98 LDI Xlo, lo8(notes)
99 ADD Xlo, t ; NOTE: can't overflow, since RAMEND == 0x5F
100 LD t, X
4466dd8b 101
986f12ae
TG
102 CLR a2
103
dd3193ab
TG
104 ; begin of mulitiplication:
105 LSR t
106 BRCC skip1
107 ADD a1, i0
108 ADC a2, i1
109 skip1:
110 LSR a2
111 ROR a1
112 LSR t
113 ; BRCC skip2 -- this bit is always zero
114 ; ADD a1, i0
115 ; ADC a2, i1
116 ;skip2:
117 LSR a2
118 ROR a1
119 LSR t
120 BRCC skip3
121 ADD a1, i0
122 ADC a2, i1
123 skip3:
124 LSR a2
125 ROR a1
126 LSR t
127 BRCC skip4
128 ADD a1, i0
129 ADC a2, i1
130 skip4:
131 LSR a2
132 ROR a1
133 LSR t
134 BRCC skip5
135 ADD a1, i0
136 ADC a2, i1
137 skip5:
138 LSR a2
139 ROR a1
140 LSR t
141 BRCC skip6 ;sbrc t, NNN
142 ADD a1, i0
143 skip6:
144 LSR a1
145 LSR t
146 BRCC skip7
147 ADD a1, i0
148 skip7:
149 LSR a1
150 LSR t
151 BRCC skip8
152 ADD a1, i0
153 skip8:
154 LSR a1
4466dd8b 155
2af726bc 156 MOV t, a1 ;;TODO: use a1 in loop: directly
ce618731 157 RET
61fab018 158
19e320a6 159main: ; setup routine
cf36b4c3 160 ; NOTE: clr i0..i2 moved to .ord 0x0
65aa7cd6 161 CLR i3
19e320a6 162 CLR acc ; we output a dummy sample before the actual first one
f99fd6f3 163 LDI Xhi, hi8(FLASHM + notes) ; never changes
ce618731 164 LDI one, 1 ; mostly for clearing TIM0_OVF bit
19e320a6 165
6d672b87 166 #define zero i0
f99fd6f3 167 LDI x, RAMEND
19e320a6
TG
168 OUT SPL, x ; init stack ptr
169 OUT SPH, zero ; -"-
170 OUT PUEB, zero ; disable pullups
ea40b11f
TG
171 LDI x, 0x05
172 OUT DDRB, x ; PORTB0:pwm, PORTB2:debug
19e320a6
TG
173 LDI x, 0xd8
174 OUT CCP, x ; change protected ioregs
175 OUT CLKPSR, one ; clock prescaler 1/2 (4Mhz)
2af726bc
TG
176 LDI x, 0xa7 ; determined by trial-and-error (->PORTB2)
177 OUT OSCCAL, x ; set oscillator calibration
ce618731 178 OUT WDTCSR, zero; turn off watchdog
19e320a6
TG
179
180 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
181 LDI x, 0x81
182 OUT TCCR0A, x
183 LDI x, 0x09
184 OUT TCCR0B, x
185 OUT TIMSK0, one ; enable tim0_ovf
19e320a6 186 SEI
6d672b87 187 #undef zero
19e320a6
TG
188
189loop:
190 SLEEP ; wait for interrupt
191 RJMP loop
192
193sample:
19e320a6 194 OUT OCR0AL, acc ; start by outputting a sample, because routine has variable runtime
ce618731 195#ifdef DEBUG
34fa6d04 196 SBI PORTB, 2 ; to measure runtime
ce618731 197#endif // DEBUG
19e320a6 198
65aa7cd6
TG
199 MOV n, i2
200 LSL n
201 LSL n
f6ef1520 202 #define tmp _
65aa7cd6
TG
203 MOV tmp, i1
204 SWAP tmp
205 ANDI tmp, 0x0f
206 LSR tmp
207 LSR tmp
208 OR n, tmp
f6ef1520 209 #undef tmp
65aa7cd6
TG
210 MOV s, i3
211 LSR s
212 ROR s
213 ANDI s, 0x80
f6ef1520 214 #define tmp _
65aa7cd6
TG
215 MOV tmp, i2
216 LSR tmp
217 OR s, tmp
f6ef1520 218 #undef tmp
3b86ca43 219
65aa7cd6
TG
220 ; voice 1:
221 MOV t, n
222 RCALL g
223 SWAP t
224 ANDI t, 1
225 MOV acc, t
3b86ca43 226
65aa7cd6 227 ; voice 2:
f6ef1520 228 #define tmp _
65aa7cd6
TG
229 MOV tmp, i2
230 LSL tmp
231 LSL tmp
232 LSL tmp
233 MOV t, i1
234 SWAP t
235 ANDI t, 0xf
236 LSR t
237 OR t, tmp
f6ef1520 238 #undef tmp
65aa7cd6
TG
239 EOR t, n
240 RCALL g
241 LSR t
242 LSR t
243 ANDI t, 3
244 AND t, s
245 ADD acc, t
3b86ca43 246
65aa7cd6
TG
247 ; voice 3:
248 MOV Ml, i2
249 SWAP Ml
250 ANDI Ml, 0xf0
251 LSL Ml
f6ef1520 252 #define tmp _
65aa7cd6
TG
253 MOV tmp, i1
254 LSR tmp
255 LSR tmp
256 LSR tmp
257 OR Ml, tmp
f6ef1520 258 #undef tmp
65aa7cd6
TG
259 MOV Mh, i3
260 SWAP Mh
261 ANDI Mh, 0xf0
262 LSL Mh
f6ef1520 263 #define tmp _
65aa7cd6
TG
264 MOV tmp, i2
265 LSR tmp
266 LSR tmp
267 LSR tmp
268 OR Mh, tmp
f6ef1520 269 #undef tmp
65aa7cd6
TG
270 RCALL mod3
271 ADD t, n
272 RCALL g
273 LSR t
274 LSR t
275 ANDI t, 3
276 MOV x, s
277 INC x
f6ef1520 278 #define tmp _
65aa7cd6
TG
279 MOV tmp, x
280 LSR tmp
281 LSR tmp
282 ADD tmp, x
283 ROR tmp
284 LSR tmp
285 ADD tmp, x
286 ROR tmp
287 LSR tmp
288 ADD tmp, x
289 ROR tmp
290 LSR tmp
291 AND t, tmp
f6ef1520 292 #undef tmp
65aa7cd6 293 ADD acc, t
f6ef1520 294
65aa7cd6
TG
295 ; voice 4:
296 MOV Ml, i2
297 SWAP Ml
298 ANDI Ml, 0xf0
299 LSL Ml
300 LSL Ml
f6ef1520 301 #define tmp _
65aa7cd6
TG
302 MOV tmp, i1
303 LSR tmp
304 LSR tmp
305 OR Ml, tmp
f6ef1520 306 #undef tmp
65aa7cd6
TG
307 MOV Mh, i3
308 SWAP Mh
309 ANDI Mh, 0xf0
310 LSL Mh
311 LSL Mh
f6ef1520 312 #define tmp _
65aa7cd6
TG
313 MOV tmp, i2
314 LSR tmp
315 LSR tmp
316 OR Mh, tmp
f6ef1520 317 #undef tmp
65aa7cd6
TG
318 RCALL mod3
319 SUB t, n
320 NEG t
321 SUBI t, -8
322 RCALL g
323 LSR t
324 ANDI t, 3
325 INC s
f6ef1520 326 #define tmp _
65aa7cd6
TG
327 MOV tmp, s
328 LSR tmp
329 ADD tmp, s
330 ROR tmp
331 LSR tmp
332 LSR tmp
333 ADD tmp, s
334 ROR tmp
335 ADD tmp, s
336 ROR tmp
337 LSR tmp
338 LSR tmp
339 AND t, tmp
f6ef1520 340 #undef tmp
65aa7cd6 341 ADD acc, t
3b86ca43 342
19e320a6
TG
343 SWAP acc ; acc<<4, to be passed to OCR0AL
344
f6ef1520
TG
345 SUBI i0, -1
346 SBCI i1, -1
347 SBCI i2, -1
348 SBCI i3, -1
bfce2f8c 349
ce618731
TG
350#ifdef DEBUG
351 CBI PORTB, 2 ; end runtime measurement
352#endif // DEBUG
353 OUT TIFR0, one ; clear pending interrupt (routine takes two intr.cycles)
19e320a6 354 RETI ; reenables interrupts
Imprint / Impressum