commit c1bffc1f8a0f3f05a6b46ecc5b0922aba8358ebc
parent 8b407af780b7b37e0fa3f8db7e449df55912214b
Author: neauoire <aliceffekt@gmail.com>
Date: Wed, 10 Feb 2021 11:06:36 -0800
Added screen example
Diffstat:
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));