// File: /workspace/github_cpp_makefile_star2_O3/kodejuice[P]chip8-emulator/main.cc
// Function: main
int main(int argc, char** argv) {
	if (argc < 2)
		COMMAND_USAGE;

	Chip8 cpu = Chip8();

	string arg1 = string(argv[1]);
	if (arg1 == "--decode") {
		// load/decode program
		if (argc < 3) COMMAND_USAGE;
		cpu.load_program(argv[2]);

		cout << cpu.disassemble();
		return 0;
	}
	else {
		// load program
		if (!cpu.load_program(arg1)) exit(1);
	}

	printf("\nPress P to pause emulation.\n");


	/////////
	// GUI //
	/////////

	string filename = getfilename(arg1);

	// create window
	string title = "Chip8 Emulator - " + filename;
	SDL_Window* window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, W, H, SDL_WINDOW_RESIZABLE);
	SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); SDL_RenderSetLogicalSize(renderer, W, H);
	SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h);

	// mapping of SDL keyboard symbols to chip8 keypad codes
	unordered_map<int,int> 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_5, 0x5}, {SDLK_6, 0x6}, {SDLK_7, 0x7}, {SDLK_p, -2},
		{SDLK_8, 0x8}, {SDLK_9, 0x9}, {SDLK_0, 0x0}, {SDLK_ESCAPE,-1}
	};

	// Init. SDL audio
	SDL_AudioSpec spec, obtained;
	spec.freq     = 44100;
	spec.format   = AUDIO_S16SYS;
	spec.channels = 2;
	spec.samples  = spec.freq/20;
	spec.callback = [](void*, Uint8* stream, int len) {
		short* target = (short*)stream;
		while(len > 0 && !AudioQueue.empty()) {
			auto& data = AudioQueue.front();
			for(; len && data.first; target += 2, len -= 4, --data.first)
				target[0] = target[1] = data.second*300*((len&128)-64);
			if(!data.first) AudioQueue.pop_front();
		}
	};
	SDL_OpenAudio(&spec, &obtained);
	SDL_PauseAudio(0);


	int msg = 0;
	int frames_done = 0;
	bool running = true,
		 paused = false;


	auto start = chrono::system_clock::now();
	while (running) {

		/////////////////////////
		// Execute Instruction //
		/////////////////////////
		if (!cpu.awaitingKey && !paused)
			// if not waiting for input nor paused
			cpu.emulate_op();

		if (paused && !msg) {
			printf("\nPaused\n");
			msg = 1;
		}

		////////////////////
		// Process events //
		////////////////////
		for(SDL_Event ev; SDL_PollEvent(&ev); )
			switch(ev.type)
			{
				case SDL_QUIT: running = 0; break;
				case SDL_KEYDOWN:
				case SDL_KEYUP:
					auto i = keymap.find(ev.key.keysym.sym);

					if (i == keymap.end()) break;
					if (i->second == -1) { running = 0; break; }
					if (i->second == -2 && ev.type==SDL_KEYDOWN) {
						paused=!paused, msg=0;
						if (!paused) printf("Resumed\n");
						break;
					}

					cpu.key_pressed[i->second] = (ev.type == SDL_KEYDOWN);

					if(ev.type==SDL_KEYDOWN && cpu.awaitingKey) {
						cpu.V[cpu.awaitingKey & 0x7f] = i->second;
						cpu.awaitingKey = 0;
					}
			}


		/////////////
		// Render  //
		/////////////
		auto cur = chrono::system_clock::now();

		chrono::duration<double> elapsed_seconds = cur-start;
		int frames = int(elapsed_seconds.count() * 60) - frames_done;

		if (frames > 0 && !paused) {
			frames_done += frames;

            // Update the timer registers
            int st = min<int>(frames, cpu.ST); cpu.ST -= st;
            int dt = min<int>(frames, cpu.DT); cpu.DT -= dt;

            //////////////////
            // Render audio //
            SDL_LockAudio();
             AudioQueue.emplace_back( obtained.freq*st/60,  true );
             AudioQueue.emplace_back( obtained.freq*(frames-st)/60, false );
            SDL_UnlockAudio();

			/////////////////////
			// Render graphics //
			if (cpu.redraw) {
				renderTo(pixels, cpu.screen);
				SDL_UpdateTexture(texture, nullptr, pixels, 4*w);
				SDL_RenderClear(renderer);
				SDL_RenderCopy(renderer, texture, nullptr, nullptr);
				SDL_RenderPresent(renderer);

				cpu.redraw = false;
			}
		}

		if (!paused)
			this_thread::sleep_for(chrono::microseconds(1300));
	}

	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1a88, %rsp           # imm = 0x1A88
