user: Translate the below assembly code into C programming language:

```asm
<vc4_parse_string16>:
  endbr64
  push   %r12
  mov    %rsi,%r12
  push   %rbp
  mov    %rdx,%rbp
  push   %rbx
  mov    %rdi,%rbx
  call   <strlen@plt>
  xor    %edi,%edi
  cmp    $0xf,%eax
  setg   %dil
  call   <assert@plt>
  movzbl (%rbx),%eax
  cmp    $0x30,%al
  je     L160
  cmp    $0x31,%al
  mov    $0x0,%edx
  mov    $0x8000,%eax
  cmovne %edx,%eax
  mov    %eax,%edx
L252:
  movzbl 0x1(%rbx),%ecx
  cmp    $0x30,%cl
  je     L393
  cmp    $0x31,%cl
  je     L465
L285:
  movzbl 0x2(%rbx),%ecx
  cmp    $0x30,%cl
  je     L303
L103:
  cmp    $0x31,%cl
  je     L248
L478:
  movzbl 0x3(%rbx),%ecx
  cmp    $0x30,%cl
  je     L242
L356:
  cmp    $0x31,%cl
  je     L355
L550:
  movzbl 0x4(%rbx),%ecx
  cmp    $0x30,%cl
  je     L357
L520:
  cmp    $0x31,%cl
  je     L176
L338:
  movzbl 0x5(%rbx),%ecx
  cmp    $0x30,%cl
  je     L584
L585:
  cmp    $0x31,%cl
  je     L143
L283:
  movzbl 0x6(%rbx),%ecx
  cmp    $0x30,%cl
  je     L240
L259:
  cmp    $0x31,%cl
  je     L452
L439:
  movzbl 0x7(%rbx),%ecx
  cmp    $0x30,%cl
  je     L26
L383:
  cmp    $0x31,%cl
  je     L222
L113:
  movzbl 0x8(%rbx),%ecx
  cmp    $0x30,%cl
  je     L255
L161:
  cmp    $0x31,%cl
  je     L467
L247:
  movzbl 0x9(%rbx),%ecx
  cmp    $0x30,%cl
  je     L94
L524:
  cmp    $0x31,%cl
  je     L138
L483:
  movzbl 0xa(%rbx),%ecx
  cmp    $0x30,%cl
  je     L437
L246:
  cmp    $0x31,%cl
  je     L379
L533:
  movzbl 0xb(%rbx),%ecx
  cmp    $0x30,%cl
  je     L3
L172:
  cmp    $0x31,%cl
  je     L527
L280:
  movzbl 0xc(%rbx),%ecx
  cmp    $0x30,%cl
  je     L565
L419:
  cmp    $0x31,%cl
  je     L323
L163:
  movzbl 0xd(%rbx),%ecx
  cmp    $0x30,%cl
  je     L27
L225:
  cmp    $0x31,%cl
  je     L199
L97:
  movzbl 0xe(%rbx),%ecx
  cmp    $0x30,%cl
  je     L594
L51:
  cmp    $0x31,%cl
  je     L262
L475:
  movzbl 0xf(%rbx),%ecx
  cmp    $0x30,%cl
  je     L412
  cmp    $0x31,%cl
  je     L453
  mov    %edx,(%r12)
  pop    %rbx
  mov    %eax,0x0(%rbp)
  pop    %rbp
  pop    %r12
  ret
  nopw   0x0(%rax,%rax,1)
L453:
  or     $0x1,%edx
L412:
  or     $0x1,%eax
  mov    %edx,(%r12)
  pop    %rbx
  mov    %eax,0x0(%rbp)
  pop    %rbp
  pop    %r12
  ret
  nopw   0x0(%rax,%rax,1)
L262:
  or     $0x2,%edx
  or     $0x2,%eax
  jmp    L475
L199:
  movzbl 0xe(%rbx),%ecx
  or     $0x4,%edx
  or     $0x4,%eax
  cmp    $0x30,%cl
  jne    L51
L594:
  or     $0x2,%eax
  jmp    L475
  nopl   0x0(%rax)
L323:
  movzbl 0xd(%rbx),%ecx
  or     $0x8,%edx
  or     $0x8,%eax
  cmp    $0x30,%cl
  jne    L225
L27:
  or     $0x4,%eax
  jmp    L97
  nopl   0x0(%rax)
L527:
  movzbl 0xc(%rbx),%ecx
  or     $0x10,%edx
  or     $0x10,%eax
  cmp    $0x30,%cl
  jne    L419
L565:
  or     $0x8,%eax
  jmp    L163
  nopl   0x0(%rax,%rax,1)
L379:
  movzbl 0xb(%rbx),%ecx
  or     $0x20,%edx
  or     $0x20,%eax
  cmp    $0x30,%cl
  jne    L172
L3:
  or     $0x10,%eax
  jmp    L280
  nopl   0x0(%rax,%rax,1)
L138:
  movzbl 0xa(%rbx),%ecx
  or     $0x40,%edx
  or     $0x40,%eax
  cmp    $0x30,%cl
  jne    L246
L437:
  or     $0x20,%eax
  jmp    L533
  nopl   0x0(%rax,%rax,1)
L467:
  movzbl 0x9(%rbx),%ecx
  or     $0x80,%dl
  or     $0x80,%al
  cmp    $0x30,%cl
  jne    L524
L94:
  or     $0x40,%eax
  jmp    L483
  nopw   0x0(%rax,%rax,1)
L222:
  movzbl 0x8(%rbx),%ecx
  or     $0x1,%dh
  or     $0x1,%ah
  cmp    $0x30,%cl
  jne    L161
L255:
  or     $0x80,%al
  jmp    L247
  nopw   0x0(%rax,%rax,1)
L452:
  movzbl 0x7(%rbx),%ecx
  or     $0x2,%dh
  or     $0x2,%ah
  cmp    $0x30,%cl
  jne    L383
L26:
  or     $0x1,%ah
  jmp    L113
  nopl   0x0(%rax,%rax,1)
L143:
  movzbl 0x6(%rbx),%ecx
  or     $0x4,%dh
  or     $0x4,%ah
  cmp    $0x30,%cl
  jne    L259
L240:
  or     $0x2,%ah
  jmp    L439
  nopl   0x0(%rax,%rax,1)
L176:
  movzbl 0x5(%rbx),%ecx
  or     $0x8,%dh
  or     $0x8,%ah
  cmp    $0x30,%cl
  jne    L585
L584:
  or     $0x4,%ah
  jmp    L283
  nopl   0x0(%rax,%rax,1)
L355:
  movzbl 0x4(%rbx),%ecx
  or     $0x10,%dh
  or     $0x10,%ah
  cmp    $0x30,%cl
  jne    L520
L357:
  or     $0x8,%ah
  jmp    L338
  nopl   0x0(%rax,%rax,1)
L248:
  movzbl 0x3(%rbx),%ecx
  or     $0x20,%dh
  or     $0x20,%ah
  cmp    $0x30,%cl
  jne    L356
L242:
  or     $0x10,%ah
  jmp    L550
  nopl   0x0(%rax,%rax,1)
L465:
  movzbl 0x2(%rbx),%ecx
  or     $0x40,%dh
  or     $0x40,%ah
  cmp    $0x30,%cl
  jne    L103
L303:
  or     $0x20,%ah
  jmp    L478
  nopl   0x0(%rax,%rax,1)
L393:
  or     $0x40,%ah
  jmp    L285
  nopl   0x0(%rax,%rax,1)
L160:
  mov    $0x8000,%eax
  xor    %edx,%edx
  jmp    L252
```

assistant: ```c
void vc4_parse_string16(const char *p, uint16_t *bitsp, uint16_t *maskp) {
  uint16_t mask, val, fval;
  assert(strlen(p) >= 16);
  mask = 0x8000;
  val = fval = 0;
  while (mask) {
    if (*p == '0') {
      fval |= mask;
    } else if (*p == '1') {
      val |= mask;
      fval |= mask;
    } else {
    }
    mask >>= 1;
    p++;
  }
  *bitsp = val;
  *maskp = fval;
}
```