kategorie: ANSI C, Asembler
[#31] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #29

Wydaje mi sie, ze niepotrzebnie skomplikowales sobie implementacje fifo i przy okazji ograniczyles wielkosc bufora do max 8 pozycji. Lepiej zrobic tak aby wartosci, odczytywane z portu przechowywac kazda z osobna w tablicy. Wtedy bedzie mozna pozbyc sie tych wszystkich przesuniec typu lsl, lsr i or z assemblera jak i c.
Jak bede mial chwile, to podesle ci jutro jakas prosta implementacje.
[#32] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #31

Dziękuje za sugestie.
Zrezygnowałem jednak z triku "upakowania" 4 kodów, w prymitywnym FIFO, gdzie wszystkie kody były zmieszczone w jednym 32 bitowym long'u. Dzięki takiemu upakowaniu tylko jeden przypadek mogł być szybko sprawdzony: FIFO puste (patrz skok .skip_check w starym kodzie). Natomiast podczas nawału pracy, kod przerwania musiał niepotrzebnie spędzać jeszcze dodatkowy czas na analizie chyba lepszym rozwiązaniem jest zająć trochę więcej pamięci i indeksować FIFO na tablicy UBYTE[]. Tak zrobiłem w nowym kodzie, i tutaj wykrycie zajętości pamięci to sprawdzenie czy ogon dogania głowę ;).
struct {
    UBYTE head;		        // 0 message counter head
    UBYTE tail;		        // 1 message counter tail
    ULONG sigbit;         // 2
    struct Task *task;		// 6
    APTR potgoResource;		// 10
    UBYTE codes[256];     // 14
} mousedata;

Z chęcią obejrzę tą prostą implementację.
@Don_Adan mea-culpa, rzeczywiście muszę jeszcze się dużo nauczyć w temacie asemblera. Te suffixy o których wspomniałeś mają nawet inne znaczenie dla BNE, BEQ itp, a inne dla operacji logicznych - zmyliła mnie notacja używana przez autora oryginalnego kodu.
Do tej pory korzystałem z MarkeyJester’s Motorola 68000 Beginner’s Tutorial i serii Scoopex na YT. Polecicie mi jeszcze jakieś inne materiały?
[#33] Re: przerwanie twierdzi co innego niż sterownik

@sq7bti, post #32

W przypadku skokow/branchy to suffixy oznaczaja maksymalny zasieg i w sumie dlugosc instrukcji bne.b/bne.s (2 bajty) to skok w zasiegu bajta (-128 do +126). bne.w (4 bajty) to skok w zasiegu slowa. a bne.l (6 bajtow) to skok w zasiegu dlugiego slowa, ta instrukcja dziala tylko na 68020+. Sorry, ze troche za ostro napisalem w poprzednim poscie, ale mnie bardzo razi takie mieszanie wordow i longwordow, bo przez to beda raczej tylko problemy, ze program bedzie dzialal lub nie dzialal losowo w zaleznosci od konfigu, szczescia czy uruchomionych programow w tle. Zreszta nie jestes jedynym, ktory ma taka tendencje, pewien dosc nerwowy Anglik, autor paru gier tez tak ma, no ale skoro lubi sobie potem debugowac kod, dlaczego mu cos dziala lub nie dziala to znaczy, ze ma duzo czasu. A Tobie calkiem niezle idzie.
1
[#34] Re: przerwanie twierdzi co innego niż sterownik

@Don_Adan, post #33

Dzięki!.
s.
p.s. znowu zrobiłem ten sam błąd: oczywiście powinno być "tę" ;)
[#35] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #31

Ok, zrobilem taka prosta implementacje ring buffera z limitem. Dane dodawane sa az do osiagniecia pojemnosci - powyzej nowe dane nie sa juz dodawane. QueueWriteIndex jest indexem, gdzie ma byc dodany nowy element, QueueReadIndex jet indexem, skad ma byc pobrany element. QueueSize to rozmiar bufora. Liczba elementow, ktore sa przechowywane jest zawsze o 1 mniejsza od wielkosci bufora.
Jest jedno ograniczenie - ze wzgledu na uproszczone modulo bufor musi byc wielkosci (n^2)-1 czyli np 7, 15, 31 etc

! Nie przetestowane ! - nie wiem nawet czy sie skompiluje ale na pierwszy rzut oka powinno dzialac :)

ponizej masz kod asm - moje zmiany sa mala litera:
INCLUDE "hardware/custom.i"
	INCLUDE "hardware/cia.i"
	INCLUDE "devices/input.i"
	INCLUDE "devices/inputevent.i"
	INCLUDE "resources/potgo.i"
	INCLUDE "lvo/exec_lib.i"
	INCLUDE "lvo/potgo_lib.i"


md_joydat 			equ 0
md_pra				equ 2
md_sigbit			equ 4
md_task				equ 8
md_potgoResource		equ 12
md_QueueWriteIndex	equ 16
md_QueueSize			equ 18
md_QueueReadIndex	equ 20
md_Queue			equ 22
 
* Entered with:       A0 == scratch (execpt for highest pri vertb server)
*  D0 == scratch      A1 == is_Data
*  D1 == scratch      A5 == vector to interrupt code (scratch)
*                     A6 == scratch
*
    SECTION CODE

	; Pin 5 (mouse button 3) is connected to an interrupt enabled pin on the MSP430 controller
	; Toggling this generates an interrupt and MSP430 writes the scroll wheel
	; values to X/Y mouse coordinate delta lines
	XDEF    _VertBServer
_VertBServer:

	; If the middle mouse button being held down do nothing!
	; Just in case we have plain mouse plugged in and MMB is down (line short)
	LEA	_custom,A0
	MOVE.W	potinp(A0), D0			; read POTGOR
	AND.W	#$100, D0				; mask with BIT8
	BEQ.W	abort

;check if queue is full: if(QueueWriteIndex == ((QueueReadIndex - 1 + QueueSize) % QueueSize))
 	move.l md_QueueWriteIndex(a1), d0	; 16
	move.w md_QueueReadIndex(a1), d1	; 12

	subq.w #1, d1					; 4 
	add.w d0, d1						; 4
	and.w d0, d1						; 4

	swap d0							; 4
	cmp.w d0, d1						; 4
	beq abort						; 10	= 58

	; Output enable right & middle mouse.  Write 0 to middle
	; 09    OUTLX   Output enable for Paula (pin 32 for DIL and pin 35 for PLCC) -> enable
	; 08    DATLX   I/O data Paula (pin 32 for DIL and pin 35 for PLCC)          -> set low
	MOVE.L	md_potgoResource(A1),A6	; potgoResource
	MOVE.L	#$00000200,D0			; word
	MOVE.L	#$00000300,D1			; mask
	JSR	_LVOWritePotgo(A6)			; WritePotgo(word,mask)(d0/d1)

	; Save regs for C code before
	LEA		_custom,A0
	MOVE.W	joy0dat(A0),A5			; Mouse Counters (used now)

	; Wait a bit.
	; MSP430 controller needs to catch the interrupt and reply on the X/Y mouse coordinate lines

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

	; Save regs for C code after MMB pulse
	MOVE.W	joy0dat(A0),D1				; Mouse Counters (used now)
	MOVE.W	A5,D0
	EOR.W	D0,D1					; EXOR joy0dat before and after pulse
	AND.W	#$0303,D1				; mask out everything, but the X0,X1, Y0 and Y1

	; If there was no change on data joy0dat values, no need to signal
	TST.W	D1
	BEQ	exit

	MOVE.B 	$BFE001,md_pra(A1)				; Left Mouse ODD CIA (CIA-A)

	; store data in the queue: Queue[QueueWriteIndex] = data;	
	move.w md_QueueWriteIndex(a1), d0			; 12
	move.w d1, md_Queue(a1, d0.w)				; 14

	; increment index: QueueWriteIndex = (QueueWriteIndex + 1) % QueueSize;
 	addq.w #1, d0							; 4
	and.w md_QueueSize(a1), d0 				; 12
	move.w d0, md_QueueWriteIndex(a1)			; 12 = 54

	; Signal the main task
	; delay introduced in code below is enough to confirm reception to MSP430
	;
	MOVE.L	A1,A5					; preserve A1 in A5
	MOVE.L 4.W,A6
	MOVE.L md_sigbit(A1),D0					; Signals
	MOVE.L md_task(A1),A1				; Task
	JSR _LVOSignal(A6)
	MOVE.L	A5,A1					; restore A1 from A5

exit:
	; Output enable right & middle mouse.  Write 1 to middle
	; 09    OUTLX   Output enable for Paula (pin 32 for DIL and pin 35 for PLCC) -> enable
	; 08    DATLX   I/O data Paula (pin 32 for DIL and pin 35 for PLCC)          -> set high
	MOVE.L	md_potgoResource(A1),A6				; is_Data
	MOVE.L	#$00000300,D0				; word
	MOVE.L	D0,D1					; mask
	JSR	_LVOWritePotgo(A6)			; WritePotgo(word,mask)(d0/d1)

abort:
	MOVE.L	$DFF000, A0				; if you install a vertical blank server at priority 10 or greater, you must place custom ($DFF000) in A0 before exiting
	MOVEQ.L #0,D0					; set Z flag to continue to process other vb-servers
	RTS

Zmiany w c - zamiast definicji struct mousedata wstaw to:
#define FIFO_QUEUE_ELEMENTS 6
#define FIFO_QUEUE_SIZE (FIFO_QUEUE_ELEMENTS + 1)	//  must be (power of 2) -1!

struct
{
	UWORD joy0dat;				// 0
	UBYTE pra;					// 2 0xbfe001
	UBYTE pad;					// 3
	ULONG sigbit;					// 4
	struct Task *task;				// 8
	APTR potgoResource;				// 12
	UWORD QueueWriteIndex;			// 16 do not reorder!
	UWORD QueueSize;				// 18 do not reorder!
	UWORD QueueReadIndex;			// 20
	int Queue[FIFO_QUEUE_SIZE];		// 22
} mousedata;

Wielkosc kolejki jest ustawiona na 6 elementow, mozesz sprawdzic tez dla 14 i 30 elementow.

kodem ponizej zastap petle while (1)
mousedata.QueueWriteIndex = mousedata.QueueReadIndex = 0;
	mousedata.QueueSize = FIFO_QUEUE_SIZE;
	while (1)
	{
		ULONG signals = Wait (mousedata.sigbit | SIGBREAKF_CTRL_C);
		if (signals & mousedata.sigbit)
		{
			while(mousedata.QueueWriteIndex != mousedata.QueueReadIndex)
			{
				CreateMouseEvents(wheel_code(mousedata.Queue[mousedata.QueueReadIndex));
				mousedata.QueueReadIndex = (mousedata.QueueReadIndex + 1) & mousedata.QueueSize;
	        }
		}
		if (signals & SIGBREAKF_CTRL_C)
		{
			PutStr("Exiting\n");
			break;
		}
	}

Teraz kod jest duzo prostszy i powinien byc tez duzo szybszy...
1
[#36] Re: przerwanie twierdzi co innego niż sterownik

@docent, post #35

Dzięki @docent!
Po krótkiej przerwie zmodyfikowałem kod w taki sposób by ograniczyć wpływ podłączonej zwykłej myszy na sterownik. W obu FIFO (i tym które zaproponował docent jak i w moim) każdy bajt jest wykorzystany tylko w części (4 bity na kod), dlatego umieściłem dodatkową informacje o ewentualnej zmianie już po wysłaniu sygnału dla kodu sterownika w .c. Kod przerwania nie oddaje sterowania aż sam nie skończy, więc mogę do woli modyfikować strukturę w dzielonej pamięci, aż do RTS. Dzięki temu mam 2 kody: jeśli pierwszy odczyt jest różny od zera - mam kod przesłany przez kontroler myszy, a jeśli drugi jest równy zeru, mam potwierdzenie że kontroler myszy wystawił ponownie na liniach stany takie same jak przed przerwaniem.

Widać to wyraźnie na powyższym wykresie: pierwszy moment jest zaraz po opadającym zboczu linii MMB (niebieski), drugi odczyt joy0dat w połowie impulsu z myszy, trzeci już po. Oba zbocza oznaczają odpowiednio początek i koniec obsługi przerwania - ok 90us. Nie jest do tego wliczony czas obsługi samego sterownika w .c. Muszę się bardzo postarać (kręcić szybko rolką) by Top pokazał że sterownik zajmuje więcej niż 1% czasu procesora, a gdy nic nie ruszam spada poniżej 0,01%. W tym samym czasie input.device (to jest chyba ta część OS która jest wywoływana przez
DoIO((struct IORequest *)InputIO);
na końcu sterownika, więc nie mam jej jak zoptymalizować.
s.
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