aboutsummaryrefslogtreecommitdiffstats
path: root/src/posprintf.s
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-20 22:32:04 +0200
committerBad Diode <bd@badd10de.dev>2021-05-20 22:53:09 +0200
commitd81fe3c22410be6beba3577c6985a07483da4694 (patch)
tree232bd4b2867263899b651b342eb38bcbdd50a96c /src/posprintf.s
parentab6fdd0347920cdcda9c4c3c9c3f01996adc48db (diff)
downloaduxngba-d81fe3c22410be6beba3577c6985a07483da4694.tar.gz
uxngba-d81fe3c22410be6beba3577c6985a07483da4694.zip
Apply asie's patch 2 for performance optimizations
This patch replaces the txt_printf with the public domain posprintf library.
Diffstat (limited to 'src/posprintf.s')
-rwxr-xr-xsrc/posprintf.s419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/posprintf.s b/src/posprintf.s
new file mode 100755
index 0000000..f3ef1e6
--- /dev/null
+++ b/src/posprintf.s
@@ -0,0 +1,419 @@
1/*
2
3posprintf - a condensed version of sprintf for Thumb, esp. GBA
4Copyright (C) 2003 Dan Posluns
5
6The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below.
7
8A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain.
9
10Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work.
11
12Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived.
13
14Author contact e-mail: dan at danposluns dot com
15
16
17register map:
18
19MAIN LOOP: PROCESS16:
20r0 <- dest string address r0 <- d0
21r1 <- source string address r1 <- d1
22r2 <- integer to print r2 <- d2
23r3 <- r3 <- d3
24r4 <- current char r4 <- d4
25r5 <- r5 <- work register
26r6 <- r6 <- work register
27r7 <- r7 <- dest string address
28r8 <- number of digits to print r8 <- number of digits to print
29r9 <- leading char (' ' or '0') r9 <- leading char (' ' or '0')
30r10 <- current parameter pointer r10 <- current parameter ptr
31r11 <- r11 <-
32r12 <- r12 <- source string address
33r14 <- r14 <- lr
34
35Function parameters:
36
37r0 <- destination string address
38r1 <- source string address
39r2 <- param1
40r3 <- param2
41
42*/
43 .thumb
44 .thumb_func
45 .align
46 .global posprintf
47 .type posprintf,function
48posprintf:
49
50 push {r3} @ push our second and third parameters
51 push {r2} @ onto the stack in reverse order
52 mov r12, sp @ r12 <- first parameter pointer
53
54 push {r4-r7} @ save clobbered registers
55 mov r4, r8
56 mov r5, r9
57 mov r6, r10
58 push {r4-r6, lr}
59 mov r10, r12 @ r10 <- first parameter pointer
60
61.L_STRINGLOOP:
62 ldrb r4, [r1] @ load a char from r1
63 add r1, #1 @ advance pointer to next char
64 cmp r4, #'%' @ if char == '%' then
65 beq .L_FORMATENTRY @ handle the format specifier
66 strb r4, [r0] @ store the char back to memory
67 add r0, #1 @ advance pointer to next char
68 cmp r4, #0 @ if char != 0 then
69 bne .L_STRINGLOOP @ repeat for next char
70 @ cleanup and exit
71 pop {r4-r7} @ restore clobbered registers
72 mov r8, r4
73 mov r9, r5
74 mov r10, r6
75 mov lr, r7
76 pop {r4-r7}
77 add sp, #8 @ remove parameters from stack
78 bx lr @ return from subroutine
79
80.L_FORMATENTRY:
81 mov r5, #0 @ assume no leading character for numbers
82 mov r6, #' ' @ assume print spaces if we do print leads
83 mov r8, r5
84 mov r9, r6
85.L_FORMATSPEC:
86 ldrb r4, [r1] @ load the next char from r1
87 add r1, #1 @ advance pointer to next char
88 cmp r4, #'d' @ if char == 'd'
89 beq .L_PRINT16 @ print 16-bit number
90 cmp r4, #'s' @ if char == 's'
91 beq .L_PRINTSTR @ print string
92 cmp r4, #'0' @ if char == '0'
93 beq .L_SETLEAD @ print with leading zeros
94 cmp r4, #'%' @ if char == '%'
95 beq .L_PRINTSYMBOL @ print '%' character
96 cmp r4, #'l' @ if char == 'l'
97 beq .L_PRINT29 @ print 29-bit number
98 cmp r4, #'X' @ if char == 'X'
99 beq .L_PRINTHEXUC @ print hexadecimal uppercase
100 cmp r4, #'x' @ if char == 'x'
101 beq .L_PRINTHEXLC @ print hexadecimal lowercase
102 @ we now assume that we are choosing a number of leading digits to display
103 sub r4, #'0'
104 mov r8, r4 @ r8 <- char - '0'
105 b .L_FORMATSPEC
106
107.L_SETLEAD:
108 mov r6, #'0'
109 mov r9, r6 @ print leading zeros instead of spaces
110 b .L_FORMATSPEC
111
112.L_PRINTSYMBOL:
113 strb r4, [r0] @ store '%' symbol to memory
114 add r0, #1 @ advance pointer to next char
115 b .L_STRINGLOOP
116
117.L_PRINTSTR:
118 mov r4, r10 @ r4 <- current parameter pointer
119 ldr r2, [r4] @ r2 <- address of string to print
120 add r4, #4
121 mov r10, r4 @ increase parameter pointer
122.L_PRINTSTRLOOP:
123 ldrb r4, [r2] @ load a char from r2
124 add r2, #1 @ advance pointer to next char
125 cmp r4, #0 @ if char == 0
126 beq .L_STRINGLOOP @ then we are done
127 strb r4, [r0] @ store the char back to memory
128 add r0, #1 @ advance pointer to next char
129 b .L_PRINTSTRLOOP
130
131.L_PRINT16:
132 mov r7, r0 @ r7 <- dest string address
133 mov r4, r10 @ r4 <- current parameter pointer
134 ldr r0, [r4] @ r0 <- 16-bit integer to print
135 add r4, #4
136 mov r10, r4 @ increase parameter pointer
137 mov r3, #0 @ temp marker for L_PRINTSIGN
138 cmp r0, #0 @ if integer to print is negative
139 blt .L_PRINTSIGN @ print the sign and adjust
140.L_SIGNDONE:
141 mov lr, pc @ save this location
142 bl .L_PROCESS16 @ process a 16-bit number
143 b .L_STRINGLOOP @ return when done
144
145.L_PRINTSIGN:
146 mov r4, #'-'
147 strb r4, [r7] @ print '-' character
148 add r7, #1 @ advance pointer to next char
149 neg r0, r0 @ r2 is now positive
150 mov r4, r8
151 sub r4, #1 @ print one fewer character
152 mov r8, r4 @ r8 <- new value
153 cmp r3, #0 @ check to see who called us
154 beq .L_SIGNDONE
155 b .L_SIGN29DONE
156
157.L_PRINT29:
158 mov r7, r0 @ r7 <- dest string address
159 mov r4, r10 @ r4 <- current parameter pointer
160 ldr r0, [r4] @ r0 <- 16-bit integer to print
161 add r4, #4
162 mov r10, r4 @ increase parameter pointer
163 mov r3, #1 @ temp marker for L_PRINTSIGN
164 cmp r0, #0 @ if integer to print is negative
165 blt .L_PRINTSIGN @ print the sign and adjust
166.L_SIGN29DONE:
167 mov r12, r1
168 mov r1, #0x27
169 lsl r1, r1, #8
170 add r1, #0x10 @ r1 <- 0x2710 == 10000
171 swi 6 @ split number by dividing by 10000
172 mov r3, #0
173 sub r3, #4
174 add r8, r3 @ subtract 4 from digits to display
175 cmp r0, #0 @ if the first chunk is empty
176 beq .L_P29SKIP @ then skip it
177 push {r1} @ save the second number to display
178 mov r1, r12
179 mov lr, pc @ save this location
180 bl .L_PROCESS16 @ process a 16-bit number
181 mov r12, r1
182 pop {r1} @ load in the second number
183 mov r3, #0
184 mov r8, r3 @ print leading symbols now!
185 mov r3, #'0'
186 mov r9, r3 @ make sure they are zeros!
187.L_P29SKIP:
188 mov r0, r1 @ get ready to print second number
189 mov r1, #4
190 add r8, r1 @ add 4 back on to digits
191 mov r1, r12
192 mov lr, pc @ save this location
193 bl .L_PROCESS16 @ process a 16-bit number
194 b .L_STRINGLOOP
195
196.L_PRINTHEXLC:
197 mov r7, #39
198 mov r12, r7 @ lowercase offset
199 b .L_PRINTHEX
200.L_PRINTHEXUC:
201 mov r7, #7
202 mov r12, r7 @ uppercase offset
203.L_PRINTHEX:
204 mov r4, r10 @ r4 <- current parameter pointer
205 ldr r2, [r4] @ r2 <- integer to print
206 add r4, #4
207 mov r10, r4 @ increase parameter pointer
208 mov r4, #28 @ r4 <- 8 digits to cycle through
209 mov r6, #0xF @ r6 <- nibble mask
210 mov r7, #0 @ r7 <- print flag
211.L_PRINTHEXLOOP:
212 mov r3, r2
213 lsr r3, r4
214 and r3, r6 @ r3 <- (n >> (cycle * 4)) & 0xF
215 orr r7, r3 @ if we have not encountered a digit
216 beq .L_PH_LEADZERO @ then it is a leading zero
217 add r3, #'0'
218 mov r5, r12 @ get ready to print a letter
219 cmp r3, #'9' @ if the digit is in the alpha range
220 bgt .L_PH_ALPHA @ then print a letter
221 mov r5, #0 @ else do nothing
222.L_PH_ALPHA:
223 add r3, r5 @ add offset to correct letter
224 strb r3, [r0] @ store the char in memory
225 add r0, #1 @ advance pointer to next char
226 sub r4, #4 @ advance to next digit
227 bge .L_PRINTHEXLOOP @ loop until done
228 b .L_STRINGLOOP
229
230.L_PH_LEADZERO:
231 lsr r5, r4, #2 @ r5 <- which digit we are on
232 sub r4, #4 @ if this is our last digit
233 blt .L_PH_FINAL @ then print a zero for sure
234 cmp r8, r5 @ if r8 < current digit
235 ble .L_PRINTHEXLOOP @ then keep looping
236 mov r5, r9 @ r5 <- leading symbol to print
237 strb r5, [r0] @ store the char in memory
238 add r0, #1 @ advance pointer to next char
239 b .L_PRINTHEXLOOP
240.L_PH_FINAL:
241 mov r3, #'0' @ if n == 0, print at least one 0
242 strb r3, [r0]
243 add r0, #1
244 b .L_STRINGLOOP
245
246.L_PROCESS16:
247 mov r12, r1 @ free up registers
248 mov r5, #0xF
249 lsr r1, r0, #4
250 lsr r2, r0, #8
251 lsr r3, r0, #12
252 and r0, r5 @ r0 <- n & 0xF
253 and r1, r5 @ r1 <- (n >> 4) & 0xF
254 and r2, r5 @ r2 <- (n >> 8) & 0xF
255 and r3, r5 @ r3 <- (n >> 12) & 0xF
256 mov r6, r3
257 add r6, r2
258 add r6, r1
259 lsl r5, r6, #2
260 lsl r6, r6, #1
261 add r0, r6
262 add r0, r5 @ r0 <- 6 * (d3 + d2 + d1) + d0
263 @ divide by ten: multiply by 0x19A shifted right by 12
264 lsr r5, r0, #2
265 add r5, r0
266 lsr r5, r5, #1 @ r5 <- ((d0 >> 2) + i) >> 1
267 add r5, r0
268 lsr r5, r5, #3 @ r5 = (r5 + d0) >> 3
269 add r5, r0
270 lsr r5, r5, #1 @ r5 = (r5 + d0) >> 1
271 add r5, r0
272 lsr r5, r5, #4 @ r5 <- d0 / 10
273 @ calculate remainder as d0
274 lsl r6, r5, #2
275 add r6, r5
276 lsl r6, r6, #1 @ r6 <- q * 10
277 sub r0, r6 @ r0 <- d0 - (q * 10)
278 @ finished with d0, now calculate d1
279 lsl r6, r3, #3
280 add r5, r6
281 add r5, r3 @ r5 <- q + 9 * d3
282 lsl r6, r2, #2
283 add r5, r6
284 add r5, r2 @ r5 <- q + 9 * d3 + 5 * d2
285 add r1, r5 @ r1 <- d1 + r5
286 beq .L_LEAD_D1
287 @ divide d1 by ten: multiply by 0x19A shifted right by 12
288 lsr r5, r1, #2
289 add r5, r1
290 lsr r5, r5, #1
291 add r5, r1
292 lsr r5, r5, #3
293 add r5, r1
294 lsr r5, r5, #1
295 add r5, r1
296 lsr r5, r5, #4 @ r5 <- d1 / 10
297 @ calculate remainder as d1
298 lsl r6, r5, #2
299 add r6, r5
300 lsl r6, r6, #1
301 sub r1, r6 @ r1 <- d1 - (q * 10)
302 @ finished with d1, now calculate d2
303 lsl r2, r2, #1
304 add r2, r5 @ r2 <- 2 * d2 + q
305 mov r5, r2
306 orr r5, r3 @ if (!d2) && (!d3)
307 beq .L_LEAD_D2 @ then skip
308 @ divide d2 by ten: multiply by 0x1A >> 8 is sufficient
309 lsr r5, r2, #2
310 add r5, r2
311 lsr r5, r5, #1
312 add r5, r2
313 lsr r5, r5, #4 @ r5 <- d2 / 10
314 @ calculate remainder as d2
315 lsl r6, r5, #2
316 add r6, r5
317 lsl r6, r6, #1
318 sub r2, r6 @ r2 <- d2 - (q * 10)
319 @ finished with d2, now calculate d3
320 lsl r3, r3, #2
321 add r3, r5
322 beq .L_LEAD_D3
323 @ divide d3 by ten: multiply by 0x1A >> 8 is sufficient
324 lsr r5, r3, #2
325 add r5, r3
326 lsr r5, r5, #1
327 add r5, r3
328 lsr r5, r5, #4 @ r5 <- d3 / 10
329 @ calculate remainder as d3
330 lsl r6, r5, #2
331 add r6, r5
332 lsl r6, r6, #1
333 sub r3, r6 @ r3 <- d3 - (q * 10)
334 @ finished with d3, d4 will automatically be quotient
335 mov r4, r5
336 beq .L_LEAD_D4
337 @ now print any leading digits if we are using all five
338 mov r5, r8
339 mov r6, r9
340 sub r5, #4 @ already printed five digits
341.L_EXTRA_LEAD_LOOP:
342 sub r5, #1
343 ble .L_DONE_EXTRA_LEAD
344 strb r6, [r7] @ print a leading character
345 add r7, #1
346 b .L_EXTRA_LEAD_LOOP
347.L_DONE_EXTRA_LEAD:
348 @ now print the fifth digit (d4)
349 add r4, #'0' @ r4 <- d4 + '0'
350 strb r4, [r7] @ store a character
351 add r7, #1 @ advance string pointer
352.L_DONE_D4:
353 add r3, #'0'
354 strb r3, [r7]
355 add r7, #1
356.L_DONE_D3:
357 add r2, #'0'
358 strb r2, [r7]
359 add r7, #1
360.L_DONE_D2:
361 add r1, #'0'
362 strb r1, [r7]
363 add r7, #1
364.L_DONE_D1:
365 add r0, #'0'
366 strb r0, [r7]
367 add r7, #1
368 @ Done at last! Clean up and return to calling routine
369 mov r0, r7 @ restore r0 <- dest string address
370 mov r1, r12 @ restore r1 <- source string address
371 mov pc, lr @ return from subroutine
372
373.L_LEAD_D4:
374 mov r5, r9 @ r5 <- leading character
375 mov r6, r8
376 sub r6, #4 @ r6 <- # of chars to print
377 ble .L_DONE_D4
378.L_IN_D4:
379 strb r5, [r7] @ store a character
380 add r7, #1 @ advance string pointer
381 sub r6, #1 @ if chars to print > 0
382 bgt .L_IN_D4 @ then loop
383 b .L_DONE_D4
384
385.L_LEAD_D3:
386 mov r5, r9 @ r5 <- leading character
387 mov r6, r8
388 sub r6, #3 @ r6 <- # of chars to print
389 ble .L_DONE_D3
390.L_IN_D3:
391 strb r5, [r7] @ store a character
392 add r7, #1 @ advance string pointer
393 sub r6, #1 @ if chars to print > 0
394 bgt .L_IN_D3 @ then loop
395 b .L_DONE_D3
396
397.L_LEAD_D2:
398 mov r5, r9 @ r5 <- leading character
399 mov r6, r8
400 sub r6, #2 @ r6 <- # of chars to print
401 ble .L_DONE_D2
402.L_IN_D2:
403 strb r5, [r7] @ store a character
404 add r7, #1 @ advance string pointer
405 sub r6, #1 @ if chars to print > 0
406 bgt .L_IN_D2 @ then loop
407 b .L_DONE_D2
408
409.L_LEAD_D1:
410 mov r5, r9 @ r5 <- leading character
411 mov r6, r8
412 sub r6, #1 @ r6 <- # of chars to print
413 ble .L_DONE_D1
414.L_IN_D1:
415 strb r5, [r7] @ store a character
416 add r7, #1 @ advance string pointer
417 sub r6, #1 @ if chars to print > 0
418 bgt .L_IN_D1 @ then loop
419 b .L_DONE_D1