cmpl $0x1, %edi
jg 0x32f8
movq 0x4d25(%rip), %rbx      # 0x7fd8
leaq 0x210b(%rip), %rsi      # 0x53c5
movl $0x3d, %edx
movq %rbx, %rdi
callq 0x22b0
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2250
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x21c0
movl $0x1, %ebx
jmp 0x3acb
movq %rsi, %rbx
movl %edi, %ebp
leaq 0x1260(%rsp), %rdi
movw $0x200, -0x2e(%rdi)     # imm = 0x200
xorpd %xmm0, %xmm0
movupd %xmm0, -0x2c(%rdi)
movupd %xmm0, -0x1c(%rdi)
movw $0x0, -0xc(%rdi)
movl $0x823, %edx            # imm = 0x823
xorl %esi, %esi
callq 0x21a0
leaq 0x280(%rsp), %rdi
movl $0xfb2, %edx            # imm = 0xFB2
xorl %esi, %esi
callq 0x21a0
leaq 0x4eca(%rip), %rsi      # 0x8210
leaq 0x230(%rsp), %rdi
movl $0xa, %ecx
rep  movsq (%rsi), %es:(%rdi)
movq 0x8(%rbx), %rsi
leaq 0x30(%rsp), %r14
leaq 0x118(%rsp), %rdx
movq %r14, %rdi
callq 0x2160
leaq 0x208d(%rip), %rsi      # 0x5403
movq %r14, %rdi
callq 0x2110
testl %eax, %eax
je 0x39b6
leaq 0xe8(%rsp), %r15
movq %r15, -0x10(%r15)
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
addq %rsi, %rdx
leaq 0xd8(%rsp), %rdi
callq 0x4002
leaq 0x230(%rsp), %rdi
leaq 0xd8(%rsp), %r14
movq %r14, %rsi
callq 0x263a
movl %eax, %ebx
movq (%r14), %rdi
cmpq %r15, %rdi
je 0x33de
movq 0xe8(%rsp), %rsi
incq %rsi
callq 0x2280
testb %bl, %bl
je 0x3adf
leaq 0x20d9(%rip), %rdi      # 0x54c6
callq 0x2350
leaq 0x68(%rsp), %r14
movq %r14, -0x10(%r14)
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
addq %rsi, %rdx
leaq 0x58(%rsp), %rdi
callq 0x4002
leaq 0x98(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x3bbe
movq 0x58(%rsp), %rdi
cmpq %r14, %rdi
je 0x343b
movq 0x68(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x1fca(%rip), %rsi      # 0x540c
leaq 0x78(%rsp), %rdi
leaq 0x98(%rsp), %rdx
callq 0x3d3b
movq 0x78(%rsp), %rdi
movl $0x1fff0000, %esi       # imm = 0x1FFF0000
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0x400, %ecx            # imm = 0x400
movl $0x200, %r8d            # imm = 0x200
movl $0x20, %r9d
callq 0x2080
movq %rax, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
xorl %edx, %edx
callq 0x2050
movq %rax, %rbx
movq %rax, %rdi
movl $0x400, %esi            # imm = 0x400
movl $0x200, %edx            # imm = 0x200
callq 0x2140
movq %rbx, %rdi
movl $0x16362004, %esi       # imm = 0x16362004
movl $0x1, %edx
movl $0x40, %ecx
movl $0x20, %r8d
callq 0x23c0
movq %rax, 0x28(%rsp)
leaq 0x1c36(%rip), %rsi      # 0x50fc
leaq 0x118(%rsp), %r15
movl $0xc0, %edx
movq %r15, %rdi
callq 0x2220
leaq 0x1d8(%rsp), %rdx
leaq 0x13(%rsp), %rax
movq %rax, (%rsp)
leaq 0x1d8(%rsp), %rdi
leaq 0x210(%rsp), %r8
leaq 0xb8(%rsp), %r9
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x43e4
movq %rbx, 0x18(%rsp)
leaq 0x210(%rsp), %rdi
movl $0xac44, (%rdi)         # imm = 0xAC44
movw $0x8010, 0x4(%rdi)      # imm = 0x8010
movb $0x2, 0x6(%rdi)
movw $0x89d, 0x8(%rdi)       # imm = 0x89D
leaq 0x748(%rip), %rax       # 0x3c80
movq %rax, 0x10(%rdi)
leaq 0xb8(%rsp), %rsi
callq 0x2370
xorl %edi, %edi
callq 0x2200
callq 0x2090
movq %rax, 0x50(%rsp)
leaq 0x118(%rsp), %r13
xorl %r14d, %r14d
movl $0x0, 0x14(%rsp)
xorl %ebp, %ebp
movb 0x1282(%rsp), %al
testb %al, %al
setne %cl
orb %r14b, %cl
testb $0x1, %cl
je 0x35aa
testb %al, %al
sete %al
orb %r14b, %al
testl %ebp, %ebp
sete %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x35b7
leaq 0x1f45(%rip), %rdi      # 0x54e3
callq 0x2350
movl $0x1, %ebp
jmp 0x35b7
leaq 0x230(%rsp), %rdi
callq 0x2722
movb $0x1, %al
movl %eax, %r12d
movq %r13, %rdi
callq 0x21b0
testl %eax, %eax
je 0x36f1
movl 0x118(%rsp), %r8d
leal -0x300(%r8), %eax
cmpl $0x2, %eax
jae 0x368e
movslq 0x12c(%rsp), %rcx
movq 0x1d8(%rsp), %rdi
movq 0x1e0(%rsp), %r9
movq %rcx, %rax
xorl %edx, %edx
divq %r9
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl %r12d, %eax
testq %rdx, %rdx
je 0x35b9
movq (%rdx), %r10
cmpl 0x8(%r10), %ecx
je 0x3641
movq (%r10), %r10
testq %r10, %r10
je 0x36e9
movslq 0x8(%r10), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r9
cmpq %rsi, %rdx
jne 0x36e9
cmpl %edi, %ecx
jne 0x361c
movslq 0xc(%r10), %rcx
xorl %eax, %eax
cmpq $-0x1, %rcx
je 0x35b9
cmpl $0x300, %r8d            # imm = 0x300
jne 0x36a5
cmpl $-0x2, %ecx
jne 0x36a5
movl %r14d, %ebx
xorb $0x1, %bl
xorl %ebp, %ebp
movl %r12d, %eax
testb $0x1, %r14b
movl %ebx, %r14d
je 0x35b9
leaq 0x1e6d(%rip), %rdi      # 0x54eb
callq 0x2350
movl %r12d, %eax
movl %ebx, %r14d
jmp 0x35b9
movl %r12d, %eax
cmpl $0x100, %r8d            # imm = 0x100
jne 0x35b9
xorl %eax, %eax
jmp 0x35b9
cmpl $0x300, %r8d            # imm = 0x300
sete 0x1272(%rsp,%rcx)
sete %al
movb 0x1282(%rsp), %dl
testb %dl, %dl
setne %sil
andb %al, %sil
movl %r12d, %eax
cmpb $0x1, %sil
jne 0x35b9
movzbl %dl, %eax
andl $0x7f, %eax
movb %cl, 0x1262(%rsp,%rax)
movb $0x0, 0x1282(%rsp)
movl %r12d, %eax
jmp 0x35b9
movl %ebp, 0x24(%rsp)
callq 0x2090
subq 0x50(%rsp), %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x1ab1(%rip), %xmm0     # 0x51c0
mulsd 0x1ab1(%rip), %xmm0     # 0x51c8
cvttsd2si %xmm0, %ebp
movl %ebp, %r15d
subl 0x14(%rsp), %r15d
jle 0x37d5
testb $0x1, %r14b
jne 0x3958
movzbl 0x1261(%rsp), %eax
cmpl %eax, %r15d
movl %eax, %ebx
cmovbl %r15d, %ebx
subb %bl, %al
movb %al, 0x1261(%rsp)
movb 0x1260(%rsp), %al
movl $0xff, %ecx
cmpl %ecx, %r15d
cmovbl %r15d, %ecx
subb %cl, %al
movzbl %al, %eax
movl $0x0, %ecx
cmovbl %ecx, %eax
movb %al, 0x1260(%rsp)
callq 0x20c0
movl 0xb8(%rsp), %ecx
movl %ecx, %eax
imull %ebx, %eax
movslq %eax, %rsi
imulq $-0x77777777, %rsi, %rax # imm = 0x88888889
shrq $0x20, %rax
addl %eax, %esi
movl %esi, %eax
shrl $0x1f, %eax
sarl $0x5, %esi
addl %eax, %esi
movl %esi, 0x118(%rsp)
movb $0x1, 0x13(%rsp)
movq 0x7e8e(%rip), %rax      # 0xb640
movq 0x7e97(%rip), %rdx      # 0xb650
leaq -0x8(%rdx), %rdi
cmpq %rdi, %rax
je 0x37e4
movl %esi, (%rax)
movb $0x1, 0x4(%rax)
addq $0x8, %rax
movq %rax, 0x7e6d(%rip)      # 0xb640
jmp 0x380d
testb $0x1, %r14b
je 0x3926
jmp 0x3958
leaq 0x7e25(%rip), %rdi      # 0xb610
movq %r13, %rsi
leaq 0x13(%rsp), %rdx
callq 0x478c
movl 0xb8(%rsp), %ecx
movq 0x7e3a(%rip), %rax      # 0xb640
movq 0x7e43(%rip), %rdx      # 0xb650
subl %ebx, %r15d
imull %ecx, %r15d
movslq %r15d, %rcx
imulq $-0x77777777, %rcx, %rsi # imm = 0x88888889
shrq $0x20, %rsi
addl %esi, %ecx
movl %ecx, %esi
shrl $0x1f, %esi
sarl $0x5, %ecx
addl %esi, %ecx
movl %ecx, 0x118(%rsp)
movb $0x0, 0x13(%rsp)
addq $-0x8, %rdx
cmpq %rdx, %rax
je 0x3856
movl %ecx, (%rax)
movb $0x0, 0x4(%rax)
addq $0x8, %rax
movq %rax, 0x7dec(%rip)      # 0xb640
jmp 0x386a
leaq 0x7db3(%rip), %rdi      # 0xb610
movq %r13, %rsi
leaq 0x13(%rsp), %rdx
callq 0x478c
callq 0x20f0
cmpb $0x1, 0x1a83(%rsp)
jne 0x3922
xorl %eax, %eax
leaq 0x1283(%rsp), %rcx
pxor %xmm2, %xmm2
movdqa 0x193d(%rip), %xmm3     # 0x51d0
movdqa 0x1945(%rip), %xmm4     # 0x51e0
leaq 0x5d6e(%rip), %rdx      # 0x9610
movd (%rcx), %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]
pshufd $0xf5, %xmm0, %xmm1     # xmm1 = xmm0[1,1,3,3]
pmuludq %xmm3, %xmm0
pshufd $0xe8, %xmm0, %xmm0     # xmm0 = xmm0[0,2,2,3]
pmuludq %xmm3, %xmm1
pshufd $0xe8, %xmm1, %xmm1     # xmm1 = xmm1[0,2,2,3]
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
por %xmm4, %xmm0
movdqa %xmm0, (%rax,%rdx)
addq $0x4, %rcx
addq $0x10, %rax
cmpq $0x2000, %rax           # imm = 0x2000
jne 0x38a2
movq 0x28(%rsp), %rdi
xorl %esi, %esi
movl $0x100, %ecx            # imm = 0x100
callq 0x21f0
movq 0x18(%rsp), %rdi
callq 0x2240
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x22a0
movq 0x18(%rsp), %rdi
callq 0x20b0
movb $0x0, 0x1a83(%rsp)
movl %ebp, 0x14(%rsp)
movq $0x0, 0x118(%rsp)
movq $0x13d620, 0x120(%rsp) # imm = 0x13D620
movq %r13, %rdi
movq %r13, %rsi
callq 0x2120
cmpl $-0x1, %eax
jne 0x3958
callq 0x2060
cmpl $0x4, (%rax)
je 0x393e
testb $0x1, %r12b
movl 0x24(%rsp), %ebp
jne 0x356f
leaq 0x1d8(%rsp), %rdi
callq 0x3f92
leaq 0x88(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3994
movq 0x88(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0xa8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3aae
movq 0xa8(%rsp), %rsi
jmp 0x3aa6
cmpl $0x2, %ebp
jne 0x3a0b
movq 0x4616(%rip), %rbx      # 0x7fd8
leaq 0x19fc(%rip), %rsi      # 0x53c5
movl $0x3d, %edx
movq %rbx, %rdi
callq 0x22b0
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x2250
movsbl %al, %esi
movq 0x45e4(%rip), %rdi      # 0x7fd8
callq 0x2040
movl $0x1, %ebx
movq %rax, %rdi
callq 0x21c0
jmp 0x3ab0
movq 0x10(%rbx), %rsi
leaq 0xf8(%rsp), %rdi
leaq 0x118(%rsp), %rdx
callq 0x2160
leaq 0x230(%rsp), %rdi
leaq 0xf8(%rsp), %rbx
movq %rbx, %rsi
callq 0x263a
movq (%rbx), %rdi
leaq 0x108(%rsp), %rax
cmpq %rax, %rdi
je 0x3a5c
movq 0x108(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x118(%rsp), %rdi
leaq 0x230(%rsp), %rsi
callq 0x2c40
movq 0x118(%rsp), %rsi
movq 0x120(%rsp), %rdx
movq 0x4550(%rip), %rdi      # 0x7fd8
callq 0x22b0
leaq 0x128(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3aae
movq 0x128(%rsp), %rsi
incq %rsi
callq 0x2280
xorl %ebx, %ebx
leaq 0x40(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3acb
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x2280
movl %ebx, %eax
addq $0x1a88, %rsp           # imm = 0x1A88
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x1, %edi
callq 0x22e0
movq %rax, %rbx
leaq 0x128(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3b9b
movq 0x128(%rsp), %rsi
jmp 0x3b93
jmp 0x3b3a
jmp 0x3b3a
jmp 0x3b35
jmp 0x3b35
jmp 0x3b35
movq %rax, %rbx
jmp 0x3b7a
movq %rax, %rbx
movq 0x58(%rsp), %rdi
cmpq %r14, %rdi
je 0x3b9b
movq 0x68(%rsp), %rsi
jmp 0x3b93
jmp 0x3b3a
jmp 0x3b49
movq %rax, %rbx
jmp 0x3b59
movq %rax, %rbx
jmp 0x3b9b
jmp 0x3b49
jmp 0x3b49
jmp 0x3b49
jmp 0x3b49
jmp 0x3b49
movq %rax, %rbx
leaq 0x1d8(%rsp), %rdi
callq 0x3f92
leaq 0x88(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3b7a
movq 0x88(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0xa8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3b9b
movq 0xa8(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x40(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3bb6
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x2280
movq %rbx, %rdi
callq 0x23a0