; Calcular la raíz cuadrada de un número de 32 bits ubicado
; en la dirección efectiva(offset) 0x300, poniendo el
; resultado de 16 bits en la dirección efectiva 0x304
; usando multiplicaciones y búsqueda binaria.
; Queremos que la subrutina esté ubicada a partir de la
; dirección lineal 0x50000 y el programa principal a
; partir de la dirección 0x20000.
; Compilar: nasm -f bin sqrt2.asm -o sqrt2.bin -l sqrt2.lst
RADICANDO          EQU 0x300    ; Definicion de constantes
RAIZ               EQU 0x304
SEL_PROG_PRINCIPAL EQU 0x2000
SEL_SUBRUTINA      EQU 0x5000
USE16

Inicio:
  ;Copiar programa principal
    mov ax,SEL_PROG_PRINCIPAL
    mov es,ax
    mov si,inicio_prog_principal  ;Puntero origen
    mov di,0                      ;Puntero destino
                                  ;Cantidad de bytes
    mov cx,fin_prog_principal - inicio_prog_principal
    rep cs movsb                  ;Efectuar copia
    
  ;Copiar subrutina
    mov ax,SEL_SUBRUTINA
    mov es,ax
    mov si,inicio_subrutina       ;Puntero origen
    mov di,0                      ;Puntero destino
                                  ;Cantidad de bytes
    mov cx,fin_subrutina - inicio_subrutina
    rep cs movsb                  ;Efectuar copia
    
    jmp SEL_PROG_PRINCIPAL:0
    
inicio_prog_principal:
    mov ax,0           ; Inicializar puntero de pila
    mov ss,ax          ; SS:SP.
    mov ds,ax          ; Inicializar segmento de datos.
    mov sp,0x8000
    mov eax,1000000    ; Hallar la raíz cuadrada
    mov [RADICANDO],eax ; de 1000000.
    call SEL_SUBRUTINA:0 ; Ejecutar la raíz cuadrada.
colgarse:
    jmp colgarse
fin_prog_principal:

inicio_subrutina:
raiz_cuadrada:
    mov ebx,[RADICANDO]
    mov si,0        ; Inicializar posible raíz cuadrada.
    cmp ebx,0       ; Si el radicando es cero,
    jz raiz_hallada ; la raíz cuadrada es cero.
    mov di,0x8000   ; Delta: Mitad del rango 0x0000-0xFFFF
                    ; de posibles raices cuadradas
ciclo_busqueda_binaria:
    xor eax,eax     ; Limpiar EAX.
    mov ax,si
    add ax,di       ; EAX <- SI + DI.
    mul eax         ; Elevar EAX al cuadrado.
                    ; EDX:EAX <- EAX * argumento MUL.
    cmp ebx,eax     ; Comparar radicando contra cuadrado
    jbe dividir_delta_por_2 ; Saltar si radicando <= cuadrado
    add si,di       ; Sumar delta a posible raíz.
dividir_delta_por_2:
    shr di,1        ; Dividir delta por 2 (shift right 1 bit).
    jnz ciclo_busqueda_binaria ;Volver si DI no es cero.
    inc si          ; El resultado quedó uno menos. Ajustar.
    xchg bx,bx   ;Magic breakpoint
raiz_hallada:    
    mov [RAIZ],si   ; Salvar resultado.
    retf            ; Fin de la subrutina.
fin_subrutina:    
	                ; Completar con ceros.	                
	times 0xFFF0-($-Inicio) db 0

Entrada:
	jmp Inicio-$$   ; Esta instrucción debe estar
                    ; en el offset 0xFFF0.	

                    ; Relleno hasta el final de la ROM
	times 16-($-Entrada) db 0
