Added screen example
This commit is contained in:
parent
8b407af780
commit
c1bffc1f8a
30
README.md
30
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
|
||||
|
||||
|
|
30
emulator.c
30
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");
|
||||
|
|
|
@ -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
|
||||
|
||||
BRK
|
||||
|
||||
@getmouse
|
||||
,00 IOR^ ( get mouse x )
|
||||
,02 IOR^ ( get mouse y )
|
||||
RTS
|
||||
|
||||
@putpixel
|
||||
SWP ,01 IOW ,01 IOW ( y )
|
||||
SWP ,01 IOW ,01 IOW ( x )
|
||||
,01 IOW ( color )
|
||||
,01 IOW ( redraw )
|
||||
IOW^ ( y short )
|
||||
IOW^ ( x short )
|
||||
IOW ( color byte )
|
||||
IOW ( redraw byte )
|
||||
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
|
||||
|FFFA .RESET .FRAME .ERROR
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
31
uxn.c
31
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;
|
||||
|
|
8
uxn.h
8
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));
|
||||
|
|
Loading…
Reference in New Issue