// File: /workspace/github_cpp_makefile_star2_O2/SYZYGYfpga[P]syzygy-tools/dna-tools/dna-writer.cpp
// Function: main
int main(int argc, char *argv[])
{
	std::vector<uint8_t> dna_header(SZG_DNA_HEADER_LENGTH_V1);
	uint8_t min_ver_major, min_ver_minor;

	// Print usage if there are not enough or too many arguments
	if ((argc < 3) || (argc > 4)) {
		std::cout << "USAGE: " << argv[0];
		std::cout << " in_file out_file [serial]\n";
		std::cout << "  If no serial is provided it will be ";
		std::cout << "extracted from the JSON input file\n";
		return 0;
	}

	std::ifstream input_file(argv[1]);
	std::ofstream output_file(argv[2], std::ios::out | std::ios::binary);

	json dna_json;

	// Parse the input data
	input_file >> dna_json;

	dna_header[SZG_DNA_PTR_HEADER_LENGTH] = SZG_DNA_HEADER_LENGTH_V1 & 0xFF;
	dna_header[SZG_DNA_PTR_HEADER_LENGTH + 1] =
	    (SZG_DNA_HEADER_LENGTH_V1 & 0xFF00) >> 8;

	dna_header[SZG_DNA_PTR_DNA_MAJOR] = DNA_SPEC_MAJOR;
	dna_header[SZG_DNA_PTR_DNA_MINOR] = DNA_SPEC_MINOR;

	// By default the DNA should be compatible with any version of the spec.
	min_ver_major = 0;
	min_ver_minor = 0;

	// TXR4 peripherals require version > 1.1
	if (dna_json["is_txr4"].get<bool>() == true) {
		if (min_ver_major < 1) {
			min_ver_major = 1;
			min_ver_minor = 1;
		} else if ((min_ver_major == 1) &&
		           (min_ver_minor < 1)) {
			min_ver_minor = 1;
		}
	}

	dna_header[SZG_DNA_PTR_DNA_REQUIRED_MAJOR] = min_ver_major;
	dna_header[SZG_DNA_PTR_DNA_REQUIRED_MINOR] = min_ver_minor;

	dna_header[SZG_DNA_PTR_MAX_5V_LOAD] = dna_json["max_5v_load"].get<uint16_t>() & 0xFF;
	dna_header[SZG_DNA_PTR_MAX_5V_LOAD + 1] = dna_json["max_5v_load"].get<uint16_t>() >> 8;
	dna_header[SZG_DNA_PTR_MAX_33V_LOAD] = dna_json["max_3v3_load"].get<uint16_t>() & 0xFF;
	dna_header[SZG_DNA_PTR_MAX_33V_LOAD + 1] = dna_json["max_3v3_load"].get<uint16_t>() >> 8;
	dna_header[SZG_DNA_PTR_MAX_VIO_LOAD] = dna_json["max_vio_load"].get<uint16_t>() & 0xFF;
	dna_header[SZG_DNA_PTR_MAX_VIO_LOAD + 1] = dna_json["max_vio_load"].get<uint16_t>() >> 8;

	dna_header[SZG_DNA_PTR_ATTRIBUTES] |= dna_json["is_lvds"].get<bool>() ?
	    SZG_ATTR_LVDS : 0;
	dna_header[SZG_DNA_PTR_ATTRIBUTES] |= dna_json["is_doublewide"].get<bool>() ?
	    SZG_ATTR_DOUBLEWIDE : 0;
	dna_header[SZG_DNA_PTR_ATTRIBUTES] |= dna_json["is_txr4"].get<bool>() ?
	    SZG_ATTR_TXR4 : 0;

	// Run through each range and set the values accordingly
	for (int i = 0; i < SZG_MAX_DNA_RANGES - 1; i++) {
		uint16_t vio;
		vio = dna_json["vio"][i]["min"].get<uint16_t>();
		dna_header[SZG_DNA_MIN_VIO_RANGE0 + 4*i] = vio & 0xFF;
		dna_header[SZG_DNA_MIN_VIO_RANGE0 + (4*i) + 1] = (vio & 0xFF00) >> 8;

		vio = dna_json["vio"][i]["max"].get<uint16_t>();
		dna_header[SZG_DNA_MAX_VIO_RANGE0 + 4*i] = vio & 0xFF;
		dna_header[SZG_DNA_MAX_VIO_RANGE0 + (4*i) + 1] = (vio & 0xFF00) >> 8;
	}

	uint8_t manuf_len =
	    dna_json["manufacturer_name"].get<std::string>().length();

	uint8_t name_len =
	    dna_json["product_name"].get<std::string>().length();

	uint8_t model_len =
	    dna_json["product_model"].get<std::string>().length();

	uint8_t version_len =
	    dna_json["product_version"].get<std::string>().length();

	uint8_t serial_len = 0;

	if (argc == 4) {
		serial_len = strlen(argv[3]);
	} else {
		serial_len = dna_json["serial"].get<std::string>().length();
	}

	dna_header[SZG_DNA_MANUFACTURER_NAME_LENGTH] = manuf_len;

	dna_header[SZG_DNA_PRODUCT_NAME_LENGTH] = name_len;

	dna_header[SZG_DNA_PRODUCT_MODEL_LENGTH] = model_len;

	dna_header[SZG_DNA_PRODUCT_VERSION_LENGTH] = version_len;

	dna_header[SZG_DNA_SERIAL_NUMBER_LENGTH] = serial_len;

	uint16_t dna_length = SZG_DNA_HEADER_LENGTH_V1 + manuf_len + name_len +
	                      model_len + version_len + serial_len;

	dna_header[SZG_DNA_PTR_FULL_LENGTH] = dna_length & 0xFF;
	dna_header[SZG_DNA_PTR_FULL_LENGTH + 1] = (dna_length & 0xFF00) >> 8;

	// Calculate and insert the CRC once all data has been gathered
	uint16_t crc = szgComputeCRC(&dna_header[0], SZG_DNA_HEADER_LENGTH_V1 - 2);

	dna_header[SZG_DNA_CRC16_HIGH] = (crc & 0xFF00) >> 8;
	dna_header[SZG_DNA_CRC16_LOW] = crc & 0xFF;

	for (int i = 0; i < SZG_DNA_HEADER_LENGTH_V1; i++) {
		output_file << dna_header[i];
	}

	output_file << dna_json["manufacturer_name"].get<std::string>();
	output_file << dna_json["product_name"].get<std::string>();
	output_file << dna_json["product_model"].get<std::string>();
	output_file << dna_json["product_version"].get<std::string>();

	if (argc == 4) {
		output_file << argv[3];
	} else {
		output_file << dna_json["serial"].get<std::string>();
	}

	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x458, %rsp            # imm = 0x458
movq %rsi, %rbx
movl %edi, %r14d
leaq 0x10(%rsp), %rdi
pushq $0x28
popq %rsi
leaq 0x250(%rsp), %rdx
callq 0x3b88
leal -0x5(%r14), %eax
cmpl $-0x3, %eax
ja 0x35fd
movq 0xaa30(%rip), %rdi      # 0xdfd8
leaq 0x4f85(%rip), %rsi      # 0x8534
callq 0x3240
movq (%rbx), %rsi
movq %rax, %rdi
callq 0x3240
movq 0xaa12(%rip), %rdi      # 0xdfd8
leaq 0x4f6f(%rip), %rsi      # 0x853c
callq 0x3240
movq 0xa9ff(%rip), %rdi      # 0xdfd8
leaq 0x4f78(%rip), %rsi      # 0x8558
callq 0x3240
movq 0xa9ec(%rip), %rdi      # 0xdfd8
leaq 0x4f8c(%rip), %rsi      # 0x857f
callq 0x3240
jmp 0x3af9
movq 0x8(%rbx), %rsi
leaq 0x250(%rsp), %rdi
pushq $0x8
popq %rdx
callq 0x33e0
movq 0x10(%rbx), %rsi
leaq 0x50(%rsp), %rdi
pushq $0x14
popq %rdx
callq 0x3280
movq %rbx, 0x48(%rsp)
movq %rsp, %rbx
movq %rbx, %rdi
xorl %esi, %esi
callq 0x3bda
leaq 0x250(%rsp), %rdi
movq %rbx, %rsi
callq 0x3bf6
movq 0x10(%rsp), %rax
movb $0x28, 0x2(%rax)
movq 0x10(%rsp), %rax
movb $0x0, 0x3(%rax)
movq 0x10(%rsp), %rax
movb $0x1, %cl
movb %cl, 0x4(%rax)
movq 0x10(%rsp), %rax
movb %cl, 0x5(%rax)
leaq 0x4f34(%rip), %rsi      # 0x85a3
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3dea
movq 0x10(%rsp), %rcx
movb %al, 0x6(%rcx)
movq 0x10(%rsp), %rcx
movb %al, 0x7(%rcx)
leaq 0x4f15(%rip), %rsi      # 0x85ab
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %al, 0x8(%rcx)
leaq 0x4ef6(%rip), %rsi      # 0x85ab
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %ah, 0x9(%rcx)
leaq 0x4ee3(%rip), %rsi      # 0x85b7
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %al, 0xa(%rcx)
leaq 0x4ec4(%rip), %rsi      # 0x85b7
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %ah, 0xb(%rcx)
leaq 0x4eb2(%rip), %rsi      # 0x85c4
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %al, 0xc(%rcx)
leaq 0x4e93(%rip), %rsi      # 0x85c4
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %ah, 0xd(%rcx)
leaq 0x4e81(%rip), %rsi      # 0x85d1
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3dea
movq 0x10(%rsp), %rcx
orb %al, 0xe(%rcx)
leaq 0x4e6a(%rip), %rsi      # 0x85d9
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3dea
addb %al, %al
movq 0x10(%rsp), %rcx
orb %al, 0xe(%rcx)
leaq 0x4e13(%rip), %rsi      # 0x85a3
movq %rsp, %rdi
callq 0x3cc8
movq %rax, %rdi
callq 0x3dea
shlb $0x2, %al
movq 0x10(%rsp), %rcx
orb %al, 0xe(%rcx)
xorl %ebp, %ebp
leaq 0x4e33(%rip), %r15      # 0x85e7
movq %rsp, %r12
leaq 0x4e2d(%rip), %r13      # 0x85eb
leaq 0x4e2a(%rip), %rbx      # 0x85ef
cmpq $0x3, %rbp
je 0x3849
movq %r12, %rdi
movq %r15, %rsi
callq 0x3cc8
movq %rax, %rdi
movq %rbp, %rsi
callq 0x3e20
movq %rax, %rdi
movq %r13, %rsi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %al, 0x10(%rcx,%rbp,4)
movq 0x10(%rsp), %rcx
movb %ah, 0x11(%rcx,%rbp,4)
movq %r12, %rdi
movq %r15, %rsi
callq 0x3cc8
movq %rax, %rdi
movq %rbp, %rsi
callq 0x3e20
movq %rax, %rdi
movq %rbx, %rsi
callq 0x3cc8
movq %rax, %rdi
callq 0x3e04
movq 0x10(%rsp), %rcx
movb %al, 0x12(%rcx,%rbp,4)
movq 0x10(%rsp), %rcx
movb %ah, 0x13(%rcx,%rbp,4)
incq %rbp
jmp 0x37c5
leaq 0x4da3(%rip), %rsi      # 0x85f3
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x28(%rsp), %rdi
movq 0x8(%rdi), %r15
callq 0x3120
leaq 0x4d8b(%rip), %rsi      # 0x8605
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x28(%rsp), %rdi
movq 0x8(%rdi), %r12
callq 0x3120
leaq 0x4d6e(%rip), %rsi      # 0x8612
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x28(%rsp), %rdi
movq 0x8(%rdi), %r13
callq 0x3120
leaq 0x4d52(%rip), %rsi      # 0x8620
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x28(%rsp), %rdi
movq 0x8(%rdi), %rbp
callq 0x3120
cmpl $0x4, %r14d
jne 0x390a
movq 0x48(%rsp), %rax
movq 0x18(%rax), %rdi
callq 0x3110
movq %rax, %rbx
jmp 0x3934
leaq 0x4d1f(%rip), %rsi      # 0x8630
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x28(%rsp), %rdi
movq 0x8(%rdi), %rbx
callq 0x3120
movq 0x10(%rsp), %rax
movb %r15b, 0x20(%rax)
movb %r12b, 0x21(%rax)
movb %r13b, 0x22(%rax)
movb %bpl, 0x23(%rax)
movb %bl, 0x24(%rax)
movl $0xff, %ecx
andl %ecx, %r15d
andl %ecx, %r12d
addl %r15d, %r12d
andl %ecx, %r13d
andl %ecx, %ebp
addl %r13d, %ebp
addl %r12d, %ebp
andl %ecx, %ebx
leal (%rbx,%rbp), %ecx
addl $0x28, %ecx
movb %cl, (%rax)
movq 0x10(%rsp), %rax
movb %ch, 0x1(%rax)
movq 0x10(%rsp), %rdi
pushq $0x26
popq %rsi
callq 0x7b58
rolw $0x8, %ax
movq 0x10(%rsp), %rcx
movw %ax, 0x26(%rcx)
xorl %r15d, %r15d
leaq 0x50(%rsp), %rbx
cmpq $0x28, %r15
je 0x39b6
movq 0x10(%rsp), %rax
movsbl (%rax,%r15), %esi
movq %rbx, %rdi
callq 0x32a0
incq %r15
jmp 0x3999
leaq 0x4c36(%rip), %rsi      # 0x85f3
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x50(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x3220
movq 0x48(%rsp), %rbx
leaq 0x28(%rsp), %rdi
callq 0x3120
leaq 0x4c0e(%rip), %rsi      # 0x8605
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x50(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x3220
leaq 0x28(%rsp), %rdi
callq 0x3120
leaq 0x4be6(%rip), %rsi      # 0x8612
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x50(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x3220
leaq 0x28(%rsp), %rdi
callq 0x3120
leaq 0x4bbf(%rip), %rsi      # 0x8620
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x50(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x3220
leaq 0x28(%rsp), %rdi
callq 0x3120
cmpl $0x4, %r14d
jne 0x3aa5
movq 0x18(%rbx), %rsi
leaq 0x50(%rsp), %rdi
callq 0x3240
jmp 0x3ada
leaq 0x4b84(%rip), %rsi      # 0x8630
movq %rsp, %rdi
callq 0x3cc8
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x3f74
leaq 0x50(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x3220
leaq 0x28(%rsp), %rdi
callq 0x3120
movq %rsp, %rdi
callq 0x3fb4
leaq 0x50(%rsp), %rdi
callq 0x3320
leaq 0x250(%rsp), %rdi
callq 0x3090
leaq 0x10(%rsp), %rdi
callq 0x41da
xorl %eax, %eax
addq $0x458, %rsp            # imm = 0x458
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3b21
jmp 0x3b54
jmp 0x3b21
jmp 0x3b21
jmp 0x3b21
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x3120
jmp 0x3b57
jmp 0x3b54
movq %rax, %rbx
jmp 0x3b69
jmp 0x3b4b
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
jmp 0x3b54
movq %rax, %rbx
jmp 0x3b76
jmp 0x3b54
jmp 0x3b54
movq %rax, %rbx
movq %rsp, %rdi
callq 0x3fb4
leaq 0x50(%rsp), %rdi
callq 0x3320
leaq 0x250(%rsp), %rdi
callq 0x3090
leaq 0x10(%rsp), %rdi
callq 0x41da
movq %rbx, %rdi
callq 0x33d0