hi everyone
I hope you can help me with converting some c code into assembly code, i have tried much now, and i still don't get it.
i'm new to programming ASM
this c code gets two number from the user to draw an ellipse

#include<stdio.h>
	#include<graphics.h>
	#include<math.h>
	#include<dos.h>
	void main()
    	{
    	long d1,d2;
    	long rx,ry,rxsq,rysq,tworxsq,tworysq,dx,dy;
    	int gd=DETECT,gm,x,y;
    	clrscr();
    	printf("enter x radius of the ellipse(20)");
    	scanf("%ld",&rx);
    	printf("enter y radius of the ellipse(40)");
    	scanf("%ld",&ry);
    	initgraph(&gd,&gm,"");
		
    	rxsq=rx*rx;
    	rysq=ry*ry;
    	tworxsq=2*rxsq;
    	tworysq=2*rysq;
    	x=0;
    	y=ry;
    	d1=rysq-rxsq*ry+(0.25*rxsq);
    	dx=tworysq*x;
    	dy=tworxsq*y;


        	do{
        	putpixel(200+x,200+y,15);
        	putpixel(200-x,200-y,15);
        	putpixel(200+x,200-y,15);
        	putpixel(200-x,200+y,15);		
        	if(d1<0)
            	{
            	x=x+1;
            	y=y;
            	dx=dx+tworysq;
            	d1=d1+dx+rysq;
            	}
            	else
                	{
                	x=x+1;
                	y=y-1;
                	dx=dx+tworysq;
                	dy=dy-tworxsq;
                	d1=d1+dx-dy+rysq;
                	}
                	delay(200);
                	}
                	while(dx<dy); // in dige yani chi ?
                	d2=rysq*(x+0.5)*(x+0.5)+rxsq*(y-1)*(y-1)-rxsq*rysq;
                    	do{
                    	putpixel(200+x,200+y,15);
                    	putpixel(200-x,200-y,15);
                    	putpixel(200+x,200-y,15);
                    	putpixel(200-x,200+y,15);
                        	if(d2>0){
                        	x=x;
                        	y=y-1;
                        	dy=dy-tworxsq;
                        	d2=d2-dy+rxsq;
                        	}
                        	else


                            	{
                            	x=x+1;
                            	y=y-1;
                            	dy=dy-tworxsq;
                            	dx=dx+tworysq;
                            	d2=d2+dx-dy+rxsq;
                            	}
                            	}
                            	while(y>0);
                            	getch();
                            	}

my asm code

putpix macro x,y
    mov cx,x
    mov dx,y
    mov ah,0ch
    mov al,9
    int 10h 
endm    
           
init macro
 mov al,13h
 mov ah,0
 int 10h 
endm     
    
.model small
.stack 128
.data  
d1 dw 0
d2 dw 0   
rx dw 0
ry dw 0
rxsq dw 0
rysq dw 0
tworxsq dw 0
tworysq dw 0
x dw 0
y dw 0 
dxx dw 0
dyy dw 0    
km1 dw 0
km2 dw 0 
km3 dw 0
two dw 2 
four dw 4

