;=============================================================================;
;                                                                             ;
; Plik           : arch2.asm                                                  ;
; Format         : COM                                                        ;
; Cwiczenie      : Kod U2                                                     ;
; Autorzy        : Bartosz Kapusta,Wojciech Kaszyński ,6 ,wtorek ,11:00       ;														  
; Data zaliczenia: 05.04.2011                                                 ;
; Uwagi          : Program wczytuje z klawiatury dwie liczby calkowite        ;
;                  z przedzialu [-32768..32767] wprowadzane w postaci znakow  ;
;                  ASCII, konwertuje je do 16-bitowej postaci obliczeniowej   ;
;                  w kodzie U2, oblicza ich sume reprezentowana w 32-bitowej  ;
;                  postaci kodu U2, a nastepnie dokonuje jej konwersji do     ;
;                  postaci znakow ASCII i wyswietla ja w tej postaci na       ;
;                  ekranie.                                                   ;
;=============================================================================;
        
.MODEL  TINY

        MAX_ZNAKOW              EQU     6	    ; maksymalna liczba znakow
                                                ; liczby wprowadzanej przez
                                                ; uzytkownika
        CRLF                    EQU     13,10   ; znak nowej linii
		ENTERR					EQU     13      ; klawisz enter
		
KOD SEGMENT
			ORG 100h 			 ; przesuniecie o 256 bajtow
			ASSUME  CS:Kod       ; jedyny segment programu wskazujacy na to ze program jest typu .com


WczytajZnak     MACRO
; Dzialanie:
;       Makro wczytuje znak z klawiatury bez echa.
; Uzywane rejestry:
;       AH
                mov     ah, 08h
                int     21h
                ENDM

WyswietlZnak    MACRO   Znak
; Dzialanie:
;       Makro wyswietla podany znak na ekranie.
; Parametry:
;       Znak - znak do wyswietlenia
; Uzywane rejestry:
;       AH, DL
                mov     dl, Znak
                mov     ah, 02h
                int     21h
                ENDM

WyswietlNapis   MACRO   Napis
; Dzialanie:
;       Makro wyswietla podany napis zakonczony znakiem '$' na ekranie.
; Parametry:
;       Napis - napis do wyswietlenia
; Uzywane rejestry:
;       AH, DX
                mov     dx, OFFSET Napis
                mov     ah, 09h
                int     21h
                ENDM

WczytISkonwU2   MACRO   Bufor, LiczbaZnakow
local doit
; Dzialanie:
;       Makro wczytuje z klawiatury znaki traktujac je jako liczbe
;       w postaci ciagu znakow ASCII i konwertuje ja do postaci obliczeniowej
;       w kodzie U2.
; Parametry:
;       Bufor - bufor, gdzie umieszczane beda wczytywane znaki
;       LiczbaZnakow - maksymalna liczba znakow do wczytania
; Wyjscie:
;       CF - 0 gdy powodzenie, 1 gdy niepowodzenie
;       AX - o ile CF=0 - skonwertowana liczba w kodzie U2
; Uzywane rejestry:
;       BX, CX
doit:
                mov     bx, OFFSET Bufor ;wczytujemy poczatek bufora
                mov     cx, LiczbaZnakow 
                call    WczytajLiczbe    ;wykonujemy skok do wcztania liczby
                mov     bx, OFFSET Bufor  
                mov     cx, LiczbaZnakow ;wczytujemy do rejestru cx ilosc znakow wpisanych przez uzytkownika
                call	Zakres 	         ;sprawdzamy zakres

                jc	    doit  			 ;skok jesli cf=1
                mov     bx, OFFSET Bufor ;wczytujemy poczatek bufora ponownie ,liczba jest ok
                mov     cx, LiczbaZnakow ;wczytujemy do rejestru cx ilosc znakow wpisanych przez uzytkownika
                call    KonwertujLiczbe  ;wykonujemy skok do konwertowania liczby
                ENDM

Sumuj           MACRO   Skladnik1, Skladnik2, Suma

                mov     ax, Skladnik1   ; pobierz pierwszy skladnik
                add     ax, Skladnik2   ; dodaj drugi skladnik
                mov     WORD PTR Suma, ax       ; zapamietaj mlodsze slowo
				jmp 	druga                   ; wyniku w zmiennej
