Posts Tagged ‘asembler’

PostHeaderIcon Witam na stronie

Kliknij w interesujący Cię temat.

PostHeaderIcon Assembler

Proste programy napisane w assemblerze MASM

PostHeaderIcon Program rezydentny

Program rezydentny (ang. TSR) tj. pozostający w pamięci komputera podczas normalnej pracy systemu i generujący jakiś ciekawy krótki dźwięk po naciśnięciu klawisza SPACE przy wciśniętym wcześniej klawiszu CTRL. Dźwięk jest generowany na głośniku PC (brzęczyku PC)
Program powinien się instalować w pamięci tylko jeden raz! Ponowne jego uruchomienie powinno generować komunikat, że program jest już zainstalowany.
Wywołanie programu z opcją -u odinstalowuje program i zwalnia zajmowaną przez niego pamięć

; by Pawel Konieczny
; ver 0.9
.model tiny
;..................................................

;ASSUME cs:code1, ds:code1

;................. Segment kodu ...................
code1 segment
org 100h
start:

 jmp param

 stproc    dd    0
 znacznik    dw 'vs'
 czasomierz    equ    40h
 TC     equ     36157    ; 1193181Hz/33Hz
 TD     equ     32248    ; 1193181Hz/37Hz
 TE     equ     29102    ; 1193181Hz/41Hz
 TF     equ     27118    ; 1193181Hz/44Hz
 TG     equ     24351    ; 1193181Hz/49Hz
 TA     equ     21694    ; 1193181Hz/55Hz
 TH     equ     19245    ; 1193181Hz/62Hz

; -------------------------------------------------
;              Glowny kod programu
; -------------------------------------------------

 mainprog:
 push es
 in al,60h            ;pobierz klawisz
 cmp al,39h            ;scan-code spacji
 jne koniec
 xor ax,ax
 mov es,ax
 test byte ptr es:[417h],4    ;sprawdzam czy jest 'ctrl' wcisniety
 jz koniec

 ; wlaczenie

 in al,61h                     ; czyta biezacy status kontrolera
 or al,00000011b               ; dwa ostatnie bity na '1'
 out 61h,al                    ; zapisuje nowy status

 ; melodia

 mov ax,TA                     ; 1193181 / czestotl. = ax
 mov cl,3
 shr ax,cl                     ; ax = ax / 2^oktawa
 call graj
 call czas

 mov ax,TC
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TH
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TC
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 ; -------------------

 mov ax,TE
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TG
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TE
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TD
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TE
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TE
 mov cl,4
 shr ax,cl
 call graj
 call czas

 ; ------------------

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TC
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TD
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TH
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TH
 mov cl,3
 shr ax,cl
 call graj
 call czas

 ; --------------------

 mov ax,TC
 mov cl,4
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TG
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TH
 mov cl,3
 shr ax,cl
 call graj
 call czas

 mov ax,TA
 mov cl,3
 shr ax,cl
 call graj
 call czas

 ; wylaczenie

 in al,61h                     ; czyta biezacy status kontrolera
 and al,11111100b              ; dwa ostatnie buty na '0'
 out 61h,al                    ; zapisuje nowy status

 jmp koniec

 sek PROC
 mov cx,0fh
 mov dx,4240h
 ret
 sek ENDP

 pol_sek PROC
 mov cx,7Ah
 mov dx,120h
 ret
 pol_sek ENDP

 cw_sek PROC
 mov cx,3Dh
 mov dx,090h
 ret
 cw_sek ENDP

 os_sek PROC
 mov cx,1Eh
 mov dx,848h
 ret
 os_sek ENDP

 graj PROC                        ; ax - podzielnik
 out 42h,al
 mov al,ah
 out 42h,al
 ret
 graj ENDP

 czas PROC
 xor al,al            ;opoznienie na 1 sek
 out 70h,al            ;czas odczytuje z cmosu
 jmp $+2                ;drobne opuznienie potrzebne do poprawnej wspolpracy z CMOS
 in al,71h
 mov dl,al
 petla1:                    ;w tej petli pobieram aktualna sekunde
 xor al,al
 out    70h,al
 jmp $+2                ;drobne opoznienie potrzebne do poprawnej wspolpracy z CMOS
 in al,71h
 cmp    dl,al            ;i sprawdzam czy jest rowna poprzedniej
 je petla1
 ret
 czas ENDP

 koniec:
 pop es
 jmp dword ptr cs:[stproc]        ; skok do oryginalnej procedury

; -------------------------------------------------
;           Wczytywanie parametru
; -------------------------------------------------

 param:
 mov    ax,cs
 mov    ds,ax            ; DS = CS, na wszelki wypadek

 mov    al,byte ptr es:[80h]
 cmp al,0
 je install

 mov    al,byte ptr es:[81h]        ; sprawdzamy kolejny znak w linii polecen
 cmp    al,0dh
 je install                        ; Enter = koniec linii, wiec instaluj

 mov    al,byte ptr es:[82h]
 cmp    al,'-'
 jne    Komunikat1

 mov    al,byte ptr es:[83h]
 cmp al,'u'
 jne Komunikat1

 mov    al,byte ptr es:[84h]
 cmp al,0dh
 jne Komunikat1

 jmp uninstall

