// File: /workspace/github_cpp_makefile_star2_O3/TNanukem[P]chip8-emulator/emulator.cpp
// Function: emulator::emulate(int, char**)
void emulator::emulate(int argc, char** argv){
    chip8 Chip8;
	display Display;

	// Intializes the Chip8 system and loads the game into memory
	Chip8.initialize();
	std::string load;

	// Handling the game input from command line
	if(argc >= 2)
		load = std::string("roms/") + argv[1];
	else load = std::string("roms/PONG");
	Chip8.loadGame(load);

	// Graphical System Initialization
	Display.displayInit();

	// Loading the audio file
	SDL_AudioSpec wavSpec;
	uint32_t wavLength;
	uint8_t *wavBuffer;

	SDL_LoadWAV("music/sound.wav", &wavSpec, &wavBuffer, &wavLength);

	// Opening the audio device
	SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0);

	// For the FPS count
	clock_t before = clock();
	double frameCount = 0;

	while(1){			// Emulation loop

		SDL_Event event;

		// Event loop -> This is what controls the keyboard inputs
		while(SDL_PollEvent(&event)){
			if(event.type == SDL_QUIT)		// Closes the window when the user clicks on the close button
				return;

			// Structure that pauses the game when the user presses the spacebar
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_SPACE){
				printf("Game Paused\n");

				std::this_thread::sleep_for(std::chrono::milliseconds(800));
				while(1){
					SDL_PollEvent(&event);
					if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_SPACE)
						break;
				}
				printf("Unpausing Game\n");
			}

			// Selects the load/save state SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F1){
				if(SaveStateSlot == 3)
					SaveStateSlot = 0;
				else
					SaveStateSlot++;
				printf("Selected SaveStateSlot %d\n", SaveStateSlot);
			}

			// Saves the game on the selected SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F2){
				printf("Saving the game on SaveStateSlot %d\n", SaveStateSlot);
				saveGame(SaveStateSlot, &Chip8, load);
			}

			// Loads the game from the selected SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F3){
				printf("Loading the game from SaveStateSlot %d\n", SaveStateSlot);
				Chip8 = loadGame(SaveStateSlot, &Chip8, load);
			}

			// All the pressed keys options
			if(event.type == SDL_KEYUP){
				if(event.key.keysym.sym == SDLK_1)	Chip8.keyboard[0] = 0;
				if(event.key.keysym.sym == SDLK_2)	Chip8.keyboard[1] = 0;
				if(event.key.keysym.sym == SDLK_3)	Chip8.keyboard[2] = 0;
				if(event.key.keysym.sym == SDLK_4)	Chip8.keyboard[3] = 0;
				if(event.key.keysym.sym == SDLK_q)	Chip8.keyboard[4] = 0;
				if(event.key.keysym.sym == SDLK_w)	Chip8.keyboard[5] = 0;
				if(event.key.keysym.sym == SDLK_e)	Chip8.keyboard[6] = 0;
				if(event.key.keysym.sym == SDLK_r)	Chip8.keyboard[7] = 0;
				if(event.key.keysym.sym == SDLK_a)	Chip8.keyboard[8] = 0;
				if(event.key.keysym.sym == SDLK_s)	Chip8.keyboard[9] = 0;
				if(event.key.keysym.sym == SDLK_d)	Chip8.keyboard[10] = 0;
				if(event.key.keysym.sym == SDLK_f)	Chip8.keyboard[11] = 0;
				if(event.key.keysym.sym == SDLK_z)	Chip8.keyboard[12] = 0;
				if(event.key.keysym.sym == SDLK_x)	Chip8.keyboard[13] = 0;
				if(event.key.keysym.sym == SDLK_c)	Chip8.keyboard[14] = 0;
				if(event.key.keysym.sym == SDLK_v)	Chip8.keyboard[15] = 0;
			}

			// All the release keys options
			if(event.type == SDL_KEYDOWN){
				if(event.key.keysym.sym == SDLK_1)	Chip8.keyboard[0] = 1;
				if(event.key.keysym.sym == SDLK_2)	Chip8.keyboard[1] = 1;
				if(event.key.keysym.sym == SDLK_3)	Chip8.keyboard[2] = 1;
				if(event.key.keysym.sym == SDLK_4)	Chip8.keyboard[3] = 1;
				if(event.key.keysym.sym == SDLK_q)	Chip8.keyboard[4] = 1;
				if(event.key.keysym.sym == SDLK_w)	Chip8.keyboard[5] = 1;
				if(event.key.keysym.sym == SDLK_e)	Chip8.keyboard[6] = 1;
				if(event.key.keysym.sym == SDLK_r)	Chip8.keyboard[7] = 1;
				if(event.key.keysym.sym == SDLK_a)	Chip8.keyboard[8] = 1;
				if(event.key.keysym.sym == SDLK_s)	Chip8.keyboard[9] = 1;
				if(event.key.keysym.sym == SDLK_d)	Chip8.keyboard[10] = 1;
				if(event.key.keysym.sym == SDLK_f)	Chip8.keyboard[11] = 1;
				if(event.key.keysym.sym == SDLK_z)	Chip8.keyboard[12] = 1;
				if(event.key.keysym.sym == SDLK_x)	Chip8.keyboard[13] = 1;
				if(event.key.keysym.sym == SDLK_c)	Chip8.keyboard[14] = 1;
				if(event.key.keysym.sym == SDLK_v)	Chip8.keyboard[15] = 1;
			}
		}

		// Calls the next cycle, fetching, decoding and executing the next instruction in the memory
		Chip8.nextCycle();

		if(Chip8.drawFlag){

			// SDL_SetRenderDrawColor(render, 0x00, 0x00, 0x00, 0xFF);
			// SDL_RenderClear(render);
			// int changeLine = 0;
			// int changeColumn = 0;
			//
			// for(int i = 0; i < 32*64; i++){
			// 	if((i % 64) == 0){
			// 		changeLine += 9;
			// 		changeColumn = 0;
			// 	}
			// 	if(Chip8.display[i] == 1){
			// 		SDL_Rect fillRect = {changeColumn, changeLine, 10, 10};
			// 		SDL_SetRenderDrawColor(render, 0x00, 0xFF, 0x00, 0xFF);
			// 		SDL_RenderFillRect(render, &fillRect);
			// 	}
			// 	changeColumn += 9;
			// }
			// SDL_RenderPresent(render);

			Chip8.drawFlag = false;
			Display.displayDraw(Chip8.display);

			frameCount++;
			clock_t now = clock();
			float time = 100*(float)(now-before)/CLOCKS_PER_SEC;

			//printf("%f\n", time);
			// If a second has passed, update the FPS
			if(time >= 1.0){
				char title[255];

				snprintf(title, 255, "Chip8 Emulator - FPS: %3.3f", frameCount);
				Display.changeWindowName(title);
				before = now;
				frameCount = 0;
			}
		}
		if(Chip8.playSound)
			playSound(deviceId, wavBuffer, wavLength);
			Chip8.playSound = false;

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}

	// Free every SDL structure allocated
	Display.displayDestroy();

	SDL_CloseAudioDevice(deviceId);
	SDL_FreeWAV(wavBuffer);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x61c8, %rsp           # imm = 0x61C8
