bits 64

section .rodata

section .text

read_cmos_byte:
;dil in = register number
;al out = value
;rdx and rcx are not touched

  mov al, dil
  out 0x70, al
  in al, 0x71
  ret

global enable_rtc_interrupts
enable_rtc_interrupts:

  ;secondary status register
  mov dil, 11
  call read_cmos_byte

  ;enable interrupts
  or al, 0x40
  mov cl, al

  ;do cmos write
  mov al, 11
  out 0x70, al
  mov al, cl
  out 0x71, al

  ret

global acknowledge_rtc_interrupt
acknowledge_rtc_interrupt:
  mov dil, 12
  jmp read_cmos_byte

convert_bcd:
;al in = byte (possibly bcd)
;al out = byte (not bcd)
;sil 0x02 = bcd
;does not touch rdx, rcx, sil
  test sil, 0x02
  jz .no_convert

  mov dil, al
  and dil, 0xf0
  and al, 0x0f
  shr dil, 3
  add al, dil
  shl dil, 2
  add al, dil

.no_convert:
  ret

convert_hours:
;al in = byte (possibly bcd and 12 hour)
;al out = byte (not bcd or 12 hour)
;sil 0x02 = bcd, sil 0x01 = 12 hour
;does not touch rdx, rcx, sil
  test sil, 0x01
  jz convert_bcd

  test al, 0x80
  jz .am

  and al, 0x7f
  call convert_bcd
  cmp al, 12
  je .noon

  add al, 12
  ret

.noon:
  ret

.am:
  call convert_bcd
  cmp al, 12
  je .midnight

  ret

.midnight:
  xor al, al
  ret

global get_time_from_rtc
get_time_from_rtc:
;rax out = time (see timer.cpp for encoding)
;we assume the year is 20xx (sorry)

  mov dil, 11
  call read_cmos_byte

  shr al, 1
  not al
  and al, 3
  mov sil, al

  xor rdx, rdx

.outer_loop:
  mov rcx, rdx

.wait_for_update_loop:
  ;status register - 0x80 is update in progress
  mov dil, 10
  call read_cmos_byte
  test al, 0x80
  jnz .wait_for_update_loop

  ;years
  mov dil, 9
  call read_cmos_byte
  call convert_bcd
  mov dh, al

  ;months
  mov dil, 8
  call read_cmos_byte
  call convert_bcd
  mov dl, al

  shl edx, 16

  ;days
  mov dil, 7
  call read_cmos_byte
  call convert_bcd
  mov dh, al

  ;hours
  mov dil, 4
  call read_cmos_byte
  call convert_hours
  mov dl, al

  shl rdx, 16

  ;minutes
  mov dil, 2
  call read_cmos_byte
  call convert_bcd
  mov dh, al

  ;seconds
  xor dil, dil
  call read_cmos_byte
  call convert_bcd
  mov dl, al

  cmp rdx, rcx
  jne .outer_loop

  mov rax, rdx
  ret