Last active
August 29, 2015 14:02
-
-
Save P4/fc6ad03a657e25baf8e5 to your computer and use it in GitHub Desktop.
Rysowanie krzywej Kocha: Generowanie przez LSystem, grafika żółwia
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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