movq %rdx, %r14
movl %esi, %r15d
movq %rdi, -0x40(%rbp)
leaq -0x3198(%rbp), %rdi
movw $0x0, 0x304c(%rdi)
callq 0x24cc
leaq -0x58(%rbp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
cmpl $0x2, %r15d
jl 0x366d
leaq -0x98(%rbp), %r15
movq %r15, -0x10(%r15)
leaq 0x1c1a(%rip), %rsi      # 0x5236
leaq 0x1c18(%rip), %rdx      # 0x523b
leaq -0xa8(%rbp), %rdi
callq 0x3f24
movq 0x8(%r14), %rsi
leaq -0xa8(%rbp), %rdi
callq 0x2300
leaq -0x61e0(%rbp), %r12
movq %r12, -0x10(%r12)
movq (%rax), %rdx
movq %rax, %rcx
addq $0x10, %rcx
cmpq %rcx, %rdx
je 0x36b6
movq %rdx, -0x61f0(%rbp)
movq (%rcx), %rdx
movq %rdx, -0x61e0(%rbp)
jmp 0x36be
leaq -0x61e0(%rbp), %r15
movq %r15, -0x10(%r15)
leaq 0x1bbd(%rip), %rsi      # 0x523c
leaq 0x1bbf(%rip), %rdx      # 0x5245
leaq -0x61f0(%rbp), %rdi
callq 0x3f24
leaq -0x68(%rbp), %rdi
leaq -0x61f0(%rbp), %r14
movq %r14, %rsi
callq 0x2240
movq (%r14), %rdi
cmpq %r15, %rdi
je 0x371a
movq -0x61e0(%rbp), %rsi
jmp 0x3712
movups (%rcx), %xmm0
movups %xmm0, (%r12)
movq 0x8(%rax), %rdx
leaq -0x61f0(%rbp), %r14
movq %rdx, 0x8(%r14)
movq %rcx, (%rax)
movq $0x0, 0x8(%rax)
movb $0x0, 0x10(%rax)
leaq -0x68(%rbp), %rdi
movq %r14, %rsi
callq 0x2240
movq (%r14), %rdi
cmpq %r12, %rdi
je 0x36ff
movq -0x61e0(%rbp), %rsi
incq %rsi
callq 0x21c0
movq -0xa8(%rbp), %rdi
cmpq %r15, %rdi
je 0x371a
movq -0x98(%rbp), %rsi
incq %rsi
callq 0x21c0
leaq -0x100(%rbp), %r14
movq %r14, -0x10(%r14)
movq -0x68(%rbp), %rsi
movq -0x60(%rbp), %rdx
addq %rsi, %rdx
leaq -0x110(%rbp), %rdi
callq 0x3e86
leaq -0x3198(%rbp), %rdi
leaq -0x110(%rbp), %rsi
callq 0x2560
movq -0x110(%rbp), %rdi
cmpq %r14, %rdi
je 0x376a
movq -0x100(%rbp), %rsi
incq %rsi
callq 0x21c0
leaq -0x128(%rbp), %rdi
callq 0x2d0c
leaq 0x1ac9(%rip), %rdi      # 0x5246
leaq 0x18fc(%rip), %rsi      # 0x5080
callq 0x2100
leaq -0x148(%rbp), %rdx
leaq -0xf0(%rbp), %rcx
leaq -0x44(%rbp), %r8
movq %rax, %rdi
movl $0x1, %esi
callq 0x20e0
leaq -0x148(%rbp), %rdx
xorl %edi, %edi
xorl %esi, %esi
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x2230
movl %eax, -0x2c(%rbp)
callq 0x2130
movq %rax, -0x70(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
leaq -0xa8(%rbp), %r12
leaq -0x3198(%rbp), %r13
leaq -0x61f0(%rbp), %r15
movq %r12, %rdi
callq 0x2120
testl %eax, %eax
je 0x3add
movl -0xa8(%rbp), %eax
cmpl $0x100, %eax            # imm = 0x100
je 0x3d36
movl %eax, %edx
xorl $0x300, %edx            # imm = 0x300
movl -0x94(%rbp), %ecx
movl %ecx, %esi
xorl $0x20, %esi
orl %edx, %esi
jne 0x388f
leaq 0x1adf(%rip), %rdi      # 0x5304
callq 0x22a0
movq $0x0, -0x61f0(%rbp)
movq $0x2faf0800, -0x61e8(%rbp) # imm = 0x2FAF0800
movq %r15, %rdi
movq %r15, %rsi
callq 0x20c0
cmpl $-0x1, %eax
jne 0x385a
callq 0x2060
cmpl $0x4, (%rax)
je 0x3840
movq %r12, %rdi
callq 0x2120
cmpl $0x300, -0xa8(%rbp)     # imm = 0x300
jne 0x385a
cmpl $0x20, -0x94(%rbp)
jne 0x385a
leaq 0x1a92(%rip), %rdi      # 0x5310
callq 0x22a0
movl -0xa8(%rbp), %eax
movl -0x94(%rbp), %ecx
movl %eax, %edx
xorl $0x300, %edx            # imm = 0x300
movl %ecx, %esi
xorl $0x4000003a, %esi       # imm = 0x4000003A
orl %edx, %esi
jne 0x38e0
movq -0x40(%rbp), %rdx
movb 0x3068(%rdx), %al
leal 0x1(%rax), %ecx
cmpb $0x3, %al
movzbl %cl, %eax
movl $0x0, %ecx
cmovel %ecx, %eax
movb %al, 0x3068(%rdx)
movzbl %al, %esi
leaq 0x1989(%rip), %rdi      # 0x5256
xorl %eax, %eax
callq 0x2070
movl -0xa8(%rbp), %eax
movl -0x94(%rbp), %ecx
cmpl $0x300, %eax            # imm = 0x300
jne 0x396d
cmpl $0x4000003b, %ecx       # imm = 0x4000003B
jne 0x396d
movq -0x40(%rbp), %rbx
movzbl 0x3068(%rbx), %esi
leaq 0x196c(%rip), %rdi      # 0x5271
xorl %eax, %eax
callq 0x2070
movb 0x3068(%rbx), %r14b
leaq -0xb8(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0x68(%rbp), %rsi
movq -0x60(%rbp), %rdx
addq %rsi, %rdx
leaq -0xc8(%rbp), %rdi
callq 0x3e86
movzbl %r14b, %esi
movq %r13, %rdx
leaq -0xc8(%rbp), %rcx
callq 0x2e9c
movq -0xc8(%rbp), %rdi
leaq -0xb8(%rbp), %rax
cmpq %rax, %rdi
je 0x396d
movq -0xb8(%rbp), %rsi
incq %rsi
callq 0x21c0
movl -0xa8(%rbp), %eax
cmpl $0x300, %eax            # imm = 0x300
jne 0x3a27
cmpl $0x4000003c, -0x94(%rbp) # imm = 0x4000003C
jne 0x3a27
movq %r13, %rbx
movq -0x40(%rbp), %r14
movzbl 0x3068(%r14), %esi
leaq 0x18f2(%rip), %rdi      # 0x5296
xorl %eax, %eax
callq 0x2070
movb 0x3068(%r14), %r14b
leaq -0xd8(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq -0x68(%rbp), %rsi
movq -0x60(%rbp), %rdx
addq %rsi, %rdx
leaq -0xe8(%rbp), %r13
movq %r13, %rdi
callq 0x3e86
movzbl %r14b, %edx
movq %r15, %rdi
movq %rbx, %rcx
movq %r13, %r8
callq 0x3208
movl $0x304e, %edx           # imm = 0x304E
movq %rbx, %rdi
movq %r15, %rsi
callq 0x2180
movq -0xe8(%rbp), %rdi
leaq -0xd8(%rbp), %rax
cmpq %rax, %rdi
movq %rbx, %r13
je 0x3a21
movq -0xd8(%rbp), %rsi
incq %rsi
callq 0x21c0
movl -0xa8(%rbp), %eax
cmpl $0x300, %eax            # imm = 0x300
je 0x3a63
cmpl $0x301, %eax            # imm = 0x301
jne 0x37e6
movl -0x94(%rbp), %eax
leal -0x61(%rax), %ecx
cmpl $0x19, %ecx
ja 0x3a8d
leaq 0x1776(%rip), %rdx      # 0x51c4
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movb $0x0, -0x154(%rbp)
jmp 0x37e6
movl -0x94(%rbp), %eax
leal -0x61(%rax), %ecx
cmpl $0x19, %ecx
ja 0x3ab5
leaq 0x16d4(%rip), %rdx      # 0x514c
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movb $0x1, -0x154(%rbp)
jmp 0x37e6
addl $-0x31, %eax
cmpl $0x3, %eax
ja 0x37e6
leaq 0x1714(%rip), %rcx      # 0x51b4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x0, -0x15c(%rbp)
jmp 0x37e6
addl $-0x31, %eax
cmpl $0x3, %eax
ja 0x37e6
leaq 0x1674(%rip), %rcx      # 0x513c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, -0x15c(%rbp)
jmp 0x37e6
movq %r13, %rdi
callq 0x2618
cmpb $0x1, -0x14c(%rbp)
jne 0x3b81
movb $0x0, -0x14c(%rbp)
leaq -0x128(%rbp), %rdi
leaq -0x2180(%rbp), %rsi
callq 0x2e04
movsd -0x38(%rbp), %xmm0
addsd 0x160f(%rip), %xmm0     # 0x5128
movsd %xmm0, -0x38(%rbp)
callq 0x2130
movq %rax, %rbx
subq -0x70(%rbp), %rax
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
mulss 0x15f6(%rip), %xmm0     # 0x5130
divss 0x15f2(%rip), %xmm0     # 0x5134
ucomiss 0x15ef(%rip), %xmm0     # 0x5138
jb 0x3b81
movl $0xff, %esi
movq %r15, %rdi
leaq 0x1764(%rip), %rdx      # 0x52be
movsd -0x38(%rbp), %xmm0
movb $0x1, %al
callq 0x22b0
leaq -0x128(%rbp), %rdi
movq %r15, %rsi
callq 0x2df6
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
movq %rbx, -0x70(%rbp)
cmpb $0x1, -0x14b(%rbp)
jne 0x3ba6
movq -0xf0(%rbp), %rsi
movl -0x44(%rbp), %edx
movl -0x2c(%rbp), %edi
callq 0x2310
movl -0x2c(%rbp), %edi
xorl %esi, %esi
callq 0x2250
movb $0x0, -0x14b(%rbp)
movq $0x0, -0x61f0(%rbp)
movq $0xf4240, -0x61e8(%rbp) # imm = 0xF4240
movq %r15, %rdi
movq %r15, %rsi
callq 0x20c0
cmpl $-0x1, %eax
jne 0x37e6
callq 0x2060
cmpl $0x4, (%rax)
je 0x3bc3
jmp 0x37e6
movb $0x0, -0x150(%rbp)
jmp 0x37e6
movb $0x1, -0x150(%rbp)
jmp 0x37e6
movb $0x0, -0x151(%rbp)
jmp 0x37e6
movb $0x1, -0x151(%rbp)
jmp 0x37e6
movb $0x0, -0x157(%rbp)
jmp 0x37e6
movb $0x1, -0x157(%rbp)
jmp 0x37e6
movb $0x0, -0x152(%rbp)
jmp 0x37e6
movb $0x1, -0x152(%rbp)
jmp 0x37e6
movb $0x0, -0x156(%rbp)
jmp 0x37e6
movb $0x0, -0x153(%rbp)
jmp 0x37e6
movb $0x0, -0x14e(%rbp)
jmp 0x37e6
movb $0x1, -0x156(%rbp)
jmp 0x37e6
movb $0x1, -0x153(%rbp)
jmp 0x37e6
movb $0x1, -0x14e(%rbp)
jmp 0x37e6
movb $0x0, -0x158(%rbp)
jmp 0x37e6
movb $0x0, -0x155(%rbp)
jmp 0x37e6
movb $0x1, -0x158(%rbp)
jmp 0x37e6
movb $0x0, -0x14f(%rbp)
jmp 0x37e6
movb $0x0, -0x14d(%rbp)
jmp 0x37e6
movb $0x1, -0x155(%rbp)
jmp 0x37e6
movb $0x1, -0x14f(%rbp)
jmp 0x37e6
movb $0x1, -0x14d(%rbp)
jmp 0x37e6
movb $0x0, -0x15a(%rbp)
jmp 0x37e6
movb $0x1, -0x15a(%rbp)
jmp 0x37e6
movb $0x0, -0x159(%rbp)
jmp 0x37e6
movb $0x0, -0x15b(%rbp)
jmp 0x37e6
movb $0x1, -0x159(%rbp)
jmp 0x37e6
movb $0x1, -0x15b(%rbp)
jmp 0x37e6
movq -0x68(%rbp), %rdi
leaq -0x58(%rbp), %rax
cmpq %rax, %rdi
je 0x3d4f
movq -0x58(%rbp), %rsi
incq %rsi
callq 0x21c0
addq $0x61c8, %rsp           # imm = 0x61C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3df0
movq %rax, %rbx
movq -0xa8(%rbp), %rdi
cmpq %r15, %rdi
je 0x3df3
movq -0x98(%rbp), %rsi
jmp 0x3de0
jmp 0x3df0
jmp 0x3df0
jmp 0x3df0
movq %rax, %rbx
movq -0x110(%rbp), %rdi
cmpq %r14, %rdi
je 0x3df3
movq -0x100(%rbp), %rsi
jmp 0x3de0
jmp 0x3df0
jmp 0x3df0
jmp 0x3df0
jmp 0x3df0
movq %rax, %rbx
movq -0xc8(%rbp), %rdi
leaq -0xb8(%rbp), %rax
cmpq %rax, %rdi
je 0x3df3
movq -0xb8(%rbp), %rsi
jmp 0x3de0
movq %rax, %rbx
movq -0xe8(%rbp), %rdi
leaq -0xd8(%rbp), %rax
cmpq %rax, %rdi
je 0x3df3
movq -0xd8(%rbp), %rsi
incq %rsi
callq 0x21c0
jmp 0x3df3
jmp 0x3df0
jmp 0x3df0
jmp 0x3df0
movq %rax, %rbx
movq -0x68(%rbp), %rdi
leaq -0x58(%rbp), %rax
cmpq %rax, %rdi
je 0x3e0c
movq -0x58(%rbp), %rsi
incq %rsi
callq 0x21c0
movq %rbx, %rdi
callq 0x22d0