Add stubbed EMC (emulator call) instruction
This commit is contained in:
parent
736bc261c1
commit
081b72c6ea
4
Makefile
4
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:
|
||||
|
|
1
ass.sh
1
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
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* x1phosura 2021 */
|
||||
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/* x1phosura 2021 */
|
||||
|
||||
#pragma once // WAAAAAY better than a dumb header guard ;)
|
||||
|
||||
void do_emcall(uint8_t emc_args[2]);
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
/* x1phosura 2021 */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
8
src/vm.c
8
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]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue