#!perl -w # (C) 2003 XDA Developers itsme@xs4all.nl # # $Header$ # use strict; use integer; $|=1; # todo: fix overflow handling: #fxpdiv(0x0400, 0x100, 12); printf(" wanted=%08lx\n", flp(0x400/0x1000, 0x100/0x1000, 12)); #fxpdiv(0x4000, 0x001, 12); printf(" wanted=%08lx\n", flp(0x4000/0x1000, 1/0x1000, 12)); if (0) { for (my $aa=-30000 ; $aa<30000 ; $aa+=1234) { for (my $bb=-30001 ; $bb<30000 ; $bb+=1234) { dotest($aa, $bb); } } } for my $aa ( -32768..-32766, -2..2, 32765..32767) { for my $bb ( -32768..-32766, -2..2, 32765..32767) { dotest($aa, $bb); } } exit(0); sub dotest { my ($aa, $bb)= @_; fxpdiv($aa, $bb, 12); printf(" wanted=%08lx\n", flp($aa, $bb, 12)); } sub flp { my ($r0, $r1, $r2)= @_; if ($r1==0) { return $r0<0 ? MININT() : MAXINT(); } if ($r0>MAXINT()) { $r0 -= FULLINT(); } if ($r1>MAXINT()) { $r1 -= FULLINT(); } if ($r0MAXINT()); return MININT() if ($val=0) { $r0= armlsl($r0, 1); $r2= armsub($r2, 1); } while (armtst($r1)>=0) { $r1= armlsl($r1, 1); $r2= armadd($r2, 1); } my $r6= 0; my $r7= 0; printf(" [%2d]", $r2); # I can generate an overflow here already if $r2>MAXBITS if (armtst($r2)<0) { $r0= 0; printf(" == %08lx UNDERFLOW", $r0); return $r0; } if ($r2>=16) { $r0= $r4?MININT:MAXINT; printf(" == %08lx OVERFLOW1", $r0); return $r0; } my $c; do { if ((armcmp($r0, $r1) || armcmp($r6, $r7))>=0) { ($c, $r0)= armsub($r0, $r1); ($c, $r6)= armsub($r6, $r7, $c); } else { $c= 0; } ($c, $r3)= armadd($r3, $r3, $c); if ($c) { $r0= $r4?MININT:MAXINT; printf(" == %08lx OVERFLOW2", $r0); return $r0; } ($c, $r1)= armlsr($r1, 1); $r7= armrrx($r7, $c); $r2= armsub($r2, 1); } while(armtst($r2)>=0); if (armtst($r3)<0) { $r0= $r4?MININT:MAXINT; printf(" == %08lx OVERFLOW3", $r0); return $r0; } if ($r4) { $r0= armsub(0, $r3); } else { $r0= $r3; } printf(" == %08lx", $r0); return $r0; } sub checkuint { my ($r0)= @_; my $c; if ($r0>=FULLINT) { $c= 1; $r0 -= FULLINT; } elsif ($r0<0) { $c= 1; $r0 += FULLINT; } else { $c= 0; } return ($c, $r0); } sub checksint { my ($r0)= @_; my $c; if ($r0>MAXINT) { $c= 1; $r0 -= FULLINT; } elsif ($r0MAXINT) { $r0 -= FULLINT; } return ($cnew, $r0); } sub armsub { my ($r0, $r1, $c)= @_; $c=1 if (!defined $c); ($c, $r0)= checkuint($r0-$r1+$c-1); return (1-$c, $r0); } sub armtst { my ($r0)= @_; if ($r0<0 || $r0>MAXINT) { return -1; } elsif ($r0==0) { return 0; } else { return 1; } } sub armxor { my ($r0, $r1)= @_; return ($r0 ^ $r1); }