// File: /workspace/github_cpp_makefile_star2_O3/thanoskoutr[P]Chip-8-Emulator/main.cpp
// Function: main
int main (int argc, char **argv)
{
	/* Initialize the Chip8 system and load the game into the memory */
	if(argc < 2)
	{
	  printf("No ROM given...\n");
		return 1;
	}

	// First we need to start up SDL, and make sure it went ok
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		logSDLError(std::cout, "SDL_Init");
		return 1;
	}
	// Now create a window with title "Hello World" at 100, 100 on the screen with w:640 h:480 and show it
	// Setup our window and renderer
	SDL_Window *window = SDL_CreateWindow(argv[1], SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_Width, Screen_Height, SDL_WINDOW_RESIZABLE);
	if (window == nullptr)
	{
		logSDLError(std::cout, "CreateWindow");
		return 1;
	}

	// Create a renderer that will draw to the window, -1 specifies that we want to load whichever
	// video driver supports the flags we're passing
	// Flags: SDL_RENDERER_ACCELERATED: We want to use hardware accelerated rendering
	// 				SDL_RENDERER_PRESENTVSYNC: We want the renderer's present function (update screen) to be
	// 				synchronized with the monitor's refresh rate
	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
	if (renderer == nullptr)
	{
		logSDLError(std::cout, "CreateRenderer");
		cleanup(window);
		SDL_Quit();
		return 1;
	}

	// To use a hardware accelerated texture for rendering we can create one
	SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
	if (texture == nullptr)
	{
		cleanup(texture, renderer, window);
		logSDLError(std::cout, "CreateTexture");
		SDL_Quit();
		return 1;
	}

	// Create a mapping of SDL keyboard symbols to CHIP-8 keypad codes
	std::unordered_map<int,unsigned char> keymap
	{
		{SDLK_1, 0x1}, {SDLK_2, 0x2}, {SDLK_3, 0x3}, {SDLK_4, 0xC},
		{SDLK_q, 0x4}, {SDLK_w, 0x5}, {SDLK_e, 0x6}, {SDLK_r, 0xD},
		{SDLK_a, 0x7}, {SDLK_s, 0x8}, {SDLK_d, 0x9}, {SDLK_f, 0xE},
		{SDLK_z, 0xA}, {SDLK_x, 0x0}, {SDLK_c, 0xB}, {SDLK_v, 0xF},
		{SDLK_ESCAPE, -1}
	};


  // Temporary pixel buffer for updating texture
  uint32_t pixels[2048];

  // Load Application
  if (chip8.loadApplication(argv[1]) != 0) // initialization included
	{
		std::cout << "Failed to Load Application" << std::endl;
		return 1;
	}

	// Our event structure
	SDL_Event e;
	// For tracking if we want to quit
	bool quit = false;

  // Emulation loop
	while (!quit)
	{
    chip8.emulateCycle();

		// Read any SDL events that occured
		while (SDL_PollEvent(&e))
		{
			//If user closes the window
			if (e.type == SDL_QUIT)
				quit = true;

			// If user presses any key
			if (e.type == SDL_KEYDOWN)
      {
        // If user presses ESC we exit
        if (e.key.keysym.sym == SDLK_ESCAPE)
          quit = true;
        else
        {
          // find if valid is key pressed and set to 1
          auto pressed_key = keymap.find(e.key.keysym.sym);
          if (pressed_key != keymap.end())
          {
            printf ("Pressed Key: 0x%X\n", pressed_key->first);
            printf ("Mapped to: 0x%X\n", pressed_key->second);
            chip8.key[pressed_key->second] = 1;
          }

        }
      }

      // If user releases any key
      if (e.type == SDL_KEYUP)
      {
        // find if valid is key pressed and set to 0
        auto released_key = keymap.find(e.key.keysym.sym);
        if (released_key != keymap.end())
        {
          printf ("Released Key: 0x%X\n", released_key->first);
          printf ("Mapped to: 0x%X\n", released_key->second);
          chip8.key[released_key->second] = 0;
        }

      }
		}

    // If draw occurred, redraw SDL screen
    if(chip8.drawFlag)
 	 {
     chip8.drawFlag = false;

     // Store pixels in temporary buffer
     for (int i = 0; i < SCREEN_SIZE; ++i)
     {
       unsigned char pixel = chip8.gfx[i];
       pixels[i] = (0x00FFFFFF * pixel) | 0xFF000000;
     }
     // Update SDL texture
     SDL_UpdateTexture(texture, NULL, pixels, SCREEN_WIDTH* sizeof(Uint32));
     // First clear the renderer
     SDL_RenderClear(renderer);
     // Draw the texture
     SDL_RenderCopy(renderer, texture, NULL, NULL);
     // Update the screen
     SDL_RenderPresent(renderer);
 	 }

   // Sleep to slow down emulation speed
   // std::this_thread::sleep_for(std::chrono::microseconds(1200));
   SDL_Delay(100/60);

	}

	// Clean up our objects and quit
	cleanup(renderer, window);
	SDL_Quit();

	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2098, %rsp           # imm = 0x2098
cmpl $0x1, %edi
jg 0x2e90
leaq 0x1423(%rip), %rdi      # 0x42a9
callq 0x22d0
jmp 0x3141
movq %rsi, %r14
movl $0x20, %edi
callq 0x21c0
testl %eax, %eax
je 0x2f02
leaq 0xa0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x1345(%rip), %rsi      # 0x41f9
leaq 0x1346(%rip), %rdx      # 0x4201
leaq 0x90(%rsp), %rdi
callq 0x345a
movq 0x3101(%rip), %rdi      # 0x5fd0
leaq 0x90(%rsp), %rsi
callq 0x2db4
movq 0x90(%rsp), %rdi
cmpq %r14, %rdi
je 0x3141
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x2210
jmp 0x3141
movq 0x8(%r14), %rdi
movl $0x2fff0000, %esi       # imm = 0x2FFF0000
movl $0x2fff0000, %edx       # imm = 0x2FFF0000
movl $0x280, %ecx            # imm = 0x280
movl $0x1e0, %r8d            # imm = 0x1E0
movl $0x20, %r9d
callq 0x2080
movq %rax, 0x10(%rsp)
testq %rax, %rax
je 0x302e
movq %rax, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0x6, %edx
callq 0x2060
testq %rax, %rax
je 0x306e
movq %rax, %rbp
movq %rax, %rdi
movl $0x16362004, %esi       # imm = 0x16362004
movl $0x1, %edx
movl $0x40, %ecx
movl $0x20, %r8d
callq 0x2320
movq %rax, 0x18(%rsp)
testq %rax, %rax
je 0x30d7
leaq 0x1338(%rip), %rsi      # 0x42bc
leaq 0x90(%rsp), %r15
movl $0x88, %edx
movq %r15, %rdi
callq 0x21a0
leaq 0x118(%rsp), %rdx
leaq 0xe(%rsp), %rax
movq %rax, (%rsp)
leaq 0x20(%rsp), %rdi
leaq 0x58(%rsp), %r8
leaq 0xf(%rsp), %r9
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x34f0
movq 0x8(%r14), %rsi
leaq 0x323e(%rip), %r15      # 0x620c
movq %r15, %rdi
callq 0x253e
testl %eax, %eax
je 0x315a
movq 0x2feb(%rip), %rbx      # 0x5fd0
leaq 0x1240(%rip), %rsi      # 0x422c
movl $0x1a, %edx
movq %rbx, %rdi
callq 0x2240
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x21e0
movsbl %al, %esi
movq 0x2fb9(%rip), %rdi      # 0x5fd0
callq 0x2050
movl $0x1, %ebx
movq %rax, %rdi
callq 0x2130
jmp 0x3362
leaq 0xa0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x11c1(%rip), %rsi      # 0x4202
leaq 0x11c6(%rip), %rdx      # 0x420e
leaq 0x90(%rsp), %rdi
callq 0x345a
movq 0x2f74(%rip), %rdi      # 0x5fd0
leaq 0x90(%rsp), %rsi
callq 0x2db4
jmp 0x2edc
leaq 0xa0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x118e(%rip), %rsi      # 0x420f
leaq 0x1195(%rip), %rdx      # 0x421d
leaq 0x90(%rsp), %rdi
callq 0x345a
movq 0x2f34(%rip), %rdi      # 0x5fd0
leaq 0x90(%rsp), %rsi
callq 0x2db4
movq 0x90(%rsp), %rdi
cmpq %r14, %rdi
je 0x30c6
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x2210
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
je 0x313c
callq 0x2040
jmp 0x313c
leaq 0x10(%rsp), %rsi
movq %rbp, %rdi
callq 0x33c1
leaq 0xa0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x1127(%rip), %rsi      # 0x421e
leaq 0x112d(%rip), %rdx      # 0x422b
leaq 0x90(%rsp), %rdi
callq 0x345a
movq 0x2ebe(%rip), %rdi      # 0x5fd0
leaq 0x90(%rsp), %rsi
callq 0x2db4
movq 0x90(%rsp), %rdi
cmpq %r14, %rdi
je 0x313c
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x2210
callq 0x2090
movl $0x1, %ebx
movl %ebx, %eax
addq $0x2098, %rsp           # imm = 0x2098
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x58(%rsp), %r12
leaq 0x10f4(%rip), %r13      # 0x425a
movq %r15, %rdi
callq 0x26fc
movq %rbp, %r14
xorl %ebx, %ebx
movq %r12, %rdi
callq 0x2120
testl %eax, %eax
je 0x32b0
movl 0x58(%rsp), %eax
cmpl $0x100, %eax            # imm = 0x100
sete %bpl
orb %bl, %bpl
cmpl $0x300, %eax            # imm = 0x300
jne 0x3225
movslq 0x6c(%rsp), %rsi
movb $0x1, %bl
cmpq $0x1b, %rsi
je 0x3173
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %r8
movq %rsi, %rax
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
movl %ebp, %ebx
testq %rax, %rax
je 0x3173
movq %rdx, %rcx
movq (%rax), %rbx
cmpl 0x8(%rbx), %esi
je 0x31f8
movq (%rbx), %rbx
testq %rbx, %rbx
je 0x32a9
movslq 0x8(%rbx), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
cmpq %rcx, %rdx
jne 0x32a9
cmpl %edi, %esi
jne 0x31d3
leaq 0x1048(%rip), %rdi      # 0x4247
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbx), %esi
movq %r13, %rdi
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbx), %eax
movb $0x1, 0x801(%rax,%r15)
movl 0x58(%rsp), %eax
movl %ebp, %ebx
cmpl $0x301, %eax            # imm = 0x301
jne 0x3173
movslq 0x6c(%rsp), %rsi
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %r8
movq %rsi, %rax
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
movl %ebp, %ebx
testq %rax, %rax
je 0x3173
movq %rdx, %rcx
movq (%rax), %rbx
cmpl 0x8(%rbx), %esi
je 0x3280
movq (%rbx), %rbx
testq %rbx, %rbx
je 0x32a9
movslq 0x8(%rbx), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
cmpq %rcx, %rdx
jne 0x32a9
cmpl %edi, %esi
jne 0x3263
leaq 0xfe4(%rip), %rdi       # 0x426b
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbx), %esi
movq %r13, %rdi
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbx), %eax
movb $0x0, 0x801(%rax,%r15)
movl %ebp, %ebx
jmp 0x3173
cmpb $0x1, 0x2f55(%rip)      # 0x620c
movq %r14, %rbp
jne 0x333b
movb $0x0, 0x2f49(%rip)      # 0x620c
xorl %eax, %eax
pxor %xmm2, %xmm2
movdqa 0xf0f(%rip), %xmm3      # 0x41e0
movd 0x1(%rax,%r15), %xmm0
punpcklbw %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1],xmm0[2],xmm2[2],xmm0[3],xmm2[3],xmm0[4],xmm2[4],xmm0[5],xmm2[5],xmm0[6],xmm2[6],xmm0[7],xmm2[7]
punpcklwd %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1],xmm0[2],xmm2[2],xmm0[3],xmm2[3]
pxor %xmm1, %xmm1
psubd %xmm0, %xmm1
por %xmm3, %xmm1
movdqa %xmm1, 0x90(%rsp,%rax,4)
addq $0x4, %rax
cmpq $0x800, %rax            # imm = 0x800
jne 0x32d1
movq 0x18(%rsp), %rdi
xorl %esi, %esi
leaq 0x90(%rsp), %rdx
movl $0x100, %ecx            # imm = 0x100
callq 0x2180
movq %rbp, %rdi
callq 0x21d0
movq %rbp, %rdi
movq 0x18(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2230
movq %rbp, %rdi
callq 0x20a0
movl $0x1, %edi
callq 0x2160
testb $0x1, %bl
je 0x3166
leaq 0x10(%rsp), %rsi
movq %rbp, %rdi
callq 0x33c1
callq 0x2090
xorl %ebx, %ebx
leaq 0x20(%rsp), %rdi
callq 0x33e0
jmp 0x3146
jmp 0x3383
jmp 0x33a5
jmp 0x33ac
jmp 0x3383
jmp 0x33a5
jmp 0x33a5
jmp 0x3383
jmp 0x33a5
jmp 0x33ac
movq %rax, %rbx
movq 0x90(%rsp), %rdi
cmpq %r14, %rdi
je 0x33b9
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x2210
jmp 0x33b9
movq %rax, %rbx
jmp 0x33b9
jmp 0x33ac
movq %rax, %rbx
leaq 0x20(%rsp), %rdi
callq 0x33e0
movq %rbx, %rdi
callq 0x2300