pierwsza:
				jo 		ZFOF		; skok jesli wystapil nadmiar ZF=OF=1 
				jmp 	ZF			; skok jesli ZF=1, OF=0
druga:
				jz 		pierwsza    ; skok jezeli zf=1
                jo		ZF			; skok jesli wystapil nadmiar ZF=0,OF=1 				
				js 		ZFOF		; skok jesli liczba jest ujemna ,ZF=OF=0, SF=1 
                jmp		ZF   		; a jak nie to dodatnia
				

                 
ZFOF:
    		    mov     WORD PTR Suma + 2, 0FFFFh 
    		    jmp 	koniec_proc     
ZF:                                 
                mov     WORD PTR Suma + 2, 0    ; zapelnij zerem starsze bajty
koniec_proc:                               	
                ENDM

SkonwASCII      MACRO   Liczba, Bufor
                LOCAL   Cyfra
; Dzialanie:
;       Makro konwertuje liczbe z 32-bitowej postaci obliczeniowej do postaci
;       ciagu znakow ASCII, ktore zapamietuje w buforze.
; Parametry:
;       Liczba - konwertowana liczba w 32-bitowej postaci obliczeniowej
;       Bufor - bufor, gdzie umieszczone beda znaki liczby po konwersji
; Uzywane rejestry:
;       AX, BL, DI

				push 	dx						; odkladamy rejestry wykorzystywane na stos
                mov     ax, WORD PTR Liczba     ; pobierz liczbe
                mov     di, OFFSET Bufor        ; ustaw wskaznik na poczatek
                               	                ; bufora
                mov     cx,0
                mov 	dx, WORD PTR Liczba + 2
                cmp		dx, 0FFFFh             ; porownujemy dx z 65535
                jne		plus				   ; jezeli nie to oznacza ze liczba jest dodatnia poniewaz nie ma na poczatku '1'
                mov		dl, 45                 ;wkladamy do dl 45
                mov		[di], dl
                inc		di
				cmp		ax, 0
				jne		negacja                               
				mov		dx, 54
				push	dx						; zdejmujemy rejestry wykorzystywane w procedurze ze stosu
				inc 	cx						; zwiekszamy wskaznik
				jmp		plus
negacja:
                neg 	ax  		;negujemy rejestr ax
plus:      
   	       	    mov     dx,	0       ; zerujemy rejestr dx
                cmp     ax, 10  	; czy liczba mniejsza niz 10?
                jb      Cyfra  		; tak - skocz
                mov     bx, 10  	; wkladamy dzielnik do bx
                div     bx			; dzielimy przez 10
                add     dx, 48		; skonwertuj starsza cyfre do postaci ASCII
                inc		cx			; zwiekszamy wskaznik
                push	dx          ; odkladamy rejestr wykorzystywany na stos 
                jmp		plus
Cyfra:
                add     al, '0' 		; skonwertuj cyfre do postaci ASCII
                mov     [di], al        ; zapamietaj otrzymany znak w buforze
                inc     di      		; zwieksz pozycje wskaznika
znaczek:
 				cmp 	cx, 0
 				je		koniec	
 				pop		dx              ; zdjemujemy rejestr ze stosu
	            mov     [di], dx        ; zapamietaj otrzymany znak w buforze
                inc     di      		; zwiekszamy wskaźnik
                loop    znaczek
koniec:
                mov     BYTE PTR [di], '$'      ; oznacz koniec stringa
                pop 	dx						; zdjemujemy rejestr ze stosu
ENDM