.code
 main proc far
 mov ax,@data
 mov ds,ax    
 init
 mov rx,30
 mov ry,10
 
 mov ax,rx
 mul ax
 mov rxsq,ax
 
 mov ax,ry
 mul ax
 mov rysq,ax
            
 mov ax,rxsq
 mul two
 mov tworxsq,ax
 
 mov ax,rysq
 mul two
 mov tworysq,ax
 
 mov x,0 
 mov bx,ry
 mov y,bx         
 ;----- 
 ;d1=rysq-rxsq*ry+(0.25*rxsq)
 ;4d1=4rysq-4rxsq*ry+(rxsq);
 ;
 mov ax,rysq
 mul four
 mov cx,ax
 ;
 mov ax,rxsq
 mul ry
 mul four
 mov bx,ax
 ; 
 sub cx,bx
 add cx,rxsq
 ;
 mov ax,cx
 div four
 mov d1,ax
 ;-----
 mov ax,rxsq
 mul two
 mov dxx,ax
 mov ax,rysq
 mul two
 mov dyy,ax
 ;***loop1
 lw1:cmp dxx,ax
 jge endw1
 ;200+x
  mov bx,x
  add bx,200
  ;200+y
  mov cx,y
  add cx,200 
  putpix bx,cx
  ;200-x
  mov bx,x
  sub bx,200
  neg bx
  ;200-y
  mov cx,y
  sub cx,200
  neg cx      
  putpix bx,cx
  ;200+x   
  mov bx,x
  add bx,200
  ;200-y
  mov cx,y
  sub cx,200
  neg cx
  putpix bx,cx
  ;200-x 
  mov bx,x
  sub bx,200
  neg bx
  ;200+y 
  mov cx,y
  add cx,200 
  putpix bx,cx  
 cmp d1,0
 jge else1   
 inc x
 mov bx,tworysq
 add dxx,bx
 mov bx,rysq
 add d1,bx    
 jmp ifexit1
 else1:
 inc x
 dec y          
 mov bx,tworysq
 add dxx,bx
 mov bx,tworxsq
 sub dyy,bx                               
 ;d1=d1+dx-dy+rysq;
 mov bx,dxx
 sub bx,dyy
 add bx,rysq
 add d1,bx 
 ifexit1:
mov cx,09999h
l12:
loop l12
 jmp lw1
  endw1:     
  ;d2=rysq*(x+0.5)*(x+0.5)+rxsq*(y-1)*(y-1)-rxsq*rysq;
  ;4d2=rysq*(2x+1)*(2x+1)+4rxsq*(y-1)*(y-1)-4rxsq*rysq;
  ;4d2=km1+km2+km3
  ;km1   
  mov ax,x
  mul two
  add ax,1
  mul ax
  mul rysq
  mov km1,ax
  ;km2
  mov ax,y
  dec ax
  mul ax
  mul rxsq
  mul four
  mov km2,ax
  ;km3
  mov ax,rxsq
  mul ax
  mul four
  mov km3,ax
  
  mov ax,km1
  add ax,km2
  add ax,km3
  div four
  mov d2,ax
  
  ;***loop2
  lw2:
  cmp y,0
  jle endw2
  ;200+x
  mov bx,x
  add bx,200
  ;200+y
  mov cx,y
  add cx,200 
  putpix bx,cx  
  ;200-x
  mov bx,x
  sub bx,200
  neg bx
  ;200-y
  mov cx,y
  sub cx,200
  neg cx      
  putpix bx,cx
  ;200+x   
  mov bx,x
  add bx,200
  ;200-y
  mov cx,y
  sub cx,200
  neg cx
  putpix bx,cx
  ;200-x 
  mov bx,x
  sub bx,200
  neg bx
  ;200+y 
  mov cx,y
  add cx,200 
  putpix bx,cx  
  
  cmp d2,0 
  jle else2
  dec y           
  mov bx,tworxsq
  sub dyy,bx
  ;d2=d2-dy+rxsq;
  mov bx,rxsq
  add bx,dyy
  sub d2,bx  
  jmp ifexit2
  else2:   
  inc x
  dec y
  mov bx,tworxsq
  sub y,bx
  add dx,tworysq
  ;d2=d2+dx-dy+rxsq;
  mov bx,dxx
  add bx,rxsq
  sub bx,dyy
  sub d2,dx  
  ifexit2:
  jmp lw2
  endw2:
  getch:mov ah,0
        int 16h          
 mov ah,4ch
 int 21h
 
main endp
end main

Recommended Answers

All 16 Replies

Looks like you're trying to do a deviation of the Bresenham DDA algorithm. Is this a class assignment or a personal or work project?

This is a big function. One method is to dump the assembly code generated by the compiler to get some ideas.

It also looks like you're not trying to write this for speed! You're stalling the processor almost all the time!

Interesting thing about a DDA algorithm, it uses a binary base in conjunction with increment/decrement. Rework your C code to be closer in appearance to the assembly!

How volatile is the putpixel() function? If X,Y are preserved then no need to move from memory to registers for each pixel. Just modify the displacement!

Years ago I wrote a graphics driver for drawing lines, circles, etc. With the Bresenham DDA algorithm but using self modifying code for fastest speed! If you're using an older pre Pentium computer you should be able to do the same. But one step at a time.

Okay, reformating your code while typing this have noticed a few things in the c code! Shouldn't y=y not be there? And It looks like your error correction is d1 ? (e) might be more familiar here!

Stop mixing floating-point with your integer code. Not
*0.25 instead >>2

You're dealing with integers...

d1 = rysq - rxsq*ry + (0.25*rxsq);
should be more like
d1 = rysq - rxsq*ry + (rxsq >>2);


DO NOT...
mul 4
Do a shift

shl ax,2

much much faster!!!

div 4
asr ax,2

Your operations such as...

mov bx,x
sub bx,200
neg bx

...is WRONG!
- ( x - 200)
See the problem!
Instead use something like the following!


Store your 200 in a register, interlace the +/- x/y math then process.

mov	si,200		; Center X axis
	mov	di,200		; Center Y axis

	mov	bx,si		; +x +y
	mov	cx,di
	add	bx,x
	add	cx,y
	putpix bx,cx

	mov	bx,si		; -x -y
	mov	cx,di
	sub	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; +x -y
	mov	cx,di
	add	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; -x +y
	mov	cx,di
	sub	bx,x
	add	cx,y
	putpix	bx,cx

My question is, why are you still using fossil-ware?
I mean, how many Gigs of (processor speed, memory, hard disk) do you have?

A whole football field to play in, and you're still scribbling on the back of an old envelope.

thank you Mr wildgoose for your reply
i fix some errors
i fix putmix macro
and i use shift operation instead of mul
and fixed some other things like x=x & y=y but still doesn't work

putpix macro x,y
  mov ax,0A000h
  mov es,ax        ;{es = $A000}
  mov ax,y
  shl ax,6
  mov bx,ax        ;{bx = y * 64}
  shl ax,1
  shl ax,1         ;{ax = y * 256}
  add bx,ax        ;{bx = y * 320}
  add bx,x         ;{bx = y * 320 + x}
  mov al,9    ;{load color}
  mov es:[bx],al   ;{set point}
endm    
           
init macro
 mov al,13h
 mov ah,0
 int 10h 
endm     
    
.model small
.stack 128
.data  
d1 dw 0
d2 dw 0   
rx dw 0
ry dw 0
rxsq dw 0
rysq dw 0
tworxsq dw 0
tworysq dw 0
x dw 0
y dw 0 
dxx dw 0
dyy dw 0    
km1 dw 0
km2 dw 0 
km3 dw 0
two dw 2 
four dw 4

.code
 main proc far
 mov ax,@data
 mov ds,ax    
 init
 mov rx,30
 mov ry,10

 mov ax,rx
 mul ax
 mov rxsq,ax
 
 mov ax,ry
 mul ax
 mov rysq,ax
 
 ;    	tworxsq=2*rxsq;
 ;   	tworysq=2*rysq;           
 mov ax,rxsq
 shl ax,1
 mov tworxsq,ax

 mov ax,rysq
 shl ax,1
 mov tworysq,ax
    	;x=0;
    	;y=ry; 
 mov x,0 
 mov bx,ry
 mov y,bx         
 ;----- 
 ;d1=rysq-rxsq*ry+(0.25*rxsq)
 ;d1=rysq-rxsq*ry+(rxsq>>4);
 ;
 mov bx,rxsq
 shr bx,2
 add bx,rysq
 
 mov ax,rxsq
 mul ry
 sub ax,bx
 neg ax
 mov d1,ax
 ;-----
 ;dx=tworysq*x;    	
 mov ax,tworysq
 mul x
 mov dxx,ax
 ;dy=tworxsq*y;
 mov ax,tworxsq
 mul y
 mov dyy,ax 
 ;***loop1
 lw1:cmp dxx,ax
 jge endw1
 	mov	si,200		; Center X axis
	mov	di,200		; Center Y axis
	mov	bx,si		; +x +y
	mov	cx,di
	add	bx,x
	add	cx,y
	putpix bx,cx

	mov	bx,si		; -x -y
	mov	cx,di
	sub	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; +x -y
	mov	cx,di
	add	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; -x +y
	mov	cx,di
	sub	bx,x
	add	cx,y
	putpix	bx,cx 
 cmp d1,0
 jge else1   
  ;y=y; ???
  mov y,y
 inc x
 mov bx,tworysq
 add dxx,bx
 mov bx,rysq
 add d1,bx    
 jmp ifexit1
 else1:
 inc x
 dec y          
 mov bx,tworysq
 add dxx,bx
 mov bx,tworxsq
 sub dyy,bx                               
 ;d1=d1+dx-dy+rysq;
 mov bx,dxx
 sub bx,dyy
 add bx,rysq
 add d1,bx 
 ifexit1:
mov cx,09999h
l12:
loop l12
 jmp lw1
  endw1:     
  ;d2=rysq*(x+0.5)*(x+0.5)+rxsq*(y-1)*(y-1)-rxsq*rysq;
  ;d2=rysq*(x+0.5)*(x+0.5)+rxsq*(y-1)*(y-1)-rxsq*rysq;
  ;4d2=rysq*(2x+1)*(2x+1)+4rxsq*(y-1)*(y-1)-4rxsq*rysq;
  ;4d2=km1+km2+km3
  ;km1   
  mov ax,x
  mul two
  add ax,1
  mul ax
  mul rysq
  mov km1,ax
  ;km2
  mov ax,y
  dec ax
  mul ax
  mul rxsq
  mul four
  mov km2,ax
  ;km3
  mov ax,rxsq
  mul ax
  mul four
  mov km3,ax  
  mov ax,km1
  add ax,km2
  add ax,km3
  div four
  mov d2,ax  
  ;***loop2
  lw2:
  cmp y,0
  jle endw2  
   	mov	si,200		; Center X axis
	mov	di,200		; Center Y axis
	mov	bx,si		; +x +y
	mov	cx,di
	add	bx,x
	add	cx,y
	putpix bx,cx

	mov	bx,si		; -x -y
	mov	cx,di
	sub	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; +x -y
	mov	cx,di
	add	bx,x
	sub	cx,y
	putpix	bx,cx

	mov	bx,si		; -x +y
	mov	cx,di
	sub	bx,x
	add	cx,y
	putpix	bx,cx    
  cmp d2,0 
  jle else2
  dec y           
  mov bx,tworxsq
  sub dyy,bx
  ;d2=d2-dy+rxsq;  
  mov bx,dyy
  sub bx,rxsq ;
  neg bx
  add d2,bx
  jmp ifexit2
  else2:   
  inc x
  dec y
  mov bx,tworxsq
  sub y,bx
  add dx,tworysq
  ;d2=d2+dx-dy+rxsq;
  mov bx,dxx
  add bx,rxsq
  sub bx,dyy
  add d2,dx  
  ifexit2:
  jmp lw2
  endw2:
  getch:mov ah,0
        int 16h          
 mov ah,4ch
 int 21h 
main endp
end main

Of course it doesn't work. You were suppose to analyze what I did, review your code, and single-step, etc. and make appropriate changes! One typically doesn't learn by being handed the answer. They typically need to be nudged into the correct direction so they can hopefully find the answer themselves!

Did you analyze what putpix does? If you had you would have seen that it uses bx for the offset calculation for the 256 color pixel write. You were using the BIOS call before, but now you are writing directly to memory.

What two registers are you passing in? AND what registers are pixel write using?

What processor are you using? This may be 16-bit 8086 code but are you running on a modern day Pentium type or an old 8086 through 80486? If a newer computer then using the old shifting for the multiplication is a mistake! On the older processors multiple shifts waas MUCH faster then a multiply. But on the newer processors it is quite the reverse of that!

I don't like heavy macros like you're using because of this kind of mistake. YOU DO NOT NEED TO KEEP RESETTING ES to the Video segment!!! You aren't using it anywhere else, so set it at your code initialization, and not in the write for each pixel!

Second, You aren't calling a function to plot each pixel so why are you using real X and real Y for each pixel write?

How many bytes in a stride? # of pixels for one pixel row? According to your own code 320. You use an anchor point each time.

so once you calculate your starting position (anchor point of elipse).
(+x) gets right edge -(x*2) gets left edge
(+y) gets bottom edge -(y*2) gets top edge.

Once you get this working post again, there are multitudes of optimizations you can do!

My question is, why are you still using fossil-ware?
I mean, how many Gigs of (processor speed, memory, hard disk) do you have?

A whole football field to play in, and you're still scribbling on the back of an old envelope.

this is my class assignment and i don't know why should i learn
i have no plan to develope an os or write the driver of the graphic card
i know with assembly we can crack applications through disAsm..
personaly i use c# and java to earn money
thank you Mr wildgoose for commenting

There is nothing wrong with starting with basic Assembly Language.
How are you coming with the rework?

finally i find a source that draws an ellipse!
but i have a problem when i try to tasm it please help
http://img2.pict.com/5c/e0/0d/1348515/0/untitled.gif

.MODEL small
.DATA

;	Draws an ellipse using Floating point arithmetic

X_centre	EQU	[si]		;Centre of the ellipse
Y_centre	EQU	[si+2]		;
A		EQU	word ptr [si+4]	;Ellipse 1/2 width
B		EQU	word ptr [si+6]	;Ellipse 1/2 height
colour		EQU	byte ptr [si+8]	;Colour attribute
plotadot	EQU	[si+14]		;Address of the pixel plotting routine

X_offset	dw	?		;X distance from ellipse centre
Y_offset	dw	?		;Y	"	"	"
temp		dw	?		;Scratch variable
;-------------------------------------------------------------------------------
.CODE
	PUBLIC	ellipse
;-----------------------------------------------;
; Plot the ellipse defined by the equation	;
;						;
;	X**2/A**2 + Y**2/B**2 = 1		;
;						;
; Where, 2A is the ellipse width and B is the	;
;	ellipse height. A is > B		;	
;						;
; Entry:	si = address of parameter block	;
;		es = Address of video memory	;
;-----------------------------------------------;

ellipse	proc	uses	ax bx cx dx

	mov	al,colour

;	1st plot the pixels at the extremities of the ellipse

	mov	cx,X_centre
	mov	dx,Y_centre
	add	dx,B			;Add on the ellipse 1/2 height

	call	plotadot		;Top pixel located above centre location

	mov	dx,Y_centre
	sub	dx,B			;Subtract the ellipse 1/2 height

	call	plotadot		;Bottom pixel located below the centre

	add	cx,A			;Add the ellipse 1/2 width
	mov	dx,Y_centre

	call	plotadot		;Rightmost pixel

	mov	cx,X_centre
	sub	cx,A			;Subtract the ellipse 1/2 width
	
	call	plotadot		;Leftmost pixel

;	Calculate the Y coordinates corresponding to all positions X from centre

	mov	cx,A			;Set loop index to ellipse 1/2 width 
	dec	cx			;Don't need to do the extreme positions
eloop:	push	cx			;Save the loop index
	
	mov	temp,cx			;Get the X position
	fild	temp
	fimul	temp			;st=X**2
	fild	A			;st=A,st(1)=X**2
	fimul	A			;st=A**2,st(1)=X**2

	fdiv				;st=X**2/A**2
	fld1				;st=1, st(1)=X**2/A**2
	fsubr				;st = 1 - X**2/A**2
	fsqrt				;st = SQRT(1-X**2/A**2)
	fimul	B			;st = B*SQRT(1-X**2/A**2)
	fistp	y_offset

	mov	dx,Y_offset
	mov	X_offset,cx		;Take a copy of the X offset
	mov	cx,X_centre
	add	cx,X_offset

	mov	dx,Y_centre
	add	dx,Y_offset

	call	plotadot		;X_centre+X_offset, Y_centre+Y_offset

	mov	dx,Y_centre
	sub	dx,Y_offset
	
	call	plotadot		;X_centre+X_offset, Y_centre-Y_offset

	mov	cx,X_centre
	sub	cx,X_offset
	
	call	plotadot		;X_centre-X_offset, Y_centre-Y_offset

	mov	dx,Y_centre
	add	dx,Y_offset
	
	call	plotadot		;X_centre_X_offset, Y_centre+Y_offset

skip:	pop	cx			;Restore the loop index
	loop	eloop

	ret
ellipse	endp
	end

http://img2.pict.com/5c/e0/0d/1348515/0/untitled.gif

USES is typically a MASM thing and its about register preservation. I don't use TASM but you can remove the uses line, and merely push bx yourself. AX, CX, DX are typically scratch but BX is preserved thus make sure it gets pushed, and then popped.

The version of TASM you are using is DOS based and thus 16-bit (REAL MODE), same as the code. I'm assuming you've added other code to put the computer into graphics mode and calls this function. Also that you've created a plotadot function? You can easily rework this function to fit your application!

void ellipse( short cx, short cy,     // center of ellipse
             short width, short height,
             char color,          // 2 bytes ?
             short  pad[2],     // 4 bytes
             funcptr *plotadot   2 bytes
         );

Interesting. I don't see bx inuse, Most likely used by plotadot.

Too much heavy math for a DDA but kind of looks like a DDA. Will have to pick it apart to understand the math better!

This algorithm only deals with a fixed orientation of an ellipse but it uses the width for the stepping factor. Which means that if you set the width to half the height or thinner, you will see holes between pixels. Once you get this working you should modify the algorithm to use whichever is the longest, width or height as the stepping factor. It will replot some pixels but should be a consistent drawn line of pixels, and not a series of dotted pixels. And I'm guessing the reason the corners were painted separately is that the algorithm was not inclusive of its limits. [0,width) 0<=x<width not 0<=X<=width, thus they wouldn't have been plotted. But will have to analyze the math to know for sure!

So once you get this working, you should improve upon the algoithm to make your version your own. Since you did 'find' this version, you really should have posted credit to the original author, otherwise it really is plagiarism!

Yep! Heavy lifting in the math. And the math isn't even optimized!

Essentially ratio of the inverse of the (x / width) is applied to the y axis!

x / width ranges from (x, 0] just less then 1.0 and ranges down to 0.0 (1.0, 0.0]. (They start at ((x-1(/width) not x/width. Subtract that ratio from 1.0 and applies it to the Y axis scaling it (0.0, Y] from slightly more then 0 to Y (0.0, y].

It keeps pushing integer data onto the FPU stack and converting it to Extended-Double Precision Floating-Point, does the calculation in Floating-Point, and pops the answer off the stack while converting it to integer, which all takes time. Could pre-push then recycle most of what's on the FPU stack, but hardly worth it as it is an efficient algorithm. If the ratio of width < height gets large enough such as a ratio 1 : 2, gaps in the elipse start to appear.

Get your algorithm running but look into an ellipse based DDA algorithm. If you can't find one, look for a Bresenham DDA line. Essentially, Y/X the longer axis is used as the step, it uses a N^2 mechanism in integer with an error correction factor.

Then look into the Bresenham DDA circle. Pretty cool, draws a circle as octets, eight arcs at once!

If you modify the circle from octet to quad draw, and apply an adjusted error correction, you should get your DDA ellipse!

sorry i had no access to the internet for six days
Mr wildgoose thank you for the answer
you have accurate information about this language
i wonder what is your job or what was your job ? :)

that code belong's to this book
Graphics Programming using Assembly by Ron Thomas

Just a lowly software/hardware developer!

i can't understand what is the need to develope low level software/hardware

Do you carry a cell phone?
Do you own a microwave oven?
Do you have a game console?
Do you have a television set?
Do you own an automobile?
etcetera
There you go!

commented: That's where it's at :) +36

you learned me good things thank you :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.