floating point problem

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Locked
User avatar
accelleon
Member
Member
Posts: 28
Joined: Wed Jul 22, 2009 6:49 pm

floating point problem

Post 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?
Accel OS website.
Pimpanime-#1 source for English dubbed anime
Fanael
Member
Member
Posts: 38
Joined: Fri Oct 16, 2009 9:20 am

Re: floating point problem

Post 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.
User avatar
accelleon
Member
Member
Posts: 28
Joined: Wed Jul 22, 2009 6:49 pm

Re: floating point problem

Post 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()
Accel OS website.
Pimpanime-#1 source for English dubbed anime
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: floating point problem

Post 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)...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Albert
Posts: 5
Joined: Wed Nov 18, 2009 5:27 pm

Re: floating point problem

Post 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.
User avatar
accelleon
Member
Member
Posts: 28
Joined: Wed Jul 22, 2009 6:49 pm

Re: floating point problem

Post 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

Code: Select all

dword ptr [_cr4]
The code was from this wiki page.
Accel OS website.
Pimpanime-#1 source for English dubbed anime
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: floating point problem

Post 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)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Locked