Page 1 of 1
floating point problem
Posted: Wed Dec 09, 2009 12:21 am
by accelleon
Hi, everyone. Whenever i try to divide floating point numbers bochs raises:
math_abort: MSDOS compatibility FPU exception
i tried enabling cr0.ne using this code:
Code: Select all
__asm {
mov eax, cr0
or eax, 16 //supposed to set bit 5 don't know if i did that right
mov cr0, eax
}
but when bochs does a register dump cr0 bit 5 isn't set and it still raises that exception.
cr0.em isn't set and i don't have multitasking yet so cr0.ts is never set.
I think the code that causes the problem is:
Code: Select all
void _cdecl vga_drawline(int x1, int y1, int x2, int y2, byte color)
{
int dx,dy,sdx,sdy,px,py,dxabs,dyabs,i;
float slope;
dy=y2-y1;
dx=x2-x1;
dyabs=abs(dy);
dxabs=abs(dx);
sdy=sgn(dy);
sdx=sgn(dx);
if(dxabs>=dyabs)
{
[b]slope=(float)dy/(float)dx;[/b]
for(i=0;i!=dx;i+=sdx)
{
px=i+x1;
py=slope*i+y1;
vga_plotpixle(px,py,color);
}
}
else
{
[b]slope=(float)dx / (float)dy;[/b]
for(i=0;i!=dy;i+=sdy)
{
px=slope*i+x1;
py=i+y1;
vga_plotpixle(px,py,color);
}
}
}
(the code that is bold is my guess)
I know that it's that function because if i comment that function out it works perfectly.
Any ideas?
Re: floating point problem
Posted: Wed Dec 09, 2009 1:28 am
by Fanael
Bit 5 is 32.
Use Bresenham's algorithm or fixed-point DDA, they don't use floating point arithmetic and are usually faster.
Re: floating point problem
Posted: Wed Dec 09, 2009 1:49 am
by accelleon
No more exception but it still freezes. Yea i wanted a basic working vga driver (im not too far away) that's why i wanted to start as basic as possible then make my code faster/better.
Edit: Yea that works but im still wondering why my floats wouldn't work?
Edit 2: Btw do you happen to know a replacement for this vga_drawcircle() function:
Code: Select all
void vga_drawcircle(int x,int y, int radius, byte color)
{
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1;
word dxoffset,dyoffset,offset = (y<<8)+(y<<6)+x;
while (dx<=dy)
{
dxoffset = (dx<<8) + (dx<<6);
dyoffset = (dy<<8) + (dy<<6);
VGA[offset+dy-dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-dy-dxoffset] = color; /* octant 3 */
VGA[offset-dy+dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+dy+dxoffset] = color; /* octant 7 */
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}
It relies on floats and doesn't work just like vga_drawline()
Re: floating point problem
Posted: Wed Dec 09, 2009 4:11 am
by Combuster
things for floating point support:
- check the FPU bit in CPUID
- write the EM, NE, and TS bits in CR0 with sane values
- initialize the fpu
- install the two FPU exception handlers
- make damn sure you correctly backup your floating point state on switches to and from userland.
I suspect that of the 5 points, you did only one (and barely half of it)...
Re: floating point problem
Posted: Wed Dec 09, 2009 2:15 pm
by Albert
accelleon wrote:No more exception but it still freezes. Yea i wanted a basic working vga driver (im not too far away) that's why i wanted to start as basic as possible then make my code faster/better.
Edit: Yea that works but im still wondering why my floats wouldn't work?
Edit 2: Btw do you happen to know a replacement for this vga_drawcircle() function:
Code: Select all
void vga_drawcircle(int x,int y, int radius, byte color)
{
fixed16_16 n=0,invradius=(1/(float)radius)*0x10000L;
int dx=0,dy=radius-1;
word dxoffset,dyoffset,offset = (y<<8)+(y<<6)+x;
while (dx<=dy)
{
dxoffset = (dx<<8) + (dx<<6);
dyoffset = (dy<<8) + (dy<<6);
VGA[offset+dy-dxoffset] = color; /* octant 0 */
VGA[offset+dx-dyoffset] = color; /* octant 1 */
VGA[offset-dx-dyoffset] = color; /* octant 2 */
VGA[offset-dy-dxoffset] = color; /* octant 3 */
VGA[offset-dy+dxoffset] = color; /* octant 4 */
VGA[offset-dx+dyoffset] = color; /* octant 5 */
VGA[offset+dx+dyoffset] = color; /* octant 6 */
VGA[offset+dy+dxoffset] = color; /* octant 7 */
dx++;
n+=invradius;
dy = (int)((radius * SIN_ACOS[(int)(n>>6)]) >> 16);
}
}
It relies on floats and doesn't work just like vga_drawline()
I don't have the whole algorithm on me at the moment but you can derive it fairly easily
Assume center is at 0,0 and radius r. The equation is x² + y² = r². Initial conditions are y=r
Plot the 8 pixels like you are now and increase x.
Decrease y if (x+1)² + y² > r²
Stop when x >= y
An example with r=6
Draw 0,6. 1+36 > 36 goto 1,5
Draw 1,5. 4+25 < 36
Draw 2,5. 9+25 < 36
Draw 3,5. 16+25 > 36 goto 4,4
Draw 4,4. x=y stop
This algorithm, as-is tends to give a more compressed circle since it plots pixels whose center falls inside the theoretical line. You can adjust it to plot the pixels that the theoretical line passes through by changing the decrease condition like so:
x² + y² > (r+0.5)² which can be approximated by x² + y² > r² + r
This would plot (0,6) (1,6) (2,6) (3,5) (4,5) (5,4 (note that this pixel is partially redundant since it will also be plotted by the y,x segment, but you can't do anything about it)) for the above example.
Re: floating point problem
Posted: Wed Dec 09, 2009 6:03 pm
by accelleon
Albert, the algorithm worked. And Combuster mind helping me on 2 and 3 or pointing me to a nice tut. I won't need to worry about 5 for a while.
Edit: I have the following code for initializing the fpu:
Code: Select all
int fpu_init()
{
if(!fpu_check())
return 0;
size_t _cr4;
[b]__asm mov dword ptr [_cr4], cr4[/b]
_cr4 |= 0x200;
[b]__asm mov cr4, dword ptr [_cr4][/b]
__asm finit
fpu_setcw(0x37F);
return 1;
}
But it doesn't compile(error lines are bolded).
Can I read/write to cr4 from inline asm, or is it having a fit because I'm using
The code was from this
wiki page.
Re: floating point problem
Posted: Thu Dec 10, 2009 2:20 am
by Combuster
accelleon wrote:And Combuster mind helping me on 2 and 3 or pointing me to a nice tut.
Do a bit of your own homework first - those five topics are good entry points into the Intel Manuals.
Just as you should not just randomly alter source code without knowing what you are doing. (look up those opcodes in, yes again, the intel manuals)