Assembler - Operacje blokowe

0

Witam,
Mam problem z wykorzystaniem movsw, do skopiowania całej linii do bufora( w pętli).
Przybliżę problem, program ma zasłaniać losową linię znakami, a później ją przywrócić. Pracuję na dosboxie z włączonym trybem graficznym (vga) 0b800h.
Więc żeby nie zapomnieć co było w danej linii to chciałbym ją skopiować w pętli za pomocą operacji blokowej movsw (o ile wiem działa na SI i DI) do utworzonego Bufora w segmencie danych (db 160 dup(?) ), bo linia ma 80 słów co się przekłada na 160 bajtów, a następnie z tego bufora ją "odzyskać".
Czy mógłby ktoś podpowiedzieć jak się do tego zabrać ?

Z góry dziękuję za pomoc :)

0
ECHU napisał(a):

Witam,
Mam problem z wykorzystaniem movsw, do skopiowania całej linii do bufora( w pętli).
Przybliżę problem, program ma zasłaniać losową linię znakami, a później ją przywrócić. Pracuję na dosboxie z włączonym trybem graficznym (vga) 0b800h.
Więc żeby nie zapomnieć co było w danej linii to chciałbym ją skopiować w pętli za pomocą operacji blokowej movsw (o ile wiem działa na SI i DI) do utworzonego Bufora w segmencie danych (db 160 dup(?) ), bo linia ma 80 słów co się przekłada na 160 bajtów, a następnie z tego bufora ją "odzyskać".
Czy mógłby ktoś podpowiedzieć jak się do tego zabrać ?

A jaki masz konkretnie problem? Dawno nie tykałem asemblera, więc to co tu wpiszę może nawet się nie kompilować. Movs kopiuje CX elementów z DS:SI do ES:DI. Na starcie DS wskazuje Ci na segment danych, a musisz nim wskazać na segment pamięci obrazu - w tzw. trybie tekstowym będzie to . Więc dla zachowania stanu DS wykonaj "push ds", a po operacji "pop ds". Wydaje mi się, że powinno to być coś takiego:

mov ax, ds
mov es, ax
mov di, offset_zadeklarowanego_bufora
push ds
mov ax, 0b800h
mov ds, ax
mov si, 0
mov cx, 80
rep movsw
pop ds

Skopiowanie w drugą stronę jest prostsze (zakładając, że w DS jest segment danych):
mov ax, 0b8000h
mov es, ax
mov di, 0
mov si, offset_zadeklarowanego_bufora
mov cx, 80
repo movsw

0

Dodałbym cld przed jednym i drugim movsw, choćby dla nawyku, bo jeśli w programie gdziekolwiek indziej pojawi się std to będzie bieda.

0

Progr segment

assume cs:Progr,ds:dane,es:ekran,ss:stosik

start:
	
	mov	ax,seg dane ;ładuj rejestry segmentowe DS i ES
	mov	ds,ax
	mov ax,seg ekran ;pamięć ekranu do ES
	mov	es,ax
	;mov	ax,seg code
	mov ax,stosik
	mov ss,ax
	mov sp,offset stosik
	
	;MOV	AH,0 ;wybór trybu pracy monitora
	;MOV	AL,3 ;text 80x25 kolor
	;INT	10H	;obsługa ekranu	
	; Ukryj migotający kursor
	;mov ah, 1
	;mov ch, 2bh
	;mov cl, 0bh
	;int 10h
	; Czeka na naciśnięcie dowolnego klawisza
	;mov ah, 00h
	;int 16h
	
	;mov	ek[2000],219d ; Znak ASCII blok zamalowany 
	;mov atr[2000],12d ; czerwony
	
	
	mov cx,80
	mov si,0
	jmp skopiuj
t1:	
	mov cx,80
	mov si,0

petla:
mov ek[si],219d
mov atr[si],12d
add si,2
loop petla

	jmp przywroc
	jmp koniec
ta:	int 21h
	

