uxn

Varvara Ordinator, written in ANSI C(SDL2)
git clone https://git.eamoncaddigan.net/uxn.git
Log | Files | Refs | README | LICENSE

commit 854683bdce88af7d70e6d93123d2fb56a1cdb947
parent 8c6ad15d0361dc77e1e1cd3843acc5a643d99187
Author: neauoire <aliceffekt@gmail.com>
Date:   Mon,  8 Feb 2021 14:18:01 -0800

Cleanup

Diffstat:
M.gitignore | 3+--
Ruxnasm.c -> assembler.c | 0
Mbuild.sh | 27++++++++++++++-------------
Dcpu.c | 210-------------------------------------------------------------------------------
Dcpu.h | 49-------------------------------------------------
Aemulator.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Muxn.c | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Auxn.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 313 insertions(+), 313 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,6 +3,5 @@ *png~ *gif~ *bmp~ -uxn -uxnasm +/bin *.rom \ No newline at end of file diff --git a/uxnasm.c b/assembler.c diff --git a/build.sh b/build.sh @@ -1,20 +1,21 @@ #!/bin/bash -# format code -clang-format -i uxnasm.c -clang-format -i uxn.c -clang-format -i cpu.h -clang-format -i cpu.c +# Create bin folder +mkdir -p bin -# remove old -rm -f ./uxnasm -rm -f ./uxn +# Assembler +clang-format -i assembler.c +rm -f ./assembler rm -f ./boot.rom +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 assembler.c -o bin/assembler +./bin/assembler examples/hello.usm bin/boot.rom -# 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 cpu.c uxn.c -o uxn +# Emulator +clang-format -i emulator.c +clang-format -i uxn.h +clang-format -i uxn.c +rm -f ./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 emulator.c -o bin/emulator # run -./uxnasm examples/hello.usm boot.rom -./uxn boot.rom +./bin/emulator bin/boot.rom diff --git a/cpu.c b/cpu.c @@ -1,210 +0,0 @@ -#include <stdio.h> - -/* -Copyright (c) 2021 Devine Lu Linvega - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE. -*/ - -#include "cpu.h" - -Cpu cpu; - -#pragma mark - Helpers - -void -setflag(Uint8 *status, char flag, int b) -{ - if(b) - *status |= flag; - else - *status &= (~flag); -} - -int -getflag(Uint8 *status, char flag) -{ - return *status & flag; -} - -#pragma mark - Operations - -/* clang-format off */ - -Uint16 bytes2short(Uint8 a, Uint8 b) { return (a << 8) + b; } -Uint16 mempeek16(Cpu *c, Uint16 s) { return (c->ram.dat[s] << 8) + (c->ram.dat[s+1] & 0xff); } -void wspush8(Cpu *c, Uint8 b) { c->wst.dat[c->wst.ptr++] = b; } -void wspush16(Cpu *c, Uint16 s) { wspush8(c,s >> 8); wspush8(c,s & 0xff); } -Uint8 wspop8(Cpu *c) { return c->wst.dat[--c->wst.ptr]; } -Uint16 wspop16(Cpu *c) { return wspop8(c) + (wspop8(c) << 8); } -Uint8 wspeek8(Cpu *c, Uint8 o) { return c->wst.dat[c->wst.ptr - o]; } -Uint16 wspeek16(Cpu *c, Uint8 o) { return bytes2short(c->wst.dat[c->wst.ptr - o], c->wst.dat[c->wst.ptr - o + 1]); } -Uint16 rspop16(Cpu *c) { return c->rst.dat[--c->rst.ptr]; } -void rspush16(Cpu *c, Uint16 a) { c->rst.dat[c->rst.ptr++] = a; } -/* I/O */ -void op_brk(Cpu *c) { setflag(&c->status,FLAG_HALT, 1); } -void op_lit(Cpu *c) { c->literal += c->ram.dat[c->ram.ptr++]; } -void op_nop(Cpu *c) { (void)c; printf("NOP");} -void op_ldr(Cpu *c) { wspush8(c, c->ram.dat[wspop16(c)]); } -void op_str(Cpu *c) { c->ram.dat[wspop16(c)] = wspop8(c); } -/* Logic */ -void op_jmp(Cpu *c) { c->ram.ptr = wspop16(c); } -void op_jsr(Cpu *c) { rspush16(c, c->ram.ptr); c->ram.ptr = wspop16(c); } -void op_rts(Cpu *c) { c->ram.ptr = rspop16(c); } -/* Stack */ -void op_pop(Cpu *c) { wspop8(c); } -void op_dup(Cpu *c) { wspush8(c,wspeek8(c,1)); } -void op_swp(Cpu *c) { Uint8 b = wspop8(c), a = wspop8(c); wspush8(c,b); wspush8(c,a); } -void op_ovr(Cpu *c) { Uint8 a = wspeek8(c,2); wspush8(c,a); } -void op_rot(Cpu *c) { Uint8 c1 = wspop8(c),b = wspop8(c),a = wspop8(c); wspush8(c,b); wspush8(c, c1); wspush8(c,a); } -void op_and(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a & b); } -void op_ora(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a | b); } -void op_rol(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a << b); } -/* Arithmetic */ -void op_add(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b + a); } -void op_sub(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b - a); } -void op_mul(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b * a); } -void op_div(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b / a); } -void op_equ(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b == a); } -void op_neq(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b != a); } -void op_gth(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b > a); } -void op_lth(Cpu *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b < a); } -/* Stack(16-bits) */ -void op_pop16(Cpu *c) { wspop16(c); } -void op_dup16(Cpu *c) { wspush16(c,wspeek16(c,2)); } -void op_swp16(Cpu *c) { Uint16 b = wspop16(c), a = wspop16(c); wspush16(c,b); wspush16(c,a); } -void op_ovr16(Cpu *c) { Uint16 a = wspeek16(c, 4); wspush16(c,a); } -void op_rot16(Cpu *c) { Uint16 c1 = wspop16(c), b = wspop16(c), a = wspop16(c); wspush16(c,b); wspush16(c, c1); wspush16(c,a); } -void op_and16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a & b); } -void op_ora16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a | b); } -void op_rol16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a << b); } -/* Arithmetic(16-bits) */ -void op_add16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b + a); } -void op_sub16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b - a); } -void op_mul16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b * a); } -void op_div16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b / a); } -void op_equ16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b == a); } -void op_neq16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b != a); } -void op_gth16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b > a); } -void op_lth16(Cpu *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b < a); } - -void (*ops[])(Cpu *c) = { - op_brk, op_lit, op_nop, op_nop, op_nop, op_nop, op_ldr, op_str, - op_jmp, op_jsr, op_nop, op_rts, op_nop, op_nop, op_nop, op_nop, - op_pop, op_dup, op_swp, op_ovr, op_rot, op_and, op_ora, op_rol, - op_add, op_sub, op_mul, op_div, op_equ, op_neq, op_gth, op_lth, - op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, op_and16, op_ora16, op_rol16, - op_add16, op_sub16, op_mul16, op_div16, op_equ16, op_neq16, op_gth16, op_lth16 -}; - -Uint8 opr[][2] = { - {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {2,1}, {3,0}, - {2,0}, {2,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, - {1,0}, {1,2}, {2,2}, {3,3}, {3,3}, {2,1}, {2,1}, {2,1}, - {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, - {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, /* TODO */ - {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} /* TODO */ -}; - -/* clang-format on */ - -int -error(Cpu *c, char *name, int id) -{ - printf("Error: %s#%04x, at 0x%04x\n", name, id, c->counter); - return 0; -} - -int -doliteral(Cpu *c, Uint8 instr) -{ - if(c->wst.ptr >= 255) - return error(c, "Stack overflow", instr); - wspush8(c, instr); - c->literal--; - return 1; -} - -int -dodevices(Cpu *c) /* experimental */ -{ - if(c->ram.dat[0xfff1]) { - printf("%c", c->ram.dat[0xfff1]); - c->ram.dat[0xfff1] = 0x00; - } - return 1; -} - -int -doopcode(Cpu *c, Uint8 instr) -{ - Uint8 op = instr & 0x1f; - setflag(&c->status, FLAG_SHORT, (instr >> 5) & 1); - setflag(&c->status, FLAG_SIGN, (instr >> 6) & 1); /* usused */ - setflag(&c->status, FLAG_COND, (instr >> 7) & 1); - if(getflag(&c->status, FLAG_SHORT)) - op += 16; - if(c->wst.ptr < opr[op][0]) - return error(c, "Stack underflow", op); - if(c->wst.ptr + opr[op][1] - opr[op][0] >= 255) - return error(c, "Stack overflow", instr); - if(!getflag(&c->status, FLAG_COND) || (getflag(&c->status, FLAG_COND) && wspop8(c))) - (*ops[op])(c); - dodevices(c); - return 1; -} - -int -eval(Cpu *c) -{ - Uint8 instr = c->ram.dat[c->ram.ptr++]; - if(c->literal > 0) - return doliteral(c, instr); - else - return doopcode(c, instr); - return 1; -} - -int -load(Cpu *c, char *filepath) -{ - FILE *f; - if(!(f = fopen(filepath, "rb"))) - return error(c, "Missing input.", 0); - fread(c->ram.dat, sizeof(c->ram.dat), 1, f); - return 1; -} - -void -reset(Cpu *c) -{ - size_t i; - char *cptr = (char *)c; - for(i = 0; i < sizeof c; i++) - cptr[i] = 0; -} - -int -boot(Cpu *c) -{ - reset(c); - c->vreset = mempeek16(c, 0xfffa); - c->vframe = mempeek16(c, 0xfffc); - c->verror = mempeek16(c, 0xfffe); - /* eval reset */ - c->ram.ptr = c->vreset; - setflag(&c->status, FLAG_HALT, 0); - while(!(c->status & FLAG_HALT) && eval(c)) - c->counter++; - /* eval frame */ - c->ram.ptr = c->vframe; - setflag(&c->status, FLAG_HALT, 0); - while(!(c->status & FLAG_HALT) && eval(c)) - c->counter++; - return 1; -} diff --git a/cpu.h b/cpu.h @@ -1,49 +0,0 @@ -#include <stdio.h> - -/* -Copyright (c) 2021 Devine Lu Linvega - -Permission to use, copy, modify, and distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE. -*/ - -typedef unsigned char Uint8; -typedef unsigned short Uint16; - -#define FLAG_HALT 0x01 -#define FLAG_SHORT 0x02 -#define FLAG_SIGN 0x04 -#define FLAG_COND 0x08 - -typedef struct { - Uint8 ptr; - Uint8 dat[256]; -} Stack8; - -typedef struct { - Uint8 ptr; - Uint16 dat[256]; -} Stack16; - -typedef struct { - Uint16 ptr; - Uint8 dat[65536]; -} Memory; - -typedef struct { - Uint8 literal, status; - Uint16 counter, vreset, vframe, verror; - Stack8 wst; - Stack16 rst; - Memory ram; -} Cpu; - -void setflag(Uint8 *status, char flag, int b); -int getflag(Uint8 *status, char flag); -int error(Cpu *c, char *name, int id); -int load(Cpu *c, char *filepath); -int boot(Cpu *c); diff --git a/emulator.c b/emulator.c @@ -0,0 +1,67 @@ +#include <stdio.h> +#include "uxn.h" + +/* +Copyright (c) 2021 Devine Lu Linvega + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +void +echos(Stack8 *s, Uint8 len, char *name) +{ + int i; + printf("\n%s\n", name); + for(i = 0; i < len; ++i) { + if(i % 16 == 0) + printf("\n"); + printf("%02x%c", s->dat[i], s->ptr == i ? '<' : ' '); + } + printf("\n\n"); +} + +void +echom(Memory *m, Uint8 len, char *name) +{ + int i; + printf("\n%s\n", name); + for(i = 0; i < len; ++i) { + if(i % 16 == 0) + printf("\n"); + printf("%02x ", m->dat[i]); + } + printf("\n\n"); +} + +void +echof(Uxn *c) +{ + printf("ended @ %d steps | hf: %x sf: %x sf: %x cf: %x\n", + c->counter, + getflag(&c->status, FLAG_HALT) != 0, + getflag(&c->status, FLAG_SHORT) != 0, + getflag(&c->status, FLAG_SIGN) != 0, + getflag(&c->status, FLAG_COND) != 0); +} + +int +main(int argc, char *argv[]) +{ + Uxn cpu; + if(argc < 2) + return error(&cpu, "No input.", 0); + if(!load(&cpu, argv[1])) + return error(&cpu, "Load error", 0); + if(!boot(&cpu)) + return error(&cpu, "Boot error", 0); + /* print result */ + echos(&cpu.wst, 0x40, "stack"); + echom(&cpu.ram, 0x40, "ram"); + echof(&cpu); + return 0; +} diff --git a/uxn.c b/uxn.c @@ -1,5 +1,4 @@ #include <stdio.h> -#include "cpu.h" /* Copyright (c) 2021 Devine Lu Linvega @@ -12,56 +11,200 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. */ +#include "uxn.h" + +Uxn cpu; + +#pragma mark - Helpers + void -echos(Stack8 *s, Uint8 len, char *name) +setflag(Uint8 *status, char flag, int b) { - int i; - printf("\n%s\n", name); - for(i = 0; i < len; ++i) { - if(i % 16 == 0) - printf("\n"); - printf("%02x%c", s->dat[i], s->ptr == i ? '<' : ' '); - } - printf("\n\n"); + if(b) + *status |= flag; + else + *status &= (~flag); } -void -echom(Memory *m, Uint8 len, char *name) +int +getflag(Uint8 *status, char flag) +{ + return *status & flag; +} + +#pragma mark - Operations + +/* clang-format off */ + +Uint16 bytes2short(Uint8 a, Uint8 b) { return (a << 8) + b; } +Uint16 mempeek16(Uxn *c, Uint16 s) { return (c->ram.dat[s] << 8) + (c->ram.dat[s+1] & 0xff); } +void wspush8(Uxn *c, Uint8 b) { c->wst.dat[c->wst.ptr++] = b; } +void wspush16(Uxn *c, Uint16 s) { wspush8(c,s >> 8); wspush8(c,s & 0xff); } +Uint8 wspop8(Uxn *c) { return c->wst.dat[--c->wst.ptr]; } +Uint16 wspop16(Uxn *c) { return wspop8(c) + (wspop8(c) << 8); } +Uint8 wspeek8(Uxn *c, Uint8 o) { return c->wst.dat[c->wst.ptr - o]; } +Uint16 wspeek16(Uxn *c, Uint8 o) { return bytes2short(c->wst.dat[c->wst.ptr - o], c->wst.dat[c->wst.ptr - o + 1]); } +Uint16 rspop16(Uxn *c) { return c->rst.dat[--c->rst.ptr]; } +void rspush16(Uxn *c, Uint16 a) { c->rst.dat[c->rst.ptr++] = a; } +/* I/O */ +void op_brk(Uxn *c) { setflag(&c->status,FLAG_HALT, 1); } +void op_lit(Uxn *c) { c->literal += c->ram.dat[c->ram.ptr++]; } +void op_nop(Uxn *c) { (void)c; printf("NOP");} +void op_ldr(Uxn *c) { wspush8(c, c->ram.dat[wspop16(c)]); } +void op_str(Uxn *c) { c->ram.dat[wspop16(c)] = wspop8(c); } +/* Logic */ +void op_jmp(Uxn *c) { c->ram.ptr = wspop16(c); } +void op_jsr(Uxn *c) { rspush16(c, c->ram.ptr); c->ram.ptr = wspop16(c); } +void op_rts(Uxn *c) { c->ram.ptr = rspop16(c); } +/* Stack */ +void op_pop(Uxn *c) { wspop8(c); } +void op_dup(Uxn *c) { wspush8(c,wspeek8(c,1)); } +void op_swp(Uxn *c) { Uint8 b = wspop8(c), a = wspop8(c); wspush8(c,b); wspush8(c,a); } +void op_ovr(Uxn *c) { Uint8 a = wspeek8(c,2); wspush8(c,a); } +void op_rot(Uxn *c) { Uint8 c1 = wspop8(c),b = wspop8(c),a = wspop8(c); wspush8(c,b); wspush8(c, c1); wspush8(c,a); } +void op_and(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a & b); } +void op_ora(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a | b); } +void op_rol(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,a << b); } +/* Arithmetic */ +void op_add(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b + a); } +void op_sub(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b - a); } +void op_mul(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b * a); } +void op_div(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b / a); } +void op_equ(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b == a); } +void op_neq(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b != a); } +void op_gth(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b > a); } +void op_lth(Uxn *c) { Uint8 a = wspop8(c), b = wspop8(c); wspush8(c,b < a); } +/* Stack(16-bits) */ +void op_pop16(Uxn *c) { wspop16(c); } +void op_dup16(Uxn *c) { wspush16(c,wspeek16(c,2)); } +void op_swp16(Uxn *c) { Uint16 b = wspop16(c), a = wspop16(c); wspush16(c,b); wspush16(c,a); } +void op_ovr16(Uxn *c) { Uint16 a = wspeek16(c, 4); wspush16(c,a); } +void op_rot16(Uxn *c) { Uint16 c1 = wspop16(c), b = wspop16(c), a = wspop16(c); wspush16(c,b); wspush16(c, c1); wspush16(c,a); } +void op_and16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a & b); } +void op_ora16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a | b); } +void op_rol16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,a << b); } +/* Arithmetic(16-bits) */ +void op_add16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b + a); } +void op_sub16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b - a); } +void op_mul16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b * a); } +void op_div16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush16(c,b / a); } +void op_equ16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b == a); } +void op_neq16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b != a); } +void op_gth16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b > a); } +void op_lth16(Uxn *c) { Uint16 a = wspop16(c), b = wspop16(c); wspush8(c,b < a); } + +void (*ops[])(Uxn *c) = { + op_brk, op_lit, op_nop, op_nop, op_nop, op_nop, op_ldr, op_str, + op_jmp, op_jsr, op_nop, op_rts, op_nop, op_nop, op_nop, op_nop, + op_pop, op_dup, op_swp, op_ovr, op_rot, op_and, op_ora, op_rol, + op_add, op_sub, op_mul, op_div, op_equ, op_neq, op_gth, op_lth, + op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16, op_and16, op_ora16, op_rol16, + op_add16, op_sub16, op_mul16, op_div16, op_equ16, op_neq16, op_gth16, op_lth16 +}; + +Uint8 opr[][2] = { + {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {2,1}, {3,0}, + {2,0}, {2,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, + {1,0}, {1,2}, {2,2}, {3,3}, {3,3}, {2,1}, {2,1}, {2,1}, + {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, {2,1}, + {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, /* TODO */ + {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} /* TODO */ +}; + +/* clang-format on */ + +int +error(Uxn *c, char *name, int id) +{ + printf("Error: %s#%04x, at 0x%04x\n", name, id, c->counter); + return 0; +} + +int +doliteral(Uxn *c, Uint8 instr) +{ + if(c->wst.ptr >= 255) + return error(c, "Stack overflow", instr); + wspush8(c, instr); + c->literal--; + return 1; +} + +int +dodevices(Uxn *c) /* experimental */ { - int i; - printf("\n%s\n", name); - for(i = 0; i < len; ++i) { - if(i % 16 == 0) - printf("\n"); - printf("%02x ", m->dat[i]); + if(c->ram.dat[0xfff1]) { + printf("%c", c->ram.dat[0xfff1]); + c->ram.dat[0xfff1] = 0x00; } - printf("\n\n"); + return 1; +} + +int +doopcode(Uxn *c, Uint8 instr) +{ + Uint8 op = instr & 0x1f; + setflag(&c->status, FLAG_SHORT, (instr >> 5) & 1); + setflag(&c->status, FLAG_SIGN, (instr >> 6) & 1); /* usused */ + setflag(&c->status, FLAG_COND, (instr >> 7) & 1); + if(getflag(&c->status, FLAG_SHORT)) + op += 16; + if(c->wst.ptr < opr[op][0]) + return error(c, "Stack underflow", op); + if(c->wst.ptr + opr[op][1] - opr[op][0] >= 255) + return error(c, "Stack overflow", instr); + if(!getflag(&c->status, FLAG_COND) || (getflag(&c->status, FLAG_COND) && wspop8(c))) + (*ops[op])(c); + dodevices(c); + return 1; +} + +int +eval(Uxn *c) +{ + Uint8 instr = c->ram.dat[c->ram.ptr++]; + if(c->literal > 0) + return doliteral(c, instr); + else + return doopcode(c, instr); + return 1; +} + +int +load(Uxn *c, char *filepath) +{ + FILE *f; + if(!(f = fopen(filepath, "rb"))) + return error(c, "Missing input.", 0); + fread(c->ram.dat, sizeof(c->ram.dat), 1, f); + return 1; } void -echof(Cpu *c) +reset(Uxn *c) { - printf("ended @ %d steps | hf: %x sf: %x sf: %x cf: %x\n", - c->counter, - getflag(&c->status, FLAG_HALT) != 0, - getflag(&c->status, FLAG_SHORT) != 0, - getflag(&c->status, FLAG_SIGN) != 0, - getflag(&c->status, FLAG_COND) != 0); + size_t i; + char *cptr = (char *)c; + for(i = 0; i < sizeof c; i++) + cptr[i] = 0; } int -main(int argc, char *argv[]) +boot(Uxn *c) { - Cpu cpu; - if(argc < 2) - return error(&cpu, "No input.", 0); - if(!load(&cpu, argv[1])) - return error(&cpu, "Load error", 0); - if(!boot(&cpu)) - return error(&cpu, "Boot error", 0); - /* print result */ - echos(&cpu.wst, 0x40, "stack"); - echom(&cpu.ram, 0x40, "ram"); - echof(&cpu); - return 0; + reset(c); + c->vreset = mempeek16(c, 0xfffa); + c->vframe = mempeek16(c, 0xfffc); + c->verror = mempeek16(c, 0xfffe); + /* eval reset */ + c->ram.ptr = c->vreset; + setflag(&c->status, FLAG_HALT, 0); + while(!(c->status & FLAG_HALT) && eval(c)) + c->counter++; + /* eval frame */ + c->ram.ptr = c->vframe; + setflag(&c->status, FLAG_HALT, 0); + while(!(c->status & FLAG_HALT) && eval(c)) + c->counter++; + return 1; } diff --git a/uxn.h b/uxn.h @@ -0,0 +1,49 @@ +#include <stdio.h> + +/* +Copyright (c) 2021 Devine Lu Linvega + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +typedef unsigned char Uint8; +typedef unsigned short Uint16; + +#define FLAG_HALT 0x01 +#define FLAG_SHORT 0x02 +#define FLAG_SIGN 0x04 +#define FLAG_COND 0x08 + +typedef struct { + Uint8 ptr; + Uint8 dat[256]; +} Stack8; + +typedef struct { + Uint8 ptr; + Uint16 dat[256]; +} Stack16; + +typedef struct { + Uint16 ptr; + Uint8 dat[65536]; +} Memory; + +typedef struct { + Uint8 literal, status; + Uint16 counter, vreset, vframe, verror; + Stack8 wst; + Stack16 rst; + Memory ram; +} Uxn; + +void setflag(Uint8 *status, char flag, int b); +int getflag(Uint8 *status, char flag); +int error(Uxn *c, char *name, int id); +int load(Uxn *c, char *filepath); +int boot(Uxn *c);