// File: /workspace/github_cpp_makefile_star2_O2/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 0x3150
movq 0x4ea4(%rip), %rdi      # 0x7fd8
leaq 0x223a(%rip), %rsi      # 0x5375
callq 0x2250
movq %rax, %rdi
callq 0x2180
pushq $0x1
popq %rbx
jmp 0x371f
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)
andw $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 0x5073(%rip), %rsi      # 0x8210
pushq $0xa
popq %rcx
leaq 0x230(%rsp), %rdi
rep  movsq (%rsi), %es:(%rdi)
movq 0x8(%rbx), %rsi
leaq 0x38(%rsp), %r14
leaq 0xd8(%rsp), %rdx
movq %r14, %rdi
callq 0x2140
leaq 0x21e8(%rip), %rsi      # 0x53b3
movq %r14, %rdi
callq 0x38db
testb %al, %al
je 0x3203
cmpl $0x2, %ebp
jne 0x36a6
movq 0x4df1(%rip), %rdi      # 0x7fd8
leaq 0x2187(%rip), %rsi      # 0x5375
callq 0x2250
movq %rax, %rdi
callq 0x2180
pushq $0x1
popq %rbx
jmp 0x3715
leaq 0x1f0(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x2310
leaq 0x230(%rsp), %rdi
leaq 0x1f0(%rsp), %rbx
movq %rbx, %rsi
callq 0x25a8
movl %eax, %ebp
movq %rbx, %rdi
callq 0x2170
testb %bpl, %bpl
je 0x3733
leaq 0x21ba(%rip), %rdi      # 0x5401
callq 0x2350
leaq 0x98(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x2310
leaq 0xb8(%rsp), %rdi
leaq 0x98(%rsp), %rsi
callq 0x37b7
leaq 0x98(%rsp), %rdi
callq 0x2170
leaq 0x2135(%rip), %rsi      # 0x53bc
leaq 0x78(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x38e8
movq 0x78(%rsp), %rdi
pushq $0x20
popq %r9
movl $0x1fff0000, %esi       # imm = 0x1FFF0000
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0x400, %ecx            # imm = 0x400
movl $0x200, %r8d            # imm = 0x200
callq 0x2070
pushq $-0x1
popq %rsi
movq %rax, %rdi
xorl %edx, %edx
callq 0x2040
movq %rax, %r14
movq %rax, %rdi
movl $0x400, %esi            # imm = 0x400
movl $0x200, %edx            # imm = 0x200
callq 0x2120
pushq $0x1
popq %rdx
pushq $0x40
popq %rcx
pushq $0x20
popq %r8
movq %r14, %rdi
movl $0x16362004, %esi       # imm = 0x16362004
callq 0x23b0
movq %rax, 0x28(%rsp)
leaq 0x1dfb(%rip), %rsi      # 0x50fc
leaq 0xd8(%rsp), %rbx
movl $0xc0, %edx
movq %rbx, %rdi
callq 0x2200
leaq 0x198(%rsp), %rdx
leaq 0x13(%rsp), %rax
movq %rax, (%rsp)
leaq 0x198(%rsp), %rdi
leaq 0x1d0(%rsp), %r8
leaq 0x58(%rsp), %r9
movq %rbx, %rsi
xorl %ecx, %ecx
callq 0x3f90
movq %r14, 0x20(%rsp)
leaq 0x1d0(%rsp), %rdi
movl $0xac44, (%rdi)         # imm = 0xAC44
movw $0x8010, 0x4(%rdi)      # imm = 0x8010
movb $0x2, 0x6(%rdi)
movw $0x89d, 0x8(%rdi)       # imm = 0x89D
leaq 0x4be(%rip), %rax       # 0x382e
movq %rax, 0x10(%rdi)
leaq 0x58(%rsp), %rsi
callq 0x2370
xorl %edi, %edi
callq 0x21e0
callq 0x2080
movq %rax, 0x30(%rsp)
leaq 0xec(%rsp), %r12
movb $0x1, %bpl
leaq 0xd8(%rsp), %r14
leaq 0x198(%rsp), %rbx
movl $0x0, 0x18(%rsp)
movl $0x0, 0x14(%rsp)
xorl %r15d, %r15d
testb $0x1, %bpl
je 0x3685
movb 0x1282(%rsp), %al
testb %al, %al
setne %cl
orb %r15b, %cl
testb $0x1, %cl
je 0x3407
testb %al, %al
sete %al
orb %r15b, %al
cmpl $0x0, 0x18(%rsp)
sete %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x3414
leaq 0x2025(%rip), %rdi      # 0x541e
callq 0x2350
pushq $0x1
popq %rax
movl %eax, 0x18(%rsp)
jmp 0x3414
leaq 0x230(%rsp), %rdi
callq 0x268e
movb $0x1, %cl
movl %ecx, %ebp
movq %r14, %rdi
callq 0x21b0
testl %eax, %eax
je 0x34fd
movl 0xd8(%rsp), %eax
leal -0x300(%rax), %ecx
cmpl $0x2, %ecx
jae 0x34a0
movq %rbx, %rdi
movq %r12, %rsi
callq 0x43c2
movl %ebp, %ecx
testq %rax, %rax
je 0x3416
movslq 0xc(%rax), %rax
xorl %ecx, %ecx
cmpq $-0x1, %rax
je 0x3416
movl %eax, %edx
xorl $-0x2, %edx
movl 0xd8(%rsp), %ecx
movl %ecx, %esi
xorl $0x300, %esi            # imm = 0x300
orl %edx, %esi
jne 0x34b4
movl %r15d, %r13d
xorb $0x1, %r13b
movl $0x0, 0x18(%rsp)
movl %ebp, %ecx
testb $0x1, %r15b
movl %r13d, %r15d
je 0x3416
leaq 0x1f95(%rip), %rdi      # 0x5426
callq 0x2350
movl %ebp, %ecx
movl %r13d, %r15d
jmp 0x3416
movl %ebp, %ecx
cmpl $0x100, %eax            # imm = 0x100
jne 0x3416
xorl %ecx, %ecx
jmp 0x3416
cmpl $0x300, %ecx            # imm = 0x300
sete 0x1272(%rsp,%rax)
sete %cl
movb 0x1282(%rsp), %dl
testb %dl, %dl
setne %sil
andb %cl, %sil
movl %ebp, %ecx
cmpb $0x1, %sil
jne 0x3416
movzbl %dl, %ecx
andl $0x7f, %ecx
movb %al, 0x1262(%rsp,%rcx)
movb $0x0, 0x1282(%rsp)
movl %ebp, %ecx
jmp 0x3416
callq 0x2080
subq 0x30(%rsp), %rax
cvtsi2sd %rax, %xmm0
divsd 0x1cac(%rip), %xmm0     # 0x51c0
mulsd 0x1cac(%rip), %xmm0     # 0x51c8
cvttsd2si %xmm0, %r13d
movl %r13d, 0x1c(%rsp)
subl 0x14(%rsp), %r13d
jle 0x3658
testb $0x1, %r15b
jne 0x33bd
movzbl 0x1261(%rsp), %eax
cmpl %eax, %r13d
movl %eax, %ecx
cmovbl %r13d, %ecx
movl %ecx, 0x14(%rsp)
subb %cl, %al
movb %al, 0x1261(%rsp)
movb 0x1260(%rsp), %al
movl $0xff, %ecx
cmpl %ecx, %r13d
cmovbl %r13d, %ecx
subb %cl, %al
movzbl %al, %eax
movl $0x0, %ecx
cmovbl %ecx, %eax
movb %al, 0x1260(%rsp)
callq 0x20b0
movl 0x58(%rsp), %eax
imull 0x14(%rsp), %eax
cltd
pushq $0x3c
popq %rcx
idivl %ecx
movl %eax, 0xd8(%rsp)
movb $0x1, 0x13(%rsp)
leaq 0x8069(%rip), %rdi      # 0xb610
movq %r14, %rsi
leaq 0x13(%rsp), %rdx
callq 0x395e
subl 0x14(%rsp), %r13d
imull 0x58(%rsp), %r13d
movl %r13d, %eax
cltd
pushq $0x3c
popq %rcx
idivl %ecx
movl %eax, 0xd8(%rsp)
movb $0x0, 0x13(%rsp)
leaq 0x8035(%rip), %rdi      # 0xb610
movq %r14, %rsi
leaq 0x13(%rsp), %rdx
callq 0x395e
callq 0x20e0
cmpb $0x1, 0x1a83(%rsp)
jne 0x3651
leaq 0x6012(%rip), %r13      # 0x9610
movq %r13, %rdi
leaq 0x1283(%rsp), %rsi
callq 0x30f4
movq 0x28(%rsp), %rdi
xorl %esi, %esi
movq %r13, %rdx
movl $0x100, %ecx            # imm = 0x100
callq 0x21d0
movq 0x20(%rsp), %rdi
callq 0x2230
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x22a0
movq 0x20(%rsp), %rdi
callq 0x20a0
movb $0x0, 0x1a83(%rsp)
movl 0x1c(%rsp), %r13d
jmp 0x3667
testb $0x1, %r15b
jne 0x33bd
movl 0x14(%rsp), %r13d
movq $0x514, 0xd8(%rsp) # imm = 0x514
movq %r14, %rdi
callq 0x3985
movl %r13d, 0x14(%rsp)
jmp 0x33bd
leaq 0x198(%rsp), %rdi
callq 0x3c42
leaq 0x78(%rsp), %rdi
callq 0x2170
leaq 0xb8(%rsp), %rdi
jmp 0x370e
movq 0x10(%rbx), %rsi
leaq 0x210(%rsp), %rdi
leaq 0xd8(%rsp), %rdx
callq 0x2140
leaq 0x230(%rsp), %rbx
leaq 0x210(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x25a8
movq %r14, %rdi
callq 0x2170
leaq 0xd8(%rsp), %rdi
movq %rbx, %rsi
callq 0x2b8e
movq 0x48df(%rip), %rdi      # 0x7fd8
leaq 0xd8(%rsp), %rsi
callq 0x2220
leaq 0xd8(%rsp), %rdi
callq 0x2170
xorl %ebx, %ebx
leaq 0x38(%rsp), %rdi
callq 0x2170
movl %ebx, %eax
addq $0x1a88, %rsp           # imm = 0x1A88
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x1
popq %rdi
callq 0x22d0
movq %rax, %rbx
leaq 0xd8(%rsp), %rdi
jmp 0x37a0
jmp 0x3773
jmp 0x3773
jmp 0x377e
jmp 0x377e
jmp 0x377e
jmp 0x376e
jmp 0x376e
jmp 0x376e
movq %rax, %rbx
jmp 0x3798
movq %rax, %rbx
leaq 0x98(%rsp), %rdi
jmp 0x37a0
jmp 0x3773
jmp 0x377e
movq %rax, %rbx
jmp 0x378e
movq %rax, %rbx
jmp 0x37a5
jmp 0x377e
jmp 0x377e
jmp 0x377e
movq %rax, %rbx
leaq 0x198(%rsp), %rdi
callq 0x3c42
leaq 0x78(%rsp), %rdi
callq 0x2170
leaq 0xb8(%rsp), %rdi
callq 0x2170
leaq 0x38(%rsp), %rdi
callq 0x2170
movq %rbx, %rdi
callq 0x23a0