aboutsummaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--src/main.c3
-rwxr-xr-xsrc/posprintf.h1
-rwxr-xr-xsrc/posprintf.s419
-rw-r--r--src/text.h18
-rw-r--r--src/uxn/opcodes.c315
-rw-r--r--src/uxn/uxn.c4
6 files changed, 746 insertions, 14 deletions
diff --git a/src/main.c b/src/main.c
index bdff100..6df282d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,11 +39,12 @@ nil_talk(Device *d, Uint8 b0, Uint8 w) {
39 39
40void 40void
41console_talk(Device *d, u8 b0, u8 w) { 41console_talk(Device *d, u8 b0, u8 w) {
42 char stmp[2];
42 if(!w) { 43 if(!w) {
43 return; 44 return;
44 } 45 }
45 switch(b0) { 46 switch(b0) {
46 case 0x8: txt_printf("%c", d->dat[0x8]); break; 47 case 0x8: stmp[0] = d->dat[0x8]; stmp[1] = 0; txt_printf(stmp); break;
47 case 0x9: txt_printf("0x%02x", d->dat[0x9]); break; 48 case 0x9: txt_printf("0x%02x", d->dat[0x9]); break;
48 case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break; 49 case 0xb: txt_printf("0x%04x", mempeek16(d->dat, 0xa)); break;
49 case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break; 50 case 0xd: txt_printf("%s", &d->mem[mempeek16(d->dat, 0xc)]); break;
diff --git a/src/posprintf.h b/src/posprintf.h
new file mode 100755
index 0000000..a560db5
--- /dev/null
+++ b/src/posprintf.h
@@ -0,0 +1 @@
/* posprintf - a condensed version of sprintf for Thumb, esp. GBA Copyright (C) 2003 Dan Posluns The 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. A 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. Dedicator 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. Dedicator 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. Author contact e-mail: dan at danposluns dot com INSTRUCTIONS: To call: posprintf(char *dest, const char *src[, param1[, param2[, ... paramN]]]); - src must be a valid zero-terminated C string. - dest must point to a sufficiently large block of memory to contain the result string. The following format specifiers are valid: %% - print a '%' symbol %s - print a string; parameter must point to a valid zero-terminated C string %d - print a 16-bit (short) integer; must be within [-65,535 .. 65,535] %l - print a 29-bit integer; approximate range [-500,000,000 .. 500,000,000] %x - print a hexadecimal number (lowercase digits) %X - print a hexadecimal number (uppercase digits) The specifiers %d, %l, %x and %X may be modified as follows: - Digits 1 through 9 indicate number of leading spaces to print, eg. %5d would print the number 123 as " 123" %5d would print the number 123456 as "123456" (no leading spaces) - When above digit is prefixed with 0, leading zeros are printed instead of spaces %05d would print the number 123 as "00123" %04d would print the number 12345 as "12345" (no leading zeros) - Negative sign consumes a leading space, eg. %05d would print the number -123 as "-0123" (Hexadecimal numbers are considered unsigned) IF YOU WANT MORE FUNCTIONALITY THAN THIS, YOU CAN FEEL FREE TO MODIFY THE CODE, BUT THEN I WOULD SUGGEST MOVING TO A MORE SOPHISTICATED LIBRARY ANYWAY. *** CAUTION IF NOT USED ON GAMEBOY ADVANCE *** Although this is mostly written as general Thumb code, the %l (29-bit print) specifier code currently uses a software interrupt (SWI) specific to the Gameboy Advance to perform a division. If you wish to port this to other ARM machines, you may need to alter this code. I believe that most ARM machines support SWI 7 as an alternative software divide, although you will have to swap the numerator/denominator registers (r0 and r1). *** END CAUTION *** My contact e-mail is: dan at danposluns dot com */ extern void posprintf(char *, const char *, ...); \ No newline at end of file
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
diff --git a/src/text.h b/src/text.h
index eb6149d..1142a73 100644
--- a/src/text.h
+++ b/src/text.h
@@ -250,17 +250,13 @@ txt_init_hybrid(TextMode mode, Font font, u32 *buf) {
250} 250}
251 251
252// Print text to the screen with formatting. 252// Print text to the screen with formatting.
253void 253
254txt_printf(char *msg, ...) { 254#define txt_printf(msg, ...) \
255 va_list arg_list; 255 { \
256 va_start(arg_list, msg); 256 char buf[256] = {0}; \
257 char buf[512] = {0}; 257 posprintf(buf, msg, ##__VA_ARGS__); \
258 // TODO: This call pulls in malloc() and a bunch of other things. 258 txt_puts(buf); \
259 // To reduce memory usage and filesize, it would be advisable 259 }
260 // to replace it with something simpler.
261 vsiprintf(buf, msg, arg_list);
262 txt_puts(buf);
263}
264 260
265void 261void
266txt_clear_line_tiled(void) { 262txt_clear_line_tiled(void) {
diff --git a/src/uxn/opcodes.c b/src/uxn/opcodes.c
new file mode 100644
index 0000000..f80cd79
--- /dev/null
+++ b/src/uxn/opcodes.c
@@ -0,0 +1,315 @@
1/*
2Copyright (u) 2021 Devine Lu Linvega
3Copyright (c) 2021 Adrian "asie" Siekierka
4
5Permission to use, copy, modify, and distribute this software for any
6purpose with or without fee is hereby granted, provided that the above
7copyright notice and this permission notice appear in all copies.
8
9THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10WITH REGARD TO THIS SOFTWARE.
11*/
12
13/* 8-BIT OPCODES */
14
15case UXN_OPC(0x00):
16case UXN_OPC(0x20): { // brk
17 u->ram.ptr = 0;
18} break;
19case UXN_OPC(0x01): { // lit
20 push8(u->src, mempeek8(u->ram.dat, u->ram.ptr++));
21} break;
22case UXN_OPC(0x02):
23case UXN_OPC(0x22): { // nop
24} break;
25case UXN_OPC(0x03): { // pop
26 pop8(u->src);
27} break;
28case UXN_OPC(0x04): { // dup
29 Uint8 a = pop8(u->src);
30 push8(u->src, a);
31 push8(u->src, a);
32} break;
33case UXN_OPC(0x05): { // swp
34 Uint8 a = pop8(u->src);
35 Uint8 b = pop8(u->src);
36 push8(u->src, a);
37 push8(u->src, b);
38} break;
39case UXN_OPC(0x06): { // ovr
40 Uint8 a = pop8(u->src);
41 Uint8 b = pop8(u->src);
42 push8(u->src, b);
43 push8(u->src, a);
44 push8(u->src, b);
45} break;
46case UXN_OPC(0x07): { // rot
47 Uint8 a = pop8(u->src);
48 Uint8 b = pop8(u->src);
49 Uint8 c = pop8(u->src);
50 push8(u->src, b);
51 push8(u->src, a);
52 push8(u->src, c);
53} break;
54case UXN_OPC(0x08): { // equ
55 Uint8 a = pop8(u->src);
56 Uint8 b = pop8(u->src);
57 push8(u->src, b == a);
58} break;
59case UXN_OPC(0x09): { // neg
60 Uint8 a = pop8(u->src);
61 Uint8 b = pop8(u->src);
62 push8(u->src, b != a);
63} break;
64case UXN_OPC(0x0A): { // gth
65 Uint8 a = pop8(u->src);
66 Uint8 b = pop8(u->src);
67 push8(u->src, b > a);
68} break;
69case UXN_OPC(0x0B): { // lth
70 Uint8 a = pop8(u->src);
71 Uint8 b = pop8(u->src);
72 push8(u->src, b < a);
73} break;
74case UXN_OPC(0x0C): { // jmp
75 Uint8 a = pop8(u->src);
76 u->ram.ptr += (Sint8)a;
77} break;
78case UXN_OPC(0x0D): { // jnz
79 Uint8 a = pop8(u->src);
80 if (pop8(u->src))
81 u->ram.ptr += (Sint8)a;
82} break;
83case UXN_OPC(0x0E): { // jsr
84 Uint8 a = pop8(u->src);
85 push16(u->dst, u->ram.ptr);
86 u->ram.ptr += (Sint8)a;
87} break;
88case UXN_OPC(0x0F): { // sth
89 Uint8 a = pop8(u->src);
90 push8(u->dst, a);
91} break;
92case UXN_OPC(0x10): { // pek
93 Uint8 a = pop8(u->src);
94 push8(u->src, mempeek8(u->ram.dat, a));
95} break;
96case UXN_OPC(0x11): { // pok
97 Uint8 a = pop8(u->src);
98 Uint8 b = pop8(u->src);
99 mempoke8(u->ram.dat, a, b);
100} break;
101case UXN_OPC(0x12): { // ldr
102 Uint8 a = pop8(u->src);
103 push8(u->src, mempeek8(u->ram.dat, u->ram.ptr + (Sint8)a));
104} break;
105case UXN_OPC(0x13): { // str
106 Uint8 a = pop8(u->src);
107 Uint8 b = pop8(u->src);
108 mempoke8(u->ram.dat, u->ram.ptr + (Sint8)a, b);
109} break;
110case UXN_OPC(0x14): { // lda
111 Uint16 a = pop16(u->src);
112 push8(u->src, mempeek8(u->ram.dat, a));
113} break;
114case UXN_OPC(0x15): { // sta
115 Uint16 a = pop16(u->src);
116 Uint8 b = pop8(u->src);
117 mempoke8(u->ram.dat, a, b);
118} break;
119case UXN_OPC(0x16): { // dei
120 Uint8 a = pop8(u->src);
121 push8(u->src, devpeek8(&u->dev[a >> 4], a));
122} break;
123case UXN_OPC(0x17): { // deo
124 Uint8 a = pop8(u->src);
125 Uint8 b = pop8(u->src);
126 devpoke8(&u->dev[a >> 4], a, b);
127} break;
128case UXN_OPC(0x18): { // add
129 Uint8 a = pop8(u->src);
130 Uint8 b = pop8(u->src);
131 push8(u->src, b + a);
132} break;
133case UXN_OPC(0x19): { // sub
134 Uint8 a = pop8(u->src);
135 Uint8 b = pop8(u->src);
136 push8(u->src, b - a);
137} break;
138case UXN_OPC(0x1A): { // mul
139 Uint8 a = pop8(u->src);
140 Uint8 b = pop8(u->src);
141 push8(u->src, b * a);
142} break;
143case UXN_OPC(0x1B): { // div
144 Uint8 a = pop8(u->src);
145 Uint8 b = pop8(u->src);
146 push8(u->src, b / a);
147} break;
148case UXN_OPC(0x1C): { // and
149 Uint8 a = pop8(u->src);
150 Uint8 b = pop8(u->src);
151 push8(u->src, b & a);
152} break;
153case UXN_OPC(0x1D): { // ora
154 Uint8 a = pop8(u->src);
155 Uint8 b = pop8(u->src);
156 push8(u->src, b | a);
157} break;
158case UXN_OPC(0x1E): { // eor
159 Uint8 a = pop8(u->src);
160 Uint8 b = pop8(u->src);
161 push8(u->src, b ^ a);
162} break;
163case UXN_OPC(0x1F): { // sft
164 Uint8 a = pop8(u->src);
165 Uint8 b = pop8(u->src);
166 push8(u->src, b >> (a & 0x07) << ((a & 0x70) >> 4));
167} break;
168
169/* 16-BIT OPCODES */
170
171case UXN_OPC(0x21): { // lit
172 push16(u->src, mempeek16_i(u->ram.dat, u->ram.ptr));
173 u->ram.ptr += 2;
174} break;
175case UXN_OPC(0x23): { // pop
176 pop16(u->src);
177} break;
178case UXN_OPC(0x24): { // dup
179 Uint16 a = pop16(u->src);
180 push16(u->src, a);
181 push16(u->src, a);
182} break;
183case UXN_OPC(0x25): { // swp
184 Uint16 a = pop16(u->src);
185 Uint16 b = pop16(u->src);
186 push16(u->src, a);
187 push16(u->src, b);
188} break;
189case UXN_OPC(0x26): { // ovr
190 Uint16 a = pop16(u->src);
191 Uint16 b = pop16(u->src);
192 push16(u->src, b);
193 push16(u->src, a);
194 push16(u->src, b);
195} break;
196case UXN_OPC(0x27): { // rot
197 Uint16 a = pop16(u->src);
198 Uint16 b = pop16(u->src);
199 Uint16 c = pop16(u->src);
200 push16(u->src, b);
201 push16(u->src, a);
202 push16(u->src, c);
203} break;
204case UXN_OPC(0x28): { // equ
205 Uint16 a = pop16(u->src);
206 Uint16 b = pop16(u->src);
207 push8(u->src, b == a);
208} break;
209case UXN_OPC(0x29): { // neg
210 Uint16 a = pop16(u->src);
211 Uint16 b = pop16(u->src);
212 push8(u->src, b != a);
213} break;
214case UXN_OPC(0x2A): { // gth
215 Uint16 a = pop16(u->src);
216 Uint16 b = pop16(u->src);
217 push8(u->src, b > a);
218} break;
219case UXN_OPC(0x2B): { // lth
220 Uint16 a = pop16(u->src);
221 Uint16 b = pop16(u->src);
222 push8(u->src, b < a);
223} break;
224case UXN_OPC(0x2C): { // jmp
225 u->ram.ptr = pop16(u->src);
226} break;
227case UXN_OPC(0x2D): { // jnz
228 Uint16 a = pop16(u->src);
229 if (pop8(u->src))
230 u->ram.ptr = a;
231} break;
232case UXN_OPC(0x2E): { // jsr
233 push16(u->dst, u->ram.ptr);
234 u->ram.ptr = pop16(u->src);
235} break;
236case UXN_OPC(0x2F): { // sth
237 Uint16 a = pop16(u->src);
238 push16(u->dst, a);
239} break;
240case UXN_OPC(0x30): { // pek
241 Uint8 a = pop8(u->src);
242 push16(u->src, mempeek16_i(u->ram.dat, a));
243} break;
244case UXN_OPC(0x31): { // pok
245 Uint8 a = pop8(u->src);
246 Uint16 b = pop16(u->src);
247 mempoke16_i(u->ram.dat, a, b);
248} break;
249case UXN_OPC(0x32): { // ldr
250 Uint8 a = pop8(u->src);
251 push16(u->src, mempeek16_i(u->ram.dat, u->ram.ptr + (Sint8)a));
252} break;
253case UXN_OPC(0x33): { // str
254 Uint8 a = pop8(u->src);
255 Uint16 b = pop16(u->src);
256 mempoke16_i(u->ram.dat, u->ram.ptr + (Sint8)a, b);
257} break;
258case UXN_OPC(0x34): { // lda
259 Uint16 a = pop16(u->src);
260 push16(u->src, mempeek16_i(u->ram.dat, a));
261} break;
262case UXN_OPC(0x35): { // sta
263 Uint16 a = pop16(u->src);
264 Uint16 b = pop16(u->src);
265 mempoke16_i(u->ram.dat, a, b);
266} break;
267case UXN_OPC(0x36): { // dei
268 Uint8 a = pop8(u->src);
269 push16(u->src, devpeek16(&u->dev[a >> 4], a));
270} break;
271case UXN_OPC(0x37): { // deo
272 Uint8 a = pop8(u->src);
273 Uint16 b = pop16(u->src);
274 devpoke16(&u->dev[a >> 4], a, b);
275} break;
276case UXN_OPC(0x38): { // add
277 Uint16 a = pop16(u->src);
278 Uint16 b = pop16(u->src);
279 push16(u->src, b + a);
280} break;
281case UXN_OPC(0x39): { // sub
282 Uint16 a = pop16(u->src);
283 Uint16 b = pop16(u->src);
284 push16(u->src, b - a);
285} break;
286case UXN_OPC(0x3A): { // mul
287 Uint16 a = pop16(u->src);
288 Uint16 b = pop16(u->src);
289 push16(u->src, b * a);
290} break;
291case UXN_OPC(0x3B): { // div
292 Uint16 a = pop16(u->src);
293 Uint16 b = pop16(u->src);
294 push16(u->src, b / a);
295} break;
296case UXN_OPC(0x3C): { // and
297 Uint16 a = pop16(u->src);
298 Uint16 b = pop16(u->src);
299 push16(u->src, b & a);
300} break;
301case UXN_OPC(0x3D): { // ora
302 Uint16 a = pop16(u->src);
303 Uint16 b = pop16(u->src);
304 push16(u->src, b | a);
305} break;
306case UXN_OPC(0x3E): { // eor
307 Uint16 a = pop16(u->src);
308 Uint16 b = pop16(u->src);
309 push16(u->src, b ^ a);
310} break;
311case UXN_OPC(0x3F): { // sft
312 Uint16 a = pop16(u->src);
313 Uint16 b = pop16(u->src);
314 push16(u->src, b >> (a & 0x000f) << ((a & 0x00f0) >> 4));
315} break;
diff --git a/src/uxn/uxn.c b/src/uxn/uxn.c
index c1c564a..8e76660 100644
--- a/src/uxn/uxn.c
+++ b/src/uxn/uxn.c
@@ -46,7 +46,7 @@ static inline Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) <<
46int 46int
47haltuxn(Uxn *u, char *name, int id) 47haltuxn(Uxn *u, char *name, int id)
48{ 48{
49 txt_printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr); 49 // txt_printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr);
50 u->ram.ptr = 0; 50 u->ram.ptr = 0;
51 return 0; 51 return 0;
52} 52}
@@ -171,6 +171,6 @@ portuxn(Uxn *u, Uint8 id, char *name, void (*talkfn)(Device *d, Uint8 b0, Uint8
171 d->u = u; 171 d->u = u;
172 d->mem = u->ram.dat; 172 d->mem = u->ram.dat;
173 d->talk = talkfn; 173 d->talk = talkfn;
174 txt_printf("Dev:#%02x:0x%04x:%s \n", id, d->addr, name); 174 // txt_printf("Dev:#%02x:0x%04x:%s \n", id, d->addr, name);
175 return d; 175 return d;
176} 176}