kategoria: Asembler
[#1] Zwis po zakończeniu programu w ASM-One 1.20
rekreacyjnie bawię się przykładami asemblera z ksiązki A. Doligalskiego i z kursu Photona na YT, i doświadczam zjawiska o którym nie wspominają ani Photon, ani autor ksiązki - po asemblacji (a) i uruchomieniu (j) dowolnego przykładu, owszem wykonuje się on, rysuje na ekranie co powinien, po czym przy próbie wyjścia z pętli (btst przycisk myszy) nastepuje zwis. I albo nic się nie dzieje, albo leci sieczka, albo czerwone GURU MEDITATION.
Dlaczego?
Np przykład poniżej rysuje białą linie na czarnym tle, po czym zwis:

;adolig_47.asm
Start:
	MOVE.L	#Copper_List, $dff080

	MOVE.L	#0, $dff088

Wait_Mouse_Button:
	BTST.B	#6, $bfe001
	BNE	Wait_Mouse_Button
	RTS

Copper_List:
	DC.L	$01000000
	DC.L	$01800000
	DC.L	$4001fffe
	DC.L	$01800fff
	DC.L	$4101fffe
	DC.L	$01800000
	DC.L	$fffffffe


PS. przykłady uruchamiam na WinUAE - na kilku konfigach, począwszy od gołej A500 z 1MB RAM.
[wyróżniony] [#2] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #1

no tak, bo to Amiga, nic samo z siebie sie nie zrobi, wiec po odczekaniu na przycisk myszki musisz przywrocic stara copperliste :)

looknij na 76 linie w tym przykladzie: http://vikke.net/index.php?id=horizontalshift-1 a nastepnie na 399 :) jak widzisz nalezy wpierw zapisac sobie pewne wartosci, zeby je pozniej przed wyjsciem przywrocic.

Ostatnia aktualizacja: 14.03.2016 14:39:09 przez juen
[#3] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #1

Napisz jaki system i jakiego assemblera używasz. Wygląda na to, że problem jest przez brak przywrócenia adresu copperlisty do starego stanu (choć system po wywołaniu swojego przerwania powinien przywrócić, ale może obecna jest nadpisywana danymi przy wyjściu i nadpisuje inne rejestry). Jak na ekranie jest sieczka, możesz spróbować zmienić ekran (chyba prawa Amiga + M).
[#4] Re: Zwis po zakończeniu programu w ASM-One 1.20

@juen, post #2

dzięki juen, działa :)

Co prawda prosty przykład wydłużył się ok 10x, ale po odtworzeniu rejestrów program działa poprawnie, rysuje co ma rysować i elegancko wraca do systemu.
Efekt finalny po zerżnieciu procedur init/exit Vikke'go wygląda tak:

DMACONR	EQU	$dff002 
ADKCONR	EQU	$dff010 
INTENAR	EQU	$dff01c 
INTREQR	EQU	$dff01e 
   
DMACON	EQU	$dff096 
ADKCON	EQU	$dff09e 
INTENA	EQU	$dff09a  
INTREQ	EQU	$dff09c

init: 
; own blitter, wait for blitter AND finally forbid multitasking! 
; all this just to be able to exit gracely 

; store data in hardwareregisters ORed with $8000 (bit 15 is a write-set bit when 
; values are written back into the system) 
	move.w	DMACONR,d0 
	or.w	#$8000,d0 
	move.w 	d0,olddmareq 
	move.w 	INTENAR,d0 
	or.w 	#$8000,d0 
	move.w 	d0,oldintena 
	move.w  INTREQR,d0 
	or.w 	#$8000,d0 
	move.w 	d0,oldintreq 
	move.w  ADKCONR,d0 
	or.w 	#$8000,d0 
	move.w 	d0,oldadkcon 

	move.l	$4,a6 
	move.l	#gfxname,a1 
	moveq	#0,d0 
	jsr	-408(a6)    ; oldOpenLibrary offset=-408 ... 
			;would OpenLibrary be better? offset=-552 
	move.l	d0,gfxbase 
	move.l	d0,a6 
	move.l	34(a6),oldview 
	move.l	38(a6),oldcopper 

	move.l #0,a1 
	jsr -222(a6)    ; LoadView 
	jsr -270(a6)    ; WaitTOF 
	jsr -270(a6)    ; WaitTOF 
	jsr -456(a6)    ; OwnBlitter 
	jsr -228(a6)    ; WaitBlit 
	move.l    $4,a6 
	jsr -132(a6)    ; Forbid 



Start:
	MOVE.L	#Copper_List, $dff080

	MOVE.L	#0, $dff088

Wait_Mouse_Button:
	BTST.B	#6, $bfe001
	BNE	Wait_Mouse_Button
	
exit: 
	; exit gracely - reverse everything done in init 
	move.w #$7fff,DMACON 
	move.w    olddmareq,DMACON 
	move.w #$7fff,INTENA 
	move.w    oldintena,INTENA 
	move.w #$7fff,INTREQ 
	move.w    oldintreq,INTREQ 
	move.w #$7fff,ADKCON 
	move.w    oldadkcon,ADKCON 

	move.l    oldcopper,$dff080 
	move.l     gfxbase,a6 
	move.l     oldview,a1 
	jsr -222(a6)    ; LoadView 
	jsr -270(a6)    ; WaitTOF 
	jsr -270(a6)    ; WaitTOF 
	jsr -228(a6)    ; WaitBlit 
	jsr -462(a6)    ; DisownBlitter 
	move.l    $4,a6 
	jsr -138(a6)    ; Permit 
 
	RTS

oldview:    dc.l 0 
oldcopper:    dc.l 0 
gfxbase:    dc.l 0 	   


olddmareq:    dc.w 0 
oldintreq:    dc.w 0 
oldintena:    dc.w 0 
oldadkcon:    dc.w 0 

gfxname:    dc.b 'graphics.library',0

	even
Copper_List:
	DC.L	$01000000
	DC.L	$01800000
	DC.L	$4001fffe
	DC.L	$01800fff
	DC.L	$4101fffe
	DC.L	$01800000
	DC.L	$fffffffe


PS. sprawdzone na emulowanej A500, 68000, 1MB RAM, Asm_ONE 1.20
[#5] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #4

Garść porad ode mnie, mam nadzięje, że się przydadzą.

Jeśli używasz Asm-One to masz do tego odpowiednią opcję w preferencjach 'Safety'. Jeśli jest włączoną to Asm-One zadba o poprawne wyjście. Oczywiście problem się pojawi gdy zechcesz zrobić plik wykonywalny, wtedy to wyjścia nie będzie to systemu.

Jeśli wywołujesz OldOpenLibrary, to nie musisz w D0 dawać wersji biblioteki, wystarczy w A1 - nazwa biblioteki. Różnica między OldOpenLibrary i OpenLibrary jest taka że w przypadku pierwszej nie podajesz wersji biblioteki w D0, a sama funkcja wygląda tak:
OldOpenLibrary:
 moveq #0,d0
 jmp -552(a6)

Czyli OldOpenLibrary tak po prawdzie wykonuje OpenLibrary, tyle że w D0 jest 0 (czyli, że odpowiada nam każda wersja biblioteki).

Wypadałoby na końcu zamknąć bibliotekę graphics, skoro została ona otwarta przez nasz program. Oczywiście w tym przypadku nic się nie stanie, system będzie dalej pracował.

Zamiast
move.l #0,$dff088

powinno być move.w, bo chcesz uruchomić natychmiast nową copperlistę. I nie musisz używać zero do tego, by spowodować natychmiastowy start copperlisty wystarczy dowolna wartość, więc można by zrobić
move.w d0,$dff088

I też będzie poprawne. W żadnym razie nie robimy numerów w stylu clr.w $dff088 jak to można spotkać w starych źródłach, bo jest robiony odczyt na rejestrze, który jest tylko do zapisu. I ma to miejsce dla 68000, wyższe procki już (tak myśle) poprawnie wykonują clr, bez odczytu.

Tak po prawdzie to nie musisz w sposób natychmiastowy uruchamiać copperlistę. Gdyż jeśli pominiesz zapis do $dff088, to o ile nie jest wykonywana copperlista która zmienia copperlistę (brzmi to jak masło maślane, ale tak nie jest), to wystarczy zapisać $dff080. I podczas nowej ramki zostanie wykonana Twoja copperlista.

Dla zaawansowanych: A jeśli zaczniesz bawić się blitterem i copperem jednocześnie to proponuje zrezygnować z $dff088, bo w amidze jest okrutny bug z tym związany, jeśli pracuje blitter i zrobisz zapis do $dff088 to program przestanie działać. O dziwo na WinUAE taki numer przejdzie :). W większości przypadków nie musisz się martwić takimi rzeczami, ale warto to sobie przypomnieć w sytuacjach kryzysowych.

Wyjaśnienie o copperliście zmieniającej copperlistę. Copperlista może modyfikować także $dff080 i można w ten sposób zmusić Coppera do uruchomienia innej copperlisty ( na przykład podwójne buforowanie ekranów)
copper:
 dc.w $0180, 0
 dc.w $80
 dc.w copper2  - wyższe 16 bitów
 dc.w $82
 dc.w copper2  - niskie 16 bitów
 dc.w $ffff,$fffe

copper2:
 dc.w $0180, $0fff
 dc.w $080
 dc.w copper - wyższe 16 bitów
 dc.w $082
 dc.w copper - niższe 16 bitów
 dc.w $ffff,$fffe
[#6] Re: Zwis po zakończeniu programu w ASM-One 1.20

@asman, post #5

Widzę tutaj potencjał na nowy przykład do repozytorium ;).
[#7] Re: Zwis po zakończeniu programu w ASM-One 1.20

@asman, post #5

Jeśli używasz Asm-One to masz do tego odpowiednią opcję w preferencjach 'Safety'.

Fajna opcja - AsmOne sam w sobie zasługuje na kurs, mam wrażenie że znam jego możliwości w 10 może procentach...

Co do otwierania/zamykania bibliotek - to mniej więcej mam ogarnięte, bo to akurat jest dobrze omówione w kursach C czy AmigaE, tutaj to po prostu przykład skopiowany ze strony podanej przez juena. Ale faktycznie razi brak zamknięcia biblioteki.

Ciekawi mnie za to czemu do natychmiastowego uruchomienie copperlisty trzeba stosować move.w zamiast move.l? Ze względów optymalizacyjnych? Dlaczego zatem nie move.b, albo moveq? Skoro dowolna wartość...

Blitter i copper jednocześnie - taaaa... Może za jakos czas ;) Copperlista zmieniająca cooperlistę też wymiata

Ostatnia aktualizacja: 15.03.2016 00:04:39 przez vojo
[#8] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #7

A ja tradycyjnie polecam programowanie w asemblerze pod system. Bez problemu da się zrobić copperlistę przy pomocy systemu. A zwie się ona copperlistą użytkownika.

Żeby nie być gołosłownym, przygotowałem przykład własnej copperlisty pisanej pod system. Program otwiera ekran i umieszcza tęczę Coppera a następnie czeka 6 sekund po czym wychodzi. Tutaj można zobaczyć cały kod tego programu, który jest niewielki, jak również pobrać całe archiwum z plikiem wykonywalnym, gotowym do uruchomienia.

Pobierz archiwum z przykładem

Obejrzyj kod źródłowy przykładu

Zaletą tego rozwiązania jest m.in to, że multitasking jest cały czas włączony i ze względu na zgodność z systemem - powinno działać na każdej Amidze.

Dlatego też promuję programowanie pod system Amigi. I według mnie nie jest wcale za dużo z tym roboty - powyższy przykład przygotowałem dziś wieczorem w ciągu ok. godziny.

--
Uwaga do kodu źródłowego: Brak zwalniania pamięci po copperliście użytkownika jest celowy, ponieważ copperlista użytkownika sama jest zwalniana podczas zamykania ekranu. Kod ma również mało komentarzy, więc może nie być łatwo zrozumiały dla początkującego.

Ostatnia aktualizacja: 15.03.2016 00:48:19 przez Hexmage960
[#9] Re: Zwis po zakończeniu programu w ASM-One 1.20

@Hexmage960, post #8

Ciekawy przykład, dzięki - ale jak pisac pod system to jednak wolę AmigaE, ewentualnie C :)
[#10] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #7

Co do AsmOne - to polecam książkę Adama Doligalskiego 'Asm-One. Opis rodziny'

Ciekawi mnie za to czemu do natychmiastowego uruchomienie copperlisty trzeba stosować move.w zamiast move.l? Ze względów optymalizacyjnych? Dlaczego zatem nie move.b, albo moveq? Skoro dowolna wartość...

Powinno być move.w bo rejestr $dff088 (COPJMP1) ma taki rozmiar (rozmiar słowa) a zaraz za nim czyli pod $dff08a (COPJMP2) rezyduje rejestr startu dla drugiej lokacji coppera. Pisząc move.l najpierw uruchamiasz copperlistę pod adresem $dff080 (COP1LC) a potem uruchamiasz copperlistę pod adresem $dff084(COP2LC). Wszystko fajnie ale dlaczego Twój przykład działa. Przecież powinna zostać odpalona copperlista, której adres leży w COP2LC. I tak też się dzieje. Najpierw zostaje uruchomiona copperlista numer 1 a potem zaraz numer 2, dla uproszczenia tak je nazwijmy. copperlista numer dwa jest przetwarzana aż do momentu wygaszenia pionowego, potem następuję ponowne przeładowanie copperlisty 1 (tej której adres jest w COP1LC) i tylko jej. To przeładowanie adresu copperlist w COP1LC odbywa się co każde wygaszenie pionowe (no chyba że wyłączysz DMA coppera i tym samym go zatrzymasz) . COP2LC nie posiada tej cechy i właśnie z tego powodu przykład działa. A działa tylko dlatego że copperlista 2 nie zmienia COP1LC, bo gdyby tak było, to Twój kod by nie działał. A o to mały przykładzik negatywny, który pokazuje że copperlista numer 1 nie działa, bo użyliśmy move.l zamiast move.w.
program:
		move.l	#copper3,d0
		lea	copper2,a0
		move.w	d0,6(a0)
		swap	d0
		move.w	d0,2(a0)

		move.w	#$7fff,$dff096
		move.w	#$7fff,$dff09a
		move.w	#$7fff,$dff09c

		move.l	#copper1,$dff080
		move.l	#copper2,$dff084
		move.l	#0,$dff088

		move.w	#$8280,$dff096

lmb:		btst	#6,$bfe001
		bne	lmb
		rts

	SECTION	gfx,DATA_C

copper1:
	dc.w	$0180,$0a00
	dc.w	$ffff,$fffe

copper2:
	dc.w	$0080,0
	dc.w	$0082,0
	dc.w	$0180,$0505
	dc.w	$ffff,$fffe

copper3:
	dc.w	$0180,$0050
	dc.w	$ffff,$fffe


Oczywiście zamiast move.w może być move.b d0,$dff088, ale ilość cykli i rozmiar samej instrukcji nie zmienia się czy to będzie move.b czy move.w, więc optymalizacja czasowa (mniej cykli) i pamięci (mniej pamięci zajmuje program) żadna. Dlatego najlepiej używać move.w, ja osobiście nie widziałem move.b d0,$dff088 w źródłach jak i w grach, które przeglądałem, za to widziałem zarówno clr.w jak i move.l i bodajże clr.l. W każdym razie nie może to być move.l bo rejestr jest rozmiaru słowa a nie długiego słowa i może się zdarzyć że ktoś zostawił taką wesołą copperlistą leżącą pod $dff088, która zmienia COP1LC i wtedy po ptakach.

Instrukcja moveq jest specyficzną instrukcją i jej zadanie to przeniesienie 8-bitowej liczby do rejestru Dx przy czym znak jest rozszerzany na całe długie słowo, z czego często i gęsto wszyscy korzystają. Czyli nie można użyć tutaj rozkazu moveq.

Mam nadzieję, że wszystko jest jasne, jakby co to śmiało proszę o pytania.


@strim_ - Potencjał to jest tylko te moje przeogromne lenistwo... Ale powalcze ze sobą w tym temacie.


Edit: Przykład negatywny ma wyjście do systemu o ile używany Asm-One z opcją Safety włączoną.

Ostatnia aktualizacja: 15.03.2016 23:18:57 przez asman
[#11] Re: Zwis po zakończeniu programu w ASM-One 1.20

@vojo, post #9

Cieszę się, że przykład się przydał. Jeszcze jedną, bardzo ważną zaletą pisania pod system jest możliwość debugowania kodu np. w Asm-One. Jeśli program działa na własnym ekranie i nie wyłącza wielozadaniowości możemy na bieżąco śledzić program w debuggerze i korygować ewentualne błędy.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem