kategorie: ANSI C, Asembler
[#1] przerwanie twierdzi co innego niż sterownik
We wstępie uprzedzam: kod nie jest pierwotnie mojego autorstwa. Ja go dostosowałem do moich potrzeb, więc najprawdopodobniej problem wynika z niezrozumienia działania cudzego kodu.

Jest sobie kod przerwania VBR napisany w asemblerze. Za zadanie ma sprawdzić ZMIANĘ stanu linii na portu myszy (_custom+joy0dat, bity 0x0303). Robi to przez:

Następnie jeśli różnicy nie ma, ma zaniechać sygnalizowania sterownika (w C). W przeciwnym przypadku ma wygenerować sygnał przez skok do _LVOSignal. W obu przypadkach na zakończenie ustawiana jest linia MMB ponownie do stanu wysokiego.

Teoretycznie, kod sterownika w switch nie powinien nigdy napotkać wartości zero, który odpowiadałby brakowi zmiany stanów na liniach X0/X1/Y0/Y1.

Niestety od czasu do czasu na konsoli sterownik "wypluwa" "bang!". Taka sytuacja najczęściej występuje przy dużym obciążeniu - kiedy np. przewijam cały ekran w IBrowse, ale nie zauważam opóźnieniu w wykonaniu kodu przerwania (przebiegi na linii MMB wyglądają tak samo).

Dlaczego tak się dzieje? Czy wartości komórki pamięci przydzielonej dla sterownika i kodu przerwania jest modyfikowana przez jakiś inny program? (AmigaDOS nie ma ochrony pamięci). Jest to struktura, do której dostęp maja oba kody, nie jest to sprzętowy rejestr joy0dat:

struct {
    UWORD potgo;		// 0 0xdff016
    UWORD joy0dat;		// 2
    UBYTE pra;			// 4 0xbfe001
    UBYTE pad;			// 5
    ULONG sigbit;		// 6
    struct Task *task;		// 10
    APTR potgoResource;		// 14
} mousedata;


Kod przerwania odwołuje się do pola joy0dat przez offset względem rejestru A1: 2(A1)

Czy jakieś narzędzia np. do analizy wpisów poza za-alokowanym obszarem pamięci byłby w stanie pomóc w lokalizacji problemu? Jak to zrobić?

s.

Ostatnia aktualizacja: 25.10.2021 12:21:09 przez sq7bti

Ostatnia aktualizacja: 25.10.2021 12:22:10 przez sq7bti
[#2] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #1

Problem może też wynikać z tego że program jest niewłaściwie napisany i działa przez przypadek.
O ile dobrze zrozumiałem to program ma działać w zgodzie z OS. Z tego wynika, że nie powinniśmy grzebać w rejestrach hardware.
W samym przerwaniu jest robiony WritePotgo, ale ja nie widzę tam pary AllocPotBits/FreePotBits() i sprawdzenia czy udało się zaalokować bity dla naszych celów.

Nie jestem pewny czy przerwanie vertb jest tutaj dobrym pomysłem. Może lepszym byłoby się podpięcie własnego input handlera.

Przy wołaniu amigowych procedur bibliotecznych to o ile nie zostało napisane to trzeba pamiętać że rejestry a0/a1/d0/d1 mogą być dowolnie używane przez nie. W przypadku devices to chyba także obowiązuje, jeśli się mylę to poprawcie mnie.

I najważniejsze pytanie. Co chcesz osiągnąć ?
[#3] Re: przerwanie twierdzi co innego niż sterownik

@asman, post #2

Co chcesz osiągnąć ?

Przede wszystkim chciałbym żeby procedura obsługująca przerwanie VBR zajmowała możliwie jak najmniej czasu procesora.
I chciałbym oczywiście by był jak najbardziej zgodny z OS.

Co się dzieje w sterowniku .c, to już reakcja na kody przesłane przez mysz: np. wygenerowanie InputEvent który emuluje funkcję rolki, albo środkowego klawisza myszy.

ZTCW to wszystkie inne sterowniki myszek wykorzystują właśnie taki sposób na cykliczny odczyt stanu myszy: co 20ms w takim momencie by nie przeszkadzać w normalnej pracy portu myszy.

A'propos AllocPotBits/FreePotBits dopisałem takie coś do procedury alokowania zasobów (korzystając z przykładu):

@@ -266,7 +276,13 @@ int AllocResources()
                                                InputBase = (struct InputBase *)InputIO->io_Device;
                                                if (mousedata.potgoResource = OpenResource("potgo.resource"))
                                                {
-                                                       return 1;
+                                                       potbits = AllocPotBits(OUTLX | DATLX);
+                                                       if(potbits == OUTLX | DATLX)
+                                                       {
+                                                               return 1;
+                                                       }
+                                                       else
+                                                               PutStr("Error: Could not allocate potgo output MMB");
                                                }
                                                else
                                                        PutStr("Error: Could not open potgo.resource\n");
@@ -290,6 +306,7 @@ int AllocResources()
 
 void FreeResources()
 {
+       FreePotBits(OUTLX | DATLX);
        if (InputIO)
        {
                CloseDevice((struct IORequest *)InputIO);

Niestety ta zmiana doprowadziła do problemu przy uruchamianiu. Program nawet nie pokazuje powitania na początku main(), tylko:
potgo.resource failed to load


To nie błąd przy wywołaniu AllocPotBits(), ale już przy samym starcie.

Co do zachowania zawartości rejestrów przy wywołaniu procedur systemowych, gdzie znajdę taki kompletny opis procedur z Kickstartu (exec?) do każdej z procedur (np. _LVOWritePotGo, albo _LVOSignal), takie jak informacje co w którym rejestrze mam umieścić jako argument, które będą modyfikowane, i w których mam wynik i w jakim formacie? Czy są one takie same jak dla C opisane w elowar?

Co do toolchain'a to korzystam z gcc-2.95 i gcc-6.5 (bebbo). Ten pierwszy niestety nie linkuje z ostatnimi zmianami (AllocPotGo()):
$ make
/opt/m68k-amigaos/bin/m68k-amigaos-gcc -c -o mousedriver.o mousedriver.c -O2 -noixemul
vasmm68k_mot -quiet -Fhunk -phxass -I /opt/gnu-6.5.0b/m68k-amigaos/ndk-include/ -o vbrserver.o vbrserver.s
/opt/m68k-amigaos/bin/m68k-amigaos-gcc -O2 -noixemul -o Blabber.driver mousedriver.o vbrserver.o
/opt/m68k-amigaos/m68k-amigaos/lib/libamiga.a(allocpotbits.o)(.text+0x4): undefined reference to `PotgoBase'
/opt/m68k-amigaos/m68k-amigaos/lib/libamiga.a(freepotbits.o)(.text+0x4): undefined reference to `PotgoBase'
collect2: ld returned 1 exit status
make: *** [Makefile:20: Blabber.driver] Error 1

Natomiast 6.5 wypluwa ostrzeżenia:
mousedriver.c:297:18: warning: implicit declaration of function 'AllocPotBits' [-Wimplicit-function-declaration]
        potbits = AllocPotBits(OUTLX | DATLX);


s.
[#4] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #3

Co do toolchain'a to korzystam z gcc-2.95 i gcc-6.5 (bebbo). Ten pierwszy niestety nie linkuje z ostatnimi zmianami (AllocPotGo()):


Spróbuj dodać includa <clib/potgo_protos.h> i dopisz struct Potgo *PotgoBase;
[#5] Re: przerwanie twierdzi co innego niż sterownik

@forge, post #4

Dzięki, pomogło przy kompilacji - "bang!" nadal jest drukowany. Sama alokacja tutaj nie pomogła.

Mam następne pytanie: Czy sposób w jaki zaimplementowana jest komunikacja między kodem przerwania i sterownika .c jest optymalna? W szczególności chodzi mi o flagę ustawioną przez _LVOSignal: czy ta flaga nie powinna być czasem skasowana po Wait()? W Elowar piszą że czytanie jest bezpieczne ale ustawianie może być niebezpieczne. W jaki inny bezpieczniejszy sposób to zaimplementować? Czy tu chodzi tylko o niebezpieczeństwo hazardu?
FUNCTION
    This function can query or modify the state of the current task's
    received signal mask.  Setting the state of signals is considered
    dangerous.  Reading the state of signals is safe.


Kod wygenerowany przez gcc-6.5 wywołuje funkcję OpenLib na potgo.resource, z opcjami "Ver 0", która kończy się niepowodzeniem. Tak przynajmniej wskazał SnoopDOS.
[#6] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #3

Co do zachowania zawartości rejestrów przy wywołaniu procedur systemowych, gdzie znajdę taki kompletny opis procedur z Kickstartu (exec?) do każdej z procedur (np. _LVOWritePotGo, albo _LVOSignal), takie jak informacje co w którym rejestrze mam umieścić jako argument, które będą modyfikowane, i w których mam wynik i w jakim formacie? Czy są one takie same jak dla C opisane w elowar?

Tak, kazdy parameter wejsciowy ma podany rejestr, w ktorym powinien sie znalezc. Wynik dzialania funkcji umieszczany jest zawsze w rejestrze d0.
Wszystko to jest opisane w autodocach.
[#7] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #1

Dzieje sie tak dlatego, ze struktura jest wspoldzielona miedzy przerwaniem a programem. Wykorzystujesz to samo pole do odczytania/sprawdzenia stanu portu w przerwaniu jak i w sygnalizowanym tasku. W momencie wiekszego obciazenia systemu (np. gdy pojawi sie task o wiekszym priorytecie np. renderowanie ui w kontekscie input device) twoj task nawet po otrzymaniu sygnalu z przerwania i przejsciu w stan ready nie bedzie od razu aktywny, co spowoduje opoznienie sprawdzenia pola joy0dat. W miedzyczasie vblank jest wywolywany ponownie i np. zeruje to pole -> bang :)
Najprostsze rozwiazanie to taka zmiana obslugi przerwania aby pole joy0dat zapisywac tylko gdy wykryta zostanie zmiana sygnalu.

W assemblerze:
1. zastap
31 MOVE.W joy0dat(A0),2(A1) ; Mouse Counters (used now)
32 AND.W #$0303, 2(A1) ; mask out everything, but the X0,X1, Y0 and Y1
tym
move.w joy0dat(a0), a5
and.w #$0303, a5

2. zastap
61 EOR.W D0,2(A1) ; EXOR joy0dat before and after pulse
62 AND.W #$0303,2(A1) ; mask out everything, but the X0,X1, Y0 and Y1
tym:
eor.w d0, a5
3. zastap
70 TST.W 2(A1)
tym
tst.w a5
4. dodaj w linii 72 (po beq exit)
move.w a5, 2(a1)

dodatkowym bonusem bedzie zmniejszenie czasu wykonywania tego przerwania (skrocenie i zminimalizowanie dostepow do pamieci)
W c zrob nastepujace poprawki:
1. usun SetSignal w linii 104 - jest niepotrzebny, bo Wait zeruje juz ten bit
2. przenies sprawdzanie ctrl c PO sprawdzaniu sygnalu z przerwania - jest ono mniej istotne od obslugi sygnalu z przerwania, wiec powinno byc obslugiwane w drugiej kolejnosci
3. dorob odczyt ze struktury do lokalnej zmiennej ZARAZ po Wait np. WORD joydata = mousedata.joy0dat;
4. zamien switch (mousedata.joy0dat) na switch (joydata), w kolejnych case jesli potrzebujesz to odwoluj sie do zmiennej joydata nie do pola struktury.
5. zamiast CreateMouseEvents(code); wpisz if (code!=MM_NOTHING) CreateMouseEvents(code); Mozesz tez usunac ten test z CreateMouseEvents. W ten sposob bedziesz wywolywal CreateMOuseEvents tylko gdy faktycznie trzeba wygenerowac input event.

zmiany 3,4,5 zmniejsza czas obslugi sygnalu oraz szanse, ze pole joy0dat zmieni sie w trakcie obslugi switcha
Aby w pelni zabezpieczyc sie przed taka sytuacja, dostep do pola joy0dat powinien byc serializowany np za pomoca semafora albo Disable/Enable

Ostatnia aktualizacja: 26.10.2021 02:10:37 przez docent
1
[#8] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #7

Ja sobie myślę, że autor powinien odpowiedzieć na pytanie, czy VERTB w tym przypadku jest mu niezbędny. Powoduje on problemy, które opisałeś.

Nie lepiej użyć timer.device ? Odpadło by współdzielenie struktury. Poza tym można by zlikwidować ten kawałek kodu

Delay:
	; cocolino 36,
	; ez-mouse 25
	MOVEQ	#18,D1					; Needs testing on a slower Amiga!
.wait1
	MOVE.B	vhposr+1(A0),D0				; Bits 7-0     H8-H1 (horizontal position)
.wait2
	CMP.B	vhposr+1(A0),D0
	BEQ.B	.wait2
	DBF	D1,	.wait1


dzięki timer.device.
[#9] Re: przerwanie twierdzi co innego niż sterownik

@asman, post #8

Moze wystarczy zwiekszyc wait po prostu z 18 linii na 36 i wtedy sprawdzic, czy dziala ok? Timer moze byc tez dobry, ale nie wiem czy nie bedzie z nim problemu jezeli za duzo programow bedzie go na raz wykorzystywac.
[#10] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #7

Raczej nie da sie A5 tak wykorzystywac, chyba o inny rejestr Ci chodzilo.
[#11] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #10

Dlaczego? a5 to scratch, wiec mozna go zajechac.
[#12] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #11

Nie sadze, zeby dzialaly nastepujace instrukcje, bo a5 to jest rejestr adresowy

and.w #$0303, a5

eor.w d0, a5

a tst.w a5 to chyba zadziala tylko na 68020+.

Ostatnia aktualizacja: 26.10.2021 19:12:24 przez Don_Adan
[#13] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #10

hmm, faktycznie zdaje sie, ze rejestr adresowy nie moze byc ea dla operacji typu eor, and. Trzeba to troche przerobic.
[#14] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #12

heh, wlasnie to zauwazylem. Za duzo ostatnio siedzenia po nocy I assemblera arm - oto skutki :)
[#15] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #7

Aktualizacja:

W assemblerze:
1. zastap
31 MOVE.W joy0dat(A0),2(A1) ; Mouse Counters (used now)
32 AND.W #$0303, 2(A1) ; mask out everything, but the X0,X1, Y0 and Y1
tym
move.w joy0dat(a0), d0
and.w #$0303, d0
move.w d0, a5
2. zastap
61 EOR.W D0,2(A1) ; EXOR joy0dat before and after pulse
62 AND.W #$0303,2(A1) ; mask out everything, but the X0,X1, Y0 and Y1
tym:
move.w a5, d1
eor.w d0, d1
3. zastap
70 TST.W 2(A1)
tym
tst.w d1
4. dodaj w linii 72 (po beq exit)
move.w d1, 2(a1)

- teraz powinno byc ok
[#16] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #9

Myślę że zwiększenie wait na 36 linii to i tak dużo za dużo dla mnie jak na przerwanie. Wolałbym spróbować z timer.device. Też nie wiem czy timer.device może być dobry ale myślę że podoła :) (oczywiście trzeba by to sprawdzić )
[#17] Re: przerwanie twierdzi co innego niż sterownik

@asman, post #16

Tak za duzo, ale do testow czy to jest problem waitu powinno wystarczyc. Do tego scanline wait jest zalezny od uzywanego trybu wyswietlania obrazu, co tez trzeba wziac pod uwagu. Wszystkie podwojne tryby potrzebuja dwukrotnie wiekszej wartosci niz pojedyncze.
[#18] Re: przerwanie twierdzi co innego niż sterownik

@asman, post #8

Tak, ta petla nie jest najlepszym rozwiazaniem - powoduje, ze driver zuzywa na nia kilka procent czasu procesora no i nie bedzie dzialac na systemach bez custom chipow :)
Wszystko zalezy od tego, jak bardzo musi byc stabilna czestosc odswiezania odczytu stanu myszki. Jesli nie jest to niezbedne to faktycznie timer.device moglby byc rozwiazaniem. Wydaje mi sie jednak, ze zmiany pozycji myszki powinny byc sprawdzane w regularnych odstepach czasu tak, aby np. przesuwanie bylo plynne. Timer.device nie gwarantuje, ze opoznienie bedzie mialo dokladnie tyle, ile zostalo podane ale conajmniej tyle i jest ono zalezne np. od obciazenia systemu. Jesli hardware wymaga dokladnych timingow zmiany jakiegos sygnalu, to timer device mozne nie wystarczyc.
W sumie mozna by bylo sprobowac takiego rozwiazania z timerem, moze by zadzialalo.
[#19] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #18

Dzięki za wszystkie podpowiedzi. Co zmieniłem:
  • w .c odczyt joy0dat jak najszybciej po Wait(signal) i potem analiza na kopii
  • w .s przechowanie pierwszego odczytu joy0dat w A5
  • zapis EXOR z drugim odczytem już po sprawdzeniu czy jest niezerowy


Tylko teraz nie wiem czy .c obsłużył poprzednie zadanie, bo nie sprawdzam czy nadpisuje dzieloną komórkę pamięci niezerowym nowym kodem. Może lepiej byłoby na początku .s jeszcze sprawdzić stan flagi Signal i tak po prostu poczekać z dokończeniem przerwania aż .c wykona powierzone zadanie?
Musiałby to być assemblerowy odpowiedznik pierwszego przykładu kodu z elowar:
SYNOPSIS
	oldSignals = SetSignal(newSignals, signalMask)
	D0		       D0	   D1
EXAMPLES
	Get the current state of all signals:
	    SetSignal(0L,0L);


Czy to będzie coś takiego? Mają być zera w D0 i D1, a wynik porównuje z 6(A1):
;
; Check if the main task already processed previous code
; if not wait for another round
;
MOVE.L A1,-(SP)                                ; preserve A1 on stack
MOVE.L 4.W,A6
MOVE.L #$0,D0                                  ; newSignals
MOVE.L #$0,D1                                  ; signalsMask
MOVE.L 10(A1),A1                               ; Task
JSR _LVOSetSignal(A6)
MOVE.L (SP)+,A1                                ; restore A1 from stack

CMP.L 6(A1),D0                                 ; check if the signal is still there
BEQ.s    abort


etykieta "abort" to wyjście z przerwania nawet bez ustawienia linii MMB.

Co do GNU-gcc-6.5 to chyba miałem jakiś stary. Zaciągnąłem z git'a bebbo najnowszą wersje i "potgo.resource failed to load" już się nie pokazuje.


Ostatnia aktualizacja: 26.10.2021 21:39:31 przez sq7bti
[#20] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #18

Wszystko zalezy od tego, jak bardzo musi byc stabilna czestosc odswiezania odczytu stanu myszk


Tu chyba jest pies pogrzebany i autor powinien tu się wypowiedzieć.

Przez przypadek wpadłem na pomysł, że można by użyć softwareowych przerwań link. Szczególnie to zdanie napawa optymistycznie

a self-perpetuating PA_SOFTINT timer port can provide an application with quite consistent timing under varying multitasking loads.

Z ręką na sercu muszę przyznać że mam bardzo małą wiedzę w tym zakresie.
[#21] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #7

Dzieje sie tak dlatego, ze struktura jest wspoldzielona miedzy przerwaniem a programem.


Żeby tego uniknąć wprowadziłem zmiany które opisałem w poprzednim(-ich) postach. Zmieniłem też sposób "przechowania" zawartości rejestru A1 podczas skoku do _LVOSignal: zamiast przez stos (odwołanie do pamięci), przez rejestr A5 który w tym czasie jest nieużywany. Takie zagranie jest chyba szybsze(?). Poza uniknięciem wywołania kodu .c przy zerowym kodzie z myszy, robię to też dla kodów które specjalnie nie używam bo mają największe prawdopodobieństwo pojawienia się przez przypadek (nie przy myszy która reaguje na MMB, ale np. myszy klasyczna, albo inna która może wystawić dowolny stan w dowolnym momencie na liniach XY).

Mam nadal pewną wątpliwość czy nie lepiej byłoby po prostu wstrzymać generowanie przerwania, do czasu gdy kod .c obsłuży odebrany kod. Tylko jak sprawdzić czy sygnał jest wyzerowany z wnętrza kodu przerwania .s? Wprowadziłem warunkowe wyjście na samym początku przerwania, ale nie widzę żeby się wykonywał kiedy przewijam okno IBrowse (wtedy miałem "bang!" - czyli nadpisywanie zawartości mousedata.joy0data przez przerwanie).

;
        ; Check if the main task already processed previous code
        ; if not wait for another round
        ;
        MOVE.L  A1,A5                                   ; preserve A1 in A5
        MOVE.L 4.W,A6
        MOVE.L #$0,D0                                   ; newSignals
        MOVE.L #$0,D1                                   ; signalsMask
        MOVE.L 10(A1),A1                                ; Task
        JSR _LVOSetSignal(A6)
        MOVE.L  A5,A1                                   ; restore A1 from A5

        CMP.L 6(A1),D1                                  ; check if the signal is still there
        BEQ.s   abort


Czyżby kod był na tyle szybki że zdążył się wykonać podczas jednej ramki?

Mam pomysł, ale nie wiem czy da się go łatwo zaimplementować. Chciałbym zmienić kolor wyświetlanej linii na czas wykonywanie kodu .c (czyli zmienić paletę COLOR# na początku, i odtworzyć na końcu procedury .c). W taki sposób powinno być widać na ekranie pasek który miałby szerokość proporcjonalną do czasu spędzonego na wykonaniu kodu .c. Jak to zrobić?

Co do częstotliwości odczytu stanu myszy, to jest to już chyba standard w myszach Amigowych że odbywa się to co ramkę:

Przy szybkim ruchu rolką do przewijania, myszy potrzebuje kilku ramek by przesłać wszystkie sygnały odpowiadające za pojedynczy sygnał z rolki. Wystarczy policzyć zbocza na liniach QRA i QRB i odpowiadające im impulsy na liniach XY, które zsynchronizowane z MMB służą za przekaz kodów dla rolki.

Od częstotliwości odczytu stanu myszy ważniejsze jest utrzymanie stałych czasowych między zboczami na MMB - od ich stabilności zależy pomyślność współpracy z kontrolerem myszy. Jeśli timer.device dałby dokładność na poziomie części us to mogę go zastosować. Tylko jak we wnętrzu kodu przerwania wywołać timer.device i powrócić po np. 80us by dokończyć obsługę przerwania?
[#22] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #21

Mozesz pewnie uzyc CIA-B do obslugi przerwania tak jak to jest zrobione w playerze PHX dla Protrackera do obslugi DMA wait. Zrodla sa chyba na Aminecie.
A co do szybkosci dzialania, to lepiej zamiast instrukcji move.l #0,D0 uzyc moveq #0,D0, no chyba ze zdajesz sie na optymalizacje asemblera.
No i to mozesz zmienic, kod bedzie krotszy, choc to juz chyba tylko exit jest.

MOVE.L #$00000300,D0 ; word
;MOVE.L #$00000300,D1 ; mask
move.l d0,d1
[#23] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #22

Poszukam tych źródeł. A co z malowaniem na ekranie?
[#24] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #23

Nie wiem, na grafice sie nie znam.

Tutaj sa te zrodla.

link
1
[#25] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #19

Zaczalbym od zdecydowania, czy kazda zmiana stanu myszki musi zostac obsluzona - wtedy trzeba by zrobic jakis rodzaj buforowania zmiany stanow jesli ich przetwarzanie na input eventy nie wyrabia sie. Jesli to nie jest kluczowe tak jak w obecnym kodzie, to synchronizacje mozesz robic prosciej, bez wywolywania SetSignal.
Zwroc uwage, ze pole joy0dat musi zawierac jakas wartosc <>0 w momencie wyslania sygnalu do tasku w c.
Robisz wiec tak:
1. Wyrzucasz dodany kod SetSignal I wykonujesz przerwanie tak jak w poprawkach, ktore wczesniej podeslalem
2. Po tst.w d1 ; beq exit sprawdzasz czy joy0dat w strukturze jest <>0, jesli tak, to wychodzisz z przerwania
tst.w 2(a1)
bne exit
3. Jesli nie, procesujesz sygnaly z portu jak poprzednio

W c po obsluzeniu i wygenerowaniu input eventu zerujesz joy0dat w strukturze.

W ten sposob bedziesz obslugiwal sygnaly myski tylko gdy task w c nie bedzie w trakcie generowania input eventow.
[#26] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #21

Mam nadal pewną wątpliwość czy nie lepiej byłoby po prostu wstrzymać generowanie przerwania, do czasu gdy kod .c obsłuży odebrany kod. Tylko jak sprawdzić czy sygnał jest wyzerowany z wnętrza kodu przerwania .s?

Zobacz porzedni moj post - tam masz rozwiazanie.
Wprowadziłem warunkowe wyjście na samym początku przerwania, ale nie widzę żeby się wykonywał kiedy przewijam okno IBrowse (wtedy miałem "bang!" - czyli nadpisywanie zawartości mousedata.joy0data przez przerwanie). Czyżby kod był na tyle szybki że zdążył się wykonać podczas jednej ramki?

Nie, moja poprzednia zmiana w kodzie vblank gwarantuje, ze joy0dat w strukturze zostanie wyzerowany tylko w przypadku pojawienia sie jakiejs niezerowej wartosci sygnalu myszki. Bang jest wyswietlany gdy wartosc jest zerowa a taka wartosc juz sie nie pojawia.
Generalnie nie przejmowalbym sie czy kod w c bedzie sie wyrabial w ramce - generowanie eventow jest dosyc szybkie i na pewno ramki nie zajmie. Problem pojawia sie tylko gdy jakis task o wyzszym priorytecie niz twoj zajmuje wiecej czasu.
[#27] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #25

Zacznę może od tego że mój kontroler myszy przesyła każdą informację: o wciśniętym, zwolnionym klawiszu, albo obrocie myszy, która jest różna od stanu zarejestrowanego do tej pory po stronie komputera. Przesłanie każdego kodu jest potwierdzona, dlatego może być traktowana jako "doręczona", i wtedy i tylko wtedy zaprzestaje jej przesłania. Może nastąpić taka sytuacja że podczas krótkotrwałej przerwy w komunikacji został na krótko wciśnięty któryś z klawiszy. Taka sytuacja nie zostanie wtedy zarejestrowana przez komputer. Nie wydaje mi się że jest to jakiś rażący problem. To samo tyczy się licznika pozycji rolki - jeśli obracana jest szybko w obu kierunkach, następuje próba przesłania nie wszystkich impulsów, ale tylko delta.
Takie krótkie przerwy w komunikacji są przewidywalne (widoczne, i pewnie też słyszalne) i świadomy użytkownik zdawałby sobie sprawę, że jeśli na ekranie widzi wolno (klatkująco) przewijaną zawartość ekranu, to "coś jest na rzeczy":

Wracają do proponowanych zmian, pozwoliłem sobie trochę zmodyfikować i wyjście z przerwania przeprowadzać jeszcze zanim wysterowana jest linia MMB (dlatego na wykresie powyżej występują przerwy - najdłuższa jest na ok 200ms - podczas gdy powinny odbywać się co ok 18ms).
Mam w planach dodać licznik wiadomości (zwiększane niezależnie w .s i w .c) którego modulo(4) wskazywałoby w którym miejscu mousedata.joydat umieszczony jest kod:
  • 0 - 0x0303
  • 1 - 0x0C0C
  • 2 - 0x3030
  • 3 - 0xC0C0

Takie bardzo proste FIFO o głębokości 4.

Co do szybkości wykonania kodu, na forum EAB zostało pokazane ciekawe narzędzie które analizuje kod 68k i pozwala na ocenę wydajności (długość wykonywanego kodu oraz ilość zapisów i odczytów (z pamięci)). Poniżej widać różnicę w długości o którą się pytałem w jednym z poprzednich postów:


Brakuje mi tylko jak bardzo kosztowne jest wywołanie jakichś funkcji kernela - jak np. na powyższym przykładzie SetSignal()
[#28] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #27

Takie proste fifo to dobry pomysl. Co do kodu przerwania to, tak jak napisalem poprzednio, mozesz wyrzucic caly ten kod z SetSignal w liniach 38-47 bo jest niepotrzebny - pole joy0dat pelni te sama funkcje. W c jeszcze musisz zrobic w linii 253 mousedata.joy0dat = 0;
Wywolanie kodu z romu bedzie zawsze kosztowne,nie tylko ze wzgledu na to, ze trzeba ustawic odp. parametry w rejestrach, to dodatkowo wywolana funkcja z reguly takze odklada rejestry na stosie itp. Dodaj to, ze czesc bibliotek w romie to skompilowane c I aczyna sie robic sporo.
SetSignal akurat jest dosyc prosta funkcja (tu w wersji z ks 1.2):
FC1E48  lea       $1A(A1),A0        Get the set of received signals.
FC1E4C  move.w    #$4000,DFF09A     Disable()
FC1E54  addq.b    #1,$0126(A6)
FC1E58  move.l    (A0),-(SP)        Store the signals.
FC1E5A  or.l      D0,(A0)           Or the new signals into the old ones.

        ; The code from here down is common to SetExcept, SetSignal, and
        ; Signal.  It checks if the task whose signals are being modified
        ; should be awakened.

FC1E5C  move.l    $1E(A1),D1        Check the exception signals,
FC1E60  and.l     D0,D1             and see if any of them have become set.
FC1E62  bne.s     FC1EAE            If so, go process them.
FC1E64  cmp.b     #4,$0F(A1)        See if the task is in the TS_WAIT state.
FC1E6A  bne.s     FC1EBE            If not, we're done.
FC1E6C  and.l     $16(A1),D0        See if a signal being waited for has been
FC1E70  beq.s     FC1EBE            set.  If not, we are done.

.....

        ; Exit here if the current task was allowed to keep running (i.e.
        ; the other task did not preempt it).

FC1EBE  subq.b    #1,$0126(A6)      Enable()
FC1EC2  bge.s     FC1ECC
FC1EC4  move.w    #$C000,DFF09A
FC1ECC  move.l    (SP)+,D0          Return old signals.
FC1ECE  rts


Ale I tak to duuuuzo wiecej niz jeden test rejestru :)
[#29] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #28

Takie proste fifo to dobry pomysl.

FIFO dało trochę "ulgi" przy odbiorze sygnałów o obrotach rolki z myszki podczas przewijania dużego okna. Na wykresie poniżej widać już najdłuższe przerwy tylko około 90us. Problem nie występuje np. przy przewijaniu prostych list (np. MUI).

Zajętość procesora jest pewnie też do zoptymalizowania. Podczas próby udało mi się osiągnąć 0.5% czasu procesora (060/90MHz), a podczas spoczynku ledwo mierzalna.
Do optymalizacji np. jest kod który jest wykonywany za każdym razem, czyli wykrycie czy FIFO jest pełne:
Pierwotnie napisałem kod który sprawdza bity jeden po drugim (index FIFO jest dwubitowy) i przesuwa o 0, 2, 4 albo o 6 pozycji zawartość rejestru który ma być przekazany do .c:

Skoro przesunięcie jest w najgorszym przypadku o 6 pozycji kod poniższy okazał się nieco szybszy:

Jeśli macie jakieś uwagi do aktualnego kodu, byłbym wdzięczny za wszelkie uwagi i podpowiedzi.
[#30] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #29

Tak mam. Jak uzywasz word typu move.w 2(a1),d1 to nie uzywaj potem longword lsr.l #4,d1, bo to niechlujne, i moga byc problemy jesli highword nie jest zerem. no chyba, ze specjalnie tak sie robi, ale to nie ten przypadek. Dzialasz na wordach to uzywaj wordow, dzialasz na longwordach to uzywaj longwordow. A jezeli laczysz jedno z drugim to w komentarzu napisz, ze high word jest wyzerowany, albo ma jakas wartosc.
nie ma instrukcji typu btst.w czy lsl.l D1, to ze nie ktore asemblery to lykaja to ich sprawa. jest btst dzialajacy na rejestrze (longword) i na pamieci (bajt). Oraz lsl.l #1,d1. Te Twoje lsl.l d1, mozesz zastapic add.w d1,d1.

A
move.w (a1),d1
and.w #3,d1
z
moveq #3,d1
and.w (a1),d1
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