diff --git a/codigo/advinha.asm b/codigo/advinha.asm new file mode 100644 index 0000000..8070c4b --- /dev/null +++ b/codigo/advinha.asm @@ -0,0 +1,252 @@ +;------------------------------------------------------------------------------ +; +; Programação em Baixo Nível (PBN) +;------------------------------------------------------------------------------ +; Projeto final de curso: advinha.asm +; Data: 23/08/2025 +; Autor: Daniel Ramos Gonçalves +; E-mail: daniel@drginfo.com.br +; Professor/Instrutor/Mentor: Blau Araujo (MUITO FERA) +; +; Proposta: Criar um programa em Assembly, jogo de advinhação. +; O programa deve gerar um número aleatório, e você deve advinhar. +; Entrar com um número inteiro entre 1 e 100. Deve ter críticas +; de Maior / Menor / Igual. Deve aceitar somente números, e qualquer +; entrada diferente deve ser decartada e encerrar o programa com +; uma mensagem de erro. +; +;------------------------------------------------------------------------------ + + +;------------------------------------------------------------------------------ +; difinições de pré-processamento padronizadas +;------------------------------------------------------------------------------ + +%define SYS_READ 0 +%define SYS_STDIN 0 +%define SYS_WRITE 1 +%define SYS_STDOUT 1 +%define SYS_TIME 201 +%define SYS_EXIT 60 +%define SYS_OK 0 +%define SYS_ERR 1 +%define BUF_SIZE 2048 +%define BUF_COUNT 5 + +;------------------------------------------------------------------------------ +section .rodata +;------------------------------------------------------------------------------ + + ; mensagens que serão exibidas na tela... + + msg_ini db "Digite um número entre 1 e 100: ", 0 + len_msg_ini equ $-msg_ini + + ; com a mensagem entre crases, ela aceita caracteres de controle como '\n' + + msg_maior db `Muito acima! Tente novamente...\n`, 0 + len_msg_maior equ $-msg_maior + + msg_menor db `Muito abaixo! Tente novamente...\n`, 0 + len_msg_menor equ $-msg_menor + + msg_ok_ini db "Você acertou com: ", 0 + len_msg_ok_ini equ $-msg_ok_ini + msg_ok_end db " Tentativas!", 10, 0 + len_msg_ok_end equ $-msg_ok_end + + ; mensagem de uso...caso não digite nada ou digitação inválida... + + msg_uso db "Você deve digitar um numero inteiro entre 1 e 100.", 10, 0 + len_msg_uso equ $-msg_uso + +;------------------------------------------------------------------------------ +section .bss + buffer resb BUF_SIZE + tentativas resb BUF_COUNT + +;------------------------------------------------------------------------------ +; seção do codigo em si... +;------------------------------------------------------------------------------ + +section .text + +global _start +_start: + +;------------------------------------------------------------------------------ +; gera um número inteiro randômico de 0..100 e salva resultado em r9 +; registradores: eax, edx, ebx, r9 +; resultado: r9 +;------------------------------------------------------------------------------ +_num_rand: + mov eax, SYS_TIME + mov edx, 0 + syscall + mov ebx, 100 + div ebx + add edx, 1 + mov r9d, edx + +;-------------------------------------------------------- +; rdi rsi rdx +; | | | +; syscall: i64 read(int fd, void *buf[.count], u64 size) +; | +; rax -> quantidade de bytes lidos (-1 = erro) +;-------------------------------------------------------- +_msg_ini: + mov rax, SYS_WRITE ; sys_write = 1 + mov rdi, SYS_STDOUT ; fd=1 (stdout) + mov rsi, msg_ini ; Mensagem Inicial + mov rdx, len_msg_ini ; Tamanho da mensagem + syscall + + mov rax, SYS_READ ; sys_read = 0 + mov rdi, SYS_STDIN ; fd=0 (stdin) + mov rsi, buffer ; buffer da leitura (armazenamento) + mov rdx, BUF_SIZE ; máximo caracteres a ler + syscall ; retorna quantidade de bytes lidos em rax + +;-------------------------------------------------------- +; conversão de string para inteiro... +; registradores: rax, rbx, rcx, r8 +;-------------------------------------------------------- +_convert_strtoint: + dec rax + mov byte [buffer + rax], 0 ; garante terminador nulo '\0' + mov rbx, 10 ; multiplicador (x10) + xor rcx, rcx ; contador = 0 + xor rax, rax ; resultados da conversão + +.digit_loop: + mov r8b, byte [buffer + rcx] ; caractere em buf[rcx] + cmp r8b, '0' ; caractere < 0x30? + jl _done ; se menor, termina + cmp r8b, '9' ; caractere > 0x39? + jg _done ; se maior, termina + sub r8b, 0x30 ; converte de ASCII para numero + mul rbx ; rdx:rax = rax * 10 (rbx = 10) + add rax, r8 ; armazena dígito em rax + inc rcx ; incrementa para receber o próximo byte + jmp .digit_loop + +;-------------------------------------------------------- +; conversão de inteiro para string... +; registradores: rax(int), rbx, rcx, r12, r15 +;-------------------------------------------------------- +_convert_inttostr: + mov rcx, tentativas ; buffer para receber o inteiro + mov rbx, 10 ; divisor + mov r12, 0 ; contador de dígitos + +.proximo_digito: + xor rdx, rdx ; limpa rdx para divisão + div rbx ; divide rdx:rax/rbx = rax / 10, resto em rdx + add rdx, '0' ; converte o resto(digito) para seu caracter ASCII + push rdx ; salva rdx na pilha + inc r12 ; incrementa contador de dígitos + + cmp rax, 0 ; verifica se o quociente é zero + jnz .proximo_digito ; se não, continua o loop + +.print_str: + cmp r12, 0 ; verifica se ainda há digitos para desempilhar + jz _str_final ; se não, pula para o final + + pop rax ; desempilha o caractere do dígito em rax + mov [rcx], al + inc rcx + dec r12 + jmp .print_str + +_str_final: + mov rsi, tentativas ; Endereço do buffer com a string + mov rdx, rcx ; Endereço do final da string + sub rdx, rsi ; Calcula o tamanho da string (final - início) + ret + +;-------------------------------------------------------------------- +; compara o numero digitado que está em 'rax' com o numero gerado +; pelo systema 'random' 'r9' ( rax < r9 ?) +;-------------------------------------------------------------------- +_compara: + cmp rax, 0 ; se rax == 0, erro + je _exit_err ; pula para saida de erro + cmp rax, 0x64 ; se maior que 100, erro + ja _exit_err ; pula para saida de erro + cmp rax, r9 ; compara os numeros + je .igual ; se for igual, pula para '.igual' + jb .menor ; se for menor pula para '.menor' + ja .maior ; se for mais alto pula para '.maior' + +.menor: + mov rsi, msg_menor + mov rdx, len_msg_menor + call _print + call _msg_ini + +.maior: + mov rsi, msg_maior + mov rdx, len_msg_maior + call _print + call _msg_ini + +.igual: + ; primeira parte da mensagem... + mov rsi, msg_ok_ini + mov rdx, len_msg_ok_ini + call _print + + ; quantidade de tentativas... + mov rax, r15 ; copia qtd tentativas para rax + mov rsi, tentativas ; buffer de tentativas + call _convert_inttostr + call _print + + ; final da mensagem... + mov rsi, msg_ok_end + mov rdx, len_msg_ok_end + call _print + call _exit_ok + +_done: + inc r15 ; incrementa contador + jmp _compara + +;---------------------------------------------------- +; Imprime a mensagem na saída padrão STD_OUT FD = 1 +;---------------------------------------------------- +_print: + mov rax, SYS_WRITE + mov rdi, SYS_STDOUT + syscall + ret + +;---------------------------------------------------- +; Imprime a mensagem na saída padrão se acertou +;---------------------------------------------------- +;_print_ok: + ; mov rax, SYS_WRITE + ; mov rdi, r15 + ; syscall + ;jmp _exit_ok + +;-------------------------------------------------------- +; saída em caso de erro... +;-------------------------------------------------------- +_exit_err: + mov rsi, msg_uso + mov rdx, len_msg_uso + call _print + mov rax, SYS_EXIT + mov rdi, SYS_ERR + syscall + +;-------------------------------------------------------- +; saída em caso de sucesso... +;-------------------------------------------------------- +_exit_ok: + mov rax, SYS_EXIT + mov rdi, SYS_OK + syscall