Added screen example

This commit is contained in:
neauoire 2021-02-10 11:06:36 -08:00
parent 8b407af780
commit c1bffc1f8a
7 changed files with 149 additions and 76 deletions

View File

@ -31,15 +31,13 @@ A [stack-based VM](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C.
( hello world ) ( hello world )
;iterator ;iterator
:dev1r FFF0
:dev1w FFF1
|0100 @RESET |0100 @RESET
@word1 "hello_word ( len: 0x0b ) @word1 "hello_world ( len: 0x0b )
@loop @loop
,dev1w STR ( write to stdout ) ,00 IOW ( write to device#0 )
,incr JSR ( increment itr ) ,incr JSR ( increment itr )
,word1 ,strlen JSR ( get strlen ) ,word1 ,strlen JSR ( get strlen )
NEQ ,loop ROT JSR? ( loop != strlen ) NEQ ,loop ROT JSR? ( loop != strlen )
@ -64,25 +62,11 @@ BRK
## TODOs ## TODOs
### Assembler - Implement signed flag to operators.
- On-screen debugger.
- Implement shorthand operators - 16b mode for str/ldr
- Signed operations - Auto-advance ldr?
- Getting rid of IOR/IOW would be nice..
### 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.
## Refs ## Refs

View File

@ -59,7 +59,7 @@ void
putpixel(Uint32 *dst, int x, int y, int color) putpixel(Uint32 *dst, int x, int y, int color)
{ {
if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8) 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 void
@ -145,14 +145,18 @@ echof(Uxn *c)
void void
domouse(SDL_Event *event) domouse(SDL_Event *event)
{ {
devmouse->mem[0] = event->motion.x / ZOOM - PAD * 8; int x = event->motion.x / ZOOM;
devmouse->mem[1] = event->motion.y / ZOOM - PAD * 8; 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) { switch(event->type) {
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
devmouse->mem[2] = 0; devmouse->mem[4] = 0;
break; break;
case SDL_MOUSEBUTTONDOWN: 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 Uint8
screenr(Device *d, Uint8 b) screenr(Device *d, Uint8 b)
{ {
(void)b; return d->mem[b];
(void)d;
return 0;
} }
Uint8 Uint8
@ -197,8 +199,8 @@ screenw(Device *d, Uint8 b)
d->mem[d->len++] = b; d->mem[d->len++] = b;
if(d->len > 5) { if(d->len > 5) {
putpixel(pixels, putpixel(pixels,
(d->mem[0] << 8) + d->mem[1],
(d->mem[2] << 8) + d->mem[3], (d->mem[2] << 8) + d->mem[3],
(d->mem[0] << 8) + d->mem[1],
d->mem[4]); d->mem[4]);
if(d->mem[5]) if(d->mem[5])
redraw(pixels); redraw(pixels);
@ -244,6 +246,11 @@ start(Uxn *u)
{ {
int ticknext = 0; int ticknext = 0;
evaluxn(u, u->vreset); evaluxn(u, u->vreset);
echos(&u->wst, 0x40, "stack");
echom(&u->ram, 0x40, "ram");
echof(u);
while(1) { while(1) {
int tick = SDL_GetTicks(); int tick = SDL_GetTicks();
SDL_Event event; SDL_Event event;
@ -286,6 +293,11 @@ main(int argc, char **argv)
devmouse = portuxn(&u, "mouse", mouser, mousew); devmouse = portuxn(&u, "mouse", mouser, mousew);
devkey = portuxn(&u, "key", keyr, keyw); 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); start(&u);
echos(&u.wst, 0x40, "stack"); echos(&u.wst, 0x40, "stack");

View File

@ -1,46 +1,40 @@
( draw pixel ) ( mouse )
:dev/r fff8 ( std read port )
:dev/w fff9 ( std write port )
|0100 @RESET |0100 @RESET
( draw 3 pixels ) ,02 ,dev/r STR ( set dev/read mouse#02 )
,00 ,01 ,0000 ,0000 ,putpixel JSR ,01 ,dev/w STR ( set dev/write screen#01 )
,00 ,02 ,0001 ,0001 ,putpixel JSR
,01 ,03 ,0002 ,0002 ,putpixel JSR
BRK BRK
|c000 @FRAME |c000 @FRAME
( get mouse button, or break ) ( get mouse button, or break )
,02 ,02 IOR ,04 IOR
,01 NEQ ,01 NEQ
BRK? BRK?
( print A to console on click )
,02 ,02 IOR
,41 ADD
,putbyte JSR
( paint a white pixel ) ( paint a white pixel )
,01 ,01 ,01 ,01
,getmouse JSR ,getmouse JSR
,putpixel JSR ,putpixel JSR
BRK BRK
@getmouse
,00 IOR^ ( get mouse x )
,02 IOR^ ( get mouse y )
RTS
@putpixel @putpixel
SWP ,01 IOW ,01 IOW ( y ) IOW^ ( y short )
SWP ,01 IOW ,01 IOW ( x ) IOW^ ( x short )
,01 IOW ( color ) IOW ( color byte )
,01 IOW ( redraw ) IOW ( redraw byte )
RTS RTS
@getmouse ( push y,x to stack )
,00 ,01 ,02 IOR ( grab y )
,00 ,00 ,02 IOR ( grab x )
RTS
@putbyte ( print to console )
,00 IOW RTS
|d000 @ERROR BRK |d000 @ERROR BRK
|FFFA .RESET .FRAME .ERROR |FFFA .RESET .FRAME .ERROR

38
examples/screen.usm Normal file
View File

@ -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

View File

@ -1,13 +1,45 @@
( my default test file ) ( my default test file )
;iterator :dev/r fff8 ( std read port )
:dev/w fff9 ( std write port )
|0100 @RESET |0100 @RESET
,1234 ,02 ,dev/r STR ( set dev/read mouse#02 )
,01 ,dev/w STR ( set dev/write screen#01 )
,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 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 |d000 @ERROR BRK
|FFFA .RESET .FRAME .ERROR |FFFA .RESET .FRAME .ERROR

31
uxn.c
View File

@ -19,13 +19,13 @@ WITH REGARD TO THIS SOFTWARE.
void setflag(Uint8 *st, char flag, int b) { if(b) *st |= flag; else *st &= (~flag); } void setflag(Uint8 *st, char flag, int b) { if(b) *st |= flag; else *st &= (~flag); }
int getflag(Uint8 *st, char flag) { return *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; } 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 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 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); } 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 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; } 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); } 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_li1(Uxn *u) { u->literal += 1; }
void op_lix(Uxn *u) { u->literal += u->ram.dat[u->ram.ptr++]; } void op_lix(Uxn *u) { u->literal += u->ram.dat[u->ram.ptr++]; }
void op_nop(Uxn *u) { printf("NOP"); (void)u; } 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_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 devid = wspop8(u); Uint16 devop = wspop8(u); Device *dev = &u->dev[devid]; if(devid < u->devices) dev->wfn(dev,devop); } 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_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; } void op_str(Uxn *u) { Uint16 a = wspop16(u); Uint8 b = wspop8(u); u->ram.dat[a] = b; }
/* Logic */ /* 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_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_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_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) */ /* Stack(16-bits) */
void op_pop16(Uxn *u) { wspop16(u); } void op_pop16(Uxn *u) { wspop16(u); }
void op_dup16(Uxn *u) { wspush16(u, wspeek16(u, 2)); } 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_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_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_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_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 op_add16, op_sub16, op_mul16, op_div16, op_equ16, op_neq16, op_gth16, op_lth16
}; };
Uint8 opr[][2] = { 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}, {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}, {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}, {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 */
{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_SIGN, (instr >> 6) & 1); /* usused */
setflag(&u->status, FLAG_COND, (instr >> 7) & 1); setflag(&u->status, FLAG_COND, (instr >> 7) & 1);
if(getflag(&u->status, FLAG_SHORT)) if(getflag(&u->status, FLAG_SHORT))
op += 16; op += 32;
if(u->wst.ptr < opr[op][0]) if(u->wst.ptr < opr[op][0])
return haltuxn(u, "Stack underflow", op); return haltuxn(u, "Stack underflow", op);
if(u->wst.ptr + opr[op][1] - opr[op][0] >= 255) 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"))) if(!(f = fopen(filepath, "rb")))
return haltuxn(u, "Missing input.", 0); return haltuxn(u, "Missing input.", 0);
fread(u->ram.dat, sizeof(u->ram.dat), 1, f); fread(u->ram.dat, sizeof(u->ram.dat), 1, f);
u->devr = 0xfff8;
u->devw = 0xfff9;
u->vreset = mempeek16(u, 0xfffa); u->vreset = mempeek16(u, 0xfffa);
u->vframe = mempeek16(u, 0xfffc); u->vframe = mempeek16(u, 0xfffc);
u->verror = mempeek16(u, 0xfffe); u->verror = mempeek16(u, 0xfffe);
@ -188,11 +201,11 @@ loaduxn(Uxn *u, char *filepath)
/* to start: evaluxn(u, u->vreset); */ /* to start: evaluxn(u, u->vreset); */
Device * 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++]; Device *d = &u->dev[u->devices++];
d->rfn = onread; d->read = rfn;
d->wfn = onwrite; d->write = wfn;
d->len = 0; d->len = 0;
printf("Device#%d: %s \n", u->devices, name); printf("Device#%d: %s \n", u->devices, name);
return d; return d;

8
uxn.h
View File

@ -36,13 +36,13 @@ typedef struct {
typedef struct Device { typedef struct Device {
Uint8 len, mem[8]; Uint8 len, mem[8];
Uint8 (*rfn)(struct Device *, Uint8); Uint8 (*read)(struct Device *, Uint8);
Uint8 (*wfn)(struct Device *, Uint8); Uint8 (*write)(struct Device *, Uint8);
} Device; } Device;
typedef struct { typedef struct {
Uint8 literal, status, devices; Uint8 literal, status, devices;
Uint16 counter, vreset, vframe, verror; Uint16 counter, devr, devw, vreset, vframe, verror;
Stack8 wst; Stack8 wst;
Stack16 rst; Stack16 rst;
Memory ram; Memory ram;
@ -54,4 +54,4 @@ int getflag(Uint8 *status, char flag);
int loaduxn(Uxn *c, char *filepath); int loaduxn(Uxn *c, char *filepath);
int bootuxn(Uxn *c); int bootuxn(Uxn *c);
int evaluxn(Uxn *u, Uint16 vec); 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));