// File: rpavlik[P]edid-decode/calc-gtf-cvt.cpp
// Function: edid_state::calc_gtf_mode(unsigned int, unsigned int, double, bool, gtf_ip_parm, bool, bool, double, double, double, double)
timings edid_state::calc_gtf_mode(unsigned h_pixels, unsigned v_lines,
				  double ip_freq_rqd, bool int_rqd,
				  enum gtf_ip_parm ip_parm, bool margins_rqd,
				  bool secondary, double C, double M, double K, double J)
{
	timings t = {};
	/* C' and M' are part of the Blanking Duty Cycle computation */
	double C_PRIME = ((C - J) * K / 256.0) + J;
	double M_PRIME = K / 256.0 * M;

	double h_pixels_rnd = round(h_pixels / CELL_GRAN) * CELL_GRAN;
	double v_lines_rnd = int_rqd ? round(v_lines / 2.0) : v_lines;
	unsigned hor_margin = margins_rqd ?
		round(h_pixels_rnd * MARGIN_PERC / 100.0 / CELL_GRAN)  * CELL_GRAN : 0;
	unsigned vert_margin = margins_rqd ? round(MARGIN_PERC / 100.0 * v_lines_rnd) : 0;
	double interlace = int_rqd ? 0.5 : 0;
	double total_active_pixels = h_pixels_rnd + hor_margin * 2;

	t.hact = h_pixels_rnd;
	t.vact = v_lines;
	t.interlaced = int_rqd;

	double pixel_freq;
	double h_blank_pixels;
	double total_pixels;
	double v_sync_bp;

	if (ip_parm == gtf_ip_vert_freq) {
		// vertical frame frequency (Hz)
		double v_field_rate_rqd = int_rqd ? ip_freq_rqd * 2 : ip_freq_rqd;
		double h_period_est = ((1.0 / v_field_rate_rqd) - GTF_MIN_VSYNC_BP / 1000000.0) /
			(v_lines_rnd + vert_margin * 2 + GTF_MIN_PORCH + interlace) * 1000000.0;
		v_sync_bp = round(GTF_MIN_VSYNC_BP / h_period_est);
		double total_v_lines = v_lines_rnd + vert_margin * 2 +
			v_sync_bp + interlace + GTF_MIN_PORCH;
		double v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
		double h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
		double ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		pixel_freq = total_pixels / h_period;
	} else if (ip_parm == gtf_ip_hor_freq) {
		// horizontal frequency (kHz)
		double h_freq = ip_freq_rqd;
		v_sync_bp = round(GTF_MIN_VSYNC_BP * h_freq / 1000.0);
		double ideal_duty_cycle = C_PRIME - (M_PRIME / h_freq);
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		pixel_freq = total_pixels * h_freq / 1000.0;
	} else {
		// pixel clock rate (MHz)
		pixel_freq = ip_freq_rqd;
		double ideal_h_period =
			((C_PRIME - 100.0) +
			 sqrt(((100.0 - C_PRIME) * (100.0 - C_PRIME) +
			       (0.4 * M_PRIME * (total_active_pixels + hor_margin * 2) /
				pixel_freq)))) / 2.0 / M_PRIME * 1000.0;
		double ideal_duty_cycle = C_PRIME - (M_PRIME * ideal_h_period) / 1000.0;
		h_blank_pixels = round(total_active_pixels * ideal_duty_cycle /
				       (100.0 - ideal_duty_cycle) /
				       (2 * CELL_GRAN)) * 2 * CELL_GRAN;
		total_pixels = total_active_pixels + h_blank_pixels;
		double h_freq = pixel_freq / total_pixels * 1000.0;
		v_sync_bp = round(GTF_MIN_VSYNC_BP * h_freq / 1000.0);
	}

	double v_back_porch = v_sync_bp - GTF_V_SYNC_RQD;

	t.vbp = v_back_porch;
	t.vsync = GTF_V_SYNC_RQD;
	t.vfp = GTF_MIN_PORCH;
	t.pixclk_khz = round(1000.0 * pixel_freq);
	t.hsync = round(GTF_H_SYNC_PERC / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
	t.hfp = (h_blank_pixels / 2.0) - t.hsync;
	t.hbp = t.hfp + t.hsync;
	t.hborder = hor_margin;
	t.vborder = vert_margin;
	t.pos_pol_hsync = secondary;
	t.pos_pol_vsync = !secondary;
	t.rb = secondary ? RB_GTF : RB_NONE;
	return t;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x150, %rsp            # imm = 0x150
movl %r8d, %eax
movl %ecx, -0x114(%rbp)
movl %edx, %r8d
movq %rsi, %r10
movl -0x114(%rbp), %esi
movq %rdi, -0x110(%rbp)
movb %al, %dl
movq %rdi, %rax
movq %rax, -0x108(%rbp)
movb 0x18(%rbp), %al
movb 0x10(%rbp), %cl
movq %r10, -0x8(%rbp)
movl %r8d, -0xc(%rbp)
movl %esi, -0x10(%rbp)
movsd %xmm0, -0x18(%rbp)
andb $0x1, %dl
movb %dl, -0x19(%rbp)
movl %r9d, -0x20(%rbp)
andb $0x1, %cl
movb %cl, -0x21(%rbp)
andb $0x1, %al
movb %al, -0x22(%rbp)
movsd %xmm1, -0x30(%rbp)
movsd %xmm2, -0x38(%rbp)
movsd %xmm3, -0x40(%rbp)
movsd %xmm4, -0x48(%rbp)
xorps %xmm0, %xmm0
movups %xmm0, 0x40(%rdi)
movups %xmm0, 0x30(%rdi)
movups %xmm0, 0x20(%rdi)
movups %xmm0, 0x10(%rdi)
movups %xmm0, (%rdi)
movl $0x0, 0x50(%rdi)
movsd -0x30(%rbp), %xmm0
movsd -0x48(%rbp), %xmm2
subsd %xmm2, %xmm0
movsd -0x40(%rbp), %xmm1
mulsd %xmm1, %xmm0
movsd 0xc2d2(%rip), %xmm1     # 0x39370
mulsd %xmm1, %xmm0
addsd %xmm2, %xmm0
movsd %xmm0, -0x50(%rbp)
movsd -0x40(%rbp), %xmm0
mulsd %xmm1, %xmm0
movsd -0x38(%rbp), %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -0x58(%rbp)
movl -0xc(%rbp), %eax
cvtsi2sd %rax, %xmm0
movsd 0x15ab6(%rip), %xmm1    # 0x42b88
divsd %xmm1, %xmm0
callq 0x4160
movsd 0x15aa5(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
movsd %xmm0, -0x60(%rbp)
testb $0x1, -0x19(%rbp)
je 0x2d115
movl -0x10(%rbp), %eax
cvtsi2sd %rax, %xmm0
movsd 0x1f0e(%rip), %xmm1     # 0x2f010
divsd %xmm1, %xmm0
callq 0x4160
movsd %xmm0, -0x120(%rbp)
jmp 0x2d125
movl -0x10(%rbp), %eax
cvtsi2sd %rax, %xmm0
movsd %xmm0, -0x120(%rbp)
movsd -0x120(%rbp), %xmm0
movsd %xmm0, -0x68(%rbp)
testb $0x1, -0x21(%rbp)
je 0x2d178
movsd 0x15a50(%rip), %xmm0    # 0x42b90
mulsd -0x60(%rbp), %xmm0
movsd 0x1eeb(%rip), %xmm1     # 0x2f038
divsd %xmm1, %xmm0
movsd 0x15a2f(%rip), %xmm1    # 0x42b88
divsd %xmm1, %xmm0
callq 0x4160
movsd 0x15a1e(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
movsd %xmm0, -0x128(%rbp)
jmp 0x2d185
xorps %xmm0, %xmm0
movsd %xmm0, -0x128(%rbp)
jmp 0x2d185
movsd -0x128(%rbp), %xmm0
cvttsd2si %xmm0, %rax
movl %eax, -0x6c(%rbp)
testb $0x1, -0x21(%rbp)
je 0x2d1b7
movsd 0x159f5(%rip), %xmm0    # 0x42b98
mulsd -0x68(%rbp), %xmm0
callq 0x4160
movsd %xmm0, -0x130(%rbp)
jmp 0x2d1c4
xorps %xmm0, %xmm0
movsd %xmm0, -0x130(%rbp)
jmp 0x2d1c4
movsd -0x130(%rbp), %xmm0
cvttsd2si %xmm0, %rax
movl %eax, -0x70(%rbp)
movb -0x19(%rbp), %al
testb $0x1, %al
movsd 0x1e37(%rip), %xmm0     # 0x2f018
xorps %xmm1, %xmm1
movsd %xmm1, -0x140(%rbp)
movsd %xmm0, -0x138(%rbp)
jne 0x2d206
movsd -0x140(%rbp), %xmm0
movsd %xmm0, -0x138(%rbp)
movq -0x110(%rbp), %rax
movsd -0x138(%rbp), %xmm0
movsd %xmm0, -0x78(%rbp)
movsd -0x60(%rbp), %xmm0
movl -0x6c(%rbp), %ecx
addl %ecx, %ecx
cvtsi2sd %rcx, %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, -0x80(%rbp)
cvttsd2si -0x60(%rbp), %rcx
movl %ecx, (%rax)
movl -0x10(%rbp), %ecx
movl %ecx, 0x4(%rax)
movb -0x19(%rbp), %cl
andb $0x1, %cl
movb %cl, 0x18(%rax)
cmpl $0x1, -0x20(%rbp)
jne 0x2d43b
testb $0x1, -0x19(%rbp)
je 0x2d270
movsd 0x1daf(%rip), %xmm0     # 0x2f010
mulsd -0x18(%rbp), %xmm0
movsd %xmm0, -0x148(%rbp)
jmp 0x2d27d
movsd -0x18(%rbp), %xmm0
movsd %xmm0, -0x148(%rbp)
movsd -0x148(%rbp), %xmm0
movsd %xmm0, -0xa8(%rbp)
movsd -0xa8(%rbp), %xmm1
movsd 0x65eb(%rip), %xmm2     # 0x33888
movaps %xmm2, %xmm0
divsd %xmm1, %xmm0
movsd 0x1590c(%rip), %xmm1    # 0x42bb8
addsd %xmm1, %xmm0
movsd -0x68(%rbp), %xmm1
movl -0x70(%rbp), %eax
addl %eax, %eax
cvtsi2sd %rax, %xmm3
addsd %xmm3, %xmm1
addsd %xmm2, %xmm1
movsd -0x78(%rbp), %xmm2
addsd %xmm2, %xmm1
divsd %xmm1, %xmm0
movsd 0x158d4(%rip), %xmm1    # 0x42bb0
mulsd %xmm1, %xmm0
movsd %xmm0, -0xb0(%rbp)
movsd -0xb0(%rbp), %xmm1
movsd 0x158a8(%rip), %xmm0    # 0x42ba0
divsd %xmm1, %xmm0
callq 0x4160
movsd %xmm0, -0xa0(%rbp)
movsd -0x68(%rbp), %xmm0
movl -0x70(%rbp), %eax
addl %eax, %eax
cvtsi2sd %rax, %xmm1
addsd %xmm1, %xmm0
addsd -0xa0(%rbp), %xmm0
addsd -0x78(%rbp), %xmm0
movsd 0x6557(%rip), %xmm1     # 0x33888
addsd %xmm1, %xmm0
movsd %xmm0, -0xb8(%rbp)
movsd 0x6543(%rip), %xmm0     # 0x33888
divsd -0xb0(%rbp), %xmm0
divsd -0xb8(%rbp), %xmm0
movsd 0x15853(%rip), %xmm1    # 0x42bb0
mulsd %xmm1, %xmm0
movsd %xmm0, -0xc0(%rbp)
movsd -0xb0(%rbp), %xmm0
movsd -0xa8(%rbp), %xmm1
divsd -0xc0(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0xc8(%rbp)
movsd -0x50(%rbp), %xmm0
movsd -0x58(%rbp), %xmm1
mulsd -0xc8(%rbp), %xmm1
movsd 0x1c79(%rip), %xmm2     # 0x2f020
divsd %xmm2, %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, -0xd0(%rbp)
movsd -0x80(%rbp), %xmm0
mulsd -0xd0(%rbp), %xmm0
movsd 0x1c6c(%rip), %xmm1     # 0x2f038
subsd -0xd0(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd 0x107a0(%rip), %xmm1    # 0x3db80
divsd %xmm1, %xmm0
callq 0x4160
movsd 0x1c1f(%rip), %xmm1     # 0x2f010
mulsd %xmm1, %xmm0
movsd 0x1578b(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
movsd %xmm0, -0x90(%rbp)
movsd -0x80(%rbp), %xmm0
addsd -0x90(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
movsd -0x98(%rbp), %xmm0
divsd -0xc8(%rbp), %xmm0
movsd %xmm0, -0x88(%rbp)
jmp 0x2d6aa
cmpl $0x2, -0x20(%rbp)
jne 0x2d529
movsd -0x18(%rbp), %xmm0
movsd %xmm0, -0xd8(%rbp)
movsd 0x15746(%rip), %xmm0    # 0x42ba0
mulsd -0xd8(%rbp), %xmm0
movsd 0x1bb6(%rip), %xmm1     # 0x2f020
divsd %xmm1, %xmm0
callq 0x4160
movsd %xmm0, -0xa0(%rbp)
movsd -0x50(%rbp), %xmm0
movsd -0x58(%rbp), %xmm1
divsd -0xd8(%rbp), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, -0xe0(%rbp)
movsd -0x80(%rbp), %xmm0
mulsd -0xe0(%rbp), %xmm0
movsd 0x1b8a(%rip), %xmm1     # 0x2f038
subsd -0xe0(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd 0x106be(%rip), %xmm1    # 0x3db80
divsd %xmm1, %xmm0
callq 0x4160
movsd 0x1b3d(%rip), %xmm1     # 0x2f010
mulsd %xmm1, %xmm0
movsd 0x156a9(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
movsd %xmm0, -0x90(%rbp)
movsd -0x80(%rbp), %xmm0
addsd -0x90(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
movsd -0x98(%rbp), %xmm0
mulsd -0xd8(%rbp), %xmm0
movsd 0x1b08(%rip), %xmm1     # 0x2f020
divsd %xmm1, %xmm0
movsd %xmm0, -0x88(%rbp)
jmp 0x2d6a8
movsd -0x18(%rbp), %xmm0
movsd %xmm0, -0x88(%rbp)
movsd -0x50(%rbp), %xmm0
movsd 0x1af5(%rip), %xmm2     # 0x2f038
movaps %xmm0, %xmm1
subsd %xmm2, %xmm1
movsd %xmm1, -0x150(%rbp)
subsd %xmm0, %xmm2
movaps %xmm2, %xmm0
movsd -0x58(%rbp), %xmm1
movsd 0x15642(%rip), %xmm3    # 0x42ba8
mulsd %xmm3, %xmm1
movsd -0x80(%rbp), %xmm3
movl -0x6c(%rbp), %eax
addl %eax, %eax
cvtsi2sd %rax, %xmm4
addsd %xmm4, %xmm3
mulsd %xmm3, %xmm1
divsd -0x88(%rbp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
callq 0x4280
movaps %xmm0, %xmm1
movsd -0x150(%rbp), %xmm0
addsd %xmm1, %xmm0
movsd 0x1a63(%rip), %xmm1     # 0x2f010
divsd %xmm1, %xmm0
divsd -0x58(%rbp), %xmm0
movsd 0x1a62(%rip), %xmm1     # 0x2f020
mulsd %xmm1, %xmm0
movsd %xmm0, -0xe8(%rbp)
movsd -0x50(%rbp), %xmm0
movsd -0x58(%rbp), %xmm1
mulsd -0xe8(%rbp), %xmm1
movsd 0x1a3c(%rip), %xmm2     # 0x2f020
divsd %xmm2, %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, -0xf0(%rbp)
movsd -0x80(%rbp), %xmm0
mulsd -0xf0(%rbp), %xmm0
movsd 0x1a2f(%rip), %xmm1     # 0x2f038
subsd -0xf0(%rbp), %xmm1
divsd %xmm1, %xmm0
movsd 0x10563(%rip), %xmm1    # 0x3db80
divsd %xmm1, %xmm0
callq 0x4160
movsd 0x19e2(%rip), %xmm1     # 0x2f010
mulsd %xmm1, %xmm0
movsd 0x1554e(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
movsd %xmm0, -0x90(%rbp)
movsd -0x80(%rbp), %xmm0
addsd -0x90(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
movsd -0x88(%rbp), %xmm0
divsd -0x98(%rbp), %xmm0
movsd 0x19ad(%rip), %xmm1     # 0x2f020
mulsd %xmm1, %xmm0
movsd %xmm0, -0xf8(%rbp)
movsd 0x15519(%rip), %xmm0    # 0x42ba0
mulsd -0xf8(%rbp), %xmm0
movsd 0x1989(%rip), %xmm1     # 0x2f020
divsd %xmm1, %xmm0
callq 0x4160
movsd %xmm0, -0xa0(%rbp)
jmp 0x2d6aa
movq -0x110(%rbp), %rax
movsd -0xa0(%rbp), %xmm0
movsd 0x154ff(%rip), %xmm1    # 0x42bc0
addsd %xmm1, %xmm0
movsd %xmm0, -0x100(%rbp)
cvttsd2si -0x100(%rbp), %ecx
movl %ecx, 0x34(%rax)
movl $0x3, 0x30(%rax)
movl $0x1, 0x2c(%rax)
movsd -0x88(%rbp), %xmm0
movsd 0x192a(%rip), %xmm1     # 0x2f020
mulsd %xmm1, %xmm0
callq 0x4160
movq -0x110(%rbp), %rax
cvttsd2si %xmm0, %rcx
movl %ecx, 0x10(%rax)
movsd -0x98(%rbp), %xmm0
movsd 0x154aa(%rip), %xmm1    # 0x42bc8
mulsd %xmm1, %xmm0
movsd 0xbc2e(%rip), %xmm1     # 0x39358
mulsd %xmm1, %xmm0
callq 0x4160
movq -0x110(%rbp), %rcx
movq -0x108(%rbp), %rax
movsd 0x1543f(%rip), %xmm1    # 0x42b88
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %rdx
movl %edx, 0x20(%rcx)
movsd -0x90(%rbp), %xmm0
movsd 0x18b3(%rip), %xmm1     # 0x2f018
mulsd %xmm1, %xmm0
movl 0x20(%rcx), %edx
cvtsi2sd %rdx, %xmm1
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %edx
movl %edx, 0x1c(%rcx)
movl 0x1c(%rcx), %edx
addl 0x20(%rcx), %edx
movl %edx, 0x24(%rcx)
movl -0x6c(%rbp), %edx
movl %edx, 0x3c(%rcx)
movl -0x70(%rbp), %edx
movl %edx, 0x40(%rcx)
movb -0x22(%rbp), %dl
andb $0x1, %dl
movb %dl, 0x28(%rcx)
movb -0x22(%rbp), %dl
xorb $-0x1, %dl
andb $0x1, %dl
movb %dl, 0x38(%rcx)
movb -0x22(%rbp), %dil
xorl %edx, %edx
movl $0x4, %esi
testb $0x1, %dil
cmovnel %esi, %edx
movl %edx, 0x14(%rcx)
addq $0x150, %rsp            # imm = 0x150
popq %rbp
retq
nopw %cs:(%rax,%rax)