diff --git a/Makefile b/Makefile index 26a3c04..6d8380d 100644 --- a/Makefile +++ b/Makefile @@ -32,17 +32,19 @@ disass: bin/disass.o bin/vm.o bin/%.o: src/%.c $(CC) $(CFLAGS) -o $@ -c $^ +bin/emcalls.o: bin/vm.o: bin/main.o: bin/disass.o: +# needs to be run separately rom: rom.bin xxd -i src/$^ > src/$@.h rom.bin: src/rom.asm src/zeropage.incbin ./ass.sh src/rom.asm src/zeropage.incbin -$(TARGET): bin/main.o bin/vm.o +$(TARGET): bin/main.o bin/vm.o bin/emcalls.o $(CC) $(CFLAGS) -o bin/$@$(TRACE_SUFFIX) $^ clean: diff --git a/ass.sh b/ass.sh index bb8229f..d6d6dcd 100755 --- a/ass.sh +++ b/ass.sh @@ -37,6 +37,7 @@ bad_assemble() { sed -i 's/JMP[[:blank:]]/0d/gi' "$1" sed -i 's/BEQ[[:blank:]]/0e/gi' "$1" sed -i 's/BNQ[[:blank:]]/0f/gi' "$1" + sed -i 's/EMC[[:blank:]]/10/gi' "$1" sed -i 's/NOP[[:blank:]]*/ff 00 00/gi' "$1" sed -i 's/H//gi' "$1" # remove hex suffix 'h' after only hex digits remain diff --git a/src/disass.c b/src/disass.c index d605898..a433328 100644 --- a/src/disass.c +++ b/src/disass.c @@ -1,3 +1,5 @@ +/* x1phosura 2021 */ + #include #include #include diff --git a/src/emcalls.c b/src/emcalls.c new file mode 100644 index 0000000..d97fe5a --- /dev/null +++ b/src/emcalls.c @@ -0,0 +1,34 @@ +/* emcalls.c: This file implements emulator calls ("emcalls"). Emcalls are +analogous to system calls, except since there's no real OS, they're handled +directly by the emulator. The basic usage should revolve around adding cases +to the emcall switch-case, where each case is a special emcall that calls a +function to handle it. This is perhaps the easiest way to plug fancy features +into the emulator itself; basically treat the EMC instruction is like the ioctl +syscall (_now_ I see why ioctl is such a tempting serpent of a syscall to have) + +x1phosura 2021 +*/ + +#include +#include + + +void do_emcall(uint8_t emc_args[2]) +{ + // emc_args[1] may be used in the future + switch(emc_args[0]) { + case 0x00: + printf("I'm a zero emcall!\n"); // replace with emcall handler + break; + case 0x01: + printf("I'm a one emcall!\n"); // replace with emcall handler + break; + case 0x02: + printf("I'm a two emcall!\n"); // replace with emcall handler + break; + default: + printf("EMC: 1st arg: 0x%02x, 2nd arg: 0x%02x\n", emc_args[0], emc_args[1]); + } + printf("[DEBUG] TODO: finish (stubbed)\n"); +} + diff --git a/src/emcalls.h b/src/emcalls.h new file mode 100644 index 0000000..56b6848 --- /dev/null +++ b/src/emcalls.h @@ -0,0 +1,6 @@ +/* x1phosura 2021 */ + +#pragma once // WAAAAAY better than a dumb header guard ;) + +void do_emcall(uint8_t emc_args[2]); + diff --git a/src/main.c b/src/main.c index e6f0fb1..3202dd7 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,5 @@ +/* x1phosura 2021 */ + #include #include #include diff --git a/src/rom.asm b/src/rom.asm index 9cda500..0888d40 100644 --- a/src/rom.asm +++ b/src/rom.asm @@ -419,7 +419,7 @@ push 0x400b # check fourth block pushi 0x1d00 push 0x410b pushi 0x1600 -0xee 0x07 0x30 # junk NOP +emc 0x0122 0x30 0x30 0x30 # junk NOP push 0x420b pushi 0x4400 @@ -431,7 +431,7 @@ bnq 0xd102 # Fail if any two bytes ever not equal pop 0xffff pop 0xffff 0xee 0x07 0x30 # junk NOP -0xee 0x07 0x30 # junk NOP +emc 0x3344 bnq 0xd102 # Fail if any two bytes ever not equal pop 0xffff 0xee 0x07 0x30 # junk NOP diff --git a/src/rom.h b/src/rom.h index 9c63a50..3257723 100644 --- a/src/rom.h +++ b/src/rom.h @@ -85,10 +85,10 @@ unsigned char src_rom_bin[] = { 0x30, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0x01, 0x40, 0x0b, 0x03, 0x1d, 0x00, 0x01, 0x41, - 0x0b, 0x03, 0x16, 0x00, 0xee, 0x07, 0x30, 0x30, 0x30, 0x30, 0x01, 0x42, + 0x0b, 0x03, 0x16, 0x00, 0x10, 0x01, 0x22, 0x30, 0x30, 0x30, 0x01, 0x42, 0x0b, 0x03, 0x44, 0x00, 0x01, 0x43, 0x0b, 0x03, 0x75, 0x00, 0x0f, 0xd1, - 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0xee, 0x07, - 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, + 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x10, 0x33, + 0x44, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x02, 0xff, 0xff, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xee, 0x07, 0x30, 0x0f, 0xd1, 0x02, 0x02, 0xff, 0xff, 0x30, 0x30, 0x30, 0x02, 0xff, 0xff, 0x0d, 0xcb, 0x02, 0x01, 0xcb, 0x02, 0x40, 0x77, 0x12, 0x00, 0x00, diff --git a/src/vm.c b/src/vm.c index 006bd6b..dd8e3b5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -23,6 +23,7 @@ use assert()s to make sure pc, sp, etc... are valid #endif #include "vm.h" +#include "emcalls.h" #ifdef TRACE // TRACE_VARS @@ -50,7 +51,6 @@ static inline void push(struct CPU *cpu, uint8_t val) ++cpu->sp; } - static inline uint8_t pop(struct CPU *cpu) { uint8_t val; @@ -62,7 +62,6 @@ static inline uint8_t pop(struct CPU *cpu) return val; } - /* vm_do_instruction: */ uint16_t vm_do_instruction(struct CPU *cpu, uint8_t *mem, uint8_t instr[3]) @@ -163,6 +162,10 @@ uint16_t vm_do_instruction(struct CPU *cpu, uint8_t *mem, uint8_t instr[3]) return operand; pc += 3; break; + case EMC: + do_emcall(operands); + pc += 3; + break; case NOP: pc += 3; break; @@ -208,6 +211,7 @@ void print_op_decoded(uint8_t i[3], bool pargs) case JMP: printf("JMP"); if (pargs) printf(fmt, i[1], i[2]); break; case BEQ: printf("BEQ"); if (pargs) printf(fmt, i[1], i[2]); break; case BNQ: printf("BNQ"); if (pargs) printf(fmt, i[1], i[2]); break; + case EMC: printf("EMC"); if (pargs) printf(fmt, i[1], i[2]); break; case NOP: printf("NOP"); break; default: printf("0x%02x 0x%02x 0x%02x", i[0], i[1], i[2]); } diff --git a/src/vm.h b/src/vm.h index 3bd56c6..a8bf070 100644 --- a/src/vm.h +++ b/src/vm.h @@ -23,6 +23,7 @@ enum instructions { JMP = 13, BEQ = 14, BNQ = 15, + EMC = 16, // every opcode 0x10-0xfe is basically just a NOP just to be annoying NOP = 0xff };