From 200bd42550a94487d6c0434c3ad8781b18a7a104 Mon Sep 17 00:00:00 2001
From: Daniel Jones <admin@danieljon.es>
Date: Fri, 21 Aug 2020 07:42:26 +0930
Subject: more instructions implemented

a good few roms work now, many glitches and such though. some roms wont work
---
 CMakeLists.txt |   2 +-
 chip8.c        | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 main.c         |   6 +--
 3 files changed, 122 insertions(+), 18 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index bda00bc..9f3f950 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ add_executable(
 	chip8
 	main.c chip8.c chip8.h)
 
-target_compile_options(chip8 PRIVATE -Wall)
+target_compile_options(chip8 PRIVATE -Wall -Wextra)
 
 target_link_libraries(chip8 PRIVATE SDL2::SDL2)
 
diff --git a/chip8.c b/chip8.c
index 32803bb..748cca4 100644
--- a/chip8.c
+++ b/chip8.c
@@ -96,10 +96,8 @@ chip8_draw_sprite(int startx, int starty, uint16_t mem, uint8_t size)
 	/*
 	 * draw sprite located at loc of height size at startx,starty
 	 */
-
 	uint8_t byte = 0;
 	uint8_t mask = 0x1;
-	V[0xF] = 0; /* set collision register to 0 */
 	for (uint8_t byteoffset = 0; byteoffset < size; byteoffset++)
 	{
 		/* loop through each byte from mem to mem+size */
@@ -110,12 +108,10 @@ chip8_draw_sprite(int startx, int starty, uint16_t mem, uint8_t size)
 			if (byte & mask)
 			{
 				uint32_t pixel = WIDTH*(starty%HEIGHT)+((startx%WIDTH)+bit);
-				if (video[pixel] != 0)
-				{
-					/* if the video bit is already set, we need to set the collision register */
-					V[0xF] = 1;
-				}
+				/* if the video bit is already set, we need to set the collision register */
+				V[0xF] = (video[pixel] != 0) ? 1 : 0;
 				video[pixel] ^= PIXEL_COLOR;
+				draw_flag = 1;
 			}
 			bit++;
 		}
