Skip to content

Instantly share code, notes, and snippets.

@P4
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save P4/fc6ad03a657e25baf8e5 to your computer and use it in GitHub Desktop.
Save P4/fc6ad03a657e25baf8e5 to your computer and use it in GitHub Desktop.
Rysowanie krzywej Kocha: Generowanie przez LSystem, grafika żółwia
; Pawel Maniecki
; Asemblery, IET AGH
; Zadanie 3: Rysowanie krzywej Kocha
; Maksymalna liczba iteracji dla L-systemu: 6
; Maksymalna dlugosc odcinka: 100px
ITERMAX equ 6 ; Maksymalna ilosc iteracji ( nie wieksza od 6 )
; Dlugosc napisu opisujacego krzywa Kocha dla n iteracji dana jest wzorem
; K(n) = 7 * 4^n
; K(6) = 28672, K(7)=114688, rozmiar segmentu to 65536
KOCHSIZE equ 28672
TERM equ 0 ; znak konca stringu
.186 ; pusha, popa
.387 ; koprocesor
_Dane segment
; napis
string db KOCHSIZE dup(?) ; miejsce na LSystem
db ? ; miejsce na znak konca, w wypadku pelnego stringu
; Argumenty linii komend
argc db 0 ; ilosc argumentow ( dlugosc args )
args dw 10h dup(?) ; offsety na poczatki argumentow w argv
argv db 80h dup('$') ; wartosci argumentow rozdz $
; Parsowane argumenty
iternum db ?
len dw ?
db '$'
; Stale pomocnicze dla FPU
three dw 3
; wymiana (x,y) miedzy rejestrami, a FPU.
intx dw 20
inty dw 20
; ** Komunikaty bledow **
UsageMsg db "Uzycie: Koch ITERNUM LEN ",13,10,'$'
ArgumMsg db "Podano bledne argumenty.",13,10,'$'
IterMsg db "Liczba iteracji musi miescic sie w przedziale 0..6",13,10,'$'
LenMsg db "Podano niepoprawna dlugosc odcinka, maksymalnie 100",13,10,'$'
_Dane ends
_Kod segment
start:
; 0) Inicjowanie stosu
mov ax, seg wstosu
mov ss, ax
mov sp, offset wstosu
; 1) Wczytanie argumentow
; DS na segment kodu zaw PSP
call LoadArgs ; wypelnia (argc,args,argv) argumentami z DS:[80h]
; Teraz DS i ES na segment danych
mov ax, seg argv
mov ds, ax
mov es, ax
; 2) Weryfikacja argumentow
call ParseArgs ; konwertuje argumenty na iternum, len
; lub konczy program z komunikatem o bledzie
; 3) Generowanie napisu LSystemu
call LSystem
; tryb graficzny 320x200, 256 kolorow
mov ax,13
int 10h
; segment grafiki
mov ax, 0A000h
mov es, ax
call Prepare
call DrawString
; czekaj na dowolny klawisz
xor ax,ax
int 16h
; wyjscie z trybu graficznego
mov ax,3
int 10h
; 5) Wyjscie z programu
exit:
mov ax, 4C00h ; exit(0)
int 21h
; ** Procedury **
; *** Grafika ***
; Te metody celowo modyfikuja stan rejestrow miedzy wywolaniami. Zalecana ostroznosc
; Ustaw FPU w stan poczatkowy, przygotuj do rysowania
; Modyfikuje AX, oraz stos FPU
Prepare proc
; FPU (W nawiasach stan stosu)
finit ; inicjalizuj
fldpi ; load PI
; [ PI ]
fidiv word ptr ds:[three] ; dziel st(0) przez [mem], czyli 3
; [ PI/3 ]
fldz ; zaladuj zero, czyli kat fi
; [ fi=0, PI/3]
; zaladuj wspolrzedne poczatkowe (x0,y0)
fild word ptr ds:[inty]
fild word ptr ds:[intx]
; [ x=x0, y=y0, fi=0, PI/3 ]
; Przed rysowaniem
; Rysowanie przerwaniem 10h (funkcja 0Ch)
mov ah, 0Ch ; WRITE GRAPHICS PIXEL - ustaw kolor piksela
mov al, 0Fh ; Kolor - 15 to bialy
; BH = strona, w naszym trybie ignorowana, cala grafika miesci sie w segmencie
; CX,DX = (kolumna,wiersz) = (x,y)
RET
Prepare endp
; Rysuj LSystem na ekranie
; Modyfikuje SI, BL, posrednio CX, DX, DI, stos FPU (fi,x,y)
DrawString proc
mov si, offset string ; si na poczatek stringa
drawLoop:
mov bl,al ; zachowaj al
lodsb ; AL <= kod znaku z DS:SI, SI++
or al,al ; cmp al, TERM ; dla TERM = 0
jz drawEnd ; TERM konczy petle
; Switch(AL):
cmp al, '-'
je minus
cmp al, '+'
je plus
; al == 'F'
mov al,bl ; przywroc
call DrawLine
jmp drawLoop ; kolejny znak
minus:
mov al,bl
call RotMinus
jmp drawLoop
plus:
mov al,bl
call RotPlus
jmp drawLoop
drawEnd:
RET
DrawString endp
; W matematycznych biegunowych fi rosnie przeciwnie do wskazowek,
; Na ekranie os OY jest skierowana w dol, wiec fi rosnie zgodnie ze wskazowkami.
; Obrot o 60 stopni zgodnie z ruchem wskazowek
; Wymagane wywolanie Prepare przed ta funkcja
; Modyfikuje stos FPU (fi)
RotPlus proc
; [ x, y, fi, PI/3 ]
fxch st(2) ; x <=> fi
; [ fi, y, x, PI/3 ]
fadd st, st(3) ; fi += PI/3
fxch st(2) ; fi <=> x
; uklad oryginalny
RET
RotPlus endp
; Analogiczna operacja, przeciwnie do ruchu wskazowek
; Wymagane wywolanie Prepare przed ta funkcja
; Modyfikuje stos FPU (fi)
RotMinus proc
fxch st(2) ; x <=> fi
fsub st, st(3) ; fi -= PI/3
fxch st(2) ; fi <=> x
RET
RotMinus endp
; Rysuj linie dlugosci len
; Wymagane wywolanie Prepare przed ta funkcja
; Modyfikuje CX, DX, DI, stos FPU (x,y)
DrawLine proc
mov di, word ptr ds:[len] ; dlugosc linii do di
; oblicz sinus i cosinus
; [ x, y, fi, PI/3 ]
fld st(2)
; [ fi, x, y, fi, PI/3 ]
fsincos
; [ cos, sin, x, y, fi, pi/3 ]
fincstp ; obroc stosem st(0) na koniec, st(1) na wierzchu
fincstp
; [ x, y, fi, pi/3, ..., cos, sin ]
lineLoop:
or di,di
jz lineEnd
; [ x, y, fi, pi/3, ..., cos, sin ]
fadd st(0), st(6) ; x += cos(fi)
fist word ptr ds:[intx] ; nowy x do pamieci
fxch st(1) ; zamien st0 i st1 miejscami
; [ y, x, fi, pi/3, ..., cos, sin ]
fadd st(0), st(7) ; y += sin(fi)
fist word ptr ds:[inty] ; nowy y do pamieci
fwait ; synchronizuj CPU
fxch st(1) ; przywroc kolejnosc x,y
; [ x, y, fi, pi/3, ..., cos, sin ]
; pobierz wspolrzedne do rejestrow CPU
mov cx, word ptr ds:[intx]
mov dx, word ptr ds:[inty]
; nie rysuj poza ekranem
cmp cx, 320 - 1
ja skipdraw
cmp dx, 200 - 1
ja skipdraw
int 10h ; Zapisz pixel w kolorze AL do CX,DX; BH jest ignorowany
skipdraw:
dec di
jmp lineLoop
lineEnd:
; [ x, y, fi, pi/3, ..., cos, sin ]
ffree st(7) ; pozbadz sie sinusa i cosinusa
ffree st(6)
RET
DrawLine endp
; *** LSystem ***
; Generuje L-System o iternum iteracjach, zapisuje go do tablicy string
; Zaklada ze ES wskazuje na segment danych
LSystem proc
; LSystem sklada sie z bajtow + - F, konczy sie znakiem specjalnym
; Dla zera iteracji ma postac F++F++F
; Kazda iteracja dokonuje zamiany F = F-F++F-F
push ax
push cx
push dx
push di
xor cx,cx
mov cl, byte ptr ds:[iternum] ; CX <- liczba iteracji
mov di, offset string ; DI na poczatek stringu
; wartosci dla znakow
mov ah, 'F'
mov dl, '-'
mov dh, '+'
; napis poczatkowy
call kochstep ; F
mov al, dh
stosb ; +
stosb ; +
call kochstep ; F
mov al, dh
stosb ; +
stosb ; +
call kochstep ; F
; symbol konczacy
mov al, TERM
stosb
pop di
pop dx
pop cx
pop ax
RET
; rekurencyjne wykonanie podstawienia
kochstep:
jcxz stoprecursion ; CX == 0, warunek konca
dec cx ; wywolania rekurencyjne z (cx-1)
; F-F++F-F
call kochstep ; F
mov al, dl
stosb ; -
call kochstep ; F
mov al, dh
stosb ; +
stosb ; +
call kochstep ; F
mov al, dl
stosb ; -
call kochstep ; F
inc cx ; powrot
RET
stoprecursion:
; F
mov al, ah
stosb ; ES:[DI] <- AL, DI++
RET
LSystem endp
; Sprawdza poprawnosc i parsuje wczytane argumenty.
; DS powinien wskazywac na segment danych
ParseArgs proc
push ax
push bx
push cx
push dx
; Walidacja ilosci
call GetArgNum ; ax <- ilosc argumentow
cmp ax, 2 ; ITER oraz LEN
jne ArgError
; ITER
ITERMAX equ 6
xor dl,dl ; dl=0, zerowy argument
call GetArgLen ; ax <- dlugosc DL-tego argumentu
cmp ax,1 ; ITER w [0..ITERMAX], jednocyfrowy
jne IterError
call GetArgPos ; ax <- adres DL-tego argumentu
mov bx,ax
mov al, byte ptr ds:[bx] ; AL <- kod ascii znaku
sub al, '0' ; konwersja na liczbe, z porownaniem
jb IterError ; ITER < 0 niepoprawne
cmp al, ITERMAX
ja IterError ; ITER > ITERMAX
mov byte ptr ds:[iternum], al ; ITER -> iternum
; LEN
MAXLEN equ 100
inc dl ; dl=1
call GetArgLen ; ax <- dlugosc DL-tego argumentu
cmp ax,3 ; Len do 3 cyfr
ja LenError ; 4-cyfrowe niedopuszczalne
mov cx,ax ; zapisz dlugosc do iteracji
; Konwersja cyfr na liczbe
call GetArgPos ; ax <- adres poczatku argumentu
mov bx,ax
mov dl,10
xor ax,ax ; Wynik konwersji na liczbe
digitLoop:
mov dh, byte ptr ds:[bx] ; kod ascii cyfry do DH
sub dh, '0' ; konwersja na cyfre dziesietna z porownaniem
jb LenError ; znak nie byl cyfra
cmp dh, 9
ja LenError ; nie cyfra
mul dl ; Mnozenie bez znaku, AX = AL*DL
add al,dh ; Kolejna cyfra na koniec wyniku
adc ah,0 ; Dodajemy DH do AX, w dwoch czesciach
inc bx ; kolejna cyfra z pamieci
loop digitLoop ; powtarzanie CX razy
; Wynik konwersji w AX
cmp ax, MAXLEN ; koncowe sprawdzenie
ja LenError ; ax > MAXLEN, zle
mov word ptr ds:[len], ax ; len <- AX
;wyjscie z procedury
pop dx
pop cx
pop bx
pop ax
RET
; Obsluga bledow:
; Wyswietl komunikat i natychmiast wyjdz z programu
IterError:
mov dx, offset IterMsg
jmp ShowError
LenError:
mov dx, offset LenMsg
jmp ShowError
ArgError:
mov dx, offset ArgumMsg
;jmp ShowError
ShowError:
; odkomentowac jesli zmieniamy segment
;mov ax, seg ; segment wspolny dla wszystkich bledow
;mov ds, ax ; ustaw segment ds na bledy
; wypisanie bledu na ekran
mov ah, 9
int 21h
; wypisanie uzycia
mov dx, offset UsageMsg
;mov ah, 9
int 21h
; wyjscie
mov ax, 4C01h ; exit(1) zakoncz program
int 21h
ParseArgs endp
; LoadArgs -------------------------------------------------
; wczytaj argumenty z [80h] do struktury (argc,args,argv)
; wykorzystujac EatWS i CopyWord.
; przy wywolaniu rejestr DS powinien wskazywac na segment PSP
LoadArgs proc
pusha ; push AX, CX, DX, BX, SP, BP, SI, DI
xor cx,cx ; CX = 0
mov cl, byte ptr ds:[80h] ; cx na ilosc bajtow lini komend
mov si, 81h ; ds:[si] na poczatek bufora argumentow w PSP
mov ax, seg argv ;
mov es, ax ; es na segment danych
mov di, offset argv ; es:[di] na poczatek argv
iter:
call EatWS ; zmniejsz cx, zwieksz si
and cx,cx ; cmp cx,0
jz return ; Bufor byl pusty / zawieral same biale znaki
; dodaj nowy parametr do args
xor bh, bh ; Ustaw bx na
mov bl, byte ptr es:[argc] ; ilosc argumentow
shl bx, 1 ; bx *= 2, adresujemy word
mov word ptr es:[args+bx], di ; aktualne di jako adr tego parametru
inc byte ptr es:[argc] ; argc++
call CopyWord ; zmniejsz cx, zwieksz si+di
jmp iter
return:
popa ; odwrotnie do PUSHA, nie kopiuje SP, pomija go
ret
LoadArgs endp
;MAKRO: Jump if Equal -- jesli Reg ma wartosc Val, skocz do Label
jmpEq macro Reg, Val, Label
cmp Reg, Val
je Label
endm
; Eat WhiteSpace -------------------------
; przesun SI na pierwszy niebialy bajt
; zmienia: si, cx
EatWS proc
iter: ; wyjdz gdy bufor sie skonczyl
and cx,cx ; cx == 0 ?
jz return ; tak -> break
dec cx ; cx--
lodsb ; al = ds:[si] ; si++
; if ( bialy ) continue
jmpEq al, 20h, iter ; spacja
jmpEq al, 09h, iter ; \t tab
jmpEq al, 0Ah, iter ; \n line-feed
jmpEq al, 0Ch, iter ; \f form-feed
jmpEq al, 0Dh, iter ; \r carriage-return
; gdy niebialy:
inc cx ; "oddajemy" pobrany znak,
dec si ; cofajac sie w buforze
return:
ret
EatWS endp
; CopyWord --------------------------------------------------------
; kopiuj bajty z ds:[si] do es:[di], az do pierwszego bialego znaku
; przesun SI na pierwszy bialy, DI na miejsce na kolejny argument
; zmienia: si, di, cx
CopyWord proc
iter: ; wyjdz gdy bufor sie skonczyl
and cx,cx ; cx == 0 ?
jz return ; tak -> break
dec cx ; pobranie znaku:
lodsb ; al = ds:[si] ; si++
; if ( bialy ) break
jmpEq al, 20h, done ; spacja
jmpEq al, 09h, done ; \t tab
jmpEq al, 0Ah, done ; \n line-feed
jmpEq al, 0Ch, done ; \f form-feed
jmpEq al, 0Dh, done ; \r carriage-return
; gdy niebialy
stosb ; es:[di] = al, di++
jmp iter
done: ; petla trafila na bialy znak, koryguj indeksy
inc cx ; oddaj pobrany znak
dec si ; wroc w buforze
inc di ; zostaw 1 bajt (dolar) przerwy w argv
return:
ret
CopyWord endp
; Ponizsze procedury zakladaja, ze ds wskazuje na segment danych:
; GetArgNum --------------------
; zaladuj do AL ilosc argumentow
; (zaklada, ze ds wskazuje na segment danych)
GetArgNum proc
xor ax,ax ; AX = 0
mov al, byte ptr ds:[argc] ; kopiuj
ret
GetArgNum endp
; GetArgPos -----------------------------------
; zaladuj do AX adres argumentu o indeksie z DL
; (zaklada, ze ds wskazuje na segment danych)
GetArgPos proc
push bx
xor ax,ax ; AX = 0
mov al, dl ; AX = DL
shl ax, 1 ; AX*2, word ptr
mov bx, offset args
add bx, ax ; BX na args[DL]
; AX = adres DL-tego argumentu
mov ax, word ptr ds:[bx]
pop bx
ret
GetArgPos endp
; GetArgLen -------------------------------------
; zaladuj do AX dlugosc argumentu o indeksie z DL
; (zaklada, ze ds wskazuje na segment danych)
GetArgLen proc
push bx
call GetArgPos ; znajdz poczatek DL-tego argumentu
mov bx, ax
xor ax,ax ; ax = 0
lenLoop:
cmp byte ptr ds:[bx], '$'
je return
inc ax
inc bx
jmp lenLoop
return:
pop bx
ret
GetArgLen endp
_Kod ends
_Stos segment stack
; Rozmiar 80h w slowach (256d bajtow)
dw 7Fh dup(?)
wstosu dw ?
_Stos ends
end start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment