user: 请从给定的汇编指令推导出C源代码:

```asm
<vga_font_load>:
  endbr64
  push   %r14
  push   %r13
  mov    %ecx,%r13d
  push   %r12
  mov    %edx,%r12d
  push   %rbp
  mov    %rdi,%rbp
  mov    $0x2,%edi
  push   %rbx
  mov    %rsi,%rbx
  call   <read_seq_b@plt>
  mov    $0x3c4,%esi
  mov    $0x2,%edi
  mov    %eax,%r14d
  call   <outb@plt>
  mov    %r14d,%edi
  mov    $0x3c5,%esi
  and    $0xf0,%edi
  or     $0x4,%edi
  call   <outb@plt>
  mov    $0x4,%edi
  call   <read_seq_b@plt>
  mov    $0x3c4,%esi
  mov    $0x4,%edi
  mov    %eax,%r14d
  call   <outb@plt>
  or     $0x4,%r14d
  mov    $0x3c5,%esi
  movzbl %r14b,%edi
  call   <outb@plt>
  mov    $0x3ce,%esi
  mov    $0x4,%edi
  call   <outb@plt>
  mov    $0x3cf,%esi
  mov    $0x2,%edi
  call   <outb@plt>
  mov    $0x5,%edi
  call   <read_gra_b@plt>
  mov    $0x3ce,%esi
  mov    $0x5,%edi
  mov    %eax,%r14d
  call   <outb@plt>
  mov    %r14d,%edi
  mov    $0x3cf,%esi
  and    $0xef,%edi
  call   <outb@plt>
  mov    $0x3ce,%esi
  mov    $0x6,%edi
  call   <outb@plt>
  xor    %edi,%edi
  mov    $0x3cf,%esi
  call   <outb@plt>
  xor    %r8d,%r8d
  movslq %r12d,%rdi
  test   %r13d,%r13d
  jle    L10
  nopl   0x0(%rax,%rax,1)
L31:
  test   %r12d,%r12d
  jle    L30
  mov    %r8d,%esi
  mov    %r8d,%ecx
  xor    %eax,%eax
  shl    $0x4,%esi
  shl    $0x5,%ecx
  movslq %esi,%rsi
  movslq %ecx,%rcx
  add    %rbx,%rsi
  add    %rbp,%rcx
  nop
L7:
  movzbl (%rsi,%rax,1),%edx
  mov    %dl,(%rcx,%rax,1)
  add    $0x1,%rax
  cmp    %rax,%rdi
  jne    L7
L30:
  add    $0x1,%r8d
  cmp    %r8d,%r13d
  jne    L31
L10:
  mov    $0x2,%edi
  call   <read_seq_b@plt>
  mov    $0x3c4,%esi
  mov    $0x2,%edi
  mov    %eax,%ebx
  call   <outb@plt>
  and    $0xf0,%ebx
  mov    $0x3c5,%esi
  mov    %ebx,%edi
  or     $0x3,%edi
  call   <outb@plt>
  mov    $0x4,%edi
  call   <read_seq_b@plt>
  mov    $0x3c4,%esi
  mov    $0x4,%edi
  mov    %eax,%ebx
  call   <outb@plt>
  and    $0xfb,%ebx
  mov    $0x3c5,%esi
  mov    %ebx,%edi
  call   <outb@plt>
  mov    $0x3ce,%esi
  mov    $0x4,%edi
  call   <outb@plt>
  mov    $0x3cf,%esi
  xor    %edi,%edi
  call   <outb@plt>
  mov    $0x5,%edi
  call   <read_gra_b@plt>
  mov    $0x3ce,%esi
  mov    $0x5,%edi
  mov    %eax,%ebx
  call   <outb@plt>
  or     $0x10,%ebx
  mov    $0x3cf,%esi
  movzbl %bl,%edi
  call   <outb@plt>
  mov    $0x3ce,%esi
  mov    $0x6,%edi
  call   <outb@plt>
  pop    %rbx
  mov    $0x3cf,%esi
  pop    %rbp
  mov    $0xe,%edi
  pop    %r12
  pop    %r13
  pop    %r14
  jmp    1080 <outb@plt>
```

assistant: ```c
void vga_font_load(unsigned char *vidmem, const unsigned char *font, int height, int num_chars) {
  int i, j;
  unsigned char byte;
  byte = read_seq_b(0x02) & ~0xf;
  outb(0x02, 0x3C4);
  outb(byte | 4, 0x3C5);
  byte = read_seq_b(0x04);
  outb(0x04, 0x3C4);
  outb(byte | 4, 0x3C5);
  outb(0x04, 0x3CE);
  outb(2, 0x3CF);
  byte = read_gra_b(0x05) & ~0x10;
  outb(0x05, 0x3CE);
  outb(byte, 0x3CF);
  outb(0x06, 0x3CE);
  outb(0, 0x3CF);
  for (i = 0; i < num_chars; i++) {
    for (j = 0; j < height; j++) {
      vidmem[i * 32 + j] = font[i * 16 + j];
    }
  }
  byte = read_seq_b(0x02) & ~0xf;
  outb(0x02, 0x3C4);
  outb(byte | 3, 0x3C5);
  byte = read_seq_b(0x04) & ~0x4;
  outb(0x04, 0x3C4);
  outb(byte, 0x3C5);
  outb(0x04, 0x3CE);
  outb(0, 0x3CF);
  byte = read_gra_b(0x05);
  outb(0x05, 0x3CE);
  outb(byte | 0x10, 0x3CF);
  outb(0x06, 0x3CE);
  outb(0xe, 0x3CF);
}
```