- commit
- 5a47f8a
- parent
- 0805fab
- author
- xplshn
- date
- 2025-08-24 02:23:14 +0000 UTC
push ./lib/ dir Signed-off-by: xplshn <[email protected]>
22 files changed,
+371,
-65
+206,
-0
1@@ -0,0 +1,206 @@
2+exit(code) {
3+ 0(code);
4+}
5+
6+abort() {
7+ exit(69);
8+}
9+
10+putchar(c) {
11+ 0xFFEF(c);
12+}
13+
14+char __asm__(
15+ "TSX",
16+ "CLC",
17+ "ADC $0103,X", // i&0xFF
18+ "STA $00", // we can safely use zero-page, as our assembler
19+ // doesn't expect it to be preserved across op-boundaries
20+ "TYA",
21+ "ADC $0104,X", // i&0xFF00 >> 8
22+ "STA $01",
23+ "LDY #0",
24+ "LDA ($00),Y",
25+ "RTS"
26+);
27+
28+lchar __asm__(
29+ "TSX",
30+ "CLC",
31+ "ADC $0103,X", // i&0xFF
32+ "STA $00", // we can safely use zero-page, as our assembler
33+ // doesn't expect it to be preserved across op-boundaries
34+ "TYA",
35+ "ADC $0104,X", // i&0xFF00 >> 8
36+ "STA $01",
37+ "LDA $0105,X",
38+ "LDY #0",
39+ "STA ($00),Y",
40+ "RTS"
41+);
42+
43+/* TODO: fd not supported */
44+fputc(c, fd) {
45+ putchar(c);
46+}
47+
48+/* TODO: actually allocate something */
49+__heap_ptr 0x0200;
50+malloc(size) {
51+ extrn printf;
52+ auto ptr;
53+ ptr = __heap_ptr;
54+ __heap_ptr += size;
55+ if (__heap_ptr >= 0x1000) {
56+ printf("Allocation reached end: %p\nTODO: allow allocating more, implement free\n", __heap_ptr);
57+ abort();
58+ }
59+ return (ptr);
60+}
61+/* TODO: free someting? */
62+realloc(ptr, size) {
63+ return (malloc(size));
64+}
65+
66+/* TODO: Try to implement this function with assembly
67+ Problem with this implementation is that it is not
68+ mapped to the operator
69+ We cannot call this function `div` as it conflicts
70+ with the `divmod` test
71+*/
72+_div(a, b) {
73+ auto d, sign;
74+ sign = 0;
75+ if (a < 0) {
76+ sign = !sign;
77+ a = -a;
78+ }
79+ if (b < 0) {
80+ sign = !sign;
81+ b = -a;
82+ }
83+
84+ d = 0; while(a >= b) {
85+ a = a - b;
86+ d++;
87+ }
88+ if (sign) d = -d;
89+ return (d);
90+}
91+_udiv(a, b) {
92+ auto d;
93+ d = 0; while(a >= b | a < 0) {
94+ a = a - b;
95+ d++;
96+ }
97+ return (d);
98+}
99+
100+/* TODO: Try to implement this function with assembly
101+ Problem with this implementation is that it is not
102+ mapped to the operator */
103+_rem (a, b) {
104+ auto d;
105+ while(a >= b) {
106+ a = a - b;
107+ }
108+ return (a);
109+}
110+_urem(a, b) {
111+ auto d;
112+ while(a >= b | a < 0) {
113+ a = a - b;
114+ }
115+ return (a);
116+}
117+
118+printn(n, b, sign) {
119+ auto a, c, d, __div, __rem;
120+
121+ /* use correct div/rem based on sign */
122+ __div = sign ? &_div : &_udiv;
123+ __rem = sign ? &_rem : &_urem;
124+
125+ if (sign & n < 0) {
126+ putchar('-');
127+ n = -n;
128+ }
129+
130+ if(a=__div(n, b)) /* assignment, not test for equality */
131+ printn(a, b, 0); /* recursive */
132+ c = __rem(n,b) + '0';
133+ if (c > '9') c += 7;
134+ putchar(c);
135+}
136+
137+printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {
138+ auto i, j, arg, c;
139+ i = 0;
140+ j = 0;
141+
142+ arg = &x1;
143+
144+ c = char(str, i);
145+ while (c != 0) {
146+ if (c == '\n') {
147+ putchar(0xD); // \r
148+ }
149+
150+ if(c == '%') {
151+ i += 1;
152+ c = char(str, i);
153+ if (c == 0) {
154+ return;
155+ } else if (c == 'd') {
156+ printn(*arg, 10, 1);
157+ } else if (c == 'u') {
158+ printn(*arg, 10, 0);
159+ } else if (c == 'p') {
160+ putchar('$');
161+ printn(*arg, 16, 0);
162+ } else if (c == 'c') {
163+ putchar(*arg);
164+ } else if (c == 's') { /* clobbers `c`, the last one */
165+ while (c = char(*arg, j++)) {
166+ putchar(c);
167+ }
168+ } else if (c == 'z' | c == 'l') { /* hack for %zu %lu, % */
169+ c = '%';
170+ goto while_end;
171+ } else {
172+ putchar('%');
173+ arg += 2; /* word size */
174+ }
175+ arg -= 2; /* word size */
176+ } else {
177+ putchar(c); /* ECHO */
178+ }
179+ i++;
180+ c = char(str, i);
181+ while_end:;
182+ }
183+}
184+
185+strlen(s) {
186+ auto n;
187+ n = 0;
188+ while (char(s, n)) n++;
189+ return (n);
190+}
191+
192+toupper(c) {
193+ if ('a' <= c & c <= 'z') return (c - 'a' + 'A');
194+ return (c);
195+}
196+
197+
198+/* memory related functions */
199+memset(addr, val, size) {
200+ extrn lchar;
201+ auto i;
202+ i = 0;
203+ while (i < size) {
204+ lchar(addr, i, val);
205+ i += 1;
206+ }
207+}
+1,
-1
1@@ -1 +1 @@
2-arm64_darwin.b
3+gas-aarch64-darwin.b
+1,
-1
1@@ -1 +1 @@
2-arm64_linux.b
3+gas-aarch64-linux.b
+0,
-7
1@@ -1,7 +0,0 @@
2-sx64 __asm__("movslq %edi, %rax", "ret");
3-char __asm__("xorq %rax, %rax", "movb (%rdi, %rsi), %al", "ret");
4-lchar __asm__("movb %dl, (%rdi, %rsi)", "ret");
5-extrn printf;
6-extrn putchar;
7-extrn getchar;
8-extrn exit;
+1,
-0
1@@ -0,0 +1 @@
2+x86_64-Darwin.b
+0,
-7
1@@ -1,7 +0,0 @@
2-sx64 __asm__("movslq %edi, %rax", "ret");
3-char __asm__("xorq %rax, %rax", "movb (%rdi, %rsi), %al", "ret");
4-lchar __asm__("movb %dl, (%rdi, %rsi)", "ret");
5-extrn printf;
6-extrn putchar;
7-extrn getchar;
8-extrn exit;
+1,
-0
1@@ -0,0 +1 @@
2+x86_64-Linux.b
+0,
-7
1@@ -1,7 +0,0 @@
2-sx64 __asm__("xorq %rax, %rax", "movslq %ecx, %rax", "ret");
3-char __asm__("xorq %rax, %rax", "movb (%rcx, %rdx), %al", "ret");
4-lchar __asm__("movb %r8b, (%rcx, %rdx)", "ret");
5-extrn printf;
6-extrn putchar;
7-extrn getchar;
8-extrn exit;
+1,
-0
1@@ -0,0 +1 @@
2+x86_64-Windows.b
+0,
-8
1@@ -1,8 +0,0 @@
2-sx64 __asm__("sxtw x0, w0", "ret");
3-char __asm__("ldrb w0, [x0, x1]", "ret");
4-lchar __asm__("strb w2, [x0, x1]", "ret");
5-extrn printf;
6-__variadic__(printf, 1);
7-extrn putchar;
8-extrn getchar;
9-extrn exit;
+1,
-0
1@@ -0,0 +1 @@
2+aarch64-Darwin.b
+0,
-7
1@@ -1,7 +0,0 @@
2-sx64 __asm__("sxtw x0, w0", "ret");
3-char __asm__("ldrb w0, [x0, x1]", "ret");
4-lchar __asm__("strb w2, [x0, x1]", "ret");
5-extrn printf;
6-extrn putchar;
7-extrn getchar;
8-extrn exit;
+1,
-0
1@@ -0,0 +1 @@
2+aarch64-Linux.b
+8,
-0
1@@ -0,0 +1,8 @@
2+sx64 __asm__("sxtw x0, w0", "ret");
3+char __asm__("ldrb w0, [x0, x1]", "ret");
4+lchar __asm__("strb w2, [x0, x1]", "ret");
5+extrn printf;
6+__variadic__(printf, 1);
7+extrn putchar;
8+extrn getchar;
9+extrn exit;
+7,
-0
1@@ -0,0 +1,7 @@
2+sx64 __asm__("sxtw x0, w0", "ret");
3+char __asm__("ldrb w0, [x0, x1]", "ret");
4+lchar __asm__("strb w2, [x0, x1]", "ret");
5+extrn printf;
6+extrn putchar;
7+extrn getchar;
8+extrn exit;
+7,
-0
1@@ -0,0 +1,7 @@
2+sx64 __asm__("movslq %edi, %rax", "ret");
3+char __asm__("xorq %rax, %rax", "movb (%rdi, %rsi), %al", "ret");
4+lchar __asm__("movb %dl, (%rdi, %rsi)", "ret");
5+extrn printf;
6+extrn putchar;
7+extrn getchar;
8+extrn exit;
+7,
-0
1@@ -0,0 +1,7 @@
2+sx64 __asm__("movslq %edi, %rax", "ret");
3+char __asm__("xorq %rax, %rax", "movb (%rdi, %rsi), %al", "ret");
4+lchar __asm__("movb %dl, (%rdi, %rsi)", "ret");
5+extrn printf;
6+extrn putchar;
7+extrn getchar;
8+extrn exit;
+7,
-0
1@@ -0,0 +1,7 @@
2+sx64 __asm__("xorq %rax, %rax", "movslq %ecx, %rax", "ret");
3+char __asm__("xorq %rax, %rax", "movb (%rcx, %rdx), %al", "ret");
4+lchar __asm__("movb %r8b, (%rcx, %rdx)", "ret");
5+extrn printf;
6+extrn putchar;
7+extrn getchar;
8+extrn exit;
+119,
-24
1@@ -1,7 +1,106 @@
2 /* Standard Library for the Uxn target */
3
4+/*
5+ch = char(string, i);
6+returns the ith character in a string pointed to by string, 0 based
7+*/
8+
9+char __asm__(
10+ "lit 4", "ldz2", /* first arg, string */
11+ "lit 6", "ldz2", /* second arg, i */
12+ "add2",
13+ "lda",
14+ "lit 0",
15+ "swp",
16+ "lit 4", "stz2", /* return value (same spot as the first arg) */
17+ "jmp2r"
18+);
19+
20+/*
21+ch = lchar(string, i, char);
22+replaces the ith character in the string pointed to by string with the character char.
23+The value LCHAR returns is the character char that was placed in the string.
24+*/
25+
26+lchar __asm__(
27+ "lit 9", "ldz", /* low byte of the arg 2, char */
28+ "lit 4", "ldz2",
29+ "lit 6", "ldz2",
30+ "add2",
31+ "stak",
32+ "pop2",
33+ "lit 0",
34+ "swp",
35+ "lit 4", "stz2",
36+ "jmp2r"
37+);
38+
39+/*
40+value = uxn_dei(device);
41+reads 8 bit value off a device
42+*/
43+
44+uxn_dei __asm__(
45+ "lit 0", "lit 4", "stz", /* zero the high byte of arg0/return */
46+ "lit 5", "ldzk", /* low byte of arg0 */
47+ "dei",
48+ "swp",
49+ "stz",
50+ "jmp2r"
51+);
52+
53+/*
54+value = uxn_dei2(device);
55+reads 16 bit value off a device
56+*/
57+
58+uxn_dei2 __asm__(
59+ "lit 5", "ldz", /* low byte of arg0 */
60+ "dei2",
61+ "lit 4", "stz2",
62+ "jmp2r"
63+);
64+
65+/*
66+uxn_deo(device, value);
67+outputs 8 bit value to a device
68+*/
69+
70+uxn_deo __asm__(
71+ "lit 7", "ldz", /* low byte of arg1 */
72+ "lit 5", "ldz", /* low byte of arg0 */
73+ "deo",
74+ "lit2 0", "lit 4", "stz2", /* return 0 */
75+ "jmp2r"
76+);
77+
78+/*
79+uxn_deo2(device, value);
80+outputs 16 bit value to a device
81+*/
82+
83+uxn_deo2 __asm__(
84+ "lit 6", "ldz2", /* arg1 */
85+ "lit 5", "ldz", /* low byte of arg0 */
86+ "deo2",
87+ "lit2 0", "lit 4", "stz2", /* return 0 */
88+ "jmp2r"
89+);
90+
91+/*
92+uxn_udiv(a, b)
93+outputs 16 bit unsigned division of a / b.
94+*/
95+
96+uxn_div2 __asm__(
97+ "lit 4", "ldz2", /* arg0 */
98+ "lit 6", "ldz2", /* arg1 */
99+ "div2",
100+ "lit 4", "stz2",
101+ "jmp2r"
102+);
103+
104 fputc(c, fd) {
105- extrn uxn_deo;
106 uxn_deo(fd + 0x18, c); /* 0x18 - Console/write,
107 0x19 - Console/error */
108 }
109@@ -11,12 +110,22 @@ putchar(c) {
110 }
111
112 exit(code) {
113- extrn uxn_deo;
114 uxn_deo(0x0f, code | 0x80); /* System/state */
115 }
116
117+_exit_after_main 1;
118+
119+uxn_disable_exit_after_main() {
120+ _exit_after_main = 0;
121+}
122+
123+_exit_main(code) {
124+ if (_exit_after_main) {
125+ exit(code);
126+ }
127+}
128+
129 abort() {
130- extrn printf;
131 printf("Aborted\n");
132 exit(1);
133 }
134@@ -50,7 +159,6 @@ printn(n, b) _fprintn(n, b, 0);
135 /* TODO: Consider adding support for negative numbers to Uxn's printf. */
136 /* TODO: Consider adding support for %ul to Uxn's printf. */
137 fprintf(fd, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
138- extrn char;
139 auto i, j, c, arg;
140 i = 0;
141 j = 0;
142@@ -103,7 +211,6 @@ printf(string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
143
144 // TODO: doesn't skip whitespace, doesn't handle negative numbers
145 atoi(s) {
146- extrn char;
147 auto i, result, c;
148 i = 0;
149 while (1) {
150@@ -119,20 +226,16 @@ out:
151
152 /* simple bump allocator */
153
154-__alloc_ptr;
155+__alloc_ptr 0x8000; /* provide __heap_base by the compiler? */
156
157 malloc(size) {
158 auto ret;
159- if (__alloc_ptr == 0) {
160- __alloc_ptr = 0x8000; /* provide __heap_base by the compiler? */
161- }
162 ret = __alloc_ptr;
163 __alloc_ptr += size;
164 return (ret);
165 }
166
167 memset(addr, val, size) {
168- extrn lchar;
169 auto i;
170 i = 0;
171 while (i < size) {
172@@ -141,14 +244,13 @@ memset(addr, val, size) {
173 }
174 }
175
176-stdout; stderr;
177+stdout 0; stderr 1;
178
179-_args_count;
180-_args_items;
181-_prog_name;
182+_args_count 1;
183+_args_items 0x7f00; /* 128 arguments ought to be enough for everyone */
184+_prog_name "-";
185
186 _start_with_arguments() {
187- extrn uxn_dei, uxn_deo2, lchar, main;
188 auto type, c;
189 type = uxn_dei(0x17); /* Console/type */
190 c = uxn_dei(0x12);
191@@ -160,24 +262,17 @@ _start_with_arguments() {
192 } else if (type == 4) { /* arguments end */
193 lchar(__alloc_ptr++, 0, 0);
194 uxn_deo2(0x10, 0);
195- exit(main(_args_count, _args_items));
196+ _exit_main(main(_args_count, _args_items));
197 }
198 }
199
200 _start() {
201- extrn main, uxn_dei, uxn_deo2;
202- __alloc_ptr = 0x8000;
203- _args_items = 0x7f00; /* 128 arguments ought to be enough for everyone */
204- stdout = 0;
205- stderr = 1;
206- _prog_name = "-"; /* we don't have access to it */
207 *_args_items = _prog_name;
208- _args_count = 1;
209 if (uxn_dei(0x17) != 0) {
210 *(_args_items + (_args_count++)*2) = __alloc_ptr;
211 uxn_deo2(0x10, &_start_with_arguments);
212 } else {
213- exit(main(_args_count, _args_items));
214+ _exit_main(main(_args_count, _args_items));
215 }
216 }
217
+1,
-1
1@@ -1 +1 @@
2-amd64_darwin.b
3+gas-x86_64-darwin.b
+1,
-1
1@@ -1 +1 @@
2-amd64_linux.b
3+gas-x86_64-linux.b
+1,
-1
1@@ -1 +1 @@
2-amd64_windows.b
3+gas-x86_64-windows.b