[OSy] chybejici __udivdi3
Jakub Jermar
jakub at jermar.eu
Sun Nov 4 11:40:22 CET 2007
Mene masochisticka varianta je napsat ten __udivdi3 v C.
Jakub
On Nov 4, 2007, at 11:31 AM, Branislav Repček wrote:
> Zdravim.
>
> Podla mojich testov funguje do_div spravne. Ked skusim do
> nasledujuceho kodu dat tvoje hodnoty, tak mam spravne vysledky...
>
> uint64_t temp = usec * tps;
> printk("usec: %u\n", (unative_t) usec);
> printk(" Temp: lo=%u hi=%u\n", ((uint32_t *) &temp)[0], ((uint32_t *)
> &temp)[1]);
> do_div(temp, 1000000);
> printk(" Res: lo=%u hi=%u\n", ((uint32_t *) &temp)[0], ((uint32_t
> *) &temp)[1]);
>
> Vystup je:
>
> usec: 2000000
> Temp: lo=1780113024 hi=3581
> Res: lo=15382058 hi=0
>
> Co po prepocitani dava Temp=2^32 * 3581 + 1780113024 = 15382058000000.
> Z toho je jasne, ze Res je tiez spravne.
>
> To je v podstate aj to, co by som cakal. Ako som spominal, do_div je
> prevzate z Linux 2.6.23.1 a jedina moja uprava je substitucia makra
> GCC_REG_ACCUM v do_div makre za "$0".
>
> --
> Branislav Repcek
> http://minimal.matfyz.cz
>
>
> On Nov 3, 2007 11:29 PM, Josef Reidinger
> <josef.reidinger at seznam.cz> wrote:
>> Zkousel sem tvoje reseni a vysledek neni moc dobry, mozna to jen
>> spatne
>> pouzivam.
>>
>> kod:
>> unsigned long long tmp = tmr->usec*tics_per_second;
>> dprintk(" usec: %u tps: %u \n",tmr->usec,tics_per_second);
>> unsigned micro = 1000000;
>> do_div(tmp,micro);
>>
>> vysledek:
>> function timer_start: 113 - usec: 2000000 tps: 7691029
>> function timer_start: 118 - counted ticks is 1780
>>
>>
>> Branislav Repček napsal(a):
>>
>>> Zdravim,
>>>
>>> ja som mal tiez tento problem a vyriesil som ho tak, ze som si
>>> "napisal" makro, ktore robi 64 bitove delenie za mna.
>>>
>>> longdiv.h:
>>>
>>> #ifndef LONGDIV_H
>>> #define LONGDIV_H
>>>
>>> #include "types.h"
>>>
>>> #define do_div64_32(res, high, low, base) ({ \
>>> unsigned long __quot32, __mod32; \
>>> unsigned long __cf, __tmp, __tmp2, __i; \
>>> \
>>> __asm__(".set push\n\t" \
>>> ".set noat\n\t" \
>>> ".set noreorder\n\t" \
>>
>>> "move %2, $0\n\t" \
>>
>>> "move %3, $0\n\t" \
>>
>>> "b 1f\n\t" \
>>
>>> " li %4, 0x21\n" \
>>
>>> "0:\n\t" \
>>
>>> "sll $1, %0, 0x1\n\t" \
>>
>>> "srl %3, %0, 0x1f\n\t" \
>>
>>> "or %0, $1, %5\n\t" \
>>
>>> "sll %1, %1, 0x1\n\t" \
>>
>>> "sll %2, %2, 0x1\n" \
>>
>>> "1:\n\t" \
>>
>>> "bnez %3, 2f\n\t" \
>>
>>> " sltu %5, %0, %z6\n\t" \
>>
>>> "bnez %5, 3f\n" \
>>
>>> "2:\n\t" \
>>
>>> " addiu %4, %4, -1\n\t" \
>>
>>> "subu %0, %0, %z6\n\t" \
>>
>>> "addiu %2, %2, 1\n" \
>>
>>> "3:\n\t" \
>>
>>> "bnez %4, 0b\n\t" \
>>
>>> " srl %5, %1, 0x1f\n\t" \
>>
>>> ".set pop" \
>>
>>> : "=&r" (__mod32), "=&r" (__tmp), \
>>
>>> "=&r" (__quot32), "=&r" (__cf), \
>>
>>> "=&r" (__i), "=&r" (__tmp2) \
>>
>>> : "Jr" (base), "0" (high), "1" (low)); \
>>
>>> \
>>
>>> (res) = __quot32; \
>>
>>> __mod32; })
>>
>>>
>>
>>> #define do_div(n, base) ({ \
>>
>>> unsigned long long __quot; \
>>
>>> unsigned long __mod; \
>>
>>> unsigned long long __div; \
>>
>>> unsigned long __upper, __low, __high, __base; \
>>
>>> \
>>
>>> __div = (n); \
>>
>>> __base = (base); \
>>
>>> \
>>
>>> __high = __div >> 32; \
>>
>>> __low = __div; \
>>
>>> __upper = __high; \
>>
>>> \
>>
>>> if (__high) \
>>
>>> __asm__("divu $0, %z2, %z3" \
>>
>>> : "=h" (__upper), "=l" (__high) \
>>
>>> : "Jr" (__high), "Jr" (__base) \
>>
>>> : "$0"); \
>>
>>> \
>>
>>> __mod = do_div64_32(__low, __upper, __low, __base); \
>>
>>> \
>>
>>> __quot = __high; \
>>
>>> __quot = __quot << 32 | __low; \
>>
>>> (n) = __quot; \
>>
>>> __mod; })
>>
>>>
>>
>>> #endif
>>
>>>
>>
>>> Tento kod je prakticky cely prebraty z
>>> linux-2.6.23.1/include/asm-mips/div64.h a zatial mi funguje bez
>>> problemov...
>>>
>>> On Nov 3, 2007 2:33 PM, Zdeněk Doležal <zdenek.dolezal at gmail.com>
>>> wrote:
>>>> Ahoj,
>>>> nevim, zda je tohle stejny pripad jako nas, zkus make clean a
>>>> distclean a pak prolozit znovu. Delalo nam to podobnou chybu.
>>>>
>>>>
>>>> On 11/3/07, Josef Reidinger <josef.reidinger at seznam.cz> wrote:
>>>>> Ahoj,
>>>>> mam problem, ze pri prekladu deleni unsigned long long mi to pise
>>>>> .../prereq/timer.o: In function `timer_start'
>>>>> timer.c:(.text+0x4ac): undefined reference to `__udivdi3'
>>>>> timer.c:(.text+0x4ac): relocation truncated to fit: R_MIPS_26
>>>>> against
>>>>> `__udivdi3
>>>>>
>>>>> pri googleni mi to naslo, ze by to melo byt v nejaky knihovne
>>>>> /lib/libuuid.so.1 ale tu jsem nenasel a nejde mi slinkovat tedy
>>>>> kernel.
>>>>> Netusite nekdo cim by se to dalo opravit?
>>>>>
>>>> --
>>>> S pozdravem
>>>> Zdenek Dolezal
>>>
>>
> _______________________________________________
> OSy mailing list
> OSy at dsrg.mff.cuni.cz
> https://dsrg.mff.cuni.cz/mailman/listinfo/osy
More information about the NSWI004
mailing list