// File: Jumperr-labs[P]at25sf081/AT25SF081.cpp
// Function: AT25SF081::Main()
void AT25SF081::Main() {
    while (!should_stop_) {
        uint8_t opcode = 0;
        if (spi_slave_->Transmit(&opcode, nullptr, 1) == 0) {
            continue;
        }

        switch (opcode) {
            case (OP_READ_ARRAY_0B): {
                ReadArray(true);
                break;
            }

            case (OP_READ_ARRAY_03): {
                ReadArray(false);
                break;
            }

            case (OP_BYTE_OR_PAGE_PROGRAM): {
                ByteOrPageProgram();
                break;
            }

            case (OP_WRITE_ENABLE): {
                WriteEnable();
                break;
            }

            case (OP_WRITE_DISABLE): {
                WriteDisable();
                break;
            }

            case (OP_BLOCK_ERASE_4KB): {
                BlockErase(1U << 12);
                break;
            }

            case (OP_BLOCK_ERASE_32KB): {
                BlockErase(1U << 15);
                break;
            }

            case (OP_BLOCK_ERASE_64KB): {
                BlockErase(1U << 16);
                break;
            }

            case (OP_CHIP_ERASE_60): {
                ChipErase();
                break;
            }

            case (OP_CHIP_ERASE_C7): {
                ChipErase();
                break;
            }

            case (OP_READ_STATUS_REGISTER_BYTE_1): {
                ReadStatusRegister(STATUS_REGISTER_BYTE_1);
                break;
            }

            case (OP_READ_STATUS_REGISTER_BYTE_2): {
                ReadStatusRegister(STATUS_REGISTER_BYTE_2);
                break;
            }

            case (OP_READ_MANUFACTURER_AND_DEVICE_ID): {
                ReadManufacturerAndDeviceId();
                break;
            }

            case (OP_READ_DEVICE_ID): {
                ReadDeviceId();
                break;
            }

            default: {
                std::cerr << "AT25SF081: [Warning] Unsupported opcode 0x" << std::hex << (int) opcode << std::dec << std::endl;
                throw std::logic_error("AT25SF081: Unsupported opcode " + std::to_string(opcode));
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movb 0x100018(%rax), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0xeb1c
jmp 0xedef
movq -0x68(%rbp), %rax
movb $0x0, -0x9(%rbp)
movq 0x8(%rax), %rdi
movq (%rdi), %rax
leaq -0x9(%rbp), %rsi
xorl %ecx, %ecx
movl %ecx, %edx
movl $0x1, %ecx
callq *(%rax)
cmpq $0x0, %rax
jne 0xeb42
jmp 0xeb07
movzbl -0x9(%rbp), %eax
movl %eax, -0x6c(%rbp)
subl $0x2, %eax
je 0xec30
jmp 0xeb54
movl -0x6c(%rbp), %eax
subl $0x3, %eax
je 0xec20
jmp 0xeb62
movl -0x6c(%rbp), %eax
subl $0x4, %eax
je 0xec4c
jmp 0xeb70
movl -0x6c(%rbp), %eax
subl $0x5, %eax
je 0xecaf
jmp 0xeb7e
movl -0x6c(%rbp), %eax
subl $0x6, %eax
je 0xec3e
jmp 0xeb8c
movl -0x6c(%rbp), %eax
subl $0xb, %eax
je 0xec0d
jmp 0xeb96
movl -0x6c(%rbp), %eax
subl $0x20, %eax
je 0xec5a
jmp 0xeba4
movl -0x6c(%rbp), %eax
subl $0x35, %eax
je 0xecbf
jmp 0xebb2
movl -0x6c(%rbp), %eax
subl $0x52, %eax
je 0xec6d
jmp 0xebc0
movl -0x6c(%rbp), %eax
subl $0x60, %eax
je 0xec93
jmp 0xebce
movl -0x6c(%rbp), %eax
subl $0x90, %eax
je 0xece0
jmp 0xebde
movl -0x6c(%rbp), %eax
subl $0x9f, %eax
je 0xecd2
jmp 0xebee
movl -0x6c(%rbp), %eax
subl $0xc7, %eax
je 0xeca1
jmp 0xebfe
movl -0x6c(%rbp), %eax
subl $0xd8, %eax
je 0xec80
jmp 0xecee
movq -0x68(%rbp), %rdi
movl $0x1, %esi
callq 0xd580
jmp 0xedea
movq -0x68(%rbp), %rdi
xorl %esi, %esi
callq 0xd580
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xd870
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xe2a0
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xd750
jmp 0xedea
movq -0x68(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
callq 0xd180
jmp 0xedea
movq -0x68(%rbp), %rdi
movl $0x8000, %esi           # imm = 0x8000
callq 0xd180
jmp 0xedea
movq -0x68(%rbp), %rdi
movl $0x10000, %esi          # imm = 0x10000
callq 0xd180
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xd950
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xd950
jmp 0xedea
movq -0x68(%rbp), %rdi
xorl %esi, %esi
callq 0xd420
jmp 0xedea
movq -0x68(%rbp), %rdi
movl $0x1, %esi
callq 0xd420
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xdd70
jmp 0xedea
movq -0x68(%rbp), %rdi
callq 0xe0f0
jmp 0xedea
movq 0xa2fb(%rip), %rdi      # 0x18ff0
leaq 0x5319(%rip), %rsi      # 0x14015
callq 0xd970
movq %rax, %rdi
movq 0xa2dd(%rip), %rsi      # 0x18fe8
callq 0xd2b0
movq %rax, %rdi
movzbl -0x9(%rbp), %esi
callq 0xe170
movq %rax, %rdi
movq 0xa282(%rip), %rsi      # 0x18fa8
callq 0xd2b0
movq %rax, %rdi
movq 0xa243(%rip), %rsi      # 0x18f78
callq 0xd9f0
movb $0x1, -0x5d(%rbp)
movl $0x10, %edi
callq 0xd430
movq %rax, -0x78(%rbp)
movzbl -0x9(%rbp), %esi
leaq -0x50(%rbp), %rdi
callq 0xdcf0
jmp 0xed5b
leaq 0x52de(%rip), %rsi      # 0x14040
leaq -0x30(%rbp), %rdi
leaq -0x50(%rbp), %rdx
callq 0xe110
jmp 0xed71
movq -0x78(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0xdf20
jmp 0xed80
movq -0x78(%rbp), %rdi
movb $0x0, -0x5d(%rbp)
movq 0xa239(%rip), %rsi      # 0x18fc8
movq 0xa21a(%rip), %rdx      # 0x18fb0
callq 0xe150
jmp 0xee01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xedd7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
jmp 0xedce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x58(%rbp)
movl %eax, -0x5c(%rbp)
leaq -0x30(%rbp), %rdi
callq 0xd520
leaq -0x50(%rbp), %rdi
callq 0xd520
testb $0x1, -0x5d(%rbp)
jne 0xeddf
jmp 0xede8
movq -0x78(%rbp), %rdi
callq 0xd630
jmp 0xedf8
jmp 0xeb07
addq $0x80, %rsp
popq %rbp
retq
movq -0x58(%rbp), %rdi
callq 0xe1f0
nopw %cs:(%rax,%rax)