; -------------------------------------------------
;               Odinstalowanie
; -------------------------------------------------

 Uninstall:
 mov ax,3508h                              ; pobranie wektora przerwania
 int 21h
 cmp bx,offset mainprog                    ; sprawdzamy, czy sie zgadzaja offsety
 jne NieMa
 ;mov si,offset znacznik                   ; adres lokalnego znacznika do DS:SI
 ;mov di,si                                ; i znacznika sprawdzanego do ES:DI
 ;mov cx,2                                 ; dlugosc znacznika w bajtach
 ;cld
 ;repe cmpsb                               ; sprawdzamy az do rozniacego sie bajtu
 mov si,'vs'
 mov di,si
 cmp word ptr es:[bx-2],'vs'
 jne NieMa                                 ; gdy rozne znaczniki
 ;jnz NieMa

 mov dx,word ptr es:[stproc]               ; czytamy oryginalny wektor
 mov ax,word ptr es:[stproc+2]             ; z bloku TSRa
 mov ds,ax
 mov ax,2508h                              ; ustawienie wektora przerwania, adres podany w ds:dx
 int 21h

 mov ah,49h                                ; zwolnienie bloku pamieci w segmencie ES z TSRem
 int 21h

 mov ax,cs
 mov ds,ax                                 ; przywracamy do DS segment naszego programu
 mov ah,9                                  ; wydruk napisu na ekran
 mov dx,offset uninst
 int 21h                                   ; drukujemy komunikat o pomyœlym usuniêciu TSRa

 jmp koniecx

 NieMa:
 mov ah,9                                  ; wydruk napisu na ekran
 mov dx,offset blad
 int 21h
 jmp koniecx

; -------------------------------------------------
;                Instalowanie
; -------------------------------------------------

 Install:
 mov ax,3508h
 int 21h                                   ; sprawdz, czy przed procedura obslugi przerwania ...
 cmp word ptr es:[bx-2],'vs'               ; ... znajduje sie 'vs'
 je Komunikat2                             ; jesli tak, to znak, ze program byl juz zainstalowany

 mov es,word ptr ds:[2ch]                  ; numer segmentu srodowiska odczytamy z PSP, wrzucimy do ES
 mov ah,49h                                ; zwolnienie bloku pamieci
 int 21h

 mov ax,3508h                              ; pobranie adresu procedury obslugi przerwania 8h
 int 21h                                   ; wynik do ES:BX
 mov word ptr cs:[stproc],bx
 mov word ptr cs:[stproc+2],es

 mov ax,2508h                              ; ustawienie nowego adresu procedury obslugi przerwania
 mov dx,offset mainprog                    ; DS:DX - wektor naszej procedury
 int 21h

 mov ah,9                                  ; wydruk napisu na ekran
 mov dx,offset inst
 int 21h

 mov dx,offset param                       ; do DX wpisujemy adres pierwszego bajtu, który ma byc zwolniony
 int 27h                                   ; wczesniejsze pozostaja pamieci

; -------------------------------------------------
;                Reszta kodu
; -------------------------------------------------

 Komunikat1:
 lea dx,error_1
 jmp sh_err

 Komunikat2:
 lea dx,error_2
 jmp sh_err

 sh_err:                   ; wypisuje na ekran bledy
 mov ah,9h
 int 21h

 koniecx:
 mov ax,4c00h
 int 21h


error_1        db    'Bledny parametr$'
blad        db    'Nie mozna odinstalowac programu, ktory nie byl zainstalowany$'
uninst    db    'Program odinstalowano.$'
error_2    db    'Program byl juz wczesniej zainstalowany.$'
inst        db    'Program zainstalowano.$'

code1 ends
;..................................................

END start

PostHeaderIcon Tryb graficzny

Program rysujący na ekranie figury geometryczne na podstawie danych umieszczonych w pliku wejściowym o nazwie podawanej przy wywołaniu.
Figury powinny być rysowane w trybach VGA: 320×200-256kol i 640×480-16kol w jednym z czterech kolorów: biały, czerwony, zielony lub niebieski (B,C,Z lub N). Ekran jest traktowany jako pierwsza ćwiartka układu współrzędnych. Początek układu współrzędnych znajduje się w lewym dolnym rogu ekranu.
Dodatkowo w trybie 320×200 figury są wypełniane
Pierwsza linia pliku zawiera tryb ekranu: 320 lub 640
320 – oznacza tryb 320×200
640 – oznacza tryb 640×480

Kolejne linie określają poszczególne figury do wyświetlenia na ekranie. Każda taka linia zawiera na początku literę określającą kolor figury, a następnie ciąg par współrzędnych wierzchołków figury.
Przykład pliku wejściowego: (rysuje czerwony kwadrat i niebieski trójkąt w trybie 320×200):

320
C 0,0 50,0 50,50 0,50
N 100,80 150,110 200,40

Przykład wywołania Programu:
program3 dane.wej

; by Pawel Konieczny
; ver 1.0
.186
;................. Segment danych .................
dane1 segment
p0          dw  ?
q0          dw  ?
p1          dw  ?
q1          dw  ?
f_in            db  10 dup (?),'0'
uchwyt          dw  ?
bufor          db  1000 dup ('$')
errorx        db  'Za duza wspolrzedna X$'
errory            db  'Za duza wspolrzedna Y$'
error1        db  'Brak parametru$'
error2        db  'Nie znaleziono pliku$'
error4        db  'Nie mozna zamknac pliku$'
gran_linii    dw  ?
gran_ekran    dw  ?
WspX        dw  ?
WspY        dw  ?
kop_di        dw  ?
x          dw  ?
y          dw  ?
w1        dw  ?
w2        dw  ?
a          dw  ?
b          dw  ?
dex          dw  ?
dey          dw  ?
adx          dw  ?
ady          dw  ?
ix          dw  ?
iy          dw  ?
du          dw  ?
dr         dw  ?
pp          dw  ?
cp          dw  ?
kolor          db  ?
dane1 ends
;..................................................

