| ... | ... |
@@ -31,12 +31,16 @@ Begin by building the assembler and emulator by running the build script. The as |
| 31 | 31 |
./build.sh |
| 32 | 32 |
``` |
| 33 | 33 |
|
| 34 |
+### Assembler |
|
| 35 |
+ |
|
| 34 | 36 |
The following command will create an Uxn-compatible rom from an [uxntal file](https://wiki.xxiivv.com/site/uxntal.html), point to a different .tal file in `/projects` to assemble a different rom. |
| 35 | 37 |
|
| 36 | 38 |
``` |
| 37 | 39 |
bin/uxnasm projects/examples/demos/life.tal bin/life.rom |
| 38 | 40 |
``` |
| 39 | 41 |
|
| 42 |
+### Emulator |
|
| 43 |
+ |
|
| 40 | 44 |
To start the rom, point the emulator to the newly created rom: |
| 41 | 45 |
|
| 42 | 46 |
``` |
| ... | ... |
@@ -45,6 +49,14 @@ bin/uxnemu bin/life.rom |
| 45 | 49 |
|
| 46 | 50 |
You can also use the emulator without graphics by using `uxncli`. You can find additional roms [here](https://sr.ht/~rabbits/uxn/sources). |
| 47 | 51 |
|
| 52 |
+### I/O |
|
| 53 |
+ |
|
| 54 |
+You can send events from Uxn to another application, or another instance of uxn, with the Unix pipe. For a companion application that translates notes data into midi, see the [shim](https://git.sr.ht/~rabbits/shim). |
|
| 55 |
+ |
|
| 56 |
+``` |
|
| 57 |
+uxnemu orca.rom | shim |
|
| 58 |
+``` |
|
| 59 |
+ |
|
| 48 | 60 |
## Emulator Controls |
| 49 | 61 |
|
| 50 | 62 |
- `F1` toggle zoom |
| ... | ... |
@@ -18,7 +18,7 @@ typedef signed char Sint8; |
| 18 | 18 |
typedef unsigned short Uint16; |
| 19 | 19 |
|
| 20 | 20 |
typedef struct {
|
| 21 |
- char name[64], items[128][64]; |
|
| 21 |
+ char name[64], items[256][64]; |
|
| 22 | 22 |
Uint8 len; |
| 23 | 23 |
Uint16 refs; |
| 24 | 24 |
} Macro; |
| ... | ... |
@@ -141,7 +141,7 @@ sublabel(char *src, char *scope, char *name) |
| 141 | 141 |
int |
| 142 | 142 |
error(char *name, char *id) |
| 143 | 143 |
{
|
| 144 |
- printf("Error: %s[%s]\n", name, id);
|
|
| 144 |
+ fprintf(stderr, "Error: %s[%s]\n", name, id); |
|
| 145 | 145 |
return 0; |
| 146 | 146 |
} |
| 147 | 147 |
|
| ... | ... |
@@ -167,7 +167,6 @@ makemacro(char *name, FILE *f) |
| 167 | 167 |
return error("Word too long", name);
|
| 168 | 168 |
scpy(word, m->items[m->len++], 64); |
| 169 | 169 |
} |
| 170 |
- printf("New macro #%d: %s, %d items\n", p.mlen, m->name, m->len);
|
|
| 171 | 170 |
return 1; |
| 172 | 171 |
} |
| 173 | 172 |
|
| ... | ... |
@@ -185,7 +184,6 @@ makelabel(char *name, Uint16 addr) |
| 185 | 184 |
l->addr = addr; |
| 186 | 185 |
l->refs = 0; |
| 187 | 186 |
scpy(name, l->name, 64); |
| 188 |
- printf("New label #%d: %s, at 0x%04x\n", p.llen, l->name, l->addr);
|
|
| 189 | 187 |
return 1; |
| 190 | 188 |
} |
| 191 | 189 |
|
| ... | ... |
@@ -293,23 +291,22 @@ pass1(FILE *f) |
| 293 | 291 |
int ccmnt = 0; |
| 294 | 292 |
Uint16 addr = 0; |
| 295 | 293 |
char w[64], scope[64], subw[64]; |
| 296 |
- printf("Pass 1\n");
|
|
| 297 | 294 |
while(fscanf(f, "%s", w) == 1) {
|
| 298 | 295 |
if(skipblock(w, &ccmnt, '(', ')')) continue;
|
| 299 | 296 |
if(w[0] == '|') {
|
| 300 | 297 |
if(!sihx(w + 1)) |
| 301 |
- return error("Invalid padding", w);
|
|
| 298 |
+ return error("Pass 1 - Invalid padding", w);
|
|
| 302 | 299 |
addr = shex(w + 1); |
| 303 | 300 |
} else if(w[0] == '%') {
|
| 304 | 301 |
if(!makemacro(w + 1, f)) |
| 305 |
- return error("Invalid macro", w);
|
|
| 302 |
+ return error("Pass 1 - Invalid macro", w);
|
|
| 306 | 303 |
} else if(w[0] == '@') {
|
| 307 | 304 |
if(!makelabel(w + 1, addr)) |
| 308 |
- return error("Invalid label", w);
|
|
| 305 |
+ return error("Pass 1 - Invalid label", w);
|
|
| 309 | 306 |
scpy(w + 1, scope, 64); |
| 310 | 307 |
} else if(w[0] == '&') {
|
| 311 | 308 |
if(!makelabel(sublabel(subw, scope, w + 1), addr)) |
| 312 |
- return error("Invalid sublabel", w);
|
|
| 309 |
+ return error("Pass 1 - Invalid sublabel", w);
|
|
| 313 | 310 |
} else if(sihx(w)) |
| 314 | 311 |
addr += slen(w) / 2; |
| 315 | 312 |
else |
| ... | ... |
@@ -324,7 +321,6 @@ pass2(FILE *f) |
| 324 | 321 |
{
|
| 325 | 322 |
int ccmnt = 0, cmacr = 0; |
| 326 | 323 |
char w[64], scope[64], subw[64]; |
| 327 |
- printf("Pass 2\n");
|
|
| 328 | 324 |
while(fscanf(f, "%s", w) == 1) {
|
| 329 | 325 |
if(w[0] == '%') continue; |
| 330 | 326 |
if(w[0] == '&') continue; |
| ... | ... |
@@ -334,7 +330,7 @@ pass2(FILE *f) |
| 334 | 330 |
if(skipblock(w, &cmacr, '{', '}')) continue;
|
| 335 | 331 |
if(w[0] == '|') {
|
| 336 | 332 |
if(p.length && shex(w + 1) < p.ptr) |
| 337 |
- return error("Memory Overwrite", w);
|
|
| 333 |
+ return error("Pass 2 - Memory Overwrite", w);
|
|
| 338 | 334 |
p.ptr = shex(w + 1); |
| 339 | 335 |
continue; |
| 340 | 336 |
} else if(w[0] == '$') {
|
| ... | ... |
@@ -347,7 +343,7 @@ pass2(FILE *f) |
| 347 | 343 |
if(w[1] == '&') |
| 348 | 344 |
scpy(sublabel(subw, scope, w + 2), w + 1, 64); |
| 349 | 345 |
if(!parsetoken(w)) |
| 350 |
- return error("Unknown label in second pass", w);
|
|
| 346 |
+ return error("Pass 2 - Unknown label", w);
|
|
| 351 | 347 |
} |
| 352 | 348 |
return 1; |
| 353 | 349 |
} |
| ... | ... |
@@ -356,15 +352,15 @@ void |
| 356 | 352 |
cleanup(char *filename) |
| 357 | 353 |
{
|
| 358 | 354 |
int i; |
| 359 |
- printf("Assembled %s(%d bytes), %d labels, %d macros.\n\n", filename, (p.length - TRIM), p.llen, p.mlen);
|
|
| 360 | 355 |
for(i = 0; i < p.llen; ++i) |
| 361 | 356 |
if(p.labels[i].name[0] >= 'A' && p.labels[i].name[0] <= 'Z') |
| 362 | 357 |
continue; /* Ignore capitalized labels(devices) */ |
| 363 | 358 |
else if(!p.labels[i].refs) |
| 364 |
- printf("--- Unused label: %s\n", p.labels[i].name);
|
|
| 359 |
+ fprintf(stderr, "--- Unused label: %s\n", p.labels[i].name); |
|
| 365 | 360 |
for(i = 0; i < p.mlen; ++i) |
| 366 | 361 |
if(!p.macros[i].refs) |
| 367 |
- printf("--- Unused macro: %s\n", p.macros[i].name);
|
|
| 362 |
+ fprintf(stderr, "--- Unused macro: %s\n", p.macros[i].name); |
|
| 363 |
+ printf("Assembled %s(%d bytes), %d labels, %d macros.\n", filename, (p.length - TRIM), p.llen, p.mlen);
|
|
| 368 | 364 |
} |
| 369 | 365 |
|
| 370 | 366 |
int |