initialisation code, interrupt vector table
[Chiptunes.git] / foo.S
CommitLineData
f180febe
TG
1/* REGISTER NAMES */
2#define zero r16
3#define acc r17
4#define i0 r18
5#define i1 r19
6#define i2 r20
7#define i3 r21
8#define n r22
9#define s r23
10#define _ r24
11; r25
12#define x r26 //==Xlo==Mh
13#define t r27 //==Xhi==Ml
14; r28
15; r29
16; r30 Zlo
17; r31 Zhi
18; aliases:
19#define Xlo r26
20#define Xhi r27
21#define Mh r26 //mod3 vars
22#define Ml r27 // -"-
da32ed67 23
f180febe
TG
24/* I/O REGISTERS */
25OCR0AL = 0x26
26DDRB = 0x01
27PUEB = 0x03
28SPL = 0x3D
29SPH = 0x3E
30CCP = 0x3C
31CLKPSR = 0x36
19e320a6 32WDTCSR = 0x31
f180febe
TG
33SMCR = 0x3A
34TCCR0A = 0x2E
35TCCR0B = 0x2D
36TIMSK0 = 0x2B
37TIFR0 = 0x2A
4466dd8b 38
f180febe 39.section .data
65958d9d 40data:
f180febe
TG
41 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
42 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
4466dd8b 43
f180febe 44.section .text
19e320a6
TG
45.org 0x0000 ; RESET interrupt
46 RJMP main
47.org 0x0008 ; TIM0_OVF interrupt
48 RJMP sample
4466dd8b 49
f180febe 50mod3: ; mod3(Mh.Ml) -> t
8d8c00e4 51 #define tmp _
65aa7cd6
TG
52 ADD Ml, Mh
53 CLR Mh
54 ADC Mh, zero
55 MOV tmp, Ml
56 SWAP tmp
57 ANDI tmp, 0x0f
58 SWAP Mh
59 OR tmp, Mh
60 ANDI Ml, 0x0f
61 ADD Ml, tmp
62 MOV tmp, Ml
63 LSR tmp
64 LSR tmp
65 ANDI Ml, 0x03
66 ADD Ml, tmp
67 MOV tmp, Ml
68 LSR tmp
69 LSR tmp
70 ANDI Ml, 0x03
71 ADD Ml, tmp
72 CPI Ml, 3
73 BRPL skip
74 SUBI Ml, 3
75 skip:
4283632d 76 RET
8d8c00e4 77 #undef tmp
f180febe
TG
78
79; definitions to mul-tree readable:
65958d9d
TG
80#define a1 x
81#define a2 _
f180febe
TG
82.macro always _bit ; nop; for when a test() is not necessary (see tree)
83.endm
84.macro never _bit ; nop; for when a test() is not necessary (see tree)
85.endm
86.macro test _bit,_jmpto
65958d9d
TG
87 SBRC t, \_bit
88 RJMP \_jmpto
f180febe
TG
89.endm
90.macro shift16
91 LSR a2
92 ROR a1
93.endm
94.macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
95 LSR a1
96.endm
97.macro shift0 ; nop; last shift is common
98.endm
99.macro add_shift16
100 ADD a1, i0
101 ADC a2, i1
4466dd8b 102 shift16
f180febe
TG
103.endm
104.macro add_shift8 ; ditto with carrying
105 ADD a1, i0
4466dd8b 106 shift8
f180febe
TG
107.endm
108.macro add_shift0 ; last shift is common
109 ADD a1, i0
110.endm
65958d9d
TG
111#undef a2
112#undef a1
f180febe
TG
113
114g: ; g(i, t) -> t
d35c3d70 115 #define tmp _
65aa7cd6
TG
116 ANDI t, 0x07
117 MOV tmp, i2
118 ANDI tmp, 3
119 TST tmp
120 CPSE tmp, zero
121 SUBI t, -8
02f61e33 122 #undef tmp
4466dd8b
TG
123
124 #define tmp _
65aa7cd6
TG
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)
4466dd8b
TG
127 LDI Xlo, lo8(data)
128 ADD Xlo, tmp ;<-- the offset (formerly `t`) into data[]
65aa7cd6
TG
129 ADC Xhi, zero ; ditto skip
130 LD tmp, X
131 MOV t, tmp
4466dd8b
TG
132 #undef tmp
133
cc428230
TG
134 #define a1 x
135 #define a2 _
136 #define a0 t
65aa7cd6
TG
137 CLR a2
138 CLR a1
d0324785 139
4466dd8b
TG
140 /* decision tree multiplication saves cycles and (hopefully) reduces code size
141 _xxx?
142 / \
143 _xx?0 _xx1?
144 | |
145 _x?00 _x?01
146 / \ / \
147 _?000 _?100 _?001 _?101
148 / \ / \ | / \
149 _0000 _1000 _0100 _1100 _1001 _0101 _1101
150 | | | | | | |
151 ... ... ... ... ... ... ...
152 | | | | | | |
153 B0 58 84 8C 69 75 9D */
65aa7cd6 154 test 0, m____1
4466dd8b 155 m____0: shift16
65aa7cd6 156 never 1
4466dd8b 157 m___00: shift16
65aa7cd6 158 test 2, m__100
4466dd8b 159 m__000: shift16
65aa7cd6 160 test 3, m_1000
4466dd8b 161 m_0000: shift16
65aa7cd6 162 always 4
4466dd8b 163 add_shift16
65aa7cd6 164 always 5
4466dd8b 165 add_shift8
65aa7cd6 166 never 6
4466dd8b 167 shift8
65aa7cd6 168 always 7
4466dd8b 169 add_shift0
65aa7cd6 170 RJMP end_mul ; calc'd 0xb0
d0324785 171
4466dd8b 172 m_1000: add_shift16
65aa7cd6 173 always 4
4466dd8b 174 add_shift16
65aa7cd6 175 never 5
4466dd8b 176 shift8
65aa7cd6 177 always 6
4466dd8b 178 add_shift8
65aa7cd6 179 never 7
4466dd8b 180 shift0
65aa7cd6 181 RJMP end_mul ; calc'd 0x58
d0324785 182
4466dd8b 183 m__100: add_shift16
65aa7cd6 184 test 3, m_1100
4466dd8b 185 m_0100: shift16
65aa7cd6 186 RJMP upper_8 ;'ll calc 0x84
d0324785 187
4466dd8b 188 m_1100: add_shift16
65aa7cd6
TG
189 upper_8: ; used twice, so deduplicated
190 never 4
4466dd8b 191 shift16
65aa7cd6 192 never 5
4466dd8b 193 shift8
65aa7cd6 194 never 6
4466dd8b 195 shift8
65aa7cd6 196 always 7
4466dd8b 197 add_shift0
65aa7cd6 198 RJMP end_mul ; calc'd 0x8c
d0324785 199
4466dd8b 200 m____1: add_shift16
65aa7cd6 201 never 1
4466dd8b 202 m___01: shift16
65aa7cd6 203 test 2, m__101
4466dd8b 204 m__001: shift16
65aa7cd6 205 always 3
4466dd8b 206 m_1001: add_shift16
65aa7cd6 207 never 4
4466dd8b 208 shift16
65aa7cd6 209 always 5
4466dd8b 210 add_shift8
65aa7cd6 211 always 6
4466dd8b 212 add_shift8
65aa7cd6 213 never 7
4466dd8b 214 shift0
65aa7cd6 215 RJMP end_mul ; calc'd 0x69
d0324785 216
4466dd8b 217 m__101: add_shift16
65aa7cd6 218 test 3, m_1101
4466dd8b 219 m_0101: shift16
65aa7cd6 220 always 4
4466dd8b 221 add_shift16
65aa7cd6 222 always 5
4466dd8b 223 add_shift8
65aa7cd6 224 always 6
4466dd8b 225 add_shift8
65aa7cd6 226 never 7
4466dd8b 227 shift0
65aa7cd6 228 RJMP end_mul ; calc'd 0x75
d0324785 229
4466dd8b 230 m_1101: add_shift16
65aa7cd6 231 always 4
4466dd8b 232 add_shift16
65aa7cd6 233 never 5
4466dd8b 234 shift8
65aa7cd6 235 never 6
4466dd8b 236 shift8
65aa7cd6 237 always 7
4466dd8b 238 add_shift0
65aa7cd6 239 ; calc'd 0x9d
d0324785 240
4466dd8b 241 end_mul:
65aa7cd6 242 LSR a1 ;final shift is a common operation for all
4466dd8b 243
65aa7cd6 244 MOV t, a1 ;;TODO: use a1 in main() directly
d0324785
TG
245 #undef a0
246 #undef a1
247 #undef a2
65aa7cd6 248 RET ; TODO: replace CALL/RET with IJMP?
61fab018 249
19e320a6 250main: ; setup routine
65aa7cd6
TG
251 CLR zero
252 CLR i0
253 CLR i1
254 CLR i2
255 CLR i3
19e320a6
TG
256 CLR acc ; we output a dummy sample before the actual first one
257
258 #define one _
259 LDI one, 1
260 LDI x, 0x5f ; RAMEND
261 OUT SPL, x ; init stack ptr
262 OUT SPH, zero ; -"-
263 OUT PUEB, zero ; disable pullups
264 OUT DDRB, one ; PORTB[0] as output
265 LDI x, 0xd8
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)
270
271 ;set timer/counter0 to 8bit fastpwm, non-inverting, no prescaler
272 LDI x, 0x81
273 OUT TCCR0A, x
274 LDI x, 0x09
275 OUT TCCR0B, x
276 OUT TIMSK0, one ; enable tim0_ovf
277 OUT TIFR0, one ; TODO: why?
278 SEI
279 #undef one
f180febe 280 RJMP sample
19e320a6
TG
281
282loop:
283 SLEEP ; wait for interrupt
284 RJMP loop
285
286sample:
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
290
65aa7cd6
TG
291 MOV n, i2
292 LSL n
293 LSL n
f6ef1520 294 #define tmp _
65aa7cd6
TG
295 MOV tmp, i1
296 SWAP tmp
297 ANDI tmp, 0x0f
298 LSR tmp
299 LSR tmp
300 OR n, tmp
f6ef1520 301 #undef tmp
65aa7cd6
TG
302 MOV s, i3
303 LSR s
304 ROR s
305 ANDI s, 0x80
f6ef1520 306 #define tmp _
65aa7cd6
TG
307 MOV tmp, i2
308 LSR tmp
309 OR s, tmp
f6ef1520 310 #undef tmp
3b86ca43 311
65aa7cd6
TG
312 ; voice 1:
313 MOV t, n
314 RCALL g
315 SWAP t
316 ANDI t, 1
317 MOV acc, t
3b86ca43 318
65aa7cd6 319 ; voice 2:
f6ef1520 320 #define tmp _
65aa7cd6
TG
321 MOV tmp, i2
322 LSL tmp
323 LSL tmp
324 LSL tmp
325 MOV t, i1
326 SWAP t
327 ANDI t, 0xf
328 LSR t
329 OR t, tmp
f6ef1520 330 #undef tmp
65aa7cd6
TG
331 EOR t, n
332 RCALL g
333 LSR t
334 LSR t
335 ANDI t, 3
336 AND t, s
337 ADD acc, t
3b86ca43 338
65aa7cd6
TG
339 ; voice 3:
340 MOV Ml, i2
341 SWAP Ml
342 ANDI Ml, 0xf0
343 LSL Ml
f6ef1520 344 #define tmp _
65aa7cd6
TG
345 MOV tmp, i1
346 LSR tmp
347 LSR tmp
348 LSR tmp
349 OR Ml, tmp
f6ef1520 350 #undef tmp
65aa7cd6
TG
351 MOV Mh, i3
352 SWAP Mh
353 ANDI Mh, 0xf0
354 LSL Mh
f6ef1520 355 #define tmp _
65aa7cd6
TG
356 MOV tmp, i2
357 LSR tmp
358 LSR tmp
359 LSR tmp
360 OR Mh, tmp
f6ef1520 361 #undef tmp
65aa7cd6
TG
362 RCALL mod3
363 ADD t, n
364 RCALL g
365 LSR t
366 LSR t
367 ANDI t, 3
368 MOV x, s
369 INC x
f6ef1520 370 #define tmp _
65aa7cd6
TG
371 MOV tmp, x
372 LSR tmp
373 LSR tmp
374 ADD tmp, x
375 ROR tmp
376 LSR tmp
377 ADD tmp, x
378 ROR tmp
379 LSR tmp
380 ADD tmp, x
381 ROR tmp
382 LSR tmp
383 AND t, tmp
f6ef1520 384 #undef tmp
65aa7cd6 385 ADD acc, t
f6ef1520 386
65aa7cd6
TG
387 ; voice 4:
388 MOV Ml, i2
389 SWAP Ml
390 ANDI Ml, 0xf0
391 LSL Ml
392 LSL Ml
f6ef1520 393 #define tmp _
65aa7cd6
TG
394 MOV tmp, i1
395 LSR tmp
396 LSR tmp
397 OR Ml, tmp
f6ef1520 398 #undef tmp
65aa7cd6
TG
399 MOV Mh, i3
400 SWAP Mh
401 ANDI Mh, 0xf0
402 LSL Mh
403 LSL Mh
f6ef1520 404 #define tmp _
65aa7cd6
TG
405 MOV tmp, i2
406 LSR tmp
407 LSR tmp
408 OR Mh, tmp
f6ef1520 409 #undef tmp
65aa7cd6
TG
410 RCALL mod3
411 SUB t, n
412 NEG t
413 SUBI t, -8
414 RCALL g
415 LSR t
416 ANDI t, 3
417 INC s
f6ef1520 418 #define tmp _
65aa7cd6
TG
419 MOV tmp, s
420 LSR tmp
421 ADD tmp, s
422 ROR tmp
423 LSR tmp
424 LSR tmp
425 ADD tmp, s
426 ROR tmp
427 ADD tmp, s
428 ROR tmp
429 LSR tmp
430 LSR tmp
431 AND t, tmp
f6ef1520 432 #undef tmp
65aa7cd6 433 ADD acc, t
3b86ca43 434
19e320a6
TG
435 SWAP acc ; acc<<4, to be passed to OCR0AL
436
f6ef1520
TG
437 SUBI i0, -1
438 SBCI i1, -1
439 SBCI i2, -1
440 SBCI i3, -1
bfce2f8c 441
19e320a6 442 RETI ; reenables interrupts
Imprint / Impressum