Skip to content

Commit 63549c1

Browse files
authored
Merge pull request #230 from deniska/uxn-asm
uxn inline assembly
2 parents 62a7c3d + 11bc0d9 commit 63549c1

9 files changed

Lines changed: 486 additions & 135 deletions

File tree

examples/uxn/callable_globals.b

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
/*
2-
Implies -nostdlib.
3-
42
In B there's this strange syntax to initialize a global variable,
53
and a few unnamed words after that global variable, to specific values.
64

examples/uxn/hello.b

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/*
2-
Implies -nostdlib.
32
Shows how to communicate with a varvara device
43
*/
54

examples/uxn/screen.b

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
/* IMPORTANT! Implies -nostdlib.
2-
* Because the entry point from ./libb/uxn.b conflicts with the entry point of this program.
3-
* TODO: do we want to do anything about this?
4-
*/
51
logo;
62

73
x; y;
@@ -49,6 +45,7 @@ on_screen() {
4945

5046
main() {
5147
extrn uxn_deo2, lchar;
48+
uxn_disable_exit_after_main();
5249
logo = "aaaaaaaaaaaaaaaa";
5350
lchar(logo, 0, 0x00); lchar(logo, 8, 0x7e); /* ###### */
5451
lchar(logo, 1, 0x38); lchar(logo, 9, 0xc7); /* ##...### */

libb/uxn.b

Lines changed: 119 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,106 @@
11
/* Standard Library for the Uxn target */
22

3+
/*
4+
ch = char(string, i);
5+
returns the ith character in a string pointed to by string, 0 based
6+
*/
7+
8+
char __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+
/*
20+
ch = lchar(string, i, char);
21+
replaces the ith character in the string pointed to by string with the character char.
22+
The value LCHAR returns is the character char that was placed in the string.
23+
*/
24+
25+
lchar __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+
/*
39+
value = uxn_dei(device);
40+
reads 8 bit value off a device
41+
*/
42+
43+
uxn_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+
/*
53+
value = uxn_dei2(device);
54+
reads 16 bit value off a device
55+
*/
56+
57+
uxn_dei2 __asm__(
58+
"lit 5", "ldz", /* low byte of arg0 */
59+
"dei2",
60+
"lit 4", "stz2",
61+
"jmp2r"
62+
);
63+
64+
/*
65+
uxn_deo(device, value);
66+
outputs 8 bit value to a device
67+
*/
68+
69+
uxn_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+
/*
78+
uxn_deo2(device, value);
79+
outputs 16 bit value to a device
80+
*/
81+
82+
uxn_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+
/*
91+
uxn_udiv(a, b)
92+
outputs 16 bit unsigned division of a / b.
93+
*/
94+
95+
uxn_div2 __asm__(
96+
"lit 4", "ldz2", /* arg0 */
97+
"lit 6", "ldz2", /* arg1 */
98+
"div2",
99+
"lit 4", "stz2",
100+
"jmp2r"
101+
);
102+
3103
fputc(c, fd) {
4-
extrn uxn_deo;
5104
uxn_deo(fd + 0x18, c); /* 0x18 - Console/write,
6105
0x19 - Console/error */
7106
}
@@ -11,12 +110,22 @@ putchar(c) {
11110
}
12111

13112
exit(code) {
14-
extrn uxn_deo;
15113
uxn_deo(0x0f, code | 0x80); /* System/state */
16114
}
17115

116+
_exit_after_main 1;
117+
118+
uxn_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+
18128
abort() {
19-
extrn printf;
20129
printf("Aborted\n");
21130
exit(1);
22131
}
@@ -50,7 +159,6 @@ printn(n, b) _fprintn(n, b, 0);
50159
/* TODO: Consider adding support for negative numbers to Uxn's printf. */
51160
/* TODO: Consider adding support for %ul to Uxn's printf. */
52161
fprintf(fd, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
53-
extrn char;
54162
auto i, j, c, arg;
55163
i = 0;
56164
j = 0;
@@ -103,7 +211,6 @@ printf(string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
103211

104212
// TODO: doesn't skip whitespace, doesn't handle negative numbers
105213
atoi(s) {
106-
extrn char;
107214
auto i, result, c;
108215
i = 0;
109216
while (1) {
@@ -119,20 +226,16 @@ out:
119226

120227
/* simple bump allocator */
121228

122-
__alloc_ptr;
229+
__alloc_ptr 0x8000; /* provide __heap_base by the compiler? */
123230

124231
malloc(size) {
125232
auto ret;
126-
if (__alloc_ptr == 0) {
127-
__alloc_ptr = 0x8000; /* provide __heap_base by the compiler? */
128-
}
129233
ret = __alloc_ptr;
130234
__alloc_ptr += size;
131235
return (ret);
132236
}
133237

134238
memset(addr, val, size) {
135-
extrn lchar;
136239
auto i;
137240
i = 0;
138241
while (i < size) {
@@ -141,14 +244,13 @@ memset(addr, val, size) {
141244
}
142245
}
143246

144-
stdout; stderr;
247+
stdout 0; stderr 1;
145248

146-
_args_count;
147-
_args_items;
148-
_prog_name;
249+
_args_count 1;
250+
_args_items 0x7f00; /* 128 arguments ought to be enough for everyone */
251+
_prog_name "-";
149252

150253
_start_with_arguments() {
151-
extrn uxn_dei, uxn_deo2, lchar, main;
152254
auto type, c;
153255
type = uxn_dei(0x17); /* Console/type */
154256
c = uxn_dei(0x12);
@@ -160,24 +262,17 @@ _start_with_arguments() {
160262
} else if (type == 4) { /* arguments end */
161263
lchar(__alloc_ptr++, 0, 0);
162264
uxn_deo2(0x10, 0);
163-
exit(main(_args_count, _args_items));
265+
_exit_main(main(_args_count, _args_items));
164266
}
165267
}
166268

167269
_start() {
168-
extrn main, uxn_dei, uxn_deo2;
169-
__alloc_ptr = 0x8000;
170-
_args_items = 0x7f00; /* 128 arguments ought to be enough for everyone */
171-
stdout = 0;
172-
stderr = 1;
173-
_prog_name = "-"; /* we don't have access to it */
174270
*_args_items = _prog_name;
175-
_args_count = 1;
176271
if (uxn_dei(0x17) != 0) {
177272
*(_args_items + (_args_count++)*2) = __alloc_ptr;
178273
uxn_deo2(0x10, &_start_with_arguments);
179274
} else {
180-
exit(main(_args_count, _args_items));
275+
_exit_main(main(_args_count, _args_items));
181276
}
182277
}
183278

src/codegen/gas_x86_64.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -672,12 +672,12 @@ pub unsafe fn generate_program(
672672
gen: *mut c_void, program: *const Program, program_path: *const c_char, garbage_base: *const c_char, os: Os,
673673
nostdlib: bool, debug: bool,
674674
) -> Option<()> {
675-
if debug { generate_debuginfo(output, (*program).funcs, (*program).globals, os); }
676-
677675
let gen = gen as *mut Gas_x86_64;
678676
let output = &mut (*gen).output;
679677
let cmd = &mut (*gen).cmd;
680678

679+
if debug { generate_debuginfo(output, (*program).funcs, (*program).globals, os); }
680+
681681
match os {
682682
Os::Darwin => sb_appendf(output, c!(".text\n")),
683683
Os::Linux | Os::Windows => sb_appendf(output, c!(".section .text\n")),

0 commit comments

Comments
 (0)