;................. Segment kodu ...................
code1 segment
ASSUME cs:code1, ds:dane1, ss:stos1
start:
mov ax,seg dane1
mov ds,ax

call CzyParam
call CzytPar
next:
call OtwPlik
call CzytPlik
call Wcz_rozdz

mov di,5           ; tu sie zaczyna pierwszy kolor
call Wcz_kolor
inc di
inc di
jmp startuj
start3:
mov di,[kop_di]
call Wcz_kolor
inc di
inc di
startuj:
call Czytaj       ; pierwsza wspolrzedna (dwie liczby), ustawia 'di' na pierwszy znak po ostatniej liczbie
mov ax,[a]
mov [p0],ax
mov [w1],ax
mov ax,[b]
mov [q0],ax
mov [w2],ax

inc di            ; przeskocz spacje
call CzyKoniec    ; sprawdz, czy doszlismy do konca linii

start2:
call Czytaj       ; druga wspolrzedna
mov ax,[a]
mov [p1],ax
mov ax,[b]
mov [q1],ax

call Rysuj_linie

inc di
call CzyKoniec

mov ax,[p1]
mov [p0],ax
mov ax,[q1]
mov [q0],ax
jmp start2

pob_pierw:
mov ax,[w1]
mov [p0],ax
mov ax,[w2]
mov [q0],ax
call Rysuj_linie

mov di,-1
mov ax,[WspX]
dec ax
mov [gran_linii],ax         ; gran_linii = WspX - 1
xor bx,bx
jmp szuk_pier
do_nowej_linii:
mov di,[gran_linii]
mov cx,[WspX]
add [gran_linii],cx
xor bx,bx
mov cx,[gran_ekran]
cmp [gran_linii],cx
ja start3                  ; gdy dojdziemy do konca, wczytuj nastepna figure
szuk_pier:
inc di
cmp di,[gran_linii]
jae do_nowej_linii
mov al,byte ptr es:[di]
cmp al,[kolor]
jne szuk_pier
mov bx,di              ; znacznik pierwszego wystapienia
szuk_drug:               ; znaleziono pierwszy punkt
inc di
cmp di,[gran_linii]      ; drugi punkt musi byc w tej samej linii ...
ja [do_nowej_linii]     ; ... gdy go nie ma, skaczemy do nowej linii
mov al,byte ptr es:[di]
cmp al,[kolor]
je czy_nie_sa_obok     ; znaleziono drugi punkt, ale sprawdzamy, czy nie sa obok siebie
jmp szuk_drug

czy_nie_sa_obok:
inc bx
cmp bx,di
je szuk_drug
;    dec bx

cmp [WspX],320
je wypelnij_low
call ZamkPlik
call Koniec

wypelnij_low:
mov al,[kolor]
mov byte ptr es:[bx],al
inc bx
cmp bx,di
jne wypelnij_low
jmp do_nowej_linii
;jmp szuk_pier

CzyParam PROC               ; sprawdzenie czy sa parametry
mov bx,80h           ; sprawdzamy czy istnieje ...
mov cl,byte ptr es:[bx]       ; ... jakikolwiek parametr
cmp cl,0             ; jesli nie ma zadnego parametru, to ...
je Komunikat1        ; ... wypisz blad
ret
CzyParam ENDP

CzytPar PROC               ; czytanie pierwszego parametru
inc bx               ; parametry zaczynaja sie od 82h
mov dl,byte ptr es:[bx]       ; wczytujemy znak do dl
cmp dl,0dh
je next
mov f_in[di],dl      ; a nastepnie do bufora, ktory bedzie nazwa pliku
inc di
jmp CzytPar
ret
CzytPar ENDP

CzyKoniec PROC                ; ------------------ Sprawdz, czy doszlismy do konca linii ------------------------------
mov dl,[bufor+di]
mov [kop_di],di
inc [kop_di]
inc [kop_di]
cmp dl,0dh
je pob_pierw
ret
CzyKoniec ENDP
; wejscie : 'di' - miejsce w pliku
; wyjscie : skok do 'pob_pierw', gdy napotkano na koniec pliku

Wcz_rozdz PROC                ; ------------------------- Wczytanie rozdzielczosci ------------------------------------
low_res:              ; -- czy 320 x 200 --
mov dl,[bufor]
cmp dl,'3'
jne high_res
mov dl,[bufor+1]
cmp dl,'2'
jne Koniec
mov dl,[bufor+2]
cmp dl,'0'
jne Koniec
mov dl,[bufor+3]
cmp dl,13            ; sprawdzamy, czy jest znak konca linii ...
jne Koniec           ; ... gdy nie, wychodzimy (znaczy to, ze jest jeszcze jakas cyfra)
mov [WspX],320
mov [WspY],200
mov [gran_ekran],63999
call InitLow
ret

high_res:              ; -- czy 640 x 480 --
mov dl,[bufor]
cmp dl,'6'
jne Koniec
mov dl,[bufor+1]
cmp dl,'4'
jne Koniec
mov dl,[bufor+2]
cmp dl,'0'
jne Koniec
mov dl,[bufor+3]
cmp dl,13            ; sprawdzamy, czy jest znak konca linii ...
jne Koniec           ; ... gdy nie, wychodzimy
mov [WspX],640
mov [WspY],480
mov [gran_ekran],307199
call InitHigh
ret
Wcz_rozdz ENDP

