// File: /workspace/github_cpp_makefile_star2_O1/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 0x3332
movq 0x4ceb(%rip), %rbx      # 0x7fd8
leaq 0x20d1(%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 0x3b0d
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 0x4e90(%rip), %rsi      # 0x8210
leaq 0x230(%rsp), %rdi
movl $0xa, %ecx
rep  movsq (%rsi), %es:(%rdi)
movq 0x8(%rbx), %rsi
leaq 0x38(%rsp), %r14
leaq 0x118(%rsp), %rdx
movq %r14, %rdi
callq 0x2160
leaq 0x2053(%rip), %rsi      # 0x5403
movq %r14, %rdi
callq 0x2110
testl %eax, %eax
je 0x39f8
leaq 0xe8(%rsp), %r15
movq %r15, -0x10(%r15)
movq 0x38(%rsp), %rsi
movq 0x40(%rsp), %rdx
addq %rsi, %rdx
leaq 0xd8(%rsp), %rdi
callq 0x4036
leaq 0x230(%rsp), %rdi
leaq 0xd8(%rsp), %r14
movq %r14, %rsi
callq 0x2654
movl %eax, %ebx
movq (%r14), %rdi
cmpq %r15, %rdi
je 0x3418
movq 0xe8(%rsp), %rsi
incq %rsi
callq 0x2280
testb %bl, %bl
je 0x3b21
leaq 0x209f(%rip), %rdi      # 0x54c6
callq 0x2350
leaq 0x68(%rsp), %r14
movq %r14, -0x10(%r14)
movq 0x38(%rsp), %rsi
movq 0x40(%rsp), %rdx
addq %rsi, %rdx
leaq 0x58(%rsp), %rdi
callq 0x4036
leaq 0x98(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x3c00
movq 0x58(%rsp), %rdi
cmpq %r14, %rdi
je 0x3475
movq 0x68(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x1f90(%rip), %rsi      # 0x540c
leaq 0x78(%rsp), %rdi
leaq 0x98(%rsp), %rdx
callq 0x3d6f
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, 0x30(%rsp)
leaq 0x1bfc(%rip), %rsi      # 0x50fc
leaq 0x118(%rsp), %r15
movl $0xc0, %edx
movq %r15, %rdi
callq 0x2220
leaq 0x1d8(%rsp), %rdx
leaq 0xf(%rsp), %rax
movq %rax, (%rsp)
leaq 0x1d8(%rsp), %rdi
leaq 0x210(%rsp), %r8
leaq 0xb8(%rsp), %r9
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x4400
movq %rbx, 0x10(%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 0x750(%rip), %rax       # 0x3cc2
movq %rax, 0x10(%rdi)
leaq 0xb8(%rsp), %rsi
callq 0x2370
movq $0x0, 0x18(%rsp)
xorl %edi, %edi
callq 0x2200
callq 0x2090
movq %rax, %r13
movb $0x1, %r14b
leaq 0x118(%rsp), %rbp
xorl %ebx, %ebx
xorl %r12d, %r12d
movq %rax, 0x28(%rsp)
cmpb $0x0, 0x1282(%rsp)
jne 0x35cc
testb $0x1, %bl
jne 0x35cc
leaq 0x230(%rsp), %rdi
callq 0x273c
testl %r12d, %r12d
sete %al
andb %bl, %al
cmpb $0x1, %al
jne 0x35ea
leaq 0x1f04(%rip), %rdi      # 0x54e3
callq 0x2350
movl $0x1, %r12d
movl %r14d, %ecx
movl %ecx, %r14d
movq %rbp, %rdi
callq 0x21b0
testl %eax, %eax
je 0x3743
movl 0x118(%rsp), %r8d
leal -0x300(%r8), %eax
cmpl $0x2, %eax
jae 0x367b
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 $0x0, %eax
testq %rdx, %rdx
je 0x3694
movq (%rdx), %r10
movq %rdx, %rax
cmpl 0x8(%r10), %ecx
je 0x3694
movq %r10, %r11
movq (%r10), %r10
testq %r10, %r10
je 0x3692
movslq 0x8(%r10), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r9
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x3694
movq %r11, %rax
cmpl %edi, %ecx
jne 0x3651
jmp 0x3694
movl %r14d, %ecx
cmpl $0x100, %r8d            # imm = 0x100
jne 0x35ed
xorl %ecx, %ecx
jmp 0x35ed
xorl %eax, %eax
testq %rax, %rax
je 0x369e
movq (%rax), %rax
jmp 0x36a0
xorl %eax, %eax
movl %r14d, %ecx
testq %rax, %rax
je 0x35ed
movslq 0xc(%rax), %rax
xorl %ecx, %ecx
cmpq $-0x1, %rax
je 0x35ed
cmpl $0x300, %r8d            # imm = 0x300
jne 0x36fa
cmpl $-0x2, %eax
jne 0x36fa
movl %ebx, %r15d
xorb $0x1, %r15b
xorl %r12d, %r12d
movl %r14d, %ecx
testb $0x1, %bl
movl %r15d, %ebx
je 0x35ed
leaq 0x1e01(%rip), %rdi      # 0x54eb
callq 0x2350
movl %r14d, %ecx
movl %r15d, %ebx
jmp 0x35ed
cmpl $0x300, %r8d            # imm = 0x300
sete 0x1272(%rsp,%rax)
sete %cl
movb 0x1282(%rsp), %dl
testb %dl, %dl
setne %sil
andb %cl, %sil
movl %r14d, %ecx
cmpb $0x1, %sil
jne 0x35ed
movzbl %dl, %ecx
andl $0x7f, %ecx
movb %al, 0x1262(%rsp,%rcx)
movb $0x0, 0x1282(%rsp)
jmp 0x35ea
movl %r12d, 0x24(%rsp)
callq 0x2090
subq %r13, %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x1a60(%rip), %xmm0     # 0x51c0
mulsd 0x1a60(%rip), %xmm0     # 0x51c8
cvttsd2si %xmm0, %r12d
movl %r12d, %r15d
subl 0x18(%rsp), %r15d
jle 0x3962
testb $0x1, %bl
jne 0x3962
movzbl 0x1261(%rsp), %eax
cmpl %eax, %r15d
movl %eax, %r13d
cmovll %r15d, %r13d
subb %r13b, %al
movb %al, 0x1261(%rsp)
movzbl 0x1260(%rsp), %eax
cmpl %eax, %r15d
movl %eax, %ecx
cmovll %r15d, %ecx
subb %cl, %al
movb %al, 0x1260(%rsp)
callq 0x20c0
movl 0xb8(%rsp), %eax
imull %r13d, %eax
cltq
imulq $-0x77777777, %rax, %rcx # imm = 0x88888889
shrq $0x20, %rcx
addl %ecx, %eax
movl %eax, %ecx
shrl $0x1f, %ecx
sarl $0x5, %eax
addl %ecx, %eax
movl %eax, 0x118(%rsp)
movb $0x1, 0xf(%rsp)
movq 0x7e4a(%rip), %rcx      # 0xb640
movq 0x7e53(%rip), %rdx      # 0xb650
addq $-0x8, %rdx
cmpq %rdx, %rcx
je 0x3819
movl %eax, (%rcx)
movb $0x1, 0x4(%rcx)
addq $0x8, %rcx
movq %rcx, 0x7e29(%rip)      # 0xb640
jmp 0x382d
leaq 0x7df0(%rip), %rdi      # 0xb610
movq %rbp, %rsi
leaq 0xf(%rsp), %rdx
callq 0x47e0
subl %r13d, %r15d
imull 0xb8(%rsp), %r15d
movslq %r15d, %rax
imulq $-0x77777777, %rax, %rcx # imm = 0x88888889
shrq $0x20, %rcx
addl %ecx, %eax
movl %eax, %ecx
shrl $0x1f, %ecx
sarl $0x5, %eax
addl %ecx, %eax
movl %eax, 0x118(%rsp)
movb $0x0, 0xf(%rsp)
movq 0x7dda(%rip), %rcx      # 0xb640
movq 0x7de3(%rip), %rdx      # 0xb650
addq $-0x8, %rdx
cmpq %rdx, %rcx
je 0x3889
movl %eax, (%rcx)
movb $0x0, 0x4(%rcx)
addq $0x8, %rcx
movq %rcx, 0x7db9(%rip)      # 0xb640
jmp 0x389d
leaq 0x7d80(%rip), %rdi      # 0xb610
movq %rbp, %rsi
leaq 0xf(%rsp), %rdx
callq 0x47e0
callq 0x20f0
cmpb $0x1, 0x1a83(%rsp)
jne 0x3955
xorl %eax, %eax
leaq 0x1283(%rsp), %rcx
pxor %xmm2, %xmm2
movdqa 0x190a(%rip), %xmm3     # 0x51d0
movdqa 0x1912(%rip), %xmm4     # 0x51e0
leaq 0x5d3b(%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 0x38d5
movq 0x30(%rsp), %rdi
xorl %esi, %esi
movl $0x100, %ecx            # imm = 0x100
callq 0x21f0
movq 0x10(%rsp), %rdi
callq 0x2240
movq 0x10(%rsp), %rdi
movq 0x30(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x22a0
movq 0x10(%rsp), %rdi
callq 0x20b0
movb $0x0, 0x1a83(%rsp)
movl %r12d, %eax
movq %rax, 0x18(%rsp)
movq 0x28(%rsp), %r13
testb $0x1, %bl
movl 0x24(%rsp), %r12d
jne 0x399e
movq $0x0, 0x118(%rsp)
movq $0x13d620, 0x120(%rsp) # imm = 0x13D620
movq %rbp, %rdi
movq %rbp, %rsi
callq 0x2120
cmpl $-0x1, %eax
jne 0x399e
callq 0x2060
cmpl $0x4, (%rax)
je 0x3984
testb $0x1, %r14b
jne 0x35b0
leaq 0x1d8(%rsp), %rdi
callq 0x3fc6
leaq 0x88(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x39d6
movq 0x88(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0xa8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3af0
movq 0xa8(%rsp), %rsi
jmp 0x3ae8
cmpl $0x2, %ebp
jne 0x3a4d
movq 0x45d4(%rip), %rbx      # 0x7fd8
leaq 0x19ba(%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 0x45a2(%rip), %rdi      # 0x7fd8
callq 0x2040
movl $0x1, %ebx
movq %rax, %rdi
callq 0x21c0
jmp 0x3af2
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 0x2654
movq (%rbx), %rdi
leaq 0x108(%rsp), %rax
cmpq %rax, %rdi
je 0x3a9e
movq 0x108(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x118(%rsp), %rdi
leaq 0x230(%rsp), %rsi
callq 0x2c7a
movq 0x118(%rsp), %rsi
movq 0x120(%rsp), %rdx
movq 0x450e(%rip), %rdi      # 0x7fd8
callq 0x22b0
leaq 0x128(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3af0
movq 0x128(%rsp), %rsi
incq %rsi
callq 0x2280
xorl %ebx, %ebx
leaq 0x48(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3b0d
movq 0x48(%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 0x3bdd
movq 0x128(%rsp), %rsi
jmp 0x3bd5
jmp 0x3b7c
jmp 0x3b7c
jmp 0x3b77
jmp 0x3b77
jmp 0x3b77
movq %rax, %rbx
jmp 0x3bbc
movq %rax, %rbx
movq 0x58(%rsp), %rdi
cmpq %r14, %rdi
je 0x3bdd
movq 0x68(%rsp), %rsi
jmp 0x3bd5
jmp 0x3b7c
jmp 0x3b8b
movq %rax, %rbx
jmp 0x3b9b
movq %rax, %rbx
jmp 0x3bdd
jmp 0x3b8b
jmp 0x3b8b
jmp 0x3b8b
jmp 0x3b8b
jmp 0x3b8b
movq %rax, %rbx
leaq 0x1d8(%rsp), %rdi
callq 0x3fc6
leaq 0x88(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3bbc
movq 0x88(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0xa8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3bdd
movq 0xa8(%rsp), %rsi
incq %rsi
callq 0x2280
leaq 0x48(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x3bf8
movq 0x48(%rsp), %rsi
incq %rsi
callq 0x2280
movq %rbx, %rdi
callq 0x23a0