forum speccy.pl
ZX Spectrum => PROGRAMOWANIE => Wątek zaczęty przez: pgru w 2018.04.26, 21:15:44
-
W Fuse wszystko działa. Natomiast jak testuję na realnym sprzęcie(Elwro 800 Jr, bez problemu radzi sobie z innymi grami i joystick działa) nie mogę poprawnie odczytać:
pętla zwalniająca - w trakcie której powinien nastąpić odczyt danych i przerwanie, jeśli następuje ruch postacią:
int petlazwalniajaca(long int n){
long int nk,nl;
int nb;
char klawsz;
nl=1;
/*
for(nk=0;nk<n;nk++)
{nb=nb*(nb+1);
//przerwanie petli zwalniającej w czasie ruchu gracza
if(joystick()!=0) return;
};
*/
for(nk=0;nk<n;nk++)
{
if(joystick()!=0) return;
//scanf("%c",klawsz);
// printf("c %c ",klawsz);
if(klawiatura()==5) printf("kursor w prawo");
};
}
Odczyt joysticka
int joystick(){
/*int k;
int n;
n=0; */
/*
while(1){k=joystickK();
if(k!=n)
{n=k;
printf(" %d ", k);
}}; */
// zwracamy wartości
// zwrotny 1 - przycisk - w Spectrum 16
// zwrotny 2 - góra - w Spectrum 8
// zwrotny 3 - lewo - w Spectrum 2
// zwrotny 4 - dół - w Spectrum 4
// zwrotny 5 - prawo - w Spectrum 1
if (joystickK()==16) return 1;
if (joystickK()==8) return 2;
if (joystickK()==2) return 3;
if (joystickK()==4) return 4;
if (joystickK()==1) return 5;
return 0;
}
Właściwa funkcja w asemblerze odczytująca port:
int __FASTCALL__ joystickK(unsigned p){
//sprawdza i zwraca wartość w 0x1f - interfejs joysticka od Atari - Kempston
#asm
// sprawdzenie 0x1f, dziesiętnie 31, jest to port więc korzystamy z in
ld a,$00
in a,(31)
//żeby zwrócić wartość trzeba ją umieścić w hl
//h może być 0 bo a ma mniejszą wartość
ld h,$00
//ld hl, a
ld l,a
ret
#endasm
}
Do kompilacji używam z88dk.
-
A tak zapytam, po co robisz ld a,$00 zaraz przed in a,(31)?
W języku C z pętli to się chyba wychodzi przez break, a nie return.
Ogólnie, w Twoim kodzie jest tyle brzydkich rzeczy, że chyba najlepiej, jakbyś sobie odświeżył znajomość języka C z jakiegoś samouczka online.
Przy odczycie joysticka brakuje obsługi skosów oraz fire+kierunek, ale rozumiem, że to uproszczenie w początkowej fazie eksperymentu.
-
Po mojemu byłoby tak (nie mam jak sprawdzić, czy działa):
int petlazwalniajaca(long int n){
for(int nk=0;nk<n;nk++)
{
if(joystick()!=0) break;
if(klawiatura()==5) printf("kursor w prawo");
}
}
int joystick(){
// zwracamy wartości
// zwrotny 1 - przycisk - w Spectrum 16
// zwrotny 2 - góra - w Spectrum 8
// zwrotny 3 - lewo - w Spectrum 2
// zwrotny 4 - dół - w Spectrum 4
// zwrotny 5 - prawo - w Spectrum 1
int retCode = 0;
switch(joystickK()) {
case 16: retCode = 1; break;
case 8: retCode = 2; break;
case 2: retCode = 3; break;
case 4: retCode = 4; break;
case 1: retCode= 5; break;
default: retCode = 0;
}
return retCode;
}
int __FASTCALL__ joystickK(unsigned p){
//sprawdza i zwraca wartość w 0x1f - interfejs joysticka od Atari - Kempston
#asm
// sprawdzenie 0x1f, dziesiętnie 31, jest to port więc korzystamy z in
xor a
ld h, a
in a,(31)
ld l,a
ret
#endasm
}
Pewnie można to zrobić lepiej :)
-
Poniższy przykład jest zły, dlatego że działa tylko i wyłącznie wtedy, kiedy naciśnięty jest jedynie jeden kierunek lub fire. W przeciwnym razie procedura nie wykryje kompletnie nic.
Zamiast liczb 1...5 należy użyć chociażby operacji na bitach jako zwracany stan 'manipulatora'.
{
retCode = 0;
if (kierunek & bit_kontrolera_lewo) retCode |= BIT_STEROWANIA_LEWO;
if (kierunek & bit_kontrolera_lewo) retCode |= BIT_STEROWANIA_PRAWO;
itp...
return retCode;
}
gdzie bit_kontrolera_lewo to wartość jaka pojawia się kiedy zostanie naciśnięty kierunek,
zaś BIT_STEROWANIE_LEWO to nasza lokalna definicja kierunków.
-
Ja u siebie zawsze robię tak i mi działa ;)
LD BC,31
IN A,(C)
Z tego co kojarzę to IN A,(C) to tak naprawdę IN A, (BC) - czytamy z portu który ma tak naprawdę szesnastobitowy adres.
A jeśli robimy IN A,(31) to też jakbyśmy robili IN A,(BC) gdzie C=31 a B jest cóż, takie jak w danej chwili B czyli w ogólnym przypadku losowe.
Tutaj znalezłem link gdzie o tym trochę jest, to jest trochę bardziej skomplikowane:
https://electronics.stackexchange.com/questions/92466/confused-about-in-out-architecture-of-z80-chip
Co do czytania kierunków to tak naprawdę wszystko zależy od tego co chcemy osiągnąć w grze czy innym programie. Czy poruszamy się po skosach czy nie? Co ma się stać jeśli człowiek wciśnie lewo i prawo naraz? Ale zgodzę się że najlepiej jest testować bity i zależnie od ich kombinacji wykonywać określone akcje.
-
A jeśli robimy IN A,(31) to też jakbyśmy robili IN A,(BC) gdzie C=31 a B jest cóż, takie jak w danej chwili B czyli w ogólnym przypadku losowe.
W IN A,(n) dolna połówka adresu to n, a górna to aktualna zawartość A.
Jeśli interfejsy dekodują tylko dolne 8 bitów, to zerowanie akumulatora można pominąć.
W innym przypadku jest to jak najbardziej prawidłowe działanie.
-
Dzięki Pear. Człowiek uczy się całe życie ;)
Może jeszcze mógłbyś potwierdzić albo zaprzeczyć czy joystick Kempston sprawdza górny bajt adresu?
( podejrzewam że to może być rózne zaimplementowane w róznych emulatorach stąd u Pgru rozjechały
się emulacja i rzeczywisty sprzęt)
-
Kempston w większości wykonań dekoduje tylko bit A5.
Inną sprawą jest czy w systemie znajdują się inne interfejsy, dla których istotne jest pełne adresowanie.
-
- Zasadniczo do tej gry są potrzebne 2 kierunki i przycisk. Dolnego używam tylko do sprawdzania punktów, dla tych graczy którzy chcą wiedzieć ile zdobyli.
- Ładowanie akumulatora 0 to taka kiepska(z mojej strony) próba naprawy sytuacji - nie wiedziałem czy nie pojawiały się tam jakieś losowe wartości :-(
-
aby sprawdzić jak w Juniorze (i nie tylko) odczytywana jest wartość z portu, wystarczy odpalić prosty program:
10 PRINT AT 0,0;IN 31;" "
20 GO TO 20
on powie dlaczego działa pod emulatorem, a dlaczego może nie działać na J.
-
Wartości dzięki programowi Tygrysa(dziękuję):
- brak ruchu - 64
- prawo - 65
- dół - 68
- lewo - 66
- góra - 72
z przyciskiem
- brak ruchu - 80
- prawo - 81
- dół - 84
- lewo - 82
- góra - 88
co by miało sens bo wg. książki o CP/J manipulator jest podłączony do linii portu A układu transmisji równoległej MCY 7855
Trzeba było to robić na bitach, ale spróbuję poprawić na razie prowizorycznie program :-)
-
W asemblerze, po "in a, (31)" dodaj "and 1fh".
-
Na szybko poprawiłem i działa. Zmieniłem też instrukcję wychodzenia z pętli. Dziękuję Wszystkim za odpowiedzi.
Zaraz sprawdzę to z dodawaniem do asemblera - bo jak rozumiem(nie wiem czy dobrze) ta instrukcja z and powinna obciąć różne inne wartości z różnych interfejsów?
-
@pgru nie. To, że w stanie "idle" dostajesz 64 oznacza, że twój interface joysticka po prostu wystawia na szóstym bicie (liczone od zera) na stałe jedynkę (być może jest to jakiś znacznik, który pozwala odczytać coś specyficznego a być może po prostu błąd konstrukcyjny interface'u) - "and 1fh" z pobranego bajtu po prostu wyzeruje wszystko powyżej piątego bitu.