Wcz_kolor PROC                ; ----------------------------- Wczytanie koloru ----------------------------------------
mov dl,[bufor+di]
cmp dl,'B'
je bialy               ;  kolor bialy
cmp dl,'C'
je czerwony           ;  kolor czerwony
cmp dl,'Z'
je zielony           ;  kolor zielony
cmp dl,'N'
je niebieski           ;  kolor niebieski

jmp Koniec           ; gdy kolor jest niezdefiniowany, wychodzimy

bialy:
mov [kolor],15
ret

czerwony:
mov [kolor],4
ret

zielony:
mov [kolor],2
ret

niebieski:
mov [kolor],1
ret
Wcz_kolor ENDP

Czytaj PROC                   ; --------- Wczytanie liczb obok przecinka i umieszczenie ich do zmiennych a,b ----------
xor cx,cx
; --------- wczytanie pierwszego punktu do 'cx' ----------
first_p:            ; zmienna 'p'
mov al,[bufor+di]

sub al,30h
xor ah,ah         ; zamien ascii na cyfre
add cx,ax         ; dodaj cyfre do sumy
mov ax,cx         ; przenies sume do 'ax'

inc di            ; sprawdz nastepny znak
mov dl,[bufor+di]     ; ...........
cmp dl,','        ; jesli jest przecinkiem ...
je podstaw        ; ... to zakoncz wczytywanie

mov bx,ax         ; ... w przeciwnym wypadku pomnoz przez 10 poprzednia liczbe
shl ax,3            ; ax = ax * 8
shl bx,1            ; bx = bx * 2 = ax * 2
add ax,bx         ; ax = ax + bx = ax * 10

mov cx,ax
jmp first_p

podstaw:
cmp ax,[WspX]
jae Komunikatx
mov a,ax
inc di
xor cx,cx

; --------- wczytanie drugiego punktu do 'cx' ----------
second_p:            ; zmienna 'q'
mov al,[bufor+di]

sub al,30h
xor ah,ah         ; zamien ascii na cyfre
add cx,ax         ; dodaj cyfre do sumy
mov ax,cx         ; przenies sume do 'ax'

inc di            ; sprawdz nastepny znak
mov dl,[bufor+di]     ; ...........
cmp dl,' '        ; jesli jest spacja
je podstaw2        ; to zakoncz wczytywanie

mov bx,ax         ; w przeciwnym wypadku pomnoz przez 10 poprzednia liczbe
shl ax,3            ; 2^3 +
shl bx,1            ; + 2^1
add ax,bx

mov cx,ax
jmp second_p

podstaw2:
cmp ax,[WspY]
jae Komunikaty
mov [b],ax
ret
Czytaj ENDP

InitLow PROC                  ; -------------------------- Inicjalizacja trybu 320 x 200 x 256 ------------------------
mov ax,0013h
int 10h
mov ax,0A000h
mov es,ax         ; es = 0A000h
ret
InitLow ENDP

InitHigh PROC                 ; -------------------------- Inicjalizacja trybu 640 x 480 x 16 -------------------------
mov ax,0012h
int 10h
mov ax,0a000h
mov es,ax         ; es = 0A000h
ret
InitHigh ENDP

RysujPunkt PROC
cmp [WspX],320
je PunktLow
cmp [WspX],640
je PunktHigh
ret
RysujPunkt ENDP

PunktLow:                 ; ------------------------ Rysowanie punktu o wps. x,y ----------------------------------
mov ax,[y]
neg ax
add ax,199        ; ax = 199 - ax
mov bx,ax         ; bx = ax
shl ax,8            ; ax = ax*256
shl bx,6            ; bx = bx*64 = ax*64
add ax,bx         ; ax = ax*256 + ax*64 = ax*320 = wiersz*320
add ax,[x]            ; ax = wiersz*320 + kolumna = 320y+x
mov di,ax
mov al,[kolor]
mov byte ptr es:[di],al
ret

PunktHigh:               ; ------------------------ Rysowanie punktu o wps. x,y ----------------------------------
push cx
mov ax,[x]
mov bx,[y]
neg bx
add bx,479
mov dx,bx
shl bx,6
shl dx,4
add bx,dx         ; bx = y * 80
mov dx,ax
shr dx,3          ; dx = x / 8
add bx,dx         ; bx = wyliczony adres
mov cl,7
and cl,al         ; cl = n (numer bitu w wyznaczonym bajcie w bx)
mov al,80h
shr al,cl         ; al = maska
mov dx,3CFh
out dx,al               ; wpisujemy do rejestru Bit Mask

mov al,2
mov dx,3C4h
out dx,al               ; select map mask register

mov al,0Fh
mov dx,3C5h
out dx,al               ; enable all planes

mov al,es:[bx]          ; czytanie z pamieci
mov es:[bx],byte ptr 0  ; czyszczenie kolorow
mov al,[kolor]
out dx,al               ; ustawianie nowego koloru
mov es:[bx],byte ptr 0FFh ; zapisywanie do pamieci

pop cx
ret

OtwPlik PROC                  ; ----------------------------- Otwieranie pliku ----------------------------------------
mov ax,3d00h       ; otwieramy plik do odczytu
lea dx,[f_in]
int 21h
jc Komunikat2
mov [uchwyt],ax
ret
OtwPlik ENDP

