/* * lseek — 32-bit file position via ESTEX MOVE_FP ($15). * * ESTEX MOVE_FP: A=handle, B=whence (0=SET, 1=CUR, 2=END), * HL=offset high16, IX=offset low16 * → HL:IX = new absolute position, CF=err * * SDCC __sdcccall(1) on z80 for `long lseek(int fd, long offset, int whence)`: * - fd → HL (1st 16-bit arg in register) * - offset → stack as two 16-bit words (low first, then high) * - whence → stack (top after offset) * - 32-bit return: DE = low16, HL = high16 * - caller-pops (caller-side `pop af; pop af; pop af` after the call) * * IX is saved (caller frame pointer). */ #include long lseek(int fd, long offset, int whence) __naked { (void)fd; (void)offset; (void)whence; __asm push ix ; save caller-side IX ;; Layout after push: ;; SP+0..1 = saved IX ;; SP+2..3 = ret addr ;; SP+4..5 = offset low16 ;; SP+6..7 = offset high16 ;; SP+8..9 = whence ld a, l ; A = fd low byte (was in HL) ;; Walk through 5 consecutive stack bytes via HL — cheaper than ;; IY-indexed because `ld r,(hl); inc hl` (2B/13T per byte) beats ;; `ld r, n(iy)` (3B/19T) for sequential reads. ld hl, #4 add hl, sp ; HL → offset_low ld e, (hl) inc hl ld d, (hl) ; DE = offset_low push de pop ix ; IX = offset_low inc hl ld e, (hl) inc hl ld d, (hl) ; DE = offset_high inc hl ld b, (hl) ; B = whence (low byte) ex de, hl ; HL = offset_high (ESTEX wants it here) ld c, #0x15 ; ESTEX MOVE_FP rst #0x10 jr c, _lseek_err ;; Returns HL:IX = new position. Convert to SDCC long return (DE:HL). push ix pop de ; DE = low16 (was IX) ;; HL already has high16 pop ix ; restore caller-side IX ret _lseek_err: call __errno_set ld hl, #0xFFFF ld de, #0xFFFF ; long -1 pop ix ret __endasm; }