// File: sangwoojun[P]rv32emulator/emulator.cpp
// Function: parse_instr(int, char*, instr*, int, label_loc*, source*)
int parse_instr(int line, char* ftok, instr* imem, int memoff, label_loc* labels, source* src) {
	if ( memoff +4 > DATA_OFFSET ) {
		printf( "Instructions in data segment! Line %d\n", line );
		exit(1);
	}
	char* o1 = strtok(NULL, " \t\r\n,");
	char* o2 = strtok(NULL, " \t\r\n,");
	char* o3 = strtok(NULL, " \t\r\n,");
	char* o4 = strtok(NULL, " \t\r\n,");

	int ioff = memoff/4;
	int pscnt = parse_pseudoinstructions(line, ftok, imem, ioff, labels, o1, o2, o3, o4, src);
	if ( pscnt > 0 ) {
		return pscnt;
	} else {
		instr* i = &imem[ioff];
		instr_type op = parse_instr(ftok);
		i->op = op;
		i->orig_line = line;
		append_source(ftok, o1, o2, o3, src, i);

		switch( op ) {
			case UNIMPL: return 1;
			case JAL:
				if ( o2 ) { // two operands, reg, label
					if ( !o1 || !o2 || o3 || o4 ) print_syntax_error( line, "Invalid format" );
					i->a1.type = OPTYPE_REG; i->a1.reg = parse_reg(o1, line);
					i->a2.type = OPTYPE_LABEL; strncpy(i->a2.label, o2, MAX_LABEL_LEN);
				} else { // one operand, label
					if ( !o1 || o2 || o3 || o4 ) print_syntax_error( line, "Invalid format" );

					i->a1.type = OPTYPE_REG; i->a1.reg = 1;
					i->a2.type = OPTYPE_LABEL; strncpy(i->a2.label, o1, MAX_LABEL_LEN);
				}
				return 1;
			case JALR:
				if ( !o1 || !o2 || o3 || o4 ) print_syntax_error( line, "Invalid format" );
				i->a1.reg = parse_reg(o1, line);
				parse_mem(o2, &i->a2.reg, &i->a3.imm, 12, line);
				return 1;
			case ADD: case SUB: case SLT: case SLTU: case AND: case OR: case XOR: case SLL: case SRL: case SRA:
				if ( !o1 || !o2 || !o3 || o4 ) print_syntax_error( line, "Invalid format" );
				i->a1.reg = parse_reg(o1, line);
				i->a2.reg = parse_reg(o2, line);
				i->a3.reg = parse_reg(o3, line);
				return 1;
			case LB: case LBU: case LH: case LHU: case LW: case SB: case SH: case SW:
				if ( !o1 || !o2 || o3 || o4 ) print_syntax_error( line, "Invalid format" );
				i->a1.reg = parse_reg(o1, line);
				parse_mem(o2, &i->a2.reg, &i->a3.imm, 12, line);
				return 1;
			case ADDI: case SLTI: case SLTIU: case ANDI: case ORI: case XORI: case SLLI: case SRLI: case SRAI:
				if ( !o1 || !o2 || !o3 || o4 ) print_syntax_error( line, "Invalid format" );

				i->a1.reg = parse_reg(o1, line);
				i->a2.reg = parse_reg(o2, line);
				i->a3.imm = signextend(parse_imm(o3, 12, line), 12);
				return 1;
			case BEQ: case BGE: case BGEU: case BLT: case BLTU: case BNE:
				if ( !o1 || !o2 || !o3 || o4 ) print_syntax_error( line, "Invalid format" );
				i->a1.reg = parse_reg(o1, line);
				i->a2.reg = parse_reg(o2, line);
				i->a3.type = OPTYPE_LABEL; strncpy(i->a3.label, o3, MAX_LABEL_LEN);
				return 1;
			case LUI: 
			case AUIPC: // how to deal with LSB correctly? FIXME
				if ( !o1 || !o2 || o3 || o4 ) print_syntax_error( line, "Invalid format" );
				i->a1.reg = parse_reg(o1, line);
				i->a2.imm = (parse_imm(o2, 20, line));
				return 1;
			case HCF: return 1;
		}

	}
	return 1;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x98, %rsp
movl %edi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq %r8, -0x30(%rbp)
movq %r9, -0x38(%rbp)
movl -0x24(%rbp), %eax
addl $0x4, %eax
cmpl $0x8000, %eax           # imm = 0x8000
jle 0x4f3a
movl -0x10(%rbp), %esi
leaq 0x673b(%rip), %rdi      # 0xb664
movb $0x0, %al
callq 0x2040
movl $0x1, %edi
callq 0x2250
xorl %eax, %eax
movl %eax, %edi
leaq 0x6746(%rip), %rsi      # 0xb68b
callq 0x2390
movq %rax, -0x40(%rbp)
xorl %eax, %eax
movl %eax, %edi
leaq 0x6732(%rip), %rsi      # 0xb68b
callq 0x2390
movq %rax, -0x48(%rbp)
xorl %eax, %eax
movl %eax, %edi
leaq 0x671e(%rip), %rsi      # 0xb68b
callq 0x2390
movq %rax, -0x50(%rbp)
xorl %eax, %eax
movl %eax, %edi
leaq 0x670a(%rip), %rsi      # 0xb68b
callq 0x2390
movq %rax, -0x58(%rbp)
movl -0x24(%rbp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
movl %eax, -0x5c(%rbp)
movl -0x10(%rbp), %edi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
movl -0x5c(%rbp), %ecx
movq -0x30(%rbp), %r8
movq -0x40(%rbp), %r9
movq -0x48(%rbp), %rbx
movq -0x50(%rbp), %r11
movq -0x58(%rbp), %r10
movq -0x38(%rbp), %rax
movq %rbx, (%rsp)
movq %r11, 0x8(%rsp)
movq %r10, 0x10(%rsp)
movq %rax, 0x18(%rsp)
callq 0x40b0
movl %eax, -0x60(%rbp)
cmpl $0x0, -0x60(%rbp)
jle 0x4fea
movl -0x60(%rbp), %eax
movl %eax, -0xc(%rbp)
jmp 0x5483
movq -0x20(%rbp), %rax
movslq -0x5c(%rbp), %rcx
imulq $0x98, %rcx, %rcx
addq %rcx, %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rdi
callq 0x2d30
movl %eax, -0x6c(%rbp)
movl -0x6c(%rbp), %ecx
movq -0x68(%rbp), %rax
movl %ecx, (%rax)
movl -0x10(%rbp), %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x90(%rax)
movq -0x18(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq -0x48(%rbp), %rdx
movq -0x50(%rbp), %rcx
movq -0x38(%rbp), %r8
movq -0x68(%rbp), %r9
callq 0x3b70
movl -0x6c(%rbp), %eax
movq %rax, -0x78(%rbp)
subq $0x26, %rax
ja 0x547a
movq -0x78(%rbp), %rax
leaq 0x5fe5(%rip), %rcx      # 0xb040
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x48(%rbp)
je 0x50ee
cmpq $0x0, -0x40(%rbp)
je 0x5093
cmpq $0x0, -0x48(%rbp)
je 0x5093
cmpq $0x0, -0x50(%rbp)
jne 0x5093
cmpq $0x0, -0x58(%rbp)
je 0x50a2
movl -0x10(%rbp), %edi
leaq 0x6556(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x68(%rbp), %rax
movl $0x1, 0x4(%rax)
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x68(%rbp), %rax
movl $0x3, 0x30(%rax)
movq -0x68(%rbp), %rdi
addq $0x30, %rdi
addq $0x4, %rdi
movq -0x48(%rbp), %rsi
movl $0x20, %edx
callq 0x2120
jmp 0x5154
cmpq $0x0, -0x40(%rbp)
je 0x510a
cmpq $0x0, -0x48(%rbp)
jne 0x510a
cmpq $0x0, -0x50(%rbp)
jne 0x510a
cmpq $0x0, -0x58(%rbp)
je 0x5119
movl -0x10(%rbp), %edi
leaq 0x64df(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x68(%rbp), %rax
movl $0x1, 0x4(%rax)
movq -0x68(%rbp), %rax
movl $0x1, 0x28(%rax)
movq -0x68(%rbp), %rax
movl $0x3, 0x30(%rax)
movq -0x68(%rbp), %rdi
addq $0x30, %rdi
addq $0x4, %rdi
movq -0x40(%rbp), %rsi
movl $0x20, %edx
callq 0x2120
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x517c
cmpq $0x0, -0x48(%rbp)
je 0x517c
cmpq $0x0, -0x50(%rbp)
jne 0x517c
cmpq $0x0, -0x58(%rbp)
je 0x518b
movl -0x10(%rbp), %edi
leaq 0x646d(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x30, %rsi
addq $0x24, %rsi
movq -0x68(%rbp), %rdx
addq $0x5c, %rdx
addq $0x28, %rdx
movl -0x10(%rbp), %r8d
movl $0xc, %ecx
callq 0x3800
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x51f7
cmpq $0x0, -0x48(%rbp)
je 0x51f7
cmpq $0x0, -0x50(%rbp)
je 0x51f7
cmpq $0x0, -0x58(%rbp)
je 0x5206
movl -0x10(%rbp), %edi
leaq 0x63f2(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x54(%rax)
movq -0x50(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x80(%rax)
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x527f
cmpq $0x0, -0x48(%rbp)
je 0x527f
cmpq $0x0, -0x50(%rbp)
jne 0x527f
cmpq $0x0, -0x58(%rbp)
je 0x528e
movl -0x10(%rbp), %edi
leaq 0x636a(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movq -0x68(%rbp), %rsi
addq $0x30, %rsi
addq $0x24, %rsi
movq -0x68(%rbp), %rdx
addq $0x5c, %rdx
addq $0x28, %rdx
movl -0x10(%rbp), %r8d
movl $0xc, %ecx
callq 0x3800
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x52fa
cmpq $0x0, -0x48(%rbp)
je 0x52fa
cmpq $0x0, -0x50(%rbp)
je 0x52fa
cmpq $0x0, -0x58(%rbp)
je 0x5309
movl -0x10(%rbp), %edi
leaq 0x62ef(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x54(%rax)
movq -0x50(%rbp), %rdi
movl -0x10(%rbp), %edx
movl $0xc, %esi
movl $0x1, %ecx
callq 0x3720
movl %eax, %edi
movl $0xc, %esi
callq 0x2c50
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x84(%rax)
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x5393
cmpq $0x0, -0x48(%rbp)
je 0x5393
cmpq $0x0, -0x50(%rbp)
je 0x5393
cmpq $0x0, -0x58(%rbp)
je 0x53a2
movl -0x10(%rbp), %edi
leaq 0x6256(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x54(%rax)
movq -0x68(%rbp), %rax
movl $0x3, 0x5c(%rax)
movq -0x68(%rbp), %rdi
addq $0x5c, %rdi
addq $0x4, %rdi
movq -0x50(%rbp), %rsi
movl $0x20, %edx
callq 0x2120
movl $0x1, -0xc(%rbp)
jmp 0x5483
cmpq $0x0, -0x40(%rbp)
je 0x5420
cmpq $0x0, -0x48(%rbp)
je 0x5420
cmpq $0x0, -0x50(%rbp)
jne 0x5420
cmpq $0x0, -0x58(%rbp)
je 0x542f
movl -0x10(%rbp), %edi
leaq 0x61c9(%rip), %rsi      # 0xb5f3
callq 0x2c90
movq -0x40(%rbp), %rdi
movl -0x10(%rbp), %esi
movl $0x1, %edx
callq 0x3250
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x28(%rax)
movq -0x48(%rbp), %rdi
movl -0x10(%rbp), %edx
movl $0x14, %esi
movl $0x1, %ecx
callq 0x3720
movl %eax, %ecx
movq -0x68(%rbp), %rax
movl %ecx, 0x58(%rax)
movl $0x1, -0xc(%rbp)
jmp 0x5483
movl $0x1, -0xc(%rbp)
jmp 0x5483
jmp 0x547c
movl $0x1, -0xc(%rbp)
movl -0xc(%rbp), %eax
addq $0x98, %rsp
popq %rbx
popq %rbp
retq