przywroc:
;mov ax,0B800h
;mov es,ax
cld
mov si,offset Bufor
mov di,0
mov cx,80
rep movsw
;petla_p:;cmp si,0
;jz start
;jz koniec
;movsw
;LODSW
;mov ax,di
;mov bl,al
;mov bh,ah
;mov ek[si],bl
;mov atr[si],bh
;loop petla_p
jmp koniec

skopiuj:mov ax,0B800h
mov ds,ax
cld
mov di,offset Bufor
push ds
rep movsw
pop ds
mov ax, seg dane
mov ds,ax
jmp t1
koniec: Progr ends

dane segment

Bufor db 160 dup(?)

dane ends
stosik segment
stosik ends
ekran segment AT 0B800h
ek db ?
atr db ?
ekran ends

end start

0

Przy takim zapisie dosbox się wywala, albo pokazuje w "przysłoniętej linii" różnokolorowe randomowe znaki, moim zdaniem problem jest w "segmencie" przywróć, ponieważ niezbyt wiem jak przy pomocy movsw który ładuje mi do di rzeczy z bufora, wrzucić je do tablic z segmentu ekranu, gdy chce np di przypisać do ax i i odpowiednio al i ah do tablic wyskakuje błąd forward reference needs override, natomiast jak chce użyć pośrednio zmiennych to błąd żeby użyć rejestrów. Z góry przepraszam też za bałagan w kodzie, który powstaje w wyniku różnych prób rozwiązanie problemu

0

Główny problem widzę we fragmencie z etykietą "petla:"
Przy indeksowaniu tablicy rejestrem SI, używany jest rejestr segmentowy DS, a w nim, w tym miejscu programu, masz swój segment danych, a nie ekranu - nadpisujesz sobie bufor, do którego wcześniej skopiowałeś linię ekranu.

Druga sprawa - chociaż z punktu widzenia programu niekrytyczna - skoro i tak w różnych miejscach programu wpisujesz od nowa segment do DS, to "push ds" i "pop ds" które proponowałem, są bezużyteczne.

0

cld
mov si,offset Bufor
mov di,0
mov cx,80
rep movsw

0

Mam jeszcze pytanie, czy ten fragment kodu przywróci mi z Bufora automatycznie 80 "słów" na vga (ekran) ?
Bo wydaję mi się że nie powinien

0
ECHU napisał(a):

Mam jeszcze pytanie, czy ten fragment kodu przywróci mi z Bufora automatycznie 80 "słów" na vga (ekran) ?
Bo wydaję mi się że nie powinien

A mi wygląda na to, że powinien - pod warunkiem, że w tym momencie w ES jest segment ekranu.

0

https://zapodaj.net/13d9c80c42dd6.jpg.html

Gdy zakomentuje jump przywroc jest czerwona linia na górze, natomiast gdy odkomentuje i teoretycznie powinna tam wrócić wcześniejsza zawartość, modyfikuję się parę znaków w drugiej linii i pierwszy z pierwszej co widać na obrazku. poza tym za każdym razem dosboxa muszę wyłączać "ręcznie" i odpalać na nowo

0

Gdy zakomentuje jump przywroc jest czerwona linia na górze, natomiast gdy odkomentuje i teoretycznie powinna tam wrócić wcześniejsza zawartość, modyfikuję się parę znaków w drugiej linii i pierwszy z pierwszej co widać na obrazku.

Niestety nie potrafię dojrzeć co jest nie tak, a nie mam akurat gdzie skompilować/włączyć i sprawdzić.
To co bym na ten moment polecił, to spróbuj podmieniać operację "rep movsw" na "rep stosw" - w odróżnieniu od movsw, nie kopiuje ze źródłowego obszaru pamięci, a tylko zapisuje w docelowym wartość rejestru ax; ale identycznie korzysta z ES:DI i CX. Na początku możesz zmienić np. funkcję zapamiętującą linię, dzięki czemu do bufora nie będzie skopiowana zawartość ekranu, a jakaś stała wartość - i będziesz mógł sprawdzić, czy funkcja przywracająca to prawidłowo wkopiuje. I tym podobne próby...

poza tym za każdym razem dosboxa muszę wyłączać "ręcznie" i odpalać na nowo

Dos-a trzeba specjalnie poinformować o zakończeniu programu. Było to coś takiego:
mov al, 0
mov ah, 4ch
int 21h

0

Potestowałem jak mówiłeś i wychodzi na to że wszystko działa, jak używałem stosw, tylko program zamiast skopiować pierwszą linię, dodaję sobie jedną (analogicznie dla dwóch dodaje dwie) i kopiuję ją, a następnie przywraca pustą, zamiast zrobić to już na istniejących.

0

Progr segment

assume cs:Progr,ds:dane,es:ekran,ss:stosik

start:
	
	mov	ax,seg dane ;ładuj rejestry segmentowe DS i ES
	mov	ds,ax
	mov ax,seg ekran ;pamięć ekranu do ES
	mov	es,ax
	;mov	ax,seg code
	mov ax,stosik
	mov ss,ax
	mov sp,offset stosik
	
	MOV	AH,0 ;wybór trybu pracy monitora
	MOV	AL,3 ;text 80x25 kolor
	INT	10H	;obsługa ekranu	
	
	;mov bx,0
	
	; Ukryj migotający kursor
	;mov ah, 1
	;mov ch, 2bh
	;mov cl, 0bh
	;int 10h
	; Czeka na naciśnięcie dowolnego klawisza
	;mov ah, 00h
	;int 16h
	
	;mov	ek[2000],219d ; Znak ASCII blok zamalowany 
	;mov atr[2000],12d ; czerwony
	
	
	

again:
jmp losuj
t2:
jmp skopiuj
t1:
mov si,[losowe+bx]
mov ax,si
mov cx,160
mul cx
mov si,ax
mov ax, 0b800h
mov ds,ax
mov cx,80
petla:
mov ek[si],219d
mov atr[si],12d
add si,2
loop petla

	jmp przywroc
	jmp koniec
	int 21h
	

przywroc:
;mov ax,0B800h
;mov ds,ax
;mov ax,[losowe+bx]
;mov cx,160
;mul cx
cld
mov si,offset Bufor
mov di,[losowe+bx]
mov ax,di
mov cx,160
mul cx
mov di,ax
mov cx,80
rep movsw
jmp again
skopiuj:
mov ax,0B800h
mov ds,ax
mov si,[losowe+bx]
mov ax,si
mov cx,160
mul cx
mov si,ax
mov ax,seg dane
mov ds,ax
cld
mov di,offset Bufor
mov cx,80
rep movsw
jmp t1
losuj:
add bx,2
cmp bx,10
jz koniec
jmp t2
koniec:
mov al, 0
mov ah, 4ch
int 21h
Progr ends

dane segment
Bufor db 160 dup(?)
losowe dw 4,8,10,12,14,20,24
dane ends
stosik segment
stosik ends
ekran segment AT 0B800h
ek db ?
atr db ?
ekran ends

end start

0

Zrobiłem to tak żeby linia przechodziła dynamicznie po liniach a poprzednie żeby zostały przyslaniane poprzednią zawartością. Lecz program zwraca to:

0

A pozmieniaj część tych skoków na wywołania funkcji, aby było łatwiej się połapać. Chodzi mi o coś w tym rodzaju:

jakies tam poczatkowe instrukcje
call near skopiuj

skopiuj:
mov ax,0B800h
mov ds,ax
...
rep movsw
ret ; powróci w miejsce wywołania - nie trzeba jmp

Analogicznie funkcja "przywroc".
A to, co jest za "losuj:" to lepiej aby aby było wklejone w miejscu "jmp losuj", bo tak jak teraz to tylko niepotrzebny zamęt. I przed etykietami ("losuj:", "skopiuj:", "przywroc:" itp) daj pustą linię dla łatwiejszego czytania.
Może po tych zmianach będzie łatwiej wyśledzić co jest nie tak.

0

Progr segment

assume cs:Progr,ds:dane,es:ekran,ss:stosik

start:
	
	mov	ax,seg dane ;ładuj rejestry segmentowe DS i ES
	mov	ds,ax
	mov ax,seg ekran ;pamięć ekranu do ES
	mov	es,ax
	mov ax,stosik
	mov ss,ax
	mov sp,offset stosik
	
	MOV	AH,0 ;wybór trybu pracy monitora
	MOV	AL,3 ;text 80x25 kolor
	INT	10H	;obsługa ekranu	
			

again:

	add bx,2
	cmp bx,20
	jz  koniec
	call skopiuj			
	mov si,[losowe+bx]
	mov ax,si
	mov cx,160
	mul cx
	mov si,ax
	mov ax, 0b800h
	mov ds,ax
	mov cx,80
	

petla:

	mov ek[si],219d
	mov atr[si],12d
	add si,2
	loop petla		
	call przywroc
	call koniec		

przywroc:

	cld
	mov si,offset Bufor
	mov di,[losowe+bx]
	mov ax,di
	mov cx,160
	mul cx
	mov di,ax
	mov cx,80
	rep movsw
	jmp again
	

skopiuj:

	mov ax,ds
	mov es,ax
	mov ax,0B800h
	mov ds,ax		
	mov si,[losowe+bx]
	mov ax,si
	mov cx,160
	mul cx
	mov si,ax
	mov ax,seg dane
	mov ds,ax
	cld		
	mov di,offset Bufor		
	mov cx,80
	rep movsw		
	RET
	

koniec:

	mov al, 0
	mov ah, 4ch
	int 21h
	Progr ends
	

dane segment
Bufor db 160 dup(?)
losowe dw 4,8,10,12,14,20,24
dane ends
stosik segment
stosik ends
ekran segment AT 0B800h
ek db ?
atr db ?
ekran ends

end start

0

Jak widać wyświetla linie zgodnie z tablicą losowe (oprócz pierwszej i drugiej czego wynikiem jest zły warunek na początku again dla bx jak sądzę), ale głównym problemem jest to że o ile linie maluje, to program nie "zakrywa" ich rzekomo skopiowaną zawartością

0

Pokombinowałem z segmentami i wszystko bardzo fajnie rysuję i przywraca, ale tylko na "sztywnych danych". Kiedy dodaję wersję z przypisaniem elementu z tablicy:

mov si,[losowe+bx]
mov ax,si
mov cx,160
mul cx
mov si,ax

Przywracają się losowe znaki, dobrze indeksuje i przypisuję tablicę ?

0
ECHU napisał(a):

Pokombinowałem z segmentami i wszystko bardzo fajnie rysuję i przywraca, ale tylko na "sztywnych danych". Kiedy dodaję wersję z przypisaniem elementu z tablicy:

mov si,[losowe+bx]
mov ax,si
mov cx,160
mul cx
mov si,ax

Przywracają się losowe znaki, dobrze indeksuje i przypisuję tablicę ?

A opisz słowami, co chcesz w tym fragmencie uzyskać. Czy druga instrukcja nie powinna być "mov ax,[si]", albo całość tej sekwencji:

mov ax, losowe[bx]
mov cx, 160
mul cx
mov si, ax

0

mov ax, losowe[bx]
mov cx, 160
mul cx
mov si, ax

0

Używałem już takiego sposobu, i wtedy program wariuje, i zamiast ładnie kopiować i przywracać, wkleja losowe znaki. Ogólnie ten fragment miał działać tak (w pierwowzorze, wiem że bez sensu najpierw do si):
do si ładujemy pierwszy element tablicy losowe (tablica ta przetrzymuję numer lini), następnie wrzucamy to do ax (ponieważ mul mnoży ax przez coś) żeby pomnożyć przez 160 (ilość bajtów w wierszu), żeby określić gdzie zacząć kopiować, bądź przywracać.

0

I nie mam bladego pojęcia co w tym zapisie jest złego, bo gdy zamiast całej tej formuły, wrzucę "ręcznie" do si np.160 (początek 1 linii - numerowane od 0) to program działa bardzo dobrze.

1 użytkowników online, w tym zalogowanych: 0, gości: 1