CzytPlik PROC                 ; ------------------------- Czytanie z pliku do bufora ----------------------------------
mov ax,3f00h
mov bx,[uchwyt]
mov cx,500         ; czytamy..
lea dx,[bufor]       ; do bufora
int 21h
ret
CzytPlik ENDP

Rysuj_linie PROC              ; ----------------- Rysowanie linii o koncach (p0, q0), (p1, q1) ------------------------
push di
mov ax,[p1]
sub ax,p0
mov [dex],ax      ; dex = p1-p0
mov ax,[q1]
sub ax,[q0]
mov [dey],ax      ; dey = q1-q0
cmp [dex],0       ; ---- sprawdzanie dex
jge dalej
mov ax,[dex]    ; gdy dex < 0
neg ax
mov [adx],ax    ; adx = |dex|
jmp spr_y
dalej:          ; gdy dex >= 0
mov ax,[dex]
mov [adx],ax      ; adx = |dex|
spr_y:
cmp [dey],0       ; ---- sprawdzanie dey
jge dalej2
mov ax,[dey]   ; gdy dey < 0
neg ax
mov [ady],ax   ; ady = |dey|
jmp nie_spr
dalej2:          ; gdy dey >= 0
mov ax,[dey]
mov [ady],ax      ; ady = |dey|
nie_spr:
mov ax,[p0]
mov [x],ax          ; x = p0
mov ax,[q0]
mov [y],ax          ; y = q0
mov [cp],0          ; cp = 0
cmp [dex],0       ; ----- pierwszy if -------
jle dalej3
mov [ix],1     ; if dex > 0 then ix = 1
jmp if_2     ; wyskocz z petli
dalej3:
mov [ix],-1    ; if dex <= 0 then ix = -1
mov [cp],-1    ;                  cp = -1
if_2:          ; ------ drugi if --------
cmp [dey],0
jle dalej4
mov [iy],1     ; if dey > 0 then iy = 1
jmp if_3     ; wyskocz z petli
dalej4:
mov [iy],-1    ; if dey <= 0 then iy = -1
if_3:          ; ------ trzeci if -------
mov ax,[adx]
cmp ax,[ady]
jl end_else
mov ax,[ady]   ; -------  gdy adx >= ady  ---------
add ax,ax    ;  ax = 2*ady
mov [dr],ax    ; dr = 2*ady
mov ax,[adx]
add ax,ax    ;  ax = 2*adx
mov bx,[dr]    ;  bx = dr
sub bx,ax    ;  bx = dr - 2*adx
mov [du],bx    ; du = dr - 2*adx
mov ax,[dr]
sub ax,[adx]   ;  ax = dr - adx
mov [pp],ax    ; pp = dr - adx
mov ax,[adx]
inc ax
mov cx,ax
petla_for1:
call RysujPunkt
mov ax,[x]
add ax,[ix]
mov [x],ax    ; x = x + ix
mov ax,[pp]
cmp ax,[cp]   ; cp nie jest -1
jle if_el
mov ax,[y]         ; if pp > cp
add ax,[iy]
mov [y],ax   ; y = y + iy
mov ax,[pp]
add ax,[du]
mov [pp],ax  ; pp = pp + du
loop petla_for1
pop di
ret
if_el:            ; if pp <= cp
mov ax,[pp]
add ax,[dr]
mov [pp],ax  ; pp = pp + dr
loop petla_for1
pop di
ret
end_else:       ; -------  gdy adx < ady  ---------
mov ax,[adx]
add ax,ax
mov [dr],ax    ; dr = 2*adx
mov ax,[ady]
add ax,ax    ;  ax = 2*ady
mov bx,[dr]    ;  bx = dr
sub bx,ax    ;  bx = dr - 2*ady
mov [du],bx    ; du = dr - 2*ady
mov ax,[dr]
sub ax,[ady]   ;  ax = dr - ady
mov [pp],ax    ; pp = dr - ady
mov ax,ady
inc ax
mov cx,ax
petla_for2:
call RysujPunkt
mov ax,[y]
add ax,[iy]
mov [y],ax    ; y = y + iy
mov ax,[pp]
cmp ax,[cp]
jle if_else
mov ax,[x]         ; if pp > cp
add ax,[ix]
mov [x],ax   ; x = x + ix
mov ax,[pp]
add ax,[du]
mov [pp],ax  ; pp = pp + du
loop petla_for2
pop di
ret
if_else:          ; if pp <= cp
mov ax,[pp]
add ax,[dr]
mov [pp],ax  ; pp = pp + dr
loop petla_for2
pop di
ret
Rysuj_linie ENDP

ZamkPlik PROC                 ; ------------------------------- Zamykanie pliku ---------------------------------------
mov ax,3e00h
mov bx,[uchwyt]
int 21h
jc Komunikat4
ret
ZamkPlik ENDP

Komunikat1:
lea dx,[error1]
mov ah,9h
int 21h
call Koniec

Komunikat2:
lea dx,[error2]
mov ah,9h
int 21h
call Koniec

Komunikat4:
lea dx,[error4]
mov ah,9h
int 21h
call Koniec

Komunikatx:
mov ax,0003h
int 10h
lea dx,[errorx]         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Komunikaty:
mov ax,0003h
int 10h
lea dx,[errory]         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Koniec PROC                   ; ------------------------------ Procedury koncowe --------------------------------------
; ---------- Czekanie na klawisz -------------

