diff --git a/README.md b/README.md index be21d7f..649a688 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ evaluxn(u, u->vframe); /* Each frame - `+12ef`, a literal signed short. - `-1a`, a literal signed byte(negative). - `-12ef`, a literal signed short(negative). +- `.ab`, a raw byte in memory. +- `.abcd`, a raw short in memory. ### Special @@ -81,6 +83,21 @@ BRK |FFFA .RESET .FRAME .ERROR ``` +## Emulator + +### Controller(dev/ctrl) + +A device that works like a NES controller, each button is a bit from a single byte. + +- Ctrl +- Alt +- Escape +- Return +- Up +- Down +- Left +- Right + ## TODOs - Defines? diff --git a/build.sh b/build.sh index fe00044..7dc1761 100755 --- a/build.sh +++ b/build.sh @@ -24,5 +24,5 @@ rm -f ./bin/emulator 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 -L/usr/local/lib -lSDL2 -o bin/emulator # run -./bin/assembler examples/test.usm bin/boot.rom +./bin/assembler examples/controller.usm bin/boot.rom ./bin/emulator bin/boot.rom diff --git a/emulator.c b/emulator.c index 1f4087b..a10ccf3 100644 --- a/emulator.c +++ b/emulator.c @@ -37,7 +37,7 @@ SDL_Renderer *gRenderer; SDL_Texture *gTexture; Uint32 *pixels; -Device *devconsole, *devscreen, *devmouse, *devkey, *devsprite; +Device *devconsole, *devscreen, *devmouse, *devkey, *devsprite, *devctrl; #pragma mark - Helpers @@ -65,9 +65,7 @@ drawchr(Uint32 *dst, int x, int y, Uint8 *sprite) for(h = 0; h < 8; h++) { int ch1 = ((sprite[v] >> h) & 0x1); int ch2 = (((sprite[v + 8] >> h) & 0x1) << 1); - int clr = ch1 + ch2; - int guides = GUIDES && !clr && ((x + y) / 8) % 2; - putpixel(dst, x + 7 - h, y + v, guides ? 4 : clr); + putpixel(dst, x + 7 - h, y + v, ch1 + ch2); } } @@ -192,8 +190,25 @@ domouse(SDL_Event *event) void dokey(SDL_Event *event) { - (void)event; - /* printf("key\n"); */ +} + +void +doctrl(SDL_Event *event, int z) +{ + Uint8 flag = 0x00; + if(SDL_GetModState() & KMOD_LCTRL || SDL_GetModState() & KMOD_RCTRL) + flag = 0x01; + if(SDL_GetModState() & KMOD_LALT || SDL_GetModState() & KMOD_RALT) + flag = 0x02; + switch(event->key.keysym.sym) { + case SDLK_ESCAPE: flag = 0x04; break; + case SDLK_RETURN: flag = 0x08; break; + case SDLK_UP: flag = 0x10; break; + case SDLK_DOWN: flag = 0x20; break; + case SDLK_LEFT: flag = 0x40; break; + case SDLK_RIGHT: flag = 0x80; break; + } + setflag(&devctrl->mem[0], flag, z); } #pragma mark - Devices @@ -296,6 +311,20 @@ keyw(Device *d, Memory *m, Uint8 b) return 0; } +Uint8 +ctrlr(Device *d, Memory *m, Uint8 b) +{ + return d->mem[b]; +} + +Uint8 +ctrlw(Device *d, Memory *m, Uint8 b) +{ + (void)d; + (void)b; + return 0; +} + #pragma mark - Generics int @@ -314,20 +343,21 @@ start(Uxn *u) if(tick < ticknext) SDL_Delay(ticknext - tick); ticknext = tick + (1000 / FPS); - evaluxn(u, u->vframe); while(SDL_PollEvent(&event) != 0) { switch(event.type) { case SDL_QUIT: quit(); break; case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEMOTION: domouse(&event); break; - case SDL_KEYDOWN: dokey(&event); break; + case SDL_KEYDOWN: doctrl(&event, 1); break; + case SDL_KEYUP: doctrl(&event, 0); break; case SDL_WINDOWEVENT: if(event.window.event == SDL_WINDOWEVENT_EXPOSED) redraw(pixels); break; } } + evaluxn(u, u->vframe); } } @@ -350,6 +380,7 @@ main(int argc, char **argv) devmouse = portuxn(&u, "mouse", mouser, mousew); devkey = portuxn(&u, "key", keyr, keyw); devsprite = portuxn(&u, "ppu-sprite", ppusr, ppusw); + devctrl = portuxn(&u, "ctrl", ctrlr, ctrlw); start(&u); diff --git a/examples/controller.usm b/examples/controller.usm new file mode 100644 index 0000000..ce435f4 --- /dev/null +++ b/examples/controller.usm @@ -0,0 +1,54 @@ +( comment ) + +:dev/r fff8 ( const read port ) +:dev/w fff9 ( const write port ) + +;x 2 ;y 2 + +|0100 @RESET + + #05 ,dev/r STR ( set dev/read to ctrl ) + #04 ,dev/w STR ( set dev/write to ppu-sprite ) + + #0080 ,x STR2 + #0040 ,y STR2 + #01 ,cursor_icn ,x LDR2 ,y LDR2 ,putsprite JSR + +BRK + +|0200 @SPRITESHEET + +@cursor_icn .80c0 .e0f0 .f8e0 .1000 .0000 .0000 .0000 .0000 +@star_icn .1054 .28c6 .2854 .1000 .0000 .0000 .0000 .0000 + +BRK + +|c000 @FRAME + + #00 IOR #10 NEQ ,next0 ROT JMP? POP2 + ,y LDR2 #0001 SUB2 ,y STR2 + @next0 + #00 IOR #20 NEQ ,next1 ROT JMP? POP2 + ,y LDR2 #0001 ADD2 ,y STR2 + @next1 + #00 IOR #40 NEQ ,next2 ROT JMP? POP2 + ,x LDR2 #0001 SUB2 ,x STR2 + @next2 + #00 IOR #80 NEQ ,next3 ROT JMP? POP2 + ,x LDR2 #0001 ADD2 ,x STR2 + @next3 + ( redraw ) + #01 ,cursor_icn ,x LDR2 ,y LDR2 ,putsprite JSR + +BRK + +@putsprite + IOW2 ( y short ) + IOW2 ( x short ) + IOW2 ( sprite address ) + IOW ( redraw byte ) + RTS + +|d000 @ERROR BRK + +|FFFA .RESET .FRAME .ERROR diff --git a/examples/sprite.usm b/examples/sprite.usm new file mode 100644 index 0000000..873c61d --- /dev/null +++ b/examples/sprite.usm @@ -0,0 +1,46 @@ +( comment ) + +:dev/w fff9 ( const write port ) + +|0100 @RESET + + #01 ,dev/w STR ( set dev/write to screen ) + + ( draw 1 pixel ) + #00 #01 #0021 #0021 ,putpixel JSR + + #04 ,dev/w STR ( set dev/write to screen ) + + #00 ,star_icn #0001 #0001 ,putsprite JSR + #00 ,star_icn #0031 #0021 ,putsprite JSR + #00 ,cursor_icn #0021 #0016 ,putsprite JSR + #00 ,star_icn #0055 #0042 ,putsprite JSR + #01 ,cursor_icn #0067 #0031 ,putsprite JSR + +BRK + +@putsprite + IOW2 ( y short ) + IOW2 ( x short ) + IOW2 ( sprite address ) + IOW ( redraw byte ) + RTS + +@putpixel + IOW2 ( y short ) + IOW2 ( x short ) + IOW ( color byte ) + IOW ( redraw byte ) + RTS + +|0200 @SPRITESHEET + +@cursor_icn .80c0 .e0f0 .f8e0 .1000 .0000 .0000 .0000 .0000 +@star_icn .1054 .28c6 .2854 .1000 .0000 .0000 .0000 .0000 + +BRK + +|c000 @FRAME BRK +|d000 @ERROR BRK + +|FFFA .RESET .FRAME .ERROR diff --git a/examples/test.usm b/examples/test.usm index d36271b..ce435f4 100644 --- a/examples/test.usm +++ b/examples/test.usm @@ -1,22 +1,44 @@ ( comment ) +:dev/r fff8 ( const read port ) :dev/w fff9 ( const write port ) +;x 2 ;y 2 + |0100 @RESET - #01 ,dev/w STR ( set dev/write to screen ) + #05 ,dev/r STR ( set dev/read to ctrl ) + #04 ,dev/w STR ( set dev/write to ppu-sprite ) - ( draw 1 pixel ) - #00 #01 #0021 #0021 ,putpixel JSR + #0080 ,x STR2 + #0040 ,y STR2 + #01 ,cursor_icn ,x LDR2 ,y LDR2 ,putsprite JSR - #04 ,dev/w STR ( set dev/write to screen ) +BRK - #00 ,star_icn #0001 #0001 ,putsprite JSR +|0200 @SPRITESHEET - #00 ,star_icn #0031 #0021 ,putsprite JSR - #00 ,cursor_icn #0021 #0016 ,putsprite JSR - #00 ,star_icn #0055 #0042 ,putsprite JSR - #01 ,cursor_icn #0067 #0031 ,putsprite JSR +@cursor_icn .80c0 .e0f0 .f8e0 .1000 .0000 .0000 .0000 .0000 +@star_icn .1054 .28c6 .2854 .1000 .0000 .0000 .0000 .0000 + +BRK + +|c000 @FRAME + + #00 IOR #10 NEQ ,next0 ROT JMP? POP2 + ,y LDR2 #0001 SUB2 ,y STR2 + @next0 + #00 IOR #20 NEQ ,next1 ROT JMP? POP2 + ,y LDR2 #0001 ADD2 ,y STR2 + @next1 + #00 IOR #40 NEQ ,next2 ROT JMP? POP2 + ,x LDR2 #0001 SUB2 ,x STR2 + @next2 + #00 IOR #80 NEQ ,next3 ROT JMP? POP2 + ,x LDR2 #0001 ADD2 ,x STR2 + @next3 + ( redraw ) + #01 ,cursor_icn ,x LDR2 ,y LDR2 ,putsprite JSR BRK @@ -27,21 +49,6 @@ BRK IOW ( redraw byte ) RTS -@putpixel - IOW2 ( y short ) - IOW2 ( x short ) - IOW ( color byte ) - IOW ( redraw byte ) - RTS - -|0200 @SPRITESHEET - -@cursor_icn .80c0 .e0f0 .f8e0 .1000 .0000 .0000 .0000 .0000 -@star_icn .1054 .28c6 .2854 .1000 .0000 .0000 .0000 .0000 - -BRK - -|c000 @FRAME BRK |d000 @ERROR BRK |FFFA .RESET .FRAME .ERROR diff --git a/uxn.c b/uxn.c index fc04f34..2436dae 100644 --- a/uxn.c +++ b/uxn.c @@ -30,10 +30,10 @@ void push16(St8 *s, Uint16 a) { push8(s, a >> 8); push8(s, a); } Uint16 pop16(St8 *s) { return pop8(s) + (pop8(s) << 8); } Uint16 peek16(St8 *s, Uint8 a) { return peek8(s, a * 2) + (peek8(s, a * 2 + 1) << 8); } /* I/O */ -void op_brk(Uxn *u) { setflag(&u->status,FLAG_HALT, 1); } +void op_brk(Uxn *u) { setflag(&u->status, FLAG_HALT, 1); } void op_lit(Uxn *u) { u->literal += 1; } void op_lix(Uxn *u) { u->literal += u->ram.dat[u->ram.ptr++]; } -void op_nop(Uxn *u) { printf("0x%02x ", pop8(&u->wst)); } +void op_nop(Uxn *u) { printf("0x%02x \n", pop8(&u->wst)); fflush(stdout); } void op_ior(Uxn *u) { Device *dev = &u->dev[mempeek8(&u->ram, u->devr)]; if(dev) push8(&u->wst, dev->read(dev, &u->ram, pop8(&u->wst))); } void op_iow(Uxn *u) { Uint8 a = pop8(&u->wst); Device *dev = &u->dev[mempeek8(&u->ram, u->devw)]; if(dev) dev->write(dev, &u->ram, a); } void op_ldr(Uxn *u) { Uint16 a = pop16(&u->wst); push8(&u->wst, mempeek8(&u->ram, a)); }