Mais um blog inútil.

Arvorezinha

Abril 8, 2009

Arvorezinha em HASKELL

Arquivado em: arvorezinha, coding, useless — madinfo @ 11:43

Pois bem, depois de seguir atentamente os posts do falso com coisas completamente inúteis… Resolvi fazer a arvore em HASKELL.

Sem mais demoras aqui fica:

-- THIS HASKELL CODE CAN NEVER FAIL

module Main where

main = do putStr (unlines (take 5 (iterate('*':) "*")))
              putStrLn "2nd version:"
              putStr . unlines . take 5 . iterate ('*' :) $ "*" -- 2nd version

Como podem ver até é bem simples…

Podem instalar o compilador com:

sudo apt-get install ghc6sudo apt-get install haskell-mode

Compilar com:

ghc –make -O2 arvore.hs -o arvorehs

Ou mesmo utilizar o prelude que é bem fixe:

ghci

Versão optimizada por Ashes:

arvore n =  (take n (cycle ['*']))
arvorezinha n = putStr (unlines (map arvore [0..n]) )

Abril 7, 2009

Arvorezinha - Brainfuck

Arquivado em: arvorezinha — falso @ 23:29

Ola de novo!

Hoje fui desafiado a fazer a arvorezinha em brainfuck. Portanto aqui vai:

++++[>++++++++++<-]>++.>+++++++++++++.<<++[>.<-]>>.<<+++[>.<-]>>.<<++++[>.<-]>>.<<+++++[>.<-]>>.

Agora por blocos para gente normal entender:

Começa se no registo 0
++++ Define r0 a 4
[ - enquanto o registo actual não for 0, entra no ciclo

++++++++++ anda para o registo 1 e soma-lhe 10
< volta para o registo anterior r0, e retira-lhe 1
] repete ate r0 = 0
++ vai-se para o r1 e soma se 2 - e está o valor 42 (asterisco em ascii) no r1
. manda imprimir

+++++++++++++ Move-se para o registo 3 e incrementa-se 13 nele (newline)
. manda imprimir

E com isto já temos “*\n” feito… Continuando
< <++ voltamos a r0 e incrementamos 2, r0 = 2
[ se r0 != 0 entro

.< - move-se para o r1 e imprime *, volta para o r0 e decrementa
]». repete ate r0 igual a 0, e a seguir manda anda duas posicoes para a direita, vai parar a r3 e imprime uma newline.

Depois o resto é so repeticao

< <+++[>.< -]». tres asteriscos e um newline
< <++++[>.< -]». quatro asteriscos e um newline
< <+++++[>.< -]». cinco asteriscos e um newline

Eu acho que isto é uma maneira meio lame de fazer, porque os prints estão pré definidos. Tentei fazer o mesmo algoritmo que o do assembly, mas falhei miseravelmente. Ofereço um queijo a quem conseguir. Aproveita agora esta oportunidade de te tornares um homem de barba rija!!!

Podem testar o codigo neste Javascript Brainfuck Interpreter / Debugger online ou usar o magnifico Brainfuck developer.

Abril 5, 2009

Arvorezinha - Z80 Assembly

Arquivado em: arvorezinha, assembly — falso @ 23:26

Oi de novo! Como este fim de semana, foi mesmo daqueles bem passados na cave e não sabia o que fazer, entao fiz também a arvorezinha em z80 assembly, para o zx spectrum. O processador é mais ou menos parecido com ou 8085 mas com menos instruções. Este não foi muito difícil de fazer.

; this z80 assembly can never fail

org 32768

estrela: defb 0x2a
newline: defb 0xd
counter1: db 0x0
counter2: db 0x0

start:
	ld a, 2
	call $1601 ; inicializar o ecrã

_ciclo1:
	ld bc,(counter1) ; le o counter1 para bc (o valor fica em c)
	ld a,5
	cp c ; compara c com a
	jr z,_fim; se for igual sai
	ld a,0
	ld (counter2),a ; mete o counter2 a 0

_ciclo2:
	ld bc,(counter2) ; ve o valor de counter2 para c
	ld a,(counter1) ; valor de counter1 para a
	cp c ; compara c com a
	jr nc,_estrela ; se for menor -> estrela

	ld a,(newline)
	call _print ; printa um newline 

	ld a,(counter1) ; le counter1 para a
	add a,1 ;  incrementa a
	ld (counter1),a ; le a para counter1
	jr _ciclo1 ;  -> ciclo1

_estrela:
	ld a,(estrela)
	call _print ; printa um asterisco

	ld a,(counter2) ; le counter2 para a
	add a,1 ; incrementa a
	ld (counter2),a; le a para counter2
	jr _ciclo2 ; ->; ciclo2

_fim:
	ret ; volta ao basic

_print:
	rst 16 ; syscall(?) para escrever
	ret

arvorezinha.tap a correr num emulador

Download: arvorezinha.tap

Para compilar isto usei o software open sores z80asm e o bin2tap que converte o formato binario para um formato .tap que os emuladores suportam. Basta fazer “z80asm -o arvorezinha.bin arvorezinha.asm” e depois “bin2tap arvorezinha.bin arvorezinha.tap”.

Arvorezinha - MIPS Assembly Optimizada

Arquivado em: arvorezinha, assembly — falso @ 17:09

