xplshn
·
2025-08-24
uxn.b
B
1/* Standard Library for the Uxn target */
2
3/*
4ch = char(string, i);
5returns the ith character in a string pointed to by string, 0 based
6*/
7
8char __asm__(
9 "lit 4", "ldz2", /* first arg, string */
10 "lit 6", "ldz2", /* second arg, i */
11 "add2",
12 "lda",
13 "lit 0",
14 "swp",
15 "lit 4", "stz2", /* return value (same spot as the first arg) */
16 "jmp2r"
17);
18
19/*
20ch = lchar(string, i, char);
21replaces the ith character in the string pointed to by string with the character char.
22The value LCHAR returns is the character char that was placed in the string.
23*/
24
25lchar __asm__(
26 "lit 9", "ldz", /* low byte of the arg 2, char */
27 "lit 4", "ldz2",
28 "lit 6", "ldz2",
29 "add2",
30 "stak",
31 "pop2",
32 "lit 0",
33 "swp",
34 "lit 4", "stz2",
35 "jmp2r"
36);
37
38/*
39value = uxn_dei(device);
40reads 8 bit value off a device
41*/
42
43uxn_dei __asm__(
44 "lit 0", "lit 4", "stz", /* zero the high byte of arg0/return */
45 "lit 5", "ldzk", /* low byte of arg0 */
46 "dei",
47 "swp",
48 "stz",
49 "jmp2r"
50);
51
52/*
53value = uxn_dei2(device);
54reads 16 bit value off a device
55*/
56
57uxn_dei2 __asm__(
58 "lit 5", "ldz", /* low byte of arg0 */
59 "dei2",
60 "lit 4", "stz2",
61 "jmp2r"
62);
63
64/*
65uxn_deo(device, value);
66outputs 8 bit value to a device
67*/
68
69uxn_deo __asm__(
70 "lit 7", "ldz", /* low byte of arg1 */
71 "lit 5", "ldz", /* low byte of arg0 */
72 "deo",
73 "lit2 0", "lit 4", "stz2", /* return 0 */
74 "jmp2r"
75);
76
77/*
78uxn_deo2(device, value);
79outputs 16 bit value to a device
80*/
81
82uxn_deo2 __asm__(
83 "lit 6", "ldz2", /* arg1 */
84 "lit 5", "ldz", /* low byte of arg0 */
85 "deo2",
86 "lit2 0", "lit 4", "stz2", /* return 0 */
87 "jmp2r"
88);
89
90/*
91uxn_udiv(a, b)
92outputs 16 bit unsigned division of a / b.
93*/
94
95uxn_div2 __asm__(
96 "lit 4", "ldz2", /* arg0 */
97 "lit 6", "ldz2", /* arg1 */
98 "div2",
99 "lit 4", "stz2",
100 "jmp2r"
101);
102
103fputc(c, fd) {
104 uxn_deo(fd + 0x18, c); /* 0x18 - Console/write,
105 0x19 - Console/error */
106}
107
108putchar(c) {
109 fputc(c, 0);
110}
111
112exit(code) {
113 uxn_deo(0x0f, code | 0x80); /* System/state */
114}
115
116_exit_after_main 1;
117
118uxn_disable_exit_after_main() {
119 _exit_after_main = 0;
120}
121
122_exit_main(code) {
123 if (_exit_after_main) {
124 exit(code);
125 }
126}
127
128abort() {
129 printf("Aborted\n");
130 exit(1);
131}
132
133_udiv(a, b) {
134 extrn uxn_div2;
135 return (uxn_div2(a, b));
136}
137
138// TODO: `b` has to be <32768, because of `*`
139_urem(a, b) {
140 return (a - _udiv(a, b) * b);
141}
142
143/* loosely based on the original code by Ken Thompson */
144
145_fprintn(n, b, fd) {
146 auto a, c;
147
148 if(a=_udiv(n,b)) /* assignment, not test for equality */
149 _fprintn(a, b, fd); /* recursive */
150 c = _urem(n,b) + '0';
151 if (c > '9') c += 7;
152 fputc(c, fd);
153}
154
155printn(n, b) _fprintn(n, b, 0);
156
157/* doesn't support fancy features like padding, but neither did the original in B */
158
159/* TODO: Consider adding support for negative numbers to Uxn's printf. */
160/* TODO: Consider adding support for %ul to Uxn's printf. */
161fprintf(fd, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
162 auto i, j, c, arg;
163 i = 0;
164 j = 0;
165 c = char(string, i);
166 arg = &x1;
167 while (c != 0) {
168 if (c == '%') {
169 i += 1;
170 c = char(string, i);
171 if (c == 0) {
172 return;
173 } else if (c == 'x') {
174 _fprintn(*arg, 16, fd);
175 } else if (c == 'd') {
176 if (*arg < 0) {
177 fputc('-', fd);
178 *arg = -*arg;
179 }
180 _fprintn(*arg, 10, fd);
181 } else if (c == 'u') {
182 _fprintn(*arg, 10, fd);
183 } else if (c == 'o') {
184 _fprintn(*arg, 8, fd);
185 } else if (c == 'c') {
186 fputc(*arg, fd);
187 } else if (c == 's') { /* clobbers `c`, the last one */
188 while (c = char(*arg, j++)) {
189 fputc(c, fd);
190 }
191 } else if (c == 'l' | c == 'z') {
192 c = '%';
193 goto continue;
194 } else {
195 fputc('%', fd);
196 arg += 2; /* word size */
197 }
198 arg -= 2; /* word size */
199 } else {
200 fputc(c, fd);
201 }
202 i += 1;
203 c = char(string, i);
204 continue:;
205 }
206}
207
208printf(string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
209 fprintf(0, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
210}
211
212// TODO: doesn't skip whitespace, doesn't handle negative numbers
213atoi(s) {
214 auto i, result, c;
215 i = 0;
216 while (1) {
217 c = char(s, i++);
218 if (c < '0' | c > '9') {
219 goto out;
220 }
221 result = result * 10 + (c - '0');
222 }
223out:
224 return (result);
225}
226
227/* simple bump allocator */
228
229__alloc_ptr 0x8000; /* provide __heap_base by the compiler? */
230
231malloc(size) {
232 auto ret;
233 ret = __alloc_ptr;
234 __alloc_ptr += size;
235 return (ret);
236}
237
238memset(addr, val, size) {
239 auto i;
240 i = 0;
241 while (i < size) {
242 lchar(addr, i, val);
243 i += 1;
244 }
245}
246
247stdout 0; stderr 1;
248
249_args_count 1;
250_args_items 0x7f00; /* 128 arguments ought to be enough for everyone */
251_prog_name "-";
252
253_start_with_arguments() {
254 auto type, c;
255 type = uxn_dei(0x17); /* Console/type */
256 c = uxn_dei(0x12);
257 if (type == 2) { /* argument */
258 lchar(__alloc_ptr++, 0, c);
259 } else if (type == 3) { /* argument spacer */
260 lchar(__alloc_ptr++, 0, 0);
261 *(_args_items + (_args_count++)*2) = __alloc_ptr;
262 } else if (type == 4) { /* arguments end */
263 lchar(__alloc_ptr++, 0, 0);
264 uxn_deo2(0x10, 0);
265 _exit_main(main(_args_count, _args_items));
266 }
267}
268
269_start() {
270 *_args_items = _prog_name;
271 if (uxn_dei(0x17) != 0) {
272 *(_args_items + (_args_count++)*2) = __alloc_ptr;
273 uxn_deo2(0x10, &_start_with_arguments);
274 } else {
275 _exit_main(main(_args_count, _args_items));
276 }
277}
278
279strlen(s) {
280 auto n;
281 n = 0;
282 while (*s++) n++;
283 return (n);
284}
285
286toupper(c) {
287 if ('a' <= c & c <= 'z') return (c - 'a' + 'A');
288 return (c);
289}