mov ax,0
int 16h

; ---------- Powrot do tr. tekstowego -------------

mov ax,0003h
int 10h

; ---------- Wyjscie do systemu -------------

mov ax,4c00h
int 21h
ret
Koniec ENDP

code1 ends
;..................................................

;................ Segment stosu ...................
stos1 segment stack
dw 1000 dup(?)
stos1 ends
;..................................................

END start

PostHeaderIcon Operacje na macierzach

Program realizujący jednocześnie dodawanie i mnożenie dwóch macierzy. Dane – czyli dwie macierze – znajduja się w pliku wejściowym o nazwie podanej przy wywołaniu. Wynik działania programu jest umieszczany automatycznie w pliku wyjściowym o nazwie również podanej przy wywołaniu.
Liczby występujące w macierzach powinny być z zakresu: 0-100
Ogólna postać macierzy dla m kolumn i n wierszy:

m n
A11 A12 A13 …… A1m
A21 A22 A23 …… A2m
A31 A32 A33 …… A3m
… … … …… …
An1 An2 An3 …… Anm

Przykłady zapisu macierzy:

3 4
1 3 4
4 5 2
1 1 1
8 9 9

5 5
01 22 33 12 43
92 23 43 21 12
22 22 22 22 22
66 66 66 66 66
13 56 56 21 32

Przykład wywołania Programu:

program2 dane1.wej dane1.wyj

; by Pawel Konieczny
; ver 1.0
.186
;................. Segment danych .................
dane1 segment
f_in    db    10 dup (?),'0'     ; nazwa pliku wejsciowego
f_out    db    10 dup (?),'0'     ; nazwa pliku wyjsciowego
buf_in    db    1000 dup ('$')
buf_out    db    1000 dup ('$')
error_1   db    'Niewlasciwy parametr$'
error_2   db    'Nie mozna czytac z pliku wejsciowego$'
error_3   db    'Nie mozna zamknac pliku$'
error_4   db    'Nie mozna znalezc pliku wejsciowego$'
error_5   db    'Nie mozna stworzyc pliku wyjsciowego$'
error_6   db    'Nie mozna zapisac do pliku wyjsciowego$'
kom_1     db    'Nie mozna dodac macierzy. $'
kom_2     db    'Dodawanie macierzy ...$'
kom_3    db    'Nie mozna pomnozyc macierzy. $'
kom_4     db      'Mnozenie macierzy ...$'
uchwyt    dw    ?    ; wskaznij do pliku wejsciowego
uchwyt2   dw    ?    ; wskaznik do pliku wyjsciowego
x1        dw    ?    ; pierwsza wspolrzedna pierwszej macierzy
x2        dw    ?    ; druga wspolrzedna pierwszej macierzy
x3        dw    ?    ; pierwsza wspolrzedna drugiej macierzy
x4        dw    ?    ; druga wspolrzedna drugiej macierzy
sk        dw    ?       ; skok do danych o wspolrzednych w drugiej macierzy
sk1    dw    ?    ; skok do nastepnego rzedu w macierzy 1
sk2    dw    ?       ; skok do nastepnej liczby w kolumnie w macierzy 2
w1        dw    ?       ; wskazuje na elementy pierwszej macierzy
w2    dw    ?       ; wskazuje na elementy drugiej macierzy
norma1    dw    ?
norma2    dw    ?
ok2    dw    ?
licz1     dw    ?
licz2     dw    ?
licz3    dw    ?
dane1 ends
;..................................................

ASSUME cs:code1, ds:dane1, ss:stos1

;................. Segment kodu ...................
code1 segment
start:
mov ax,seg dane1
mov ds,ax

; Na poczatku zapisujemy rozmiary pierwszej macierzy do zmiennych x1, x2.
; Dalej, na podstawie znajomosci tych danych wykonywany jest skok do
; miejsca w pliku, gdzie przechowywane sa rozmiary drugiej macierzy x3, x4

call CzyParam
inc bx                  ; przechodzimy przez spacje
xor di,di
call CzytPar1
next1:
cmp di,0
je Komunikat5         ; gdy nie ma pierwszego parametru
xor di,di
call CzytPar2
next2:
cmp di,0
je Komunikat6         ; gdy nie ma drugiego parametru
call OtwPlikWej
call CzytPlikWej
call StwPlikWyj
call OtwPlikWyj

; wczytywanie zmiennych

mov di,0           ; di = 0 wskazuje na pierwsza pozycje w pliku
call Czytaj        ; pierwsza pozycje z pliku ...
mov [x1],ax          ; ... zapisz do x1

add di,3           ; di = 3 wskazuje na czwarta pozycje w pliku, ...
call Czytaj        ; ... ktora zpisujemy ...
mov [x2],ax          ; ... do x2

call Skok          ; obliczamy, gdzie znajduja sie w pliku dane drugiej macierzy

mov di,[sk]
call Czytaj        ; pierwsza wspolrzedna 2. macierzy ...
mov [x3],ax          ; ... zapisz do x3 ...

add di,3           ; ... druga, odlegla o 3 bajty od pierwszej ...
call Czytaj        ; ... odczytaj ...
mov [x4],ax          ; ... i zapisz do x4

; sprawdzanie poprawnosci romiaru macierzy w przypadku ich dodawania

mov ax,[x1]
cmp ax,[x3]
jne Kom1     ; gdy x1 != x3 skocz do mnozenia
mov ax,[x2]
cmp ax,[x4]
jne Kom1     ; gdy x2 != x4 skocz do mnozenia

