assembly - instruction - instrucciones x86
Asamblea, impresión del número de ASCII (4)
Algo así funcionaría mejor para imprimir un valor decimal (el nuevo código está en minúscula):
mov byte [buffer+9],''$''
lea si,[buffer+9]
MOV AX,CX ;CX = VALUE THAT I WANT TO CONVERT
MOV BX,10
ASC2:
mov dx,0 ; clear dx prior to dividing dx:ax by bx
DIV BX ;DIV AX/10
ADD DX,48 ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER
dec si ; store characters in reverse order
mov [si],dl
CMP AX,0
JZ EXTT ;IF AX=0, END OF THE PROCEDURE
JMP ASC2 ;ELSE REPEAT
EXTT:
mov ah,9 ; print string
mov dx,si
int 21h
RET
buffer: resb 10
En lugar de imprimir cada carácter directamente, agrega los caracteres a un búfer en orden inverso. Para el valor 123 agregaría ''3'' en el búfer [8], ''2'' en el búfer [7] y ''1'' en el búfer [6] - por lo que si imprime la cadena que comienza en el búfer + 6 obtendrá "123 ".
Estoy usando la sintaxis de NASM, pero espero que sea lo suficientemente clara.
Tengo un problema con mi código de ensamblaje. Quiero imprimir el número almacenado en el registro cx, pero cuando traté de imprimirlo, imprimí el carácter ascii en lugar del número ascii, así que decidí escribir un procedimiento para convertir ascii char en valor ascii. El problema es que cuando intento llamar a ese procedimiento, el programa se congela y tengo que reiniciar dosbox. ¿Alguien sabe qué está mal con este código? Gracias.
P4 PROC
MOV AX,CX ;CX = VALUE THAT I WANT TO CONVERT
MOV BX,10
ASC2:
DIV BX ;DIV AX/10
ADD DX,48 ;ADD 48 TO REMAINDER TO GET ASCII CHARACTER OF NUMBER
PUSH AX ;SAVE AX
MOV AH,2 ;PRINT REMAINDER STORED IN DX
INT 21H ;INTERRUP
POP AX ;POP AX BACK
CMP AX,0
JZ EXTT ;IF AX=0, END OF THE PROCEDURE
JMP ASC2 ;ELSE REPEAT
EXTT:
RET
P4 ENDP
Como Michael ha escrito en su código, debe borrar DX, es decir, hacerlo 0 antes de dividir.
Pero si me preguntas, si solo necesitas mostrar un número en el formulario ASCII (no obtener una carita sonriente cuando quieres que se muestre un número). Convertir el valor a ASCII internamente puede ser bastante inconveniente.
¿Por qué no utiliza una matriz definida al comienzo del programa que tiene todos los valores ASCII de los números y elige la que corresponde?
por ej. DB arr ''0123456789''
y compare cada número con la posición particular e imprima esa. Ha pasado mucho tiempo desde que codifiqué en 8086, pero recuerdo que utilicé esta lógica para un programa que requería que imprimiera un valor ASCII de un número hexadecimal. Así que utilicé una matriz que tenía 0123456789ABCDEF
y funcionó perfectamente.
Solo mis dos centavos. Como solo querías el resultado. realmente no importa cómo lo calcule.
Pensé que debería publicar una actualización de esto. Esta publicación realmente me ayudó a buscar una forma de obtener información clave para los scripts CLI de PHP. No pude encontrar una solución Windows / DOS en ninguna parte, así que opté por un programa externo.
Estoy usando una versión realmente antigua del ensamblador a86, por lo que el código es bastante básico.
(¿y cómo desactivo "Ejecutar fragmento de código"?)
;Key input for scripts that can use some "shell" function.
;Waits for a keypress then returns a string "key:scan"
;if "key" is 0 then you can check "scan" for arrow keys
;or other non-ASCII keys this way.
mov ah,0
int 16h
push ax
mov ah,0
mov cx,ax
call ASC
mov dx,'':''
call COUT
pop ax
shr ax,8
mov ah,0
mov cx,ax
call ASC
jp EXIT
COUT:
mov ah,2
int 21h
ret
STROUT:
mov ah,9
mov dx,si
int 21h
ret
ASC:
mov byte [buffer+9],''$''
lea si,[buffer+9]
mov ax,cx
mov bx,10
ASC_LOOP:
mov dx,0
div bx
add dx,48
dec si
mov [si],dl
cmp ax,0
jz STROUT
jmp ASC_LOOP
EXIT:
mov ah,4ch
int 21h
ret
buffer: db " " ; 10 spaces. no "resb" in my assembler.
Un script PHP de muestra para probarlo en:
<?php
function getKey() {
return shell_exec("getkey.com");
}
print "Press [ESC] to exit./n/n";
$key = "";
while (ord($key) != 27) {
$getch = explode(":",getKey());
$key = chr($getch[0]);
$scan = $getch[1];
if (ord($key) != 0) {
print $key;
} else {
print "SCAN:$scan/n";
}
}
?>
Es cierto que después de todo lo dicho y hecho me di cuenta de que podría haber hecho lo mismo en C ++. Pero aprendí mucho más sobre ASM esta vez.
Así que gracias de nuevo amigos!
Aquí está el código bien probado para imprimir el número
.186
.model SMALL
.STACK 100h
.data
HelloMessage db ''Hello World'', 13, 10, ''$''
SuperNumber dw 13565
.code
; Writes word number from AX to output
; Usage
; .186
; ....
; mov ax, 13444
; call PRINT_NUMBER
PRINT_NUMBER PROC NEAR ; Outputs integer word number stored in AX registry. Requires CPU
; Save state of registers.
PUSHA ; Save all general purpose registers
PUSH BP ; We''re going to change that.
; we need variables
; word number; 2 bytes
; byte digitsCount; 1 byte
; reserving space for variables on stack (3 bytes)
mov bp, sp; ; bp := address of the top of a stack
sub sp, 3*8 ; allocate 3 bytes on stack. Addresses of variables will be
; number: WORD PTR [rbp - 2*8]
; digitsCount: BYTE PTR [rbp - 3*8]
; Getting digits
; number = ax;
; digitsCount = 0;
; do
; {
; push number%10;
; digitsCount++;
; number = number / 10;
; }
; while (number > 0)
mov WORD PTR [bp - 2*8], ax ; number = ax;
mov BYTE PTR [bp - 3*8], 0 ; digitsCount = 0;
getDigits: ; do
mov ax, WORD PTR [bp - 2*8]; number/10: ax = number / 10, dx: number % 10
;cwd
mov dx, 0
mov bx, 10
div bx
push dx ; push number%10
mov WORD PTR[bp - 2*8], ax; number = number/10;
inc byte PTR[bp - 3*8] ; digitsCount++;
cmp WORD PTR[bp - 2*8], 0; compare number and 0
je getDigitsEnd ; if number == 0 goto getDigitsEnd
jmp getDigits ; goto getDigits;
getDigitsEnd:
mov ah, 9
mov dx, offset HelloMessage
int 21h
;while (digitsCount > 0)
;{
; pop digit into ax
; print digit
; digitsCount--;
;}
printDigits:
cmp BYTE PTR[bp - 3*8], 0; compare digits count and 0
je printDigitsEnd ; if digitsCount == 0 goto printDigitsEnd
pop ax ; pop digit into al
add al, 30h ; get character from digit into al
mov ah, 0eh ; wanna print digit!
int 10h ; BIOS, do it!
dec BYTE PTR[bp - 3*8] ; digitsCount--
jmp printDigits ; goto printDigits
printDigitsEnd:
; Deallocate local variables back.
mov sp, bp
; Restore state of registers in reverse order.
POP BP
POPA
; Exit from procedure.
RET
PRINT_NUMBER ENDP
start:
mov ax, @data
mov ds, ax
mov ah, 9
mov dx, offset HelloMessage
int 21h
mov ax, 64454
call Print_Number
mov ah, 4ch
int 21h
end start