@@ -155,7 +151,7 @@ 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);
+	printf("parsing at 0x%03X opcode = 0x%04X\n", PC, opcode);
 	PC += 2; // TODO: remove
 	switch (opcode & 0xF000)
 	{
@@ -189,18 +185,15 @@ chip8_cycle()
 		break;
 	case 0x3000: /* SE Vx, byte (skip next instruction if Vx = kk) */
 		// TODO: not tested
-		if (V[x] == kk)
-			PC += 2;
+		PC += (V[x] == kk) ? 2 : 0;
 		break;
 	case 0x4000: /* SN Vx, byte (skip next instruction if Vx != kk) */
 		// TODO: not tested
-		if (V[x] != kk)
-			PC += 2;
+		PC += (V[x] != kk) ? 2 : 0;
 		break;
 	case 0x5000: /* SE Vx, Vy (skip next instruction if Vx == Vy) */
 		// TODO: not tested
-		if (V[x] == V[y])
-			PC += 2;
+		PC += (V[x] == V[y]) ? 2 : 0;
 		break;
 	case 0x6000: /* LD Vx, byte (load byte in register x) */
 	{
@@ -264,6 +257,117 @@ chip8_cycle()
 			break;
 		default: unknown_opcode(opcode);
 		}
+		break;
+	}
+	case 0x9000: /* SNE Vx, Vy (skip next instruction if Vx != Vy) */
+		// TODO: not tested
+		PC += (V[x] != V[y]) ? 2 : 0;
+		break;
+	case 0xA000: /* LD I, addr (load register I with addr) */
+		// TODO: not tested
+		I = nnn;
+		break;
+	case 0xB000: /* JP V0, addr (set PC to location nnn + V0) */
+		// TODO: not tested
+		PC = V[0] + nnn;
+		break;
+	case 0xC000: /* RND Vx, byte (set Vx to a random byte and AND it by kk) */
+		// TODO: not tested
+		V[x] = (rand() % 256) & kk; // random number between 0 and 255
+		break;
+	case 0xD000: /* DRW Vx, Vy, n (read n bytes from starting starting at address in register I, and draws then at coordinates x,y */
+		// TODO: not tested
+		chip8_draw_sprite(V[x], V[y], I, n);
+		break;
+	case 0xE000: /* key input */
+	{
+		switch(kk)
+		{
+		case 0x9E: /* SKP Vx (skip next instruction if key Vx is pressed) */
+			// TODO: not tested
+			PC += (key[V[x]] == 1) ? 2 : 0;
+			break;
+		case 0xA1: /* SKNP Vx (skip next instruction if key Vx is not pressed) */
+			// TODO: not tested
+			PC += (key[V[x]] == 0) ? 2 : 0;
+			break;
+		default: unknown_opcode(opcode);
+		}
+		break;
+	}
+	case 0xF000:
+	{
+		switch (kk)
+		{
+		case 0x07: /* LD Vx, DT (load Vx with the value of delay timer register) */
+			// TODO: not tested
+			V[x] = delay_timer;
+			break;
+		case 0x0A: /* LD Vx, K (all execution stops until a key is pressed, then that key is put into Vx) */
+		{
+			// TODO: not tested
+			int found_key = 0;
+			for (int i = 0; i < 15; i++)
+			{
+				V[x] = key[i];
+				if (V[x] == 1)
+					found_key = 1;
+			}
+			PC -= (found_key == 0) ? 2 : 0;
+			break;
+		}
+		case 0x15: /* LD DT, Vx (delay timer is set to the value of Vx */
+			// TODO: not tested
+			delay_timer = V[x];
+			break;
+		case 0x18: /* LD ST, Vx (sound timer is set to the value of Vx */
+			// TODO: not tested
+			sound_timer = V[x];
+			break;
+		case 0x1E: /* ADD I, Vx (set I register to I + Vx) */
+			// TODO: not tested
+			I += V[x];
+			break;
+		case 0x29: /* LD F, Vx (set register I to location of the hex sprite Vx) */
+			// TODO: not tested
+			I = V[x] * 5;
+			break;
+		case 0x33: /* LD B, Vx (store BCD representation of Vx in memory locations I, I+1 and I+2) */
+			// TODO: not tested
+			memory[I]  = (V[x] % 1000) / 100;
+			memory[I+1] = (V[x] % 100) / 10;
+			memory[I+2] = (V[x] % 10);
+			break;
+		case 0x55: /* LD [I], Vx (store registers V0 through Vx starting at memory location I) */
+		{
+			// TODO: not tested
+			int reg = 0;
+			do
+			{
+				memory[I+reg] = V[reg];
+				reg++;
+			}
+			while (reg <= V[x]);
+			break;
+		}
+		case 0x65: /* LD Vx, [I] (read registers V0 through Vx from memory starting at I) */
+		{
+			// TODO: not tested
+			int reg = 0;
+			int target = V[x];
+			do
+			{
+				V[reg] = memory[I+reg];
+				reg++;
+			}
+			while (reg < target);
+			break;
+		}
+			break;
+
+		default: unknown_opcode(opcode);
+		}
+		break;
 	}
 	default: unknown_opcode(opcode);
 	}
diff --git a/main.c b/main.c
index 3b8183e..ae6f34d 100644
--- a/main.c
+++ b/main.c
@@ -14,7 +14,7 @@
  */
 
 #define VIDEO_SCALE 5
-#define STEPPING 1 // set to 1 to step manually through program
+#define STEPPING 0 // set to 1 to step manually through program
 
 SDL_Window *window;
 SDL_Renderer *renderer;
@@ -205,13 +205,14 @@ int main(int argc, char *argv[])
 
 	init_video();
 
-	const int fps = 1;
+	const int fps = 500;
 	const int frame_delay = 1000/fps;
 	uint32_t  frame_start;
 	uint32_t frame_time;
 
 	int do_quit = 0;
 
+	/*
 	chip8_draw_sprite(0, 0, 0xD*5, 0x5);
 	chip8_draw_sprite(5, 0, 0xE*5, 0x5);
 	chip8_draw_sprite(10, 0, 0xA*5, 0x5);
@@ -230,7 +231,6 @@ int main(int argc, char *argv[])
 	chip8_draw_sprite(30, 9, 0xE*5, 0x5);
 	chip8_draw_sprite(35, 9, 0xf*5, 0x5);
 
-	/*
 	chip8_draw_sprite(0, 20, 0x200, 0x6);
 	chip8_draw_sprite(8, 20, 0x200, 0x6);
 	chip8_draw_sprite(16, 20, 0x200, 0x6);
-- 
cgit v1.2.3