; dodawanie macierzy

call Kom2
mov [w1],7           ; zaczynamy wczytywanie od siodmego bajtu, ...
mov ax,[x2]          ; ... bo tu jest pierwsza wspolrzedna
mov [licz2],ax       ; licz2 = x2

; -------------------------------
for1:
mov ax,[x1]
mov [licz1],ax      ; licz1 = x1
for2:
mov di,[w1]
call Czytaj        ; czytaj pierwszy skladnik z miejsca 'di' i umiesc w ax
push ax            ; poloz na stosie pierwszy skladnik

add di,[sk]          ; di = w1 + sk
call Czytaj        ; czytaj drugi skladnik z miejsca 'di' i umiesc w ax

pop bx             ; sciagnij ze stosu pierwszy skladnik
add ax,bx          ; dodaj do drugiego
call Zapisz        ; czytaj liczbe z ax i zapisz ja do pliku
call Spacja

add [w1],3         ; w1 = w1 + 3, przejscie przez spacje
dec [licz1]
cmp [licz1],0
jne for2
call Nwln

inc [w1]            ; przejscie do nowej linii
dec [licz2]
cmp [licz2],0
jne for1
; -------------------------------
call Nwln

; sprawdzanie poprawnosci romiaru macierzy w przypadku ich mnozenia

mnozenie:
mov ax,[x1]
cmp ax,[x4]
jne Kom3     ; gdy x1 != x4 wyjdz z programu

; mnozenie macierzy

call Kom4
call Skok1
call Skok2

mov ax,[x1]          ;         .....
mov [licz1],ax       ;      licz1 = x1
mov ax,[x2]          ;         ....
mov [licz2],ax       ;         ....
mov ax,[x3]
mov [licz3],ax       ;   licz3 = licz2 = x2

mov [w1],7           ; zaczynamy wczytywanie od siodmego bajtu, bo tu jest pierwsza wspolrzedna
mov [norma1],7       ; norma1 = w1 = 7
mov ax,[sk]
add ax,7
mov [w2],ax          ; w2 = sk + 7
mov [norma2],ax
mov [ok2],ax         ; ok2 = norma2 = w2 = sk + 7
xor cx,cx

; -------------------------------
for4:                ; jedno przejscie w1 x1 razy
mov di,[w1]
call Czytaj        ; czytaj pierwszy skladnik z miejsca 'di' i umiesc w ax
push ax            ; poloz na stosie pierwszy skladnik
mov di,[w2]        ;
call Czytaj        ; czytaj drugi skladnik z miejsca 'di' i umiesc w ax
pop bx             ; sciagnij ze stosu pierwszy skladnik
mul bx             ; pomnoz ax przez bx
add cx,ax          ; dodaj do sumy 'cx'
add [w1],3           ; zwieksz w1 o 3, przejscie przez spacje
mov ax,[sk2]
add [w2],ax          ; zwieksz w2 o 'sk2'
dec [licz1]
cmp [licz1],0
jne for4             ; powtarzaj x1 razy
mov ax,cx
call Zapisz        ; zapisz liczbe
call Spacja        ; wstaw spacje
xor cx,cx          ; zerowanie sumy
mov ax,[norma1]
mov [w1],ax          ; wroc do poczatku linii
add [norma2],3       ; przejdz przez spacje do kolejnego rzedu drugiej macierzy
mov ax,[norma2]      ;      .......
mov [w2],ax          ;    w2 = norma2
mov ax,[x1]          ;       .....
mov [licz1],ax       ;    licz1 = x1
dec [licz3]
cmp [licz3],0
jne for4
call Nwln
xor cx,cx            ; zerowanie sumy
mov ax,[sk1]
add [norma1],ax      ; przejscie do nowej linii
mov ax,[norma1]      ;       ......
mov [w1],ax          ;     w1 = norma1
mov ax,[ok2]         ; wroc do pierwszego rzedu macierzy drugiej
mov [norma2],ax      ;      .......
mov [w2],ax          ;     w2 = norma2 = ok2
mov ax,[x1]          ;         ....
mov [licz1],ax       ;      licz2 = x2
mov ax,[x3]
mov [licz3],ax
dec [licz2]
cmp [licz2],0
jne for4
; ---------------------------------

call ZamkPlikWej
call ZamkPlikWyj
call Koniec

; =========================   Procedury   ===============================

CzyParam PROC               ; sprawdzenie czy sa parametry
mov bx,80h           ; sprawdzamy czy istnieje ...
mov cl,byte ptr es:[bx]       ; ... jakikolwiek parametr
cmp cl,0             ; jesli nie ma zadnego parametru, to ...
je Komunikat1        ; ... wypisz blad
ret
CzyParam ENDP

CzytPar1 PROC               ; czytanie pierwszego parametru
inc bx               ; parametry zaczynaja sie od 82h
mov dl,byte ptr es:[bx]       ; wczytujemy znak do dl
cmp dl,' '
je next1
mov f_in[di],dl      ; a nastepnie do bufora, ktory bedzie nazwa pliku
inc di
jmp CzytPar1
ret
CzytPar1 ENDP

CzytPar2 PROC               ; czytanie drugiego parametru
inc bx
mov dl,byte ptr es:[bx]       ; wczytujemy go do dl
cmp dl,0dh
je next2
mov f_out[di],dl     ; a nastepnie do bufora ,ktory bedzie nazwa pliku
inc di
jmp CzytPar2
ret
CzytPar2 ENDP

