/*
 * time.c — getdatetime / setdatetime via ESTEX SYSTIME ($21) / SETTIME ($22).
 *
 *   $21 SYSTIME  → D=day E=month IX=year H=hour L=min B=sec C=dow
 *   $22 SETTIME    D=day E=month IX=year H=hour L=min B=sec → CF=err / A=errcode
 *
 * Struct layout (datetime_t, 8 bytes):
 *   +0 day, +1 month, +2..3 year, +4 hour, +5 min, +6 sec, +7 dow
 *
 * Both routines write/read *dt directly — no static scratch.  The key
 * trick in getdatetime is `ex (sp), hl` after RST: HL holds hour:min,
 * stack TOS holds dt — one byte swaps them, then we walk the struct
 * via HL.  setdatetime uses IX as the struct pointer (re-loaded with
 * year just before RST since that's what SETTIME expects).
 */

#include <time.h>
#include <errno.h>

void getdatetime(datetime_t *dt) __naked
{
    (void)dt;
    __asm
        push  ix                    ; save caller IX (BIOS clobbers it)
        push  hl                    ; stash dt across RST (clobbers HL)
        ld    c, #0x21              ; ESTEX SYSTIME
        rst   #0x10
        ;; Returns: D=day E=month IX=year H=hour L=min B=sec C=dow

        ;; ex (sp), hl: TOS<->HL.  Now HL = dt, TOS = hour:min stash.
        ex    (sp), hl
        ld    (hl), d               ; +0 day
        inc   hl
        ld    (hl), e               ; +1 month
        inc   hl
        push  ix                    ; year → stack
        pop   de                    ; DE = year
        ld    (hl), e               ; +2 year low
        inc   hl
        ld    (hl), d               ; +3 year high
        inc   hl
        pop   de                    ; D = hour, E = min (from earlier ex(sp))
        ld    (hl), d               ; +4 hour
        inc   hl
        ld    (hl), e               ; +5 min
        inc   hl
        ld    (hl), b               ; +6 sec
        inc   hl
        ld    (hl), c               ; +7 dow
        pop   ix                    ; restore caller IX
        ret
    __endasm;
}



int setdatetime(const datetime_t *dt) __naked
{
    (void)dt;
    __asm
        push  ix                    ; save caller IX
        push  hl
        pop   ix                    ; IX = dt

        ld    d, (hl)               ; +0 D = day
        inc   hl
        ld    e, (hl)               ; +1 E = month
        inc   hl
        ld    c, (hl)               ; +2 year low
        inc   hl
        ld    b, (hl)               ; +3 year high (BC->IX)
        inc   hl
        push  bc
        ld    b, (hl)               ; +4 H = hour
        inc   hl
        ld    c, (hl)               ; +5 L = min (BC->HL)
        inc   hl
        push  bc
        ld    b, (hl)               ; +6 B = sec
        pop   hl
        pop   ix
        ld    c, #0x22              ; ESTEX SETTIME
        rst   #0x10
        pop   ix                    ; restore caller IX
        jr    c, _st_err2
        ld    de, #0
        ret
    _st_err2:
        call  __errno_set
        ld    de, #-1
        ret
    __endasm;
}