Ola de novo. Com ajuda do sir dongs, optimizei a arvorezinha em mips, e decidi vir blogar sobre isso.
As alterações foram as seguintes:
De:

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

Para:

>slt t0,s2,s1 # se s1 < s2 entao t0 = 1
bne t0, zero,_estrela # se o r0 ! 0 -> _estrela

Em vez de se verificar quando t1 é 1, compara-se t1 com o registo zero (que tem sempre o valor 0) quando não é igual a 0 é 1 entao, faz se o branch.De:

>li t1,1 # para a soma seguinte
add t0,s1,t1 # t0 = s1 (counter1) + t1 (1)
move s1,t0 # s1 = t0, actualiza counter1

Para:

addi s1, s1, 1

O dongs aqui novamente, deu me a conhecer a magia da instrução addi.
Depois disto, pensei que podia fazer uma função com o syscall do write, para não repetir duas vezes o código. Então fui descobrir como era um call, mas pelos vistos tal coisa não existe, o que há é a instrução jal “jump and link”, que faz o jump para o sitio devido, e mete o endereço para onde se deve voltar no registo $31 (ra), e para voltar basta um jr ra “jump register”.
Então adicionei o seguinte código:

.ent _print
_print:
        li a0, 1 # stdout
        li a2,1 # terceiro argumento - numero de bytes a escrever
        li v0,0x000003EC
        syscall
        jr ra
.end _print

E substitui:De:

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

Para:

la a1,newline # segundo argumento pro write() - endereco da str
jal _print

Até aqui tudo bem, corria, mas à saída dava segmentation fault. O problema é que ao inicio o registo ra tem o return address do que o que lhe executou. E ao executar a instrução jal, o ra é alterado, e depois à saida do programa quando se faz jr ra, o gajo já nao vai para onde era suposto e chora. Então adicionei logo no inicio do programa um move s8,ra que guarda o valor de ra no registo s8, e depois no final antes de sair faço o contrario move ra,s8 e assim o programa já sai sem drama.

O código completo:

#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
        move s8,ra # guarda o valor do return adress em s8
.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
        bne t0, zero,_estrela # se o r0 ! 0 -> _estrela

        la a1,newline # segundo argumento pro write() - endereco da str
        jal _print

        addi s1, s1, 1
        b _ciclo1 # volta ao _ciclo1
.end _ciclo2

.ent _estrela
_estrela:
        la a1,estrela # segundo argumento pro write() - endereco da str
        jal _print

        addi s2, s2, 1
        b _ciclo2 # volta ao ciclo2
.end _estrela

.ent _print
_print:
        li a0, 1 # stdout
        li a2,1 # terceiro argumento - numero de bytes a escrever
        li v0,0x000003EC
        syscall
        jr ra
.end _print

.ent _fim
_fim:
        move ra,s8 # volta a meter o ra em ra
        jr ra
.end _fim

Abril 4, 2009

Arvorezinha - MIPS Assembly

Arquivado em: arvorezinha, assembly — falso @ 18:33

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
*
**
***
****
*****
$

Janeiro 11, 2008

Arvorezinha

Arquivado em: arvorezinha, assembly — falso @ 01:00

O _intensdown_ no mirc disse que hoje tiveram a fazer na escola em VB um programinha que davam um certo valor, e o gajo desenhava estilo uma arvore em ascii. Por exemplo, dava o valor 5, e aquilo desenhava:

*
**
***
****
*****

Como ando ca pica toda do cracking do assembly e tal, tentei fazer isso em assembly, e aqui está o resultado de 3 horas de work:

;this asm can never fail

	section	.data
estrela db '*'
len equ $-estrela
newline db 0xa

final dd 5
counter1 dd 0
counter2 dd 5

	section	.text
global main			;must be declared for linker (ld)

main:					;tell linker entry point

_ciclo1:
	mov eax, [counter1]
	mov ebx, [final]
	cmp eax, ebx
	je _fim ; se o contador2 == final sai-se
	mov dword [counter2],0 ; mete o contador2 a 0

_ciclo2:
	mov eax,[counter2]
	cmp eax,[counter1]
	jle _estrela ; se o contador2 for menor que o 1 entao : estrelinha, senão é uma newline

	; newline
	mov edx,len
	mov ecx,newline
	mov	ebx,1	;file descriptor (stdout)
	mov	eax,4	;system call number (sys_write)
	int	0x80	;call kernel

	mov eax,[counter1]
	inc eax
	mov dword [counter1], eax ; incrementa o contador 1
	jmp _ciclo1

_estrela
	mov edx,len
	mov ecx,estrela
	mov	ebx,1	;file descriptor (stdout)
	mov	eax,4	;system call number (sys_write)
	int	0x80	;call kernel

	mov eax,[counter2]
	inc eax
	mov dword [counter2],eax ; incrmenta o contador 2
	jmp _ciclo2

_fim:
	mov	eax,1	;system call number (sys_exit)
	int	0x80	;call kernel
[bud@daemon tree]$ make
nasm -f elf -l tree2.lst tree2.asm
gcc -o tree tree2.o
[bud@daemon tree]$ ./tree
*
**
***
****
*****
[bud@daemon tree]$

Podem fazer download do sores aqui.