OtwPlikWej PROC             ; otwieranie pliku wejsciowego
mov ax,3d00h         ; otwieramy plik do odczytu
lea dx,[f_in]
int 21h
jc Komunikat4
mov [uchwyt],ax
ret
OtwPlikWej ENDP

CzytPlikWej PROC            ; czytanie z pliku wejsciowego do 'buf_in'
mov ax,3f00h
mov bx,[uchwyt]
mov cx,300         ; czytamy po 1 bajcie
lea dx,[buf_in]       ; do bufora
int 21h
jc Komunikat2
ret
CzytPlikWej ENDP

StwPlikWyj PROC             ; utworzenie pliku wyjsciowego
mov ax,3c00h        ; numer funkcji - utworzenie
xor cx,cx
lea dx,[f_out]    ; adres nazwy pliku
int 21h
jc Komunikat5
ret
StwPlikWyj ENDP

OtwPlikWyj PROC             ; otwieranie pliku wyjsciowego
mov ax,3d02h         ; otwieramy plik do zapisu
lea dx,[f_out]
int 21h
jc Komunikat4
mov [uchwyt2],ax
ret
OtwPlikWyj ENDP

Czytaj PROC                 ; czytanie z 'buf_in' i zapisywanie do 'ax'
mov al,[buf_in+di]  ; adres zmiennej ze stringiem
xor ah,ah
sub al,30h            ; ascii -> cyfra
mov bx,ax
shl ax,3                ; mnozenie przez 10
shl bx,1
add ax,bx             ; tu juz jest liczba
push ax
mov al,[buf_in+di+1]
xor ah,ah
sub al,30h
pop bx
add bx,ax
mov ax,bx
ret
Czytaj ENDP

Skok PROC                   ; obliczanie skoku do danych drugiej macierzy
mov ax,[x1]
add ax,[x1]
add ax,[x1]
inc ax
mul [x2]
add ax,9             ; ax = (3 * x1 + 1) * x2 + 9
mov [sk],ax            ; dlugosc skoku
ret
Skok ENDP

Skok1 PROC                  ; obliczanie skoku do nowej linii w pierwszej macierzy
mov ax,[x1]
add ax,[x1]
add ax,[x1]
inc ax                   ; ax = (3 * x1 + 1)
mov [sk1],ax               ; dlugosc skoku
ret
Skok1 ENDP

Skok2 PROC                  ; obliczanie skoku do kolejnej liczby w kolumnie w drugiej macierzy
mov ax,[x3]
add ax,[x3]
add ax,[x3]
inc ax                   ; ax = (3 * x3 + 1)
mov [sk2],ax               ; dlugosc skoku
ret
Skok2 ENDP

Zapisz PROC                 ; zapisz liczbe do 'buf_out', pozniej do pliku
mov bl,10
div bl               ; al = al / 10

mov ch,ah
xor ah,ah
div bl               ; al = al / 10    -    pierwsza cyfra
mov cl,ah            ; w 'cl' jest druga cyfra

add al,'0'
mov [buf_out],al

add cl,'0'
mov [buf_out+1],cl

add ch,'0'
mov [buf_out+2],ch

mov ax,4000h
mov bx,[uchwyt2]
mov cx,3
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Zapisz ENDP

Spacja PROC                 ; umieszcza znak spacji w pliku
mov [buf_out],' '
mov ax,4000h
mov bx,[uchwyt2]
mov cx,1
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Spacja ENDP

Nwln PROC                   ; umieszcza znak przejscia do nowej linii w pliku
mov buf_out[0],13
mov buf_out[1],10
mov ax,4000h
mov bx,[uchwyt2]
mov cx,2
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Nwln ENDP

ZamkPlikWej PROC            ; zamykanie pliku wejsciowego
mov ax,3e00h
mov bx,[uchwyt]
int 21h
jc Komunikat4
ret
ZamkPlikWej ENDP

ZamkPlikWyj PROC            ; zamykanie pliku wyjsciowego
mov ax,3e00h
mov bx,[uchwyt2]
int 21h
jc Komunikat2
ret
ZamkPlikWyj ENDP

Koniec PROC                 ; powrot do systemu
mov ax,4C01h
int 21h
Koniec ENDP

Komunikat1:
lea dx,error_1         ; mov dx,offset error
call sh_err

Komunikat2:
lea dx,error_2         ; mov dx,offset error
call sh_err

Komunikat3:
lea dx,error_3         ; mov dx,offset error
call sh_err

Komunikat4:
lea dx,error_4         ; mov dx,offset error
call sh_err

Komunikat5:
lea dx,error_5         ; mov dx,offset error
call sh_err

Komunikat6:
lea dx,error_6         ; mov dx,offset error
call sh_err

Kom1:
lea dx,kom_1         ; mov dx,offset error
mov ah,9h
int 21h
jmp mnozenie

Kom2:
lea dx,kom_2         ; mov dx,offset error
mov ah,9h
int 21h
ret

Kom3:
lea dx,kom_3         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Kom4:
lea dx,kom_4         ; mov dx,offset error
mov ah,9h
int 21h
ret

sh_err:                   ; wypisuje na ekran bledy
mov ah,9h
int 21h
call Koniec

code1 ends
;..................................................

;................ Segment stosu ...................
stos1 segment STACK
dw 3000 dup(?)
stos1 ends
;..................................................

END start