; 16-bit floats have an 11-bit signed value and a 5-bit signed precision. ; These control codes are required by the standard. F16_INF EQU $7BFF F16_NEGINF EQU $7FFF F16_NAN EQU $FFFF CastFloat16ToFixed48: ; de: f16 ; hl: q48 * ; returns to *hl ; Arithmetically right-shift the precision ld b, d sra b sra b sra b ; Mask away the precision and extend the sign of the value ld a, d and $7 bit 2, a jr z, .no_sign_extend or $f8 .no_sign_extend ld d, a ; Prepare the output buffer. Fixed, big-endian 48-bit numbers have the binary point 32 bits in. ld a, 0 jr z, .no_output_sign_extend dec a .no_output_sign_extend ; Sign extend push hl ld [hli], a ld [hli], a ; Load the input float ld [hl], d inc hl ld [hl], e inc hl ; Fill the rest with 0 xor a ld [hli], a ld [hl], a pop hl ; If the precision is 0, no shifting is needed ld a, b and a ret z ; Check the sign of the precision bit 7, a jr z, .precision_positive ; Right-shift to gain the required fixed-point precision cpl inc a ld b, a ld c, 6 .neg_prec_outer push hl push bc and a .neg_prec_inner rr [hl] inc hl dec c jr nz, .neg_prec_inner pop bc pop hl dec b jr nz, .neg_prec_outer ret .precision_positive ; Left-shift to gain the required fixed-point magnitude push hl ld de, 5 add hl, de ld c, 6 .pos_prec_outer push hl push bc and a .pos_prec_inner rl [hl] dec hl dec c jr nz, .pos_prec_inner pop bc pop hl dec b jr nz, .pos_prec_outer pop hl ret CastFixed48ToFloat16: ; hl: q48 * ; returns f16 de bit 7, [hl] push af ; save sign jr z, .positive ; take absolute value push hl ld c, 6 .cpl_loop ld a, [hl] cpl ld [hli], a dec c jr nz, .cpl_loop dec hl inc [hl] pop hl .positive ; find most significant position ld b, 16 .most_significant_position_loop ld c, 8 ld a, [hli] .most_significant_position_loop_inner add a jr c, .got_most_significant_position dec b dec c jr nz, .most_significant_position_loop jr .most_significant_position_loop .got_most_significant_position push bc ; calculate the shift ld a, b bit 7, a jr z, .shift_left cpl inc a ld b, a cp 16 jr c, .shift_right ; can't fit in an f16, return 0 ld de, 0 add sp, 4 ret .shift_left cp 11 jr c, .okay_shift_left ; can't fit in an f16, return infinity ld de, F16_INF pop af pop af ret z set 2, d ret .okay_shift_left ld de, 5 add hl, de inc e ld c, e .shift_left_loop_outer push bc and a .shift_left_loop_inner rl [hl] dec hl dec c jr nz, .shift_left_loop_inner pop bc add hl, de dec b jr nz, .shift_left_loop_outer inc hl jr .pack .shift_right ld de, -6 ld c, 6 .shift_right_loop_outer push bc and a .shift_right_loop_inner rr [hl] inc hl dec c jr nz, .shift_right_loop_inner pop bc add hl, de dec b jr nz, .shift_right_loop_outer .pack pop bc sla b sla b sla b inc hl inc hl ld a, [hli] ld e, [hl] and $3 ld d, a pop af jr z, .no_cpl ld a, d cpl and $7 ld d, a ld a, e cpl inc a ld e, a .no_cpl ld a, d or b ld d, a ret