transcribe fakeasm into realasm (I)
[Chiptunes.git] / foo.S
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 // -"-
23
24 /* I/O REGISTERS */
25 OCR0AL = 0x26
26 DDRB = 0x01
27 PUEB = 0x03
28 SPL = 0x3D
29 SPH = 0x3E
30 CCP = 0x3C
31 CLKPSR = 0x36
32 SMCR = 0x3A
33 TCCR0A = 0x2E
34 TCCR0B = 0x2D
35 TIMSK0 = 0x2B
36 TIFR0 = 0x2A
37
38 .section .data
39 .byte 0x84, 0x9d, 0xb0, 0x69, 0x9d, 0x84, 0x69, 0x58
40 .byte 0x75, 0x8c, 0xb0, 0x69, 0x8c, 0x75, 0x69, 0x58
41
42 .section .text
43
44 mod3: ; mod3(Mh.Ml) -> t
45 #define tmp _
46 ADD (Ml, Mh)
47 CLR (Mh)
48 ADC (Mh, zero, carry) //Mh only holds the carry bit
49 MOV (tmp, Ml)
50 SWAP (tmp)
51 ANDI (tmp, 0x0f)
52 SWAP (Mh)
53 OR (tmp, Mh)
54 ANDI (Ml, 0x0f)
55 ADD (Ml, tmp)
56 MOV (tmp, Ml)
57 LSR (tmp)
58 LSR (tmp)
59 ANDI (Ml, 0x03)
60 ADD (Ml, tmp)
61 MOV (tmp, Ml)
62 LSR (tmp)
63 LSR (tmp)
64 ANDI (Ml, 0x03)
65 ADD (Ml, tmp)
66 CPI (Ml, 3)
67 BRPL (skip)
68 SUBI (Ml, 3)
69 skip:;
70 RET
71 #undef tmp
72
73 ; definitions to mul-tree readable:
74 .macro always _bit ; nop; for when a test() is not necessary (see tree)
75 .endm
76 .macro never _bit ; nop; for when a test() is not necessary (see tree)
77 .endm
78 .macro test _bit,_jmpto
79 SBRC t, _bit
80 RJMP _jmpto
81 .endm
82 .macro shift16
83 LSR a2
84 ROR a1
85 .endm
86 .macro shift8 ; top three bits don't need to be corrrect, so save cycles by not carrying
87 LSR a1
88 .endm
89 .macro shift0 ; nop; last shift is common
90 .endm
91 .macro add_shift16
92 ADD a1, i0
93 ADC a2, i1
94 shift16
95 .endm
96 .macro add_shift8 ; ditto with carrying
97 ADD a1, i0
98 shift8
99 .endm
100 .macro add_shift0 ; last shift is common
101 ADD a1, i0
102 .endm
103
104 g: ; g(i, t) -> t
105 #define tmp _
106 ANDI (t, 0x07)
107 MOV (tmp, i2)
108 ANDI (tmp, 3)
109 TST (tmp)
110 CPSE (tmp, zero)
111 SUBI (t, -8)
112 #undef tmp
113
114 #define tmp _
115 MOV (tmp, t) //NOTE: must move value away from `t`, as that is also hi(X)
116 tmp = data[tmp];/*
117 LDI Xhi, hi8(data)
118 LDI Xlo, lo8(data)
119 ADD Xlo, tmp ;<-- the offset (formerly `t`) into data[]
120 ADC Xhi, zero
121 LD tmp, X */
122 MOV (t, tmp)
123 #undef tmp
124
125 #define a1 x
126 #define a2 _
127 #define a0 t
128 CLR (a2)
129 CLR (a1)
130
131 /* decision tree multiplication saves cycles and (hopefully) reduces code size
132 _xxx?
133 / \
134 _xx?0 _xx1?
135 | |
136 _x?00 _x?01
137 / \ / \
138 _?000 _?100 _?001 _?101
139 / \ / \ | / \
140 _0000 _1000 _0100 _1100 _1001 _0101 _1101
141 | | | | | | |
142 ... ... ... ... ... ... ...
143 | | | | | | |
144 B0 58 84 8C 69 75 9D */
145 test (0, m____1)
146 m____0: shift16
147 never (1)
148 m___00: shift16
149 test (2, m__100)
150 m__000: shift16
151 test (3, m_1000)
152 m_0000: shift16
153 always (4)
154 add_shift16
155 always (5)
156 add_shift8
157 never (6)
158 shift8
159 always (7)
160 add_shift0
161 RJMP (end_mul) // calc'd 0xb0
162
163 m_1000: add_shift16
164 always (4)
165 add_shift16
166 never (5)
167 shift8
168 always (6)
169 add_shift8
170 never (7)
171 shift0
172 RJMP (end_mul) // calc'd 0x58
173
174 m__100: add_shift16
175 test (3, m_1100)
176 m_0100: shift16
177 RJMP (upper_8) //'ll calc 0x84
178
179 m_1100: add_shift16
180 upper_8: /* used twice, so deduplicated */
181 never (4)
182 shift16
183 never (5)
184 shift8
185 never (6)
186 shift8
187 always (7)
188 add_shift0
189 RJMP (end_mul) // calc'd 0x8c
190
191 m____1: add_shift16
192 never (1)
193 m___01: shift16
194 test (2, m__101)
195 m__001: shift16
196 always (3)
197 m_1001: add_shift16
198 never (4)
199 shift16
200 always (5)
201 add_shift8
202 always (6)
203 add_shift8
204 never (7)
205 shift0
206 RJMP (end_mul) // calc'd 0x69
207
208 m__101: add_shift16
209 test (3, m_1101)
210 m_0101: shift16
211 always (4)
212 add_shift16
213 always (5)
214 add_shift8
215 always (6)
216 add_shift8
217 never (7)
218 shift0
219 RJMP (end_mul) // calc'd 0x75
220
221 m_1101: add_shift16
222 always (4)
223 add_shift16
224 never (5)
225 shift8
226 never (6)
227 shift8
228 always (7)
229 add_shift0
230 // calc'd 0x9d
231
232 end_mul:
233 LSR (a1) //final shift is a common operation for all
234
235 MOV (t, a1) //TODO: use a1 in main() directly
236 #undef a0
237 #undef a1
238 #undef a2
239 RET //TODO: replace CALL/RET with IJMP? (requires undoing goto-mul-hack)
240
241 main:
242 CLR (zero)
243 CLR (i0)
244 CLR (i1)
245 CLR (i2)
246 CLR (i3)
247 //TODO: setup stack pointer, portb, clock, sleep mode, timer0
248 RJMP sample
249 sample: //TODO: this will probably become the timer0 overflow interrupt handler
250 MOV (n, i2)
251 LSL (n)
252 LSL (n)
253 #define tmp _
254 MOV (tmp, i1)
255 SWAP (tmp)
256 ANDI (tmp, 0x0f)
257 LSR (tmp)
258 LSR (tmp)
259 OR (n, tmp)
260 #undef tmp
261 MOV (s, i3)
262 LSR (s)
263 ROR (s)
264 ANDI (s, 0x80)
265 #define tmp _
266 MOV (tmp, i2)
267 LSR (tmp)
268 OR (s, tmp)
269 #undef tmp
270
271 //voice 1:
272 MOV (t, n)
273 RCALL g();
274 SWAP (t)
275 ANDI (t, 1)
276 MOV (acc, t)
277
278 //voice 2:
279 #define tmp _
280 MOV (tmp, i2)
281 LSL (tmp)
282 LSL (tmp)
283 LSL (tmp)
284 MOV (t, i1)
285 SWAP (t)
286 ANDI (t, 0xf)
287 LSR (t)
288 OR (t, tmp)
289 #undef tmp
290 EOR (t, n)
291 RCALL g();
292 LSR (t)
293 LSR (t)
294 ANDI (t, 3)
295 AND (t, s)
296 ADD (acc, t)
297
298 //voice 3:
299 MOV (Ml, i2)
300 SWAP (Ml)
301 ANDI (Ml, 0xf0)
302 LSL (Ml)
303 #define tmp _
304 MOV (tmp, i1)
305 LSR (tmp)
306 LSR (tmp)
307 LSR (tmp)
308 OR (Ml, tmp)
309 #undef tmp
310 MOV (Mh, i3)
311 SWAP (Mh)
312 ANDI (Mh, 0xf0)
313 LSL (Mh)
314 #define tmp _
315 MOV (tmp, i2)
316 LSR (tmp)
317 LSR (tmp)
318 LSR (tmp)
319 OR (Mh, tmp)
320 #undef tmp
321 RCALL mod3();
322 ADD (t, n)
323 RCALL g();
324 LSR (t)
325 LSR (t)
326 ANDI (t, 3)
327 MOV (x, s)
328 INC (x)
329 #define tmp _
330 MOV (tmp, x)
331 LSR (tmp)
332 LSR (tmp)
333 ADD (tmp, x)
334 ROR (tmp)
335 LSR (tmp)
336 ADD (tmp, x)
337 ROR (tmp)
338 LSR (tmp)
339 ADD (tmp, x)
340 ROR (tmp)
341 LSR (tmp)
342 AND (t, tmp)
343 #undef tmp
344 ADD (acc, t)
345
346 //voice 4:
347 MOV (Ml, i2)
348 SWAP (Ml)
349 ANDI (Ml, 0xf0)
350 LSL (Ml)
351 LSL (Ml)
352 #define tmp _
353 MOV (tmp, i1)
354 LSR (tmp)
355 LSR (tmp)
356 OR (Ml, tmp)
357 #undef tmp
358 MOV (Mh, i3)
359 SWAP (Mh)
360 ANDI (Mh, 0xf0)
361 LSL (Mh)
362 LSL (Mh)
363 #define tmp _
364 MOV (tmp, i2)
365 LSR (tmp)
366 LSR (tmp)
367 OR (Mh, tmp)
368 #undef tmp
369 RCALL mod3();
370 SUB (t, n)
371 NEG (t)
372 SUBI (t, -8)
373 RCALL g();
374 LSR (t)
375 ANDI (t, 3)
376 INC (s)
377 #define tmp _
378 MOV (tmp, s)
379 LSR (tmp)
380 ADD (tmp, s)
381 ROR (tmp)
382 LSR (tmp)
383 LSR (tmp)
384 ADD (tmp, s)
385 ROR (tmp)
386 ADD (tmp, s)
387 ROR (tmp)
388 LSR (tmp)
389 LSR (tmp)
390 AND (t, tmp)
391 #undef tmp
392 ADD (acc, t)
393
394 putchar(acc<<4); //TODO
395 SUBI (i0, -1)
396 ADC (i1, zero, !i0) //XXX: must use "sbci i1,-1" in the assembly version
397 ADC (i2, zero, !i0&&!i1) // sbci i2,-1
398 ADC (i3, zero, !i0&&!i1&&!i2) // sbci i3,-1
Imprint / Impressum