uxn

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

commit c1bffc1f8a0f3f05a6b46ecc5b0922aba8358ebc
parent 8b407af780b7b37e0fa3f8db7e449df55912214b
Author: neauoire <aliceffekt@gmail.com>
Date:   Wed, 10 Feb 2021 11:06:36 -0800

Added screen example

Diffstat:
MREADME.md | 30+++++++-----------------------
Memulator.c | 30+++++++++++++++++++++---------
Mexamples/mouse.usm | 48+++++++++++++++++++++---------------------------
Aexamples/screen.usm | 38++++++++++++++++++++++++++++++++++++++
Mexamples/test.usm | 38+++++++++++++++++++++++++++++++++++---
Muxn.c | 31++++++++++++++++++++++---------
Muxn.h | 8++++----
7 files changed, 148 insertions(+), 75 deletions(-)

diff --git a/README.md b/README.md @@ -31,15 +31,13 @@ A [stack-based VM](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C. ( hello world ) ;iterator -:dev1r FFF0 -:dev1w FFF1 |0100 @RESET -@word1 "hello_word ( len: 0x0b ) +@word1 "hello_world ( len: 0x0b ) @loop - ,dev1w STR ( write to stdout ) + ,00 IOW ( write to device#0 ) ,incr JSR ( increment itr ) ,word1 ,strlen JSR ( get strlen ) NEQ ,loop ROT JSR? ( loop != strlen ) @@ -64,25 +62,11 @@ BRK ## TODOs -### Assembler - -- Implement shorthand operators -- Signed operations - -### CPU - -- Signed operations -- Catch overflow/underflow -- A Three-Way Decision Routine(http://www.6502.org/tutorials/compare_instructions.html) -- Draw pixel to screen -- Redo overflow/underflow mappping -- Detect mouse click -- SDL Layer Emulator -- Build PPU - -### Devices - -- Devices each have an input byte, an output byte and two request bytes. +- Implement signed flag to operators. +- On-screen debugger. +- 16b mode for str/ldr +- Auto-advance ldr? +- Getting rid of IOR/IOW would be nice.. ## Refs diff --git a/emulator.c b/emulator.c @@ -59,7 +59,7 @@ void putpixel(Uint32 *dst, int x, int y, int color) { if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8) - dst[(y + PAD * 8) * WIDTH + (x + PAD * 8)] = theme[color]; + dst[y * WIDTH + x] = theme[color]; } void @@ -145,14 +145,18 @@ echof(Uxn *c) void domouse(SDL_Event *event) { - devmouse->mem[0] = event->motion.x / ZOOM - PAD * 8; - devmouse->mem[1] = event->motion.y / ZOOM - PAD * 8; + int x = event->motion.x / ZOOM; + int y = event->motion.y / ZOOM; + devmouse->mem[0] = (x >> 8) & 0xff; + devmouse->mem[1] = x & 0xff; + devmouse->mem[2] = (y >> 8) & 0xff; + devmouse->mem[3] = y & 0xff; switch(event->type) { case SDL_MOUSEBUTTONUP: - devmouse->mem[2] = 0; + devmouse->mem[4] = 0; break; case SDL_MOUSEBUTTONDOWN: - devmouse->mem[2] = event->button.button == SDL_BUTTON_LEFT; + devmouse->mem[4] = event->button.button == SDL_BUTTON_LEFT; } } @@ -186,9 +190,7 @@ consolew(Device *d, Uint8 b) Uint8 screenr(Device *d, Uint8 b) { - (void)b; - (void)d; - return 0; + return d->mem[b]; } Uint8 @@ -197,8 +199,8 @@ screenw(Device *d, Uint8 b) d->mem[d->len++] = b; if(d->len > 5) { putpixel(pixels, - (d->mem[0] << 8) + d->mem[1], (d->mem[2] << 8) + d->mem[3], + (d->mem[0] << 8) + d->mem[1], d->mem[4]); if(d->mem[5]) redraw(pixels); @@ -244,6 +246,11 @@ start(Uxn *u) { int ticknext = 0; evaluxn(u, u->vreset); + + echos(&u->wst, 0x40, "stack"); + echom(&u->ram, 0x40, "ram"); + echof(u); + while(1) { int tick = SDL_GetTicks(); SDL_Event event; @@ -286,6 +293,11 @@ main(int argc, char **argv) devmouse = portuxn(&u, "mouse", mouser, mousew); devkey = portuxn(&u, "key", keyr, keyw); + devscreen->mem[0] = (WIDTH >> 8) & 0xff; + devscreen->mem[1] = WIDTH & 0xff; + devscreen->mem[2] = (HEIGHT >> 8) & 0xff; + devscreen->mem[3] = HEIGHT & 0xff; + start(&u); echos(&u.wst, 0x40, "stack"); diff --git a/examples/mouse.usm b/examples/mouse.usm @@ -1,46 +1,40 @@ -( draw pixel ) +( mouse ) -|0100 @RESET +:dev/r fff8 ( std read port ) +:dev/w fff9 ( std write port ) + +|0100 @RESET - ( draw 3 pixels ) - ,00 ,01 ,0000 ,0000 ,putpixel JSR - ,00 ,02 ,0001 ,0001 ,putpixel JSR - ,01 ,03 ,0002 ,0002 ,putpixel JSR + ,02 ,dev/r STR ( set dev/read mouse#02 ) + ,01 ,dev/w STR ( set dev/write screen#01 ) BRK -|c000 @FRAME - +|c000 @FRAME + ( get mouse button, or break ) - ,02 ,02 IOR + ,04 IOR ,01 NEQ BRK? - - ( print A to console on click ) - ,02 ,02 IOR - ,41 ADD - ,putbyte JSR - + ( paint a white pixel ) ,01 ,01 ,getmouse JSR ,putpixel JSR -BRK -@putpixel - SWP ,01 IOW ,01 IOW ( y ) - SWP ,01 IOW ,01 IOW ( x ) - ,01 IOW ( color ) - ,01 IOW ( redraw ) - RTS +BRK -@getmouse ( push y,x to stack ) - ,00 ,01 ,02 IOR ( grab y ) - ,00 ,00 ,02 IOR ( grab x ) +@getmouse + ,00 IOR^ ( get mouse x ) + ,02 IOR^ ( get mouse y ) RTS -@putbyte ( print to console ) - ,00 IOW RTS +@putpixel + IOW^ ( y short ) + IOW^ ( x short ) + IOW ( color byte ) + IOW ( redraw byte ) + RTS |d000 @ERROR BRK |FFFA .RESET .FRAME .ERROR diff --git a/examples/screen.usm b/examples/screen.usm @@ -0,0 +1,38 @@ +( screen ) + +:dev/r fff8 ( std read port ) +:dev/w fff9 ( std write port ) +;width0 +;width1 +;height0 +;height1 + +|0100 @RESET + + ( set read/write to dev/screen ) + ,01 DUP ,dev/r STR ,dev/w STR + + ( load screen size ) + ,00 IOR^ ,width0 STR^ + ,02 IOR^ ,height0 STR^ + + ( draw pixel at screen center ) + + ,0101 + ,width0 LDR^ ,0002 DIV^ + ,height0 LDR^ ,0002 DIV^ + ,putpixel JSR + +BRK + +|c000 @FRAME BRK + +@putpixel + IOW^ ( y short ) + IOW^ ( x short ) + IOW ( color byte ) + IOW ( redraw byte ) + RTS + +|d000 @ERROR BRK +|FFFA .RESET .FRAME .ERROR diff --git a/examples/test.usm b/examples/test.usm @@ -1,13 +1,45 @@ ( my default test file ) -;iterator +:dev/r fff8 ( std read port ) +:dev/w fff9 ( std write port ) |0100 @RESET + + ,02 ,dev/r STR ( set dev/read mouse#02 ) + ,01 ,dev/w STR ( set dev/write screen#01 ) - ,1234 + ,00 ,01 ,0001 ,0000 ,putpixel JSR + ,00 ,01 ,0000 ,0001 ,putpixel JSR + ,00 ,01 ,0002 ,0001 ,putpixel JSR + ,01 ,02 ,0001 ,0002 ,putpixel JSR BRK -|c000 @FRAME BRK +|c000 @FRAME + + ( get mouse button, or break ) + ,04 IOR + ,01 NEQ + BRK? + + ( paint a white pixel ) + ,01 ,01 + ,getmouse JSR + ,putpixel JSR + +BRK + +@getmouse + ,02 IOR^ ( get mouse y ) + ,00 IOR^ ( get mouse x ) + RTS + +@putpixel + IOW^ ( y short ) + IOW^ ( x short ) + IOW ( color byte ) + IOW ( redraw byte ) + RTS + |d000 @ERROR BRK |FFFA .RESET .FRAME .ERROR diff --git a/uxn.c b/uxn.c @@ -19,13 +19,13 @@ WITH REGARD TO THIS SOFTWARE. void setflag(Uint8 *st, char flag, int b) { if(b) *st |= flag; else *st &= (~flag); } int getflag(Uint8 *st, char flag) { return *st & flag; } -Uint16 bytes2short(Uint8 a, Uint8 b) { return (a << 8) + b; } void wspush8(Uxn *u, Uint8 b) { u->wst.dat[u->wst.ptr++] = b; } Uint8 wspop8(Uxn *u) { return u->wst.dat[--u->wst.ptr]; } Uint8 wspeek8(Uxn *u, Uint8 o) { return u->wst.dat[u->wst.ptr - o]; } +Uint8 mempeek8(Uxn *u, Uint16 s) { return u->ram.dat[s]; } void wspush16(Uxn *u, Uint16 s) { wspush8(u,s >> 8); wspush8(u,s & 0xff); } Uint16 wspop16(Uxn *u) { return wspop8(u) + (wspop8(u) << 8); } -Uint16 wspeek16(Uxn *u, Uint8 o) { return bytes2short(u->wst.dat[u->wst.ptr - o], u->wst.dat[u->wst.ptr - o + 1]); } +Uint16 wspeek16(Uxn *u, Uint8 o) { return (u->wst.dat[u->wst.ptr - o] << 8) + u->wst.dat[u->wst.ptr - o + 1]; } void rspush16(Uxn *u, Uint16 a) { u->rst.dat[u->rst.ptr++] = a; } Uint16 mempeek16(Uxn *u, Uint16 s) { return (u->ram.dat[s] << 8) + (u->ram.dat[s + 1] & 0xff); } @@ -34,8 +34,8 @@ void op_brk(Uxn *u) { setflag(&u->status,FLAG_HALT, 1); } void op_li1(Uxn *u) { u->literal += 1; } void op_lix(Uxn *u) { u->literal += u->ram.dat[u->ram.ptr++]; } void op_nop(Uxn *u) { printf("NOP"); (void)u; } -void op_ior(Uxn *u) { Uint8 devid = wspop8(u); Uint16 devop = wspop8(u); Device *dev = &u->dev[devid]; if(devid < u->devices) wspush8(u, dev->rfn(dev,devop)); } -void op_iow(Uxn *u) { Uint8 devid = wspop8(u); Uint16 devop = wspop8(u); Device *dev = &u->dev[devid]; if(devid < u->devices) dev->wfn(dev,devop); } +void op_ior(Uxn *u) { Device *dev = &u->dev[mempeek8(u, u->devr)]; if(dev) wspush8(u, dev->read(dev, wspop8(u))); } +void op_iow(Uxn *u) { Uint8 a = wspop8(u); Device *dev = &u->dev[mempeek8(u, u->devw)]; if(dev) dev->write(dev, a); } void op_ldr(Uxn *u) { Uint16 a = wspop16(u); wspush8(u, u->ram.dat[a]); } void op_str(Uxn *u) { Uint16 a = wspop16(u); Uint8 b = wspop8(u); u->ram.dat[a] = b; } /* Logic */ @@ -60,6 +60,11 @@ void op_equ(Uxn *u) { Uint8 a = wspop8(u), b = wspop8(u); wspush8(u, b == a); } void op_neq(Uxn *u) { Uint8 a = wspop8(u), b = wspop8(u); wspush8(u, b != a); } void op_gth(Uxn *u) { Uint8 a = wspop8(u), b = wspop8(u); wspush8(u, b > a); } void op_lth(Uxn *u) { Uint8 a = wspop8(u), b = wspop8(u); wspush8(u, b < a); } +/* --- */ +void op_ior16(Uxn *u) { Uint8 a = wspop8(u); Device *dev = &u->dev[mempeek8(u, u->devr)]; if(dev) wspush16(u, (dev->read(dev, a) << 8) + dev->read(dev, a + 1)); } +void op_iow16(Uxn *u) { Uint8 a = wspop8(u); Uint8 b = wspop8(u); Device *dev = &u->dev[mempeek8(u, u->devw)]; if(dev) { dev->write(dev, b); dev->write(dev, a); } } +void op_ldr16(Uxn *u) { Uint16 a = wspop16(u); wspush16(u, (u->ram.dat[a] << 8) + u->ram.dat[a + 1]); } +void op_str16(Uxn *u) { Uint16 a = wspop16(u); Uint16 b = wspop16(u); u->ram.dat[a] = b >> 8; u->ram.dat[a + 1] = b & 0xff; } /* Stack(16-bits) */ void op_pop16(Uxn *u) { wspop16(u); } void op_dup16(Uxn *u) { wspush16(u, wspeek16(u, 2)); } @@ -84,15 +89,21 @@ void (*ops[])(Uxn *u) = { 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, + /* 16-bit */ + op_brk, op_nop, op_li1, op_lix, op_ior16, op_iow16, op_ldr16, op_str16, + op_jmp, op_jsr, op_nop, op_rts, op_nop, op_nop, op_nop, op_nop, 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}, {2,1}, {2,0}, {2,1}, {3,0}, + {0,0}, {0,0}, {0,0}, {0,0}, {1,1}, {1,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}, + /* 16-bit */ + {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 */ {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 */ }; @@ -124,7 +135,7 @@ opcuxn(Uxn *u, Uint8 instr) setflag(&u->status, FLAG_SIGN, (instr >> 6) & 1); /* usused */ setflag(&u->status, FLAG_COND, (instr >> 7) & 1); if(getflag(&u->status, FLAG_SHORT)) - op += 16; + op += 32; if(u->wst.ptr < opr[op][0]) return haltuxn(u, "Stack underflow", op); if(u->wst.ptr + opr[op][1] - opr[op][0] >= 255) @@ -174,6 +185,8 @@ loaduxn(Uxn *u, char *filepath) if(!(f = fopen(filepath, "rb"))) return haltuxn(u, "Missing input.", 0); fread(u->ram.dat, sizeof(u->ram.dat), 1, f); + u->devr = 0xfff8; + u->devw = 0xfff9; u->vreset = mempeek16(u, 0xfffa); u->vframe = mempeek16(u, 0xfffc); u->verror = mempeek16(u, 0xfffe); @@ -188,11 +201,11 @@ loaduxn(Uxn *u, char *filepath) /* to start: evaluxn(u, u->vreset); */ Device * -portuxn(Uxn *u, char *name, Uint8 (*onread)(Device *, Uint8), Uint8 (*onwrite)(Device *, Uint8)) +portuxn(Uxn *u, char *name, Uint8 (*rfn)(Device *, Uint8), Uint8 (*wfn)(Device *, Uint8)) { Device *d = &u->dev[u->devices++]; - d->rfn = onread; - d->wfn = onwrite; + d->read = rfn; + d->write = wfn; d->len = 0; printf("Device#%d: %s \n", u->devices, name); return d; diff --git a/uxn.h b/uxn.h @@ -36,13 +36,13 @@ typedef struct { typedef struct Device { Uint8 len, mem[8]; - Uint8 (*rfn)(struct Device *, Uint8); - Uint8 (*wfn)(struct Device *, Uint8); + Uint8 (*read)(struct Device *, Uint8); + Uint8 (*write)(struct Device *, Uint8); } Device; typedef struct { Uint8 literal, status, devices; - Uint16 counter, vreset, vframe, verror; + Uint16 counter, devr, devw, vreset, vframe, verror; Stack8 wst; Stack16 rst; Memory ram; @@ -54,4 +54,4 @@ int getflag(Uint8 *status, char flag); int loaduxn(Uxn *c, char *filepath); int bootuxn(Uxn *c); int evaluxn(Uxn *u, Uint16 vec); -Device *portuxn(Uxn *u, char *name, Uint8 (*onread)(Device *, Uint8), Uint8 (*onwrite)(Device *, Uint8)); +Device *portuxn(Uxn *u, char *name, Uint8 (*rfn)(Device *, Uint8), Uint8 (*wfn)(Device *, Uint8));