mirror of
https://git.sr.ht/~rabbits/uxn
synced 2024-11-25 15:25:12 +00:00
*
This commit is contained in:
parent
588a0f8b92
commit
72d9c98f35
4 changed files with 67 additions and 50 deletions
56
README.md
56
README.md
|
@ -8,34 +8,29 @@ A stack-based VM, written in ANSI C.
|
||||||
cc uxn.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o uxn
|
cc uxn.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o uxn
|
||||||
```
|
```
|
||||||
|
|
||||||
## OP Codes
|
## Assembly Syntax
|
||||||
|
|
||||||
```
|
```
|
||||||
VALUE OPCODE EXPLANATION
|
: starting a definition
|
||||||
0x00000000 NOP do nothing
|
& obtaining pointers
|
||||||
0x00000001 ADD pop a, pop b, push a + b
|
( stack comments
|
||||||
0x00000002 SUB pop a, pop b, push a - b
|
` inlining bytecodes
|
||||||
0x00000003 AND pop a, pop b, push a & b
|
' strings
|
||||||
0x00000004 OR pop a, pop b, push a | b
|
# numbers
|
||||||
0x00000005 XOR pop a, pop b, push a ^ b
|
$ characters
|
||||||
0x00000006 NOT pop a, push !a
|
~ vector
|
||||||
0x00000007 IN read one byte from stdin, push as word on stack
|
[ 12 34 ] real values
|
||||||
0x00000008 OUT pop one word and write to stream as one byte
|
< 12 34 > relative values
|
||||||
0x00000009 LOAD pop a, push word read from address a
|
( 12 34 ) deadzone
|
||||||
0x0000000A STOR pop a, pop b, write b to address a
|
```
|
||||||
0x0000000B JMP pop a, goto a
|
|
||||||
0x0000000C JZ pop a, pop b, if a == 0 goto b
|
```
|
||||||
0x0000000D PUSH push next word
|
;add-two JSR
|
||||||
0x0000000E DUP duplicate word on stack
|
|
||||||
0x0000000F SWAP swap top two words on stack
|
BRK
|
||||||
0x00000010 ROL3 rotate top three words on stack once left, (a b c) -> (b c a)
|
|
||||||
0x00000011 OUTNUM pop one word and write to stream as number
|
:add-two
|
||||||
0x00000012 JNZ pop a, pop b, if a != 0 goto b
|
[ 2 ] ADD RTS
|
||||||
0x00000013 DROP remove top of stack
|
|
||||||
0x00000014 PUSHIP push a in IP stack
|
|
||||||
0x00000015 POPIP pop IP stack to current IP, effectively performing a jump
|
|
||||||
0x00000016 DROPIP pop IP, but do not jump
|
|
||||||
0x00000017 COMPL pop a, push the complement of a
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
@ -50,12 +45,11 @@ VALUE OPCODE EXPLANATION
|
||||||
|
|
||||||
### Assembly
|
### Assembly
|
||||||
|
|
||||||
- `%25`, decimal
|
#### Addressing
|
||||||
- `#25`, hex
|
|
||||||
|
|
||||||
```
|
- `label`, a named offset[TODO]
|
||||||
2 2 + $ef
|
- `literal`, a numeric value
|
||||||
```
|
- `pointer`, pointer to an address[TODO]
|
||||||
|
|
||||||
### Assembler
|
### Assembler
|
||||||
|
|
||||||
|
|
6
build.sh
6
build.sh
|
@ -10,14 +10,14 @@ rm -f ./uxn
|
||||||
|
|
||||||
# debug(slow)
|
# debug(slow)
|
||||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxnasm.c -o uxnasm
|
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxnasm.c -o uxnasm
|
||||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxn.c -o uxn
|
# cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxn.c -o uxn
|
||||||
|
|
||||||
# build(fast)
|
# build(fast)
|
||||||
# cc uxn.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o uxn
|
# cc uxn.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o uxn
|
||||||
|
|
||||||
# Size
|
# Size
|
||||||
echo "Size: $(du -sk ./uxn)"
|
# echo "Size: $(du -sk ./uxn)"
|
||||||
|
|
||||||
# run
|
# run
|
||||||
./uxnasm program.usm program.rom
|
./uxnasm program.usm program.rom
|
||||||
./uxn program.rom
|
# ./uxn program.rom
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#12 #34 add
|
LIT 25 26 LIT DUP ADD BRK
|
53
uxnasm.c
53
uxnasm.c
|
@ -14,13 +14,14 @@ WITH REGARD TO THIS SOFTWARE.
|
||||||
#define PRGLEN 256
|
#define PRGLEN 256
|
||||||
|
|
||||||
typedef unsigned char Uint8;
|
typedef unsigned char Uint8;
|
||||||
typedef unsigned short Uint16;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int ptr;
|
int ptr;
|
||||||
Uint16 data[PRGLEN];
|
Uint8 data[PRGLEN];
|
||||||
} Program;
|
} Program;
|
||||||
|
|
||||||
|
char opcodes[][4] = {"BRK", "LIT", "DUP", "DRP", "SWP", "SLP", "PSH", "POP", "JMP", "JSR", "RST", "BEQ", "EQU", "NEQ", "LTH", "GTH"};
|
||||||
|
|
||||||
Program p;
|
Program p;
|
||||||
|
|
||||||
#pragma mark - Helpers
|
#pragma mark - Helpers
|
||||||
|
@ -35,6 +36,16 @@ scmp(char *a, char *b) /* string compare */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
suca(char *s) /* string to uppercase */
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
char c;
|
||||||
|
while((c = s[i]))
|
||||||
|
s[i++] = c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
shex(char *s) /* string to num */
|
shex(char *s) /* string to num */
|
||||||
{
|
{
|
||||||
|
@ -53,10 +64,27 @@ shex(char *s) /* string to num */
|
||||||
Uint8
|
Uint8
|
||||||
getopcode(char *s)
|
getopcode(char *s)
|
||||||
{
|
{
|
||||||
if(scmp(s, "add")) {
|
int i;
|
||||||
return 0x01;
|
for(i = 0; i < 16; ++i)
|
||||||
|
if(scmp(opcodes[i], suca(s)))
|
||||||
|
return i;
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
echo(Uint8 *s, Uint8 len, Uint8 ptr, char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("%s\n", name);
|
||||||
|
for(i = 0; i < len; ++i) {
|
||||||
|
if(i % 16 == 0)
|
||||||
|
printf("\n");
|
||||||
|
if(ptr == i)
|
||||||
|
printf("[%02x]", s[i]);
|
||||||
|
else
|
||||||
|
printf(" %02x ", s[i]);
|
||||||
}
|
}
|
||||||
return 0;
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -64,16 +92,10 @@ pass1(FILE *f)
|
||||||
{
|
{
|
||||||
char word[64];
|
char word[64];
|
||||||
while(fscanf(f, "%s", word) == 1) {
|
while(fscanf(f, "%s", word) == 1) {
|
||||||
int lit = 0, val = 0;
|
int op = getopcode(word);
|
||||||
if(word[0] == '#') {
|
if(op == 0xff)
|
||||||
lit = 0;
|
op = shex(word);
|
||||||
val = shex(word + 1);
|
p.data[p.ptr++] = op;
|
||||||
} else {
|
|
||||||
lit = 1;
|
|
||||||
val = getopcode(word);
|
|
||||||
}
|
|
||||||
printf("#%d -> %s[%02x %02x]\n", p.ptr, word, lit, val);
|
|
||||||
p.data[p.ptr++] = (val << 8) + (lit & 0xff);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,5 +117,6 @@ main(int argc, char *argv[])
|
||||||
pass1(f);
|
pass1(f);
|
||||||
fwrite(p.data, sizeof(p.data), 1, fopen(argv[2], "wb"));
|
fwrite(p.data, sizeof(p.data), 1, fopen(argv[2], "wb"));
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
echo(p.data, 0x40, 0, "program");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue