2

I was trying to draw a circle using 8086 assembler. I tried utilizing the midpoint circle algorithm which sadly resulted in drawing a tilted square for some reason (screenshots below). For reference, I rewrote the algorithm in python and managed to draw a circle without a problem.

I have a feeling that there is something wrong with my negative numbers manipulation but can't for the life of me figure it out because Turbo Debugger is telling me literally nothing. Could you guide me in the right direction? I enclose the code below:

; Program: graph.asm
.MODEL small
.STACK 256

.DATA

.CODE

jmp start
;=========================================
; Basic program to draw a circle
;=========================================
 mode db 18 ;640 x 480
 x_center dw 300
 y_center dw 200
 y_value dw 0
 x_value dw 100
 decision dw 1
 colour db 1 ;1=blue
;=========================================
start:
 mov ah,00 ;subfunction 0
 mov al,mode ;select mode 18 
 int 10h ;call graphics interrupt
;==========================
 mov bx, x_value
 sub decision, bx
 mov al,colour ;colour goes in al
 mov ah,0ch
 
drawcircle:
 mov al,colour ;colour goes in al
 mov ah,0ch
 
 mov cx, x_value ;Octonant 1
 add cx, x_center ;( x_value + x_center,  y_value + y_center)
 mov dx, y_value
 add dx, y_center
 int 10h
 
 mov cx, x_value ;Octonant 4
 neg cx
 add cx, x_center ;( -x_value + x_center,  y_value + y_center)
 int 10h
 
 mov cx, y_value ;Octonant 2
 add cx, x_center ;( y_value + x_center,  x_value + y_center)
 mov dx, x_value
 add dx, y_center
 int 10h
 
 mov cx, y_value ;Octonant 3
 neg cx
 add cx, x_center ;( -y_value + x_center,  x_value + y_center)
 int 10h
 
 mov cx, x_value ;Octonant 7
 add cx, x_center ;( x_value + x_center,  -y_value + y_center)
 mov dx, y_value
 neg dx
 add dx, y_center
 int 10h
 
 mov cx, x_value ;Octonant 5
 neg cx
 add cx, x_center ;( -x_value + x_center,  -y_value + y_center)
 int 10h

 mov cx, y_value ;Octonant 8
 add cx, x_center ;( y_value + x_center,  -x_value + y_center)
 mov dx, x_value
 neg dx
 add dx, y_center
 int 10h
 
 mov cx, y_value ;Octonant 6
 neg cx
 add cx, x_center ;( -y_value + x_center,  -x_value + y_center)
 int 10h
 
 inc y_value

condition1:
 cmp decision,0
 ja condition2
 mov cx, y_value
 mov ax, 2
 imul cx
 add cx, 1
 inc cx
 add decision, cx
 mov bx, y_value
 mov dx, x_value
 cmp bx, dx
 ja readkey
 jmp drawcircle

condition2:
 dec x_value
 mov cx, y_value
 sub cx, x_value
 mov ax, 2
 imul cx
 inc cx
 add decision, cx
 mov bx, y_value
 mov dx, x_value
 cmp bx, dx
 ja readkey
 jmp drawcircle


 
;==========================
readkey:
 mov ah,00
 int 16h ;wait for keypress
;==========================
endd:
 mov ah,00 ;again subfunc 0
 mov al,03 ;text mode 3
 int 10h ;call int
 mov ah,04ch
 mov al,00 ;end program normally
 int 21h 

END Start

Attempt in Assembler Attempt in Assembler Attempt in Python Attempt in Python

Thanks in advance for help!

Community
  • 1
  • 1
Devon
  • 55
  • 1
  • 2
  • 7
  • 1
    You drew an L1-norm circle instead of an L2-norm circle. I'm guessing your assembly implementation is not actually squaring the x and y values. –  Mar 01 '16 at 16:33
  • 2
    Well, but the wikipedia example in C ( https://en.wikipedia.org/wiki/Midpoint_circle_algorithm ) doesn't involve any squaring, does it? I haven't used any squaring in my Python implementation either and yet it works. – Devon Mar 01 '16 at 16:42
  • You're right, my mistake. Then it seems you're not actually multiplying. –  Mar 01 '16 at 16:44
  • 2
    `ja` is unsigned comparison, are you sure you didn't want `jg` instead? Not sure how the debugger isn't helping, you can single step your code and examine registers at each point. Compare with what values you expect and it should be trivial to spot the error? – Jester Mar 01 '16 at 16:46
  • 3
    You're right! The mistake was using `ja` instead of `jg` that's why the program never entered the first condition and thus screwed up the entire algorithm. And honestly I can't wrap my head around the debugger. Especially when it comes to signed numbers. I realize it probably is supper useful and sooner or later I'll have to start using it. – Devon Mar 01 '16 at 16:50

2 Answers2

0

the square which is your assembly code drew comes from equation :

|x| + |y| = constant 

This means your values are not getting squared

Lohitaksh Trehan
  • 304
  • 2
  • 12
  • Your answer seen unclear. Please extend your Answer by referring to [How do I write a good answer](https://stackoverflow.com/help/how-to-answer) – Teocci Apr 22 '17 at 07:54
0
   ; a short program to check how
; set and get pixel color works
name "pixel"
org  100h   
PUTC    MACRO   char
        PUSH    AX
        MOV     AL, char
        MOV     AH, 0Eh
        INT     10h     
        POP     AX
ENDM
;;;;;
; first and second number:
num1 dw ?
num2 dw ? 
num3 dw ?
start:
lea dx, msg1
mov ah, 09h    ; output string at ds:dx
int 21h  
; get the multi-digit signed number
; from the keyboard, and store
; the result in cx register:
call scan_num
; store first number:
mov num1, cx ;x coordinate
; new line:
putc 0Dh
putc 0Ah  
lea dx, msg2
mov ah, 09h
int 21h  
; get the multi-digit signed number
; from the keyboard, and store
; the result in cx register:
call scan_num
; store second number:
mov num2, cx  
putc 0Dh
putc 0Ah  
lea dx, msg3
mov ah, 09h
int 21h  
; get the multi-digit signed number
; from the keyboard, and store
; the result in cx register:
call scan_num
; store third number:
mov num3, cx 
mov si,num1 ;x coordinate
mov di,num2 ;y coordinate
mov bp,num3 ;radius
mov ah, 0   ; set display mode function.
mov al, 13h ; mode 13h = 320x200 pixels, 256 colors.
int 10h     ; set it!   
mov sp,0 ;center point
         ;radius
          ;first point
mov bx,1  ;(1-r) condition
sub bx,bp ;same as above  
jmp x1
x1:
cmp bx,0  ;condition compare 
JL condt1
jmp condt2
condt1:
            ;increment x by 1
add bx,1;value for P(k+1)
mov ax,2 
add sp,1
mul sp
add bx,ax 
cmp sp,bp
jae done
mov cx, sp ;1(x,y)
add cx,si  ; column
mov dx, bp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
; pause the screen for dos compatibility:  
mov cx, bp ;2(y,x)
add cx,si  ; column
mov dx, sp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
  ;3  (-x,-y)
mov ax,-1
mul sp
add ax,si
mov cx, ax ; column
mov ax,-1
mul bp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h 
;4  (-y,-x)
mov ax,-1
mul bp
add ax,si 
mov cx, ax ; column
mov ax,-1
mul sp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel  
int 10h  
mov cx, sp ;5(x,-y)
add cx,si  ; column
mov ax,-1
mul bp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
mov cx, bp ;6(y,-x)
add cx,si  ; column
mov ax,-1
mul sp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h 
;7  (-y,x)
mov ax,-1
mul bp
add ax,si 
mov cx, ax ; column
mov dx, sp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
;8(-x,y)
mov ax,-1
mul sp
add ax,si 
mov cx, ax ; column
mov dx, bp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
jmp x1
condt2: 
mov ax,2
sub bp,1
mul bp
sub bx,ax
mov ax,2
add sp,1
mul sp
add bx,ax
add bx,1 
cmp sp,bp
jae done
mov cx, sp ;1(x,y)
add cx,si  ; column
mov dx, bp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
; pause the screen for dos compatibility:  
mov cx, bp ;2(y,x)
add cx,si  ; column
mov dx, sp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
 ;3  (-x,-y)
mov ax,-1
mul sp
add ax,si
mov cx, ax ; column
mov ax,-1
mul bp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h 
;4  (-y,-x)
mov ax,-1
mul bp
add ax,si 
mov cx, ax ; column
mov ax,-1
mul sp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel  
int 10h  
mov cx, sp ;5(x,-y)
add cx,si  ; column
mov ax,-1
mul bp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
mov cx, bp ;6(y,-x)
add cx,si  ; column
mov ax,-1
mul sp
add ax,di
mov dx,ax  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h 
;7  (-y,x)
mov ax,-1
mul bp
add ax,si 
mov cx, ax ; column
mov dx, sp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
;8(-x,y)
mov ax,-1
mul sp
add ax,si 
mov cx, ax ; column
mov dx, bp
add dx,di  ; row
mov al, 15  ; white
mov ah, 0ch ; put pixel
int 10h
xor al, al  ; al = 0
mov cx, 10  ; column
mov dx, 20  ; row
mov ah, 0dh ; get pixel
int 10h
jmp x1
 done:    
int 20h
SCAN_NUM        PROC    NEAR
        PUSH    DX
        PUSH    AX
        PUSH    SI      
        MOV     CX, 0
        ; reset flag:
      MOV     CS:make_minus, 0
next_digit:
        ; get char from keyboard
        ; into AL:
        MOV     AH, 00h
        INT     16h
        ; and print it:
        MOV     AH, 0Eh
        INT     10h
        ; check for MINUS:
        CMP     AL, '-'
        JE      set_minus
        ; check for ENTER key:
        CMP     AL, 0Dh  ; carriage return?
        JNE     not_cr
        JMP     stop_input
not_cr:
        CMP     AL, 8                   ; 'BACKSPACE' pressed?
        JNE     backspace_checked
        MOV     DX, 0                   ; remove last digit by
        MOV     AX, CX                  ; division:
        DIV     CS:ten                  ; AX = DX:AX / 10 (DX-rem).
        MOV     CX, AX
        PUTC    ' '                     ; clear position.
        PUTC    8                       ; backspace again.
        JMP     next_digit
backspace_checked:
        ; allow only digits:
        CMP     AL, '0'
        JAE     ok_AE_0
        JMP     remove_not_digit
ok_AE_0:        
        CMP     AL, '9'
        JBE     ok_digit
remove_not_digit:       
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered not digit.
        PUTC    8       ; backspace again.        
        JMP     next_digit ; wait for next input.       
ok_digit:
        ; multiply CX by 10 (first time the result is zero)
        PUSH    AX
        MOV     AX, CX
        MUL     CS:ten                  ; DX:AX = AX*10
        MOV     CX, AX
       POP     AX
        ; check if the number is too big
        ; (result should be 16 bits)
        CMP     DX, 0
        JNE     too_big
        ; convert from ASCII code:
        SUB     AL, 30h
        ; add AL to CX:
        MOV     AH, 0
        MOV     DX, CX      ; backup, in case the result will be too big.
        ADD     CX, AX
        JC      too_big2    ; jump if the number is too big.
        JMP     next_digit
set_minus:
        MOV     CS:make_minus, 1
        JMP     next_digit
too_big2:
        MOV     CX, DX      ; restore the backuped value before add.
        MOV     DX, 0       ; DX was zero before backup!
too_big:
        MOV     AX, CX
        DIV     CS:ten  ; reverse last DX:AX = AX*10, make AX = DX:AX / 10
        MOV     CX, AX
        PUTC    8       ; backspace.
        PUTC    ' '     ; clear last entered digit.
        PUTC    8       ; backspace again.        
        JMP     next_digit ; wait for Enter/Backspace.     
     stop_input:
        ; check flag:
        CMP     CS:make_minus, 0
        JE      not_minus
        NEG     CX
not_minus:
        POP     SI
        POP     AX
        POP     DX
        RET
make_minus      DB      ?       ; used as a flag.
SCAN_NUM        ENDP 
msg1 db "enter x coordinate:  $" 
msg2 db "enter y coordinate:  $"
msg3 db "enter radius:  $"  
ten             DW      10    
ret
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Vibu Singh
  • 11
  • 2
  • 2
    This needs a lot of editing to make it readable – Michael Apr 06 '18 at 20:05
  • Why are you using inefficient `MOV CX, 0` in one part of the code, but `xor al, al` in another part? (Note that xor-zeroing has no advantage over `mov` for 8-bit registers, and [is actually worse on Haswell/Skylake](https://stackoverflow.com/questions/45660139/how-exactly-do-partial-registers-on-haswell-skylake-perform-writing-al-seems-to); if anything it should be the other way around, saving code-size with xor-zeroing for CX. You probably also don't need `cs:` segment overrides, if you use the `tiny` model for `.com` executables (`org 100h`), where CS=DS=ES=SS. – Peter Cordes Apr 06 '18 at 20:40
  • My code is based on mid point circle algorithm. – Vibu Singh Apr 06 '18 at 20:43