venerdì 1 febbraio 2013

Mandelbrot in Assembler

Premettendo che niente del codice che segue e' frutto del mio lavoro ho raccolto (prima che si perdano) un po' di sorgenti per generare l'insieme di Mandelbrot in Assembler x86
Questa era una attivita' tipica del DOS quando si poteva avere accesso diretto in scrittura sulla memoria della VGA...con i nuovi sistemi operativi tale approccio e' sostanzialmente impossibile



i compilatori sono vari (TASM, FASM) e si vede anche la differenza tra la presenza e l'assenza del coprocessore matematico (che nei primi processori x86 era opzionale)

Listato 1
--------------------------------

; Mandelbrot Set - fasm example program

; requires FPU

 org 100h

 mov ax,13h
 int 10h
 push 0A000h
 pop es

 mov dx,3C8h
 xor al,al
 out dx,al
 inc dl
 mov cx,64
    vga_palette:
 out dx,al
 out dx,al
 out dx,al
 inc al
 loop vga_palette

 xor di,di
 xor dx,dx
 finit
 fld [y_top]
 fstp [y]
screen:
 xor bx,bx
 fld [x_left]
 fstp [x]
   row:
 finit
 fldz
 fldz
 mov cx,63
    iterate:
 fld st0
 fmul st0,st0
 fxch st1
 fmul st0,st2
 fadd st0,st0
 fxch st2
 fmul st0,st0
 fsubp st1,st0
 fxch st1
 fadd [y]
 fxch st1
 fadd [x]
 fld st1
 fmul st0,st0
 fld st1
 fmul st0,st0
 faddp st1,st0
 fsqrt
 fistp [i]
 cmp [i],2
 ja over
 loop iterate
    over:
 mov al,cl
 stosb
 fld [x]
 fadd [x_step]
 fstp [x]
 inc bx
 cmp bx,320
 jb row
 fld [y]
 fsub [y_step]
 fstp [y]
 inc dx
 cmp dx,200
 jb screen

 xor ah,ah
 int 16h
 mov ax,3
 int 10h
 int 20h

x_left dd -2.2
y_top dd 1.25

x_step dd 0.009375
y_step dd 0.0125

x dd ?
y dd ?

i dw ?

--------------------------------

Listato 2
--------------------------------
;value: EAX - sentinella (max. TIEFE, min. 0)
PUBLIC rechnePunkt_
rechnePunkt_ PROC NEAR
TIEFE EQU DWORD PTR [EBP + 24]
CI_S EQU QWORD PTR [EBP + 16]
CR_S EQU QWORD PTR [EBP + 8]

push ebp
mov ebp, esp

fld CI_S
fstp ci
fld CR_S
fstp cr

push ecx
mov ecx, TIEFE

; CoProzessorstack einrichten
fldZ ; z.r = 0
fldZ ; z.i = 0
fldZ ; z.r^2 = 0
fldZ ; z.i^2 = 0

l1:
;Jetzt: st(0) - (z.i)^2
; st(1) - (z.r)^2
; st(2) - z.i
; st(3) - z.r

fsubp st(1),st ; z.r^2 - z.i^2
fadd cr ; z.r^2 - z.i^2 + c.r
fstp st(3)

fmulp st(1),st ; z.r * z.i
fadd st,st ; 2 * z.r * z.i
fadd ci ; 2 * z.r * z.i + c.i

;Ora : st(0) - new z.i = z.i
; st(1) - new z.r = z.r

fld st(1) ; z.r
fmul st,st ; z.r^2
fld st(1) ; z.i
fmul st,st ; z.i^2

fld st(1) ; z.r^2
fadd st,st(1) ; z.r^2 + z.i^2

fcomp grenze ; st = zabs2, < 4.0 ?

;Ora : st(0) - (z.i)^2 (confronta con occupazione in l1:)
; st(1) - (z.r)^2
; st(2) - z.i
; st(3) - z.r

fstsw ax
sahf
jae ende ;quanso st >= 4.0 -> vai a ende

dec ecx ;piu' veloce di un ciclo
jnz l1

ende: ffree st(3)
ffree st(2)
ffree st(1)
ffree st

mov eax, TIEFE
sub eax, ecx

pop ecx

mov esp, ebp
pop ebp
ret 20

rechnePunkt_ ENDP

_TEXT ENDS

--------------------------------

Listato 3
--------------------------------
; Mandelbrot found in the FIDO-Net. Very nice.
org 100h
start: mov ax,13h
int 10h ; set 320x200 256 color mode
mov ax,0a000h
mov ds,ax ; load ds with video segment
xor di,di ; zero out screen offset
mov bp,-200 ; load y with -(screen height)
l1: mov si,-320 ; load x with -(screen width)
l2: push di ; save screen offset
xor bx,bx ; val1 = 0
xor di,di ; val2 = 0
l3: push bx
lea ax,[bx+di] ; ax = val1 + val2
sub bx,di ; bx = val1 - val2
imul bx ; ans = val1^2 - val2^2
mov bl,ah
mov bh,dl
lea bx,[bx+si-64] ; val1 = (ans/256) + x - 64
pop ax
imul di ; ans = val1 * val2
mov al,ah
mov ah,dl
add ax,ax
xchg ax,di
lea di,[bp+di-56] ; val2 = (ans/128) + y - 56
cmp bh,4
jg draw ; if val1 > 1024 then draw point
inc cl ; increment color
jne l3
draw: pop di ; restore screen offset
xchg [di],cl ; store color, and make color = 0
inc di ; increment screen offset
inc si ; increment x
jne l2 ; if x <> 0 then continue lp2
inc bp ; increment y
jne l1 ; if y <> 0 then continue lp1
xor ax,ax
int 16h
mov ax,3
int 10h ; set text mode
ret ; exit program

--------------------------------