#include "game_types.h"

/* Math_FixedDiv2 @ 0x080155E4 (real 182B) -- unsigned frameless fixed-point divide. Mirrors src/matched/Math_FixedDiv2.c. */
/* Frameless copy of the FixedDiv core (separate nibble/bit tops LshA1_/LshA_,
   `mov pc,lr` return): unsigned, returns the dividend itself when smaller,
   same ror-placed fractional loop and Lfin rounding tail. Zero divisor via
   the allocator stub. */
extern void Mem_Alloc(void);

static unsigned ror32(unsigned v, unsigned n)
{
    n &= 31;
    return n == 0 ? v : (v >> n) | (v << (32 - n));
}

unsigned Math_FixedDiv2(unsigned a, unsigned b)
{
    unsigned x = a, y = b, q = 0;
    unsigned bit = 1, scale;
    if (b == 0) {
        Mem_Alloc();
        return 0;
    }
    if (x < y)
        return x;
    scale = 1u << 28;
    while (y < scale && y < x) {
        y <<= 4;
        bit <<= 4;
    }
    scale <<= 3;
    while (y < scale && y < x) {
        y <<= 1;
        bit <<= 1;
    }
    for (;;) {
        if (x >= y)
            x -= y; /* implicit leading bit, unrecorded */
        if (x >= (y >> 1)) {
            x -= y >> 1;
            q |= ror32(bit, 1);
        }
        if (x >= (y >> 2)) {
            x -= y >> 2;
            q |= ror32(bit, 2);
        }
        if (x >= (y >> 3)) {
            x -= y >> 3;
            q |= ror32(bit, 3);
        }
        if (x == 0 || (bit >>= 4) == 0)
            break;
        y >>= 4;
    }
    if ((q & 0xE0000000u) != 0) {
        if ((q & ror32(bit, 3)) != 0)
            x += y >> 3;
        if ((q & ror32(bit, 2)) != 0)
            x += y >> 2;
        if ((q & ror32(bit, 1)) != 0)
            x += y >> 1;
    }
    return x;
}