poczatek:
			jmp start                                   ; skok do programu glownego
		    Skladnik1       DW      (?)      		    ; pierwsza liczba
			Skladnik2       DW      (?)				    ; druga liczba
			ileznakow       DW      (?)				    ; ilosc znakow wpisanych przez uzytkownika
			Suma            DD      (?)					; suma dwoch skladnikow
			Bufor1          DW      MAX_ZNAKOW DUP (?)  ; bufor dla pierwszego skladnika
			Bufor2          DW      MAX_ZNAKOW DUP (?)  ; bufor dla drugiego skladnika 
			BuforWynik      DB      MAX_ZNAKOW + 2 DUP (?) ; bufora dla sumy dwoch skladnikow
			txtPowitanie    DB      "Program sumuje dwie liczby calkowite z zakresu " ; tekst wyswietlany przy uruchomieniu programu
							DB      "[-32768..32767].$"
			txtZlec1        DB      CRLF,"Podaj pierwsza liczbe: $" ;prosba o podanie pierwszej liczby
			txtZlec2        DB      CRLF,"Podaj druga liczbe: $"    ;prosba o podanie drugiej liczby
			txtZakresZly	DB		CRLF,"Podana przez Ciebie liczba znajduje sie poza zakresem! Podaj liczbe z przedzialu [-32768,32767] : $" ; wyswietlenie informacji o zlej liczbie wpisanej przez uzytkownika
			txtWynik        DB      CRLF,"Wynik wynosi: $"  ; wyswietlenie informacji o wyniku dodawania
			minimum      	DB      "32768"                 ; minimalna liczba ktora moze wpisac uzytkownik
			maximum         DB      "32767"					; maxymalna liczba ktora moze wpisac uzytkownik
                
Zakres  PROC NEAR
; Dzialanie:
;       Procedura sprawdza czy liczba podana przez uzytkownika znajduje sie w 
;       zakresie [-32768;32767]
; Uzywane rejestry:
;       AX, CX, BX
				    push ax    			;odkladamy rejestr wykorzystywany w procedurze na stos
					mov cx, ileznakow 	;wkladamy do rejestru ilosc znakow wpisanych przez uzytkownika 
					cmp cx, 5			; czy liczba ma 5 znakow ? 
					jbe good		    ; jesli jest mniej lub 5 znakow to robimy skok do etykiety good
					mov al, [bx]		;czy ma 5 znakow ? jak tak to sprawdzamy dalej
					cmp al, '-'			;czy liczba ma '-'?
					je  Sprawdzujemna   ;jezeli jest'-' robimy skok do etykiety sprawdzujemna
					mov si, OFFSET maximum ;wkladamy do wskaznika wartosc maxymalna
					jmp spr
Sprawdzujemna:
					mov si, OFFSET minimum ;wkladamy do wskaznika wartosc minimalna
					dec cx			;	zmniejszamy wskaznik
					inc bx			; opuszczamy '-' wpisany przez uzytkownika
					cmp cx, 5		; czy po opuszczeniu ma 5 znakow ?
					jb good         ; jesli liczba ma mniej niz 5 znakow wykonujemy skok do etykiety good
spr:
					mov al, [bx]    ; wkladamy cyfre aktualnie znajdujaca sie w bx do rejestru al  
					cmp al, [si]	; porownujemy liczbe z zakresem wartosci 
					jb  good        ; jesli zakres jest ok , robimy skok do good
					cmp al, [si]    ; porownujemy liczbe z zakresem wartosci
					ja  bad         ; jezeli zakres jest zly , robimy skok do bad
					inc bx          ; zwiekszamy wskaznik
					inc si			; zwiekszamy wskaznik
					loop spr
good:
					clc						; cf = 0
					jmp koniecsprawdzania 	; zakres jest ok, konczymy sprawdzanie
bad:
					WyswietlNapis txtZakresZly ; wyswietlamy informacje o wpisaniu przez uzytkownika liczby spoza zakresu
					stc							; cf = 1
koniecsprawdzania:
				    pop ax		               ; zdejmujemy rejestr wykorzystywany w procedurze ze stosu		
			        ret							; poprawne zakonczenie procedury
Zakres   ENDP
				
WczytajLiczbe  PROC NEAR
; Dzialanie:
;       Procedura wczytuje ciag znakow z klawiatury stanowiacych liczbe
;       w postaci ASCII i zapisuje je do bufora. Przeprowadzana jest kontrola
;       dopuszczalnosci wprowadzanych znakow.
; Wejscie:
;       DS:BX - bufor
;       CX - maksymalna liczba znakow do wczytania
; Wyjscie:
;       Brak

			                push    ax      ; odloz rejestry wykorzystywane w procedurze
			                push    dx      
			        
kolejnyznak:
			                WczytajZnak     	; wczytaj znak bez echa
			                cmp     al, '-' 	; czy znak jest minus?
			                je      ujemna 		; tak - przejdz do zapamietania
			                cmp     al, '0' 	; czy znak jest cyfra?
			                jb      kolejnyznak ; nie - ignoruj znak i przejdz do wczytania
												; kolejnego
			                cmp     al, '9'     
			                ja      kolejnyznak ; jesli znak jest wiekszy od 9 , ponownie wczytujemy znak
			                dec		cx          ; zmniejszamy wskaznik
ujemna:
			                mov     [bx], al     ; tak - zapamietaj znak w buforze
			                inc     bx           ; zwieksz pozycje wskaznika w buforze
			                WyswietlZnak al      ; wyswietl wczytany znak
			                dec		cx           ; zmniejszamy wskaznik
Wczytywanie:
			                WczytajZnak     	; wczytaj znak bez echa
			                cmp		cx, 4		;jesli nie ma jeszcze zadnej cyfry nie sprawdzaj entera
			                ja		bezcrlf
			                cmp     al, ENTERR 	; czy zostal wcisniety enter?
			                jne     bezcrlf 	; jezeli nie ma to sprawdzamy dalej
							jmp		loaded		; zostal wcisniety enter, konczymy wczytywanie
bezcrlf:
			                cmp     al, '0' 	; czy znak jest cyfra?
			                jb      Wczytywanie ; nie - ignoruj znak i przejdz do wczytania
												; kolejnego
			                cmp     al, '9'
			                ja      Wczytywanie     ; jesli wieksze od 9 , wczytujemy ponownie
			                mov     [bx], al        ; tak - zapamietaj znak w buforze
			                inc     bx              ; zwieksz pozycje wskaznika w buforze
			                WyswietlZnak al         ; wyswietl wczytany znak
			                loop    Wczytywanie 	; przejdz do wczytania kolejnego znaku, o ile
loaded:                              				; nie wczytano juz wszystkich
								
							mov dx, MAX_ZNAKOW      ; wkladamy do dx maxymalna ilosc znakow jaka moze wpisac uzytkownik
							sub dx, cx              ; odejmujemy wartosc wskaznika w ktorym aktualnie sie znajduje od maxymalnej ilosci
							mov ileznakow, dx       ; otrzymujemy ilosc znakow wpisanych przez uzytkownika
							cmp cx, 0				;czy liczba 5-cyfrowa?
							jne endit               ; jesli nie jest to konczymy 
Enterek:
							WczytajZnak				; jesli liczba jest 5-cyfrowa, to poczekaj
							cmp al, ENTERR			; na zatwierdzenie enterem
							jne Enterek             ; jesli nie zostal wcisniety enter to czekamy na niego
endit:
			                pop     dx     			 ; odtworz rejestry wykorzystywane w procedurze
			                pop     ax
			                ret
WczytajLiczbe   ENDP
			
KonwertujLiczbe PROC NEAR
; Dzialanie:
;       Procedura konwertuje liczbe zapisana w buforze w postaci ciagu znakow
;       ASCII do 16-bitowej postaci obliczeniowej w kodzie U2.
; Wejscie:
;       DS:BX - bufor
; Wyjscie:
;       CF - 0 gdy powodzenie, 1 gdy niepowodzenie
;       AX - o ile CF=0 - skonwertowana liczba w kodzie U2

;; DO ZROBIENIA:
;;      Zmodyfikowac procedure umozliwoajac konwersje liczb z pelnego zakresu.
;;      W przypadku stwierdzenia sytuacji uniemozliwiajacej poprawne konwersje
;;      zwrocic informacje o niepowodzeniu ustawiajac znacznik CF.
					push 	dx				; odkladamy rejestry wykorzystywane w procedurze
					mov 	cx, ileznakow   ; wkladamy do wskaznika ilosc znakow wpisanych przez uzytkownika 
					mov 	si, bx
					mov		al, [bx]
					cmp  	al, '-' 		; czy liczba wpisana przez uzytkownika jest ujemna ?
			        jne  	signit 			; liczba jest dodatnia
			        inc		bx  			; pomijamy znak '-' wpisany przez uzytkownika
