Arvorezinha – MIPS Assembly
Ora viva amigos!
Depois do grande sucesso que foi o post da Arvorezinha em x86 assembly, fiquei sempre com ela fisgada para fazer isso em outros tipos de processador diferentes. Hoje finalmente consegui, fiz exactamente o mesmo programa inútil mas em mips assembly em IRIX.
Tinham me falado ja nao sei onde, de um simulador de mips para windows, o PCSpim instalei isso e comecei a ver como funcionava a cena, em poucas horas consegui ter a arvorezinha a funcionar naquilo.
# this asm can never fail # # arvorezinha - spim mips asm # # * # ** # *** # **** # ***** # .data estrela: .asciiz "*" newline: .byte 0xa .text .globl main main: la $s0,5 # numero total estrelas la $s1,0 # s1 = 0 - counter1 _ciclo1: beq $s1,$s0,_fim # se s1 = s0 -> _fim la $s2,0 # s2 = 0 - counter2 _ciclo2: beq $s1,$s2,_estrela # se s1 = s2 -> estrela slt $t0,$s2,$s1 # se s1 < s2 entao t0 = 1 li $t1,1 # t1 = 1 para a comparacao do branch seguinte beq $t0,$t1,_estrela # se o r0 = 1 (t1) -> _estrela li $v0,4 # printa se um newline la $a0,newline syscall add $t0,$s1,$t1 # t0 = s1 (counter1) + t1 (1) move $s1,$t0 # s1 = t0, actualiza counter1 b _ciclo1 # volta ao _ciclo1 _estrela: li $v0,4 # printa se um asterisco la $a0, estrela syscall li $t1,1 # t1 = 1 para a soma seguinte add $t0,$s2,$t1 # t0 = s2 (counter2) + t1 (1) move $s2,$t0 # $s2 = t0 , actualiza counter2 b _ciclo2 # volta ao ciclo2 _fim: jr $ra # sai
O funcionamento dos mips é bues de diferente do que o x86, primeiro tens um molho de registos, e alguns deles mantêm-se após syscalls mas outros não. E depois não existem os jumps condicionais pipis tipo jle e afins que dão muita jeito, tem que se arranjar outra forma de fazer a coisa.
Ontem às tantas da noite andei a chatear o mirage para me dar acesso ao mips dele, mas já sem efeito! Hoje quando acordei já tinha acesso e pus me a ver como eram os syscalls em IRIX assembly. Passei o código para o formato do as da cena, o "SGI MIPSpro assembler". Mas não estava correr algo tudo bem ao inicio, estava a levar com altos floods de asteriscos, andei lá as voltas com o gdb e lá descobri que era um registo temporário que estava a ser usado para o add, que era alterado quando fazia o syscall do sys_write, corrigi isso e ficou a funcionar!
#include <regdef.h> .data estrela: .asciiz "*" newline: .byte 0xa .text .globl main .ent main main: la s0,5 # numero total estrelas la s1,0 # s1 = 0 - counter1 .end main .ent _ciclo1 _ciclo1: beq s1,s0,_fim # se s1 = s0 -> _fim la s2,0 # s2 = 0 - counter2 .end _ciclo1 .ent _ciclo2 _ciclo2: beq s1,s2,_estrela # se s1 = s2 -> estrela slt t0,s2,s1 # se s1 < s2 entao t0 = 1 li t1,1 # t1 = 1 para a comparacao do branch seguinte beq t0,t1,_estrela # se o r0 = 1 (t1) -> _estrela li a0,1 # primeiro argumento pro write() - 1 = stdout la a1,newline # segundo argumento pro write() - endereco da str li a2,1 # terceiro argumento - numero de bytes a escrever li v0,0x000003EC syscall li t1,1 # para a soma seguinte add t0,s1,t1 # t0 = s1 (counter1) + t1 (1) move s1,t0 # s1 = t0, actualiza counter1 b _ciclo1 # volta ao _ciclo1 .end _ciclo2 .ent _estrela _estrela: li a0,1 # primeiro argumento pro write() - 1 = stdout la a1,estrela # segundo argumento pro write() - endereco da str li a2,1 # terceiro argumento - numero de bytes a escrever li v0,0x000003EC syscall li t1,1 # t1 = 1 para a soma seguinte add t0,s2,t1 # t0 = s2 (counter2) + t1 (1) move s2,t0 # $s2 = t0 , actualiza counter2 b _ciclo2 # volta ao ciclo2 .end _estrela .ent _fim
Exemplo:
$ uname -a IRIX kessel 6.5 01090133 IP32 mips $ make as arvorezinha.s -o arvorezinha.o gcc arvorezinha.o -o arvorezinha $ ./arvorezinha * ** *** **** ***** $
Confirmo que funciona! Venha outra arch!
És o maior pa! Juro-te que me dás tusa