From 26653bc8ac93cb748b46dae933b60fa755e400b1 Mon Sep 17 00:00:00 2001 From: Daniel Jones Date: Wed, 19 Aug 2020 16:29:58 +0930 Subject: instructions and debugging features added some more instructions, particularly calling and returning from subroutines using the stack. also added stepping through the program using the '.' key to advance one cycle --- chip8.c | 25 ++++++++++++++++++++----- main.c | 46 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/chip8.c b/chip8.c index 1d8de29..f005de8 100644 --- a/chip8.c +++ b/chip8.c @@ -133,7 +133,7 @@ chip8_beep() void unknown_opcode(uint16_t bad_opcode) { - fprintf(stderr, "unknown opcode: 0x%02X at 0x%02X\n", bad_opcode, PC); + fprintf(stderr, "unknown opcode: 0x%02X at 0x%02X\n", bad_opcode, PC-2); // minus 2 because we increment PC by 2 at the start of decoding } void chip8_cycle() @@ -145,7 +145,7 @@ chip8_cycle() /* * the opcode is a 2 byte value, while our memory is 1 byte * so to get our opcode we need to combine 2 bytes located at PC and PC+1 - * we right shift the first byte by 8 (1 byte) to place it in the high byte + * we left shift the first byte by 8 (1 byte) to place it in the high byte * and we store the second byte in the lower byte */ opcode = (memory[PC] << 8) | memory[PC+1]; @@ -155,7 +155,8 @@ chip8_cycle() uint8_t x = (opcode >> 8) & 0x000F; // lower 4 bits of the high byte, we discard the low byte by right shifting it out uint8_t y = (opcode >> 4) & 0x000F; // upper 4 bits of the low byte, so we need to discard the lower 4 bits uint8_t kk = opcode & 0x00FF; // lowest 8 bits - + printf("parsing at 0x%03X\n", PC); + PC += 2; // TODO: remove switch (opcode & 0xF000) { /* @@ -172,17 +173,32 @@ chip8_cycle() draw_flag = 1; break; case 0x00EE: /* ret (return from subroutine) */ + // TODO: test, check for out of bounds? + PC = stack[--SP]; break; default: unknown_opcode(opcode); } break; } + case 0x1000: /*JP addr (jump to memory address nnn) */ + PC = nnn; + break; + case 0x2000: /* CALL addr (call subroutine at addr, increment SP and put current PC on top of stack, set PC to nnn) */ + // TODO: test, bounds check? + stack[SP++] = PC; + PC = nnn; + break; case 0x6000: /* LD Vx, byte (load byte in register x) */ { V[x] = kk; break; } - + case 0x7000: /* ADD Vx, byte (add byte to Vx and store result in Vx) */ + V[x] = V[x] + kk; + break; + case 0x8000: /* LD Vx, Vy (load Vy into Vx register) */ + V[x] = V[y]; + break; default: unknown_opcode(opcode); } @@ -194,5 +210,4 @@ chip8_cycle() chip8_beep(); sound_timer--; } - PC += 2; } diff --git a/main.c b/main.c index f58edf7..3b8183e 100644 --- a/main.c +++ b/main.c @@ -10,9 +10,11 @@ * http://mattmik.com/files/chip8/mastering/chip8.html (lots of info) * http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#0.1 * http://www.emulator101.com/chip-8-sprites.html + * https://slack-files.com/T3CH37TNX-F3RKEUKL4-b05ab4930d?nojsmode=1 */ #define VIDEO_SCALE 5 +#define STEPPING 1 // set to 1 to step manually through program SDL_Window *window; SDL_Renderer *renderer; @@ -29,6 +31,8 @@ void handle_key_up(int keycode); uint8_t get_chip8_key(int keycode); void print_registers(); +int step_cycle = 0; + extern uint32_t video[WIDTH*HEIGHT]; extern int draw_flag; extern uint8_t key[KEY_SIZE]; @@ -38,6 +42,7 @@ extern uint16_t PC; extern int8_t SP; extern uint8_t delay_timer; extern uint8_t sound_timer; +extern uint16_t stack[STACK_SIZE]; void usage(char *program) @@ -86,13 +91,21 @@ toggle_pixel(int x, int y) void print_registers() { - puts("REGISTER DUMP"); + puts("DUMP"); puts("--------------------------"); for (int reg = 0; reg < REGISTER_COUNT; reg++) { printf("V[0x%01X] = 0x%02X\n", reg, V[reg]); } - printf("PC = 0x%03X\nI = 0x%03X\nSP = 0x%02X\ndelay_timer = 0x%02X\nsound_timer = 0x%02X\n", PC, I, SP, delay_timer, sound_timer); + // minus 2 on PC because we increment PC by 2 at the start of decoding + printf("PC = 0x%03X\nI = 0x%03X\nSP = 0x%02X\ndelay_timer = 0x%02X\nsound_timer = 0x%02X\n", PC-2, I, SP, delay_timer, sound_timer); + puts("STACK:"); + for (int i = 0; i < 16; i++) + { + printf("[%d] = 0x%03X", i, stack[i]); + if (i == 7) puts(""); + } + puts(""); puts("--------------------------"); } @@ -103,6 +116,7 @@ handle_key_down(int keycode) { /* detect interpreter debug keys */ case SDLK_p: print_registers(); break; + case SDLK_PERIOD: step_cycle = 1; break; default: break; } @@ -191,7 +205,7 @@ int main(int argc, char *argv[]) init_video(); - const int fps = 2; + const int fps = 1; const int frame_delay = 1000/fps; uint32_t frame_start; uint32_t frame_time; @@ -232,12 +246,30 @@ int main(int argc, char *argv[]) // logic do_quit = handle_sdl_events(); - chip8_cycle(); + if (STEPPING) + { + if (step_cycle == 1) + { + chip8_cycle(); + + if (draw_flag) + { + update_video(); + draw_flag = 0; + } - if (draw_flag) + step_cycle = 0; + } + } + else { - update_video(); - draw_flag = 0; + chip8_cycle(); + + if (draw_flag) + { + update_video(); + draw_flag = 0; + } } frame_time = SDL_GetTicks() - frame_start; -- cgit v1.2.3