signit:
					dec 	cx				;zmniejszamy wskaznik
					dec 	cx				;zmniejszamy wskaznik
					mov 	ax, cx
nextto:
					cmp 	cx, 0
					je 		next
					inc 	bx
					loop 	nextto
next:
					mov 	cx, ax
					mov 	ax, 1
					mov 	dx, [bx]
					xor 	dh, dh
					sub 	dx, 48 			;zamieniam kod ascii na cyfre, odejmujac 48
					cmp 	cx, 0
					je 		endofconversion
dalej:
					dec 	bx
					push 	bx 				;wstawiamy ciag na stos
					push 	dx 				;wstawiamy liczbe na stos
					mov 	dx, 10 			;ustalam mnoznik ax * 10
					mul 	dx 				;mnoze ax
				    mov 	dx, [bx] 		;do dx przekladam znak
					mov     dh, 0
					sub 	dx, 48 			;zamieniam kod ascii na cyfre
					push 	ax 				; odkladam mnoznik
					mul 	dx 				;mnoze ax razy znak
					pop 	bx 				;pobieram mnoznik do bx
					pop 	dx 				;pobieram liczbe
				    add 	dx, ax			;dodaje do liczby wynik mnozenia
					mov 	ax, bx 			;przywracam do ax mnoznik
					pop 	bx 				;pobieram ciag znakow
					loop 	dalej			
endofconversion:
					mov		al, [si]
					cmp     al, '-' 		; czy liczba wpisana przez uzytkownika jest ujemna ? 
			        jne     dodatnia 		; dodatnia
			        neg 	dx
dodatnia:

					mov 	ax, dx
				    clc             		; ustaw znacznik, ze procedura zakonczyla sie
				                            ; poprawnie
				    pop 	dx
		            ret
KonwertujLiczbe ENDP

Start:
				mov ax, seg kod
				mov ds, ax
                WyswietlNapis txtPowitanie      		; wyswietl napis powitalny
                WyswietlNapis txtZlec1  				; wyswietl napis nakazujacy
														; wprowadzenie 1-szej liczby
                WczytISkonwU2 Bufor1, MAX_ZNAKOW        ; wczytaj liczbe z
                                                        ; z klawiatury i
                                                        ; skonwertuj do
                                                        ; postaci U2
                jc      Blad    						; jezeli wystapil blad - skocz
                mov     Skladnik1, ax   				; w przeciwnym razie zapamietaj
														; skonwertowana liczbe w zmiennej
                WyswietlNapis txtZlec2  				; wyswietl napis nakazujacy
														; wprowadzenie 2-giej liczby
                wczytiskonwu2 bufor2, MAX_ZNAKOW		;konwersja2 Bufor2, MAX_ZNAKOW        
														; wczytaj liczbe z
														; z klawiatury i
														; skonwertuj do
														; postaci U2
                jnc     Zsumuj          				; jezeli nie wystapil blad - skocz
Blad:
                mov     ax, 4C01h       				; w przeciwnym razie zakoncz program
                int     21h             				; z kodem powrotu oznaczajacym
														; wystapienie bledu
Zsumuj:
                mov     Skladnik2, ax   				; zapamietaj skonwertowana liczbe
														; w zmiennej
                Sumuj   Skladnik1, Skladnik2, Suma      ; zsumuj obie
                                                        ; wprowadzone liczby
                                                        ; i zapamietaj wynik
                                                        ; w zmiennej
                SkonwASCII Suma, BuforWynik     		; skonwertuj wynik do postaci
														; ASCII i zapamietaj w buforze
                WyswietlNapis txtWynik  				; wyswietl napis informujacy o wyniku
                WyswietlNapis BuforWynik        		; wyswietl wynik w postaci
														; ASCII
                mov     ax, 4C00h       				; zakoncz program z kodem powrotu                                        
                int     21h             				; zakonczenia poprawnego

Kod             ENDS									;koniec segmentu

                END     Poczatek						;wywolanie etykiety poczatek