// File: /workspace/github_cpp_makefile_star2_O2/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 $0x61b8, %rsp           # imm = 0x61B8
movq %rdx, %r14
movl %esi, %r15d
movq %rdi, %rbx
leaq -0x3188(%rbp), %rdi
andw $0x0, 0x304c(%rdi)
callq 0x24ec
leaq -0x90(%rbp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
cmpl $0x2, %r15d
jl 0x31e1
leaq 0x109d(%rip), %rsi      # 0x4236
leaq -0x78(%rbp), %rdi
leaq -0x118(%rbp), %rdx
callq 0x3830
movq 0x8(%r14), %rdx
leaq -0x61e0(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x38cb
leaq -0xa0(%rbp), %rdi
leaq -0x61e0(%rbp), %r14
movq %r14, %rsi
callq 0x2220
movq %r14, %rdi
callq 0x2110
leaq -0x78(%rbp), %rdi
jmp 0x3211
leaq 0x1054(%rip), %rsi      # 0x423c
leaq -0x61e0(%rbp), %rdi
leaq -0x78(%rbp), %rdx
callq 0x3830
leaq -0xa0(%rbp), %rdi
leaq -0x61e0(%rbp), %r14
movq %r14, %rsi
callq 0x2220
movq %r14, %rdi
callq 0x2110
leaq -0xc0(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x2260
leaq -0x3188(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x2590
leaq -0xc0(%rbp), %rdi
callq 0x2110
leaq -0xd8(%rbp), %rdi
callq 0x2cf4
leaq 0xfeb(%rip), %rdi       # 0x4246
leaq 0xe1e(%rip), %rsi       # 0x4080
callq 0x20f0
pushq $0x1
popq %rsi
leaq -0x118(%rbp), %rdx
leaq -0x80(%rbp), %rcx
leaq -0x38(%rbp), %r8
movq %rax, %rdi
callq 0x20d0
leaq -0x118(%rbp), %rdx
xorl %edi, %edi
xorl %esi, %esi
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x2210
movl %eax, -0x34(%rbp)
callq 0x2130
movq %rax, -0x40(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x30(%rbp)
leaq -0x78(%rbp), %r13
movq %r13, %rdi
callq 0x2120
testl %eax, %eax
je 0x350b
movl -0x78(%rbp), %eax
cmpl $0x100, %eax            # imm = 0x100
je 0x3742
movl %eax, %edx
xorl $0x300, %edx            # imm = 0x300
movl -0x64(%rbp), %ecx
movl %ecx, %esi
xorl $0x20, %esi
orl %edx, %esi
jne 0x332c
leaq 0x101d(%rip), %rdi      # 0x4304
callq 0x22a0
movq $0x320, -0x61e0(%rbp) # imm = 0x320
leaq -0x61e0(%rbp), %rdi
callq 0x38f4
movq %r13, %rdi
callq 0x2120
cmpl $0x300, -0x78(%rbp)     # imm = 0x300
jne 0x3303
cmpl $0x20, -0x64(%rbp)
jne 0x3303
leaq 0xfef(%rip), %rdi       # 0x4310
callq 0x22a0
movl -0x78(%rbp), %eax
movl -0x64(%rbp), %ecx
movl %eax, %edx
xorl $0x300, %edx            # imm = 0x300
movl %ecx, %esi
xorl $0x4000003a, %esi       # imm = 0x4000003A
orl %edx, %esi
jne 0x3373
movb 0x3068(%rbx), %al
leal 0x1(%rax), %ecx
cmpb $0x3, %al
movzbl %cl, %eax
movl $0x0, %ecx
cmovel %ecx, %eax
movb %al, 0x3068(%rbx)
movzbl %al, %esi
leaq 0xef0(%rip), %rdi       # 0x4256
xorl %eax, %eax
callq 0x2070
movl -0x78(%rbp), %eax
movl -0x64(%rbp), %ecx
cmpl $0x300, %eax            # imm = 0x300
jne 0x33d9
cmpl $0x4000003b, %ecx       # imm = 0x4000003B
jne 0x33d9
movzbl 0x3068(%rbx), %esi
leaq 0xee1(%rip), %rdi       # 0x4271
xorl %eax, %eax
callq 0x2070
movb 0x3068(%rbx), %r14b
leaq -0xf8(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x2260
movzbl %r14b, %esi
leaq -0x3188(%rbp), %rdx
leaq -0xf8(%rbp), %r15
movq %r15, %rcx
callq 0x2e7c
movq %r15, %rdi
callq 0x2110
movl -0x78(%rbp), %eax
movl -0x64(%rbp), %ecx
cmpl $0x300, %eax            # imm = 0x300
jne 0x345b
cmpl $0x4000003c, %ecx       # imm = 0x4000003C
jne 0x345b
movzbl 0x3068(%rbx), %esi
leaq 0xea0(%rip), %rdi       # 0x4296
xorl %eax, %eax
callq 0x2070
movq %rbx, %r12
movb 0x3068(%rbx), %r14b
leaq -0x138(%rbp), %rbx
movq %rbx, %rdi
leaq -0xa0(%rbp), %rsi
callq 0x2260
movzbl %r14b, %edx
leaq -0x61e0(%rbp), %r15
movq %r15, %rdi
leaq -0x3188(%rbp), %r14
movq %r14, %rcx
movq %rbx, %r8
callq 0x2fba
movl $0x304e, %edx           # imm = 0x304E
movq %r14, %rdi
movq %r15, %rsi
callq 0x2180
movq %rbx, %rdi
callq 0x2110
movl -0x78(%rbp), %eax
movq %r12, %rbx
cmpl $0x300, %eax            # imm = 0x300
je 0x3494
cmpl $0x301, %eax            # imm = 0x301
jne 0x32ae
movl -0x64(%rbp), %eax
leal -0x61(%rax), %ecx
cmpl $0x19, %ecx
ja 0x34bb
leaq 0xd45(%rip), %rdx       # 0x41c4
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movb $0x0, -0x144(%rbp)
jmp 0x32ae
movl -0x64(%rbp), %eax
leal -0x61(%rax), %ecx
cmpl $0x19, %ecx
ja 0x34e3
leaq 0xca6(%rip), %rdx       # 0x414c
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movb $0x1, -0x144(%rbp)
jmp 0x32ae
addl $-0x31, %eax
cmpl $0x3, %eax
ja 0x32ae
leaq 0xce6(%rip), %rcx       # 0x41b4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x0, -0x14c(%rbp)
jmp 0x32ae
addl $-0x31, %eax
cmpl $0x3, %eax
ja 0x32ae
leaq 0xc46(%rip), %rcx       # 0x413c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, -0x14c(%rbp)
jmp 0x32ae
leaq -0x3188(%rbp), %rdi
callq 0x264a
cmpb $0x1, -0x13c(%rbp)
jne 0x35b7
movb $0x0, -0x13c(%rbp)
leaq -0xd8(%rbp), %rdi
leaq -0x2170(%rbp), %rsi
callq 0x2de2
movsd -0x30(%rbp), %xmm0
addsd 0xbdd(%rip), %xmm0      # 0x4128
movsd %xmm0, -0x30(%rbp)
callq 0x2130
movq %rax, %r14
subq -0x40(%rbp), %rax
cvtsi2ss %rax, %xmm0
mulss 0xbc7(%rip), %xmm0      # 0x4130
divss 0xbc3(%rip), %xmm0      # 0x4134
ucomiss 0xbc0(%rip), %xmm0      # 0x4138
jb 0x35b7
movl $0xff, %esi
leaq -0x61e0(%rbp), %r15
movq %r15, %rdi
leaq 0xd2e(%rip), %rdx       # 0x42be
movsd -0x30(%rbp), %xmm0
movb $0x1, %al
callq 0x22c0
leaq -0xd8(%rbp), %rdi
movq %r15, %rsi
callq 0x2dd4
xorps %xmm0, %xmm0
movsd %xmm0, -0x30(%rbp)
movq %r14, -0x40(%rbp)
cmpb $0x1, -0x13b(%rbp)
jne 0x35cf
movq -0x80(%rbp), %rsi
movl -0x38(%rbp), %edx
movl -0x34(%rbp), %edi
callq 0x312c
movb $0x0, -0x13b(%rbp)
movq $0x1, -0x61e0(%rbp)
leaq -0x61e0(%rbp), %rdi
callq 0x38f4
jmp 0x32ae
movb $0x0, -0x140(%rbp)
jmp 0x32ae
movb $0x1, -0x140(%rbp)
jmp 0x32ae
movb $0x0, -0x141(%rbp)
jmp 0x32ae
movb $0x1, -0x141(%rbp)
jmp 0x32ae
movb $0x0, -0x147(%rbp)
jmp 0x32ae
movb $0x1, -0x147(%rbp)
jmp 0x32ae
movb $0x0, -0x142(%rbp)
jmp 0x32ae
movb $0x1, -0x142(%rbp)
jmp 0x32ae
movb $0x0, -0x146(%rbp)
jmp 0x32ae
movb $0x0, -0x143(%rbp)
jmp 0x32ae
movb $0x0, -0x13e(%rbp)
jmp 0x32ae
movb $0x1, -0x146(%rbp)
jmp 0x32ae
movb $0x1, -0x143(%rbp)
jmp 0x32ae
movb $0x1, -0x13e(%rbp)
jmp 0x32ae
movb $0x0, -0x148(%rbp)
jmp 0x32ae
movb $0x0, -0x145(%rbp)
jmp 0x32ae
movb $0x1, -0x148(%rbp)
jmp 0x32ae
movb $0x0, -0x13f(%rbp)
jmp 0x32ae
movb $0x0, -0x13d(%rbp)
jmp 0x32ae
movb $0x1, -0x145(%rbp)
jmp 0x32ae
movb $0x1, -0x13f(%rbp)
jmp 0x32ae
movb $0x1, -0x13d(%rbp)
jmp 0x32ae
movb $0x0, -0x14a(%rbp)
jmp 0x32ae
movb $0x1, -0x14a(%rbp)
jmp 0x32ae
movb $0x0, -0x149(%rbp)
jmp 0x32ae
movb $0x0, -0x14b(%rbp)
jmp 0x32ae
movb $0x1, -0x149(%rbp)
jmp 0x32ae
movb $0x1, -0x14b(%rbp)
jmp 0x32ae
leaq -0xa0(%rbp), %rdi
callq 0x2110
addq $0x61b8, %rsp           # imm = 0x61B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x37a8
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
jmp 0x379b
jmp 0x37a8
jmp 0x37a8
jmp 0x37a8
movq %rax, %rbx
leaq -0xc0(%rbp), %rdi
jmp 0x379b
jmp 0x37a8
jmp 0x37a8
jmp 0x37a8
jmp 0x37a8
movq %rax, %rbx
leaq -0xf8(%rbp), %rdi
jmp 0x379b
movq %rax, %rbx
leaq -0x138(%rbp), %rdi
callq 0x2110
jmp 0x37ab
jmp 0x37a8
jmp 0x37a8
jmp 0x37a8
movq %rax, %rbx
leaq -0xa0(%rbp), %rdi
callq 0x2110
movq %rbx, %rdi
callq 0x22e0