Gamepad von Sega Mega Drive und Raspberry Pi Part 2 (letzte Sechs-Tasten)



Weiter, der einfachste ist vorbei! Und nun zu den schwierigsten und interessantesten. Wenn Sie zu faul zum Lesen sind, finden Sie unten (am Ende des Artikels) einen Link zum Video mit dem Ergebnis und der Erklärung von allem, einschließlich dessen, was im ersten Teil beschrieben wird. Wenn Sie interessiert sind, folgen Sie bitte als nächstes.

Im 6-Tasten-Modus erfolgt das Lesen in 4 Zyklen oder Phasen (sofern in der Sprache des Emulators ausgedrückt). Das heißt, alle 16 ms ändert sich der Status des Select-Ausgangs zyklisch (4 Zyklen), und in jedem vierten Zyklus am Ausgang des Controllers wird der Status der zusätzlichen Tasten angezeigt. Nachfolgend finden Sie aus Gründen der Übersichtlichkeit eine Lesetabelle, die wiederholt werden muss:



Es ist gut, dass ich einen Logikanalysator habe, mit dessen Hilfe ich einen Fehler entdeckt habe, der sich darin manifestierte, dass der Zyklus die vierte Phase nicht verlassen hat.

Ich werde nicht um den heißen Brei herumreden, ich werde sofort eine Auflistung dieser Funktion geben:

static u32 read_pad_6btn(int i, u32 out_bits) { u32 pad = ~PicoIn.padInt[i]; // Get inverse of pad MXYZ SACB RLDU int phase = Pico.m.padTHPhase[i]; u32 value = 0; if (i == 0 && phase == 0 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 0 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 1 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 2 && (out_bits & 0x40)) // TH { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read UP button value ^= digitalRead(Data1) << 1; //read DOWN button value ^= digitalRead(Data2) << 2; //read LEFT button value ^= digitalRead(Data3) << 3; //read RIGHT button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 2 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); } if (i == 0 && phase == 3 && (out_bits & 0x40)) { digitalWrite (Select, HIGH); delayMicroseconds (20); value ^= digitalRead(Data0) << 0; //read Z button value ^= digitalRead(Data1) << 1; //read Y button value ^= digitalRead(Data2) << 2; //read X button value ^= digitalRead(Data3) << 3; //read MODE button value ^= digitalRead(Data4) << 4; //read B button value ^= digitalRead(Data5) << 5; //read C button } if (i == 0 && phase == 3 && !(out_bits & 0x40)) { digitalWrite (Select, LOW); delayMicroseconds (30); value ^= digitalRead(Data4) << 4; //read A button value ^= digitalRead(Data5) << 5; //read Start button digitalWrite (Select, HIGH); delayMicroseconds (10); value |= 0x0f; } if (i == 1 && phase == 0 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 0 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 1 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 1 && !(out_bits & 0x40)) // TH { value = ((pad & 0xc0) >> 2) | (pad & 3); // ?0SA 00DU } if (i == 1 && phase == 2 && (out_bits & 0x40)) // TH { value = pad & 0x3f; // ?1CB RLDU } if (i == 1 && phase == 2 && !(out_bits & 0x40)) { value = (pad & 0xc0) >> 2; // ?0SA 0000 } if(i == 1 && phase == 3 && (out_bits & 0x40)) { return (pad & 0x30) | ((pad >> 8) & 0xf); // ?1CB MXYZ } if(i == 1 && phase == 3 && !(out_bits & 0x40)) { return ((pad & 0xc0) >> 2) | 0x0f; // ?0SA 1111 } return value; } 

Lassen Sie uns eine der Bedingungen analysieren, zum Beispiel:

 if (i == 0 && phase == 1 && !(out_bits & 0x40)) // TH 

Hier wird überprüft, ob wir vom ersten Gamepad (i == 0) , der zweiten Lesephase (Phase == 1) und dem Select-Ausgang auf 0 lesen! (Out_bits & 0x40) . Um zu verstehen, wie dies im Emulator funktioniert, habe ich den Code auf Xubuntu kompiliert, und Visual Studio Code, der eine Reihe von Haltepunkten festlegt, hat den Code im Debug-Modus ausgeführt. Das Ergebnis ist so ein schönes Bild:



Eigentlich ist das Ergebnis der Arbeit:


Hier muss ich ein paar Worte über den Emulator selbst sagen. Entweder habe ich es nicht herausgefunden, oder dies ist ein Fehler, aber der Emulator wird zunächst im 3-Tasten-Modus geladen, auch wenn in den globalen Einstellungen das Gegenteil angegeben ist. Für 99% der Spiele reicht dies aus. Um mit einem 6-Tasten-Gamepad in den Betriebsmodus zu gelangen, müssen Sie in die Einstellungen gehen und zum Spiel zurückkehren, ohne etwas zu ändern.
Aber es gibt ein Spiel, das außerhalb dieses Kontexts liegt: Lost Vikings. Die Tasten X, Z und MODE funktionieren gut, ohne zu tanzen.

PS

Aber Sie können es noch einfacher machen, eine freundliche Person hat bereits einen Treiber für die Arbeit mit einem Gamepad geschrieben, und zwar auf einem sehr niedrigen Niveau. Davon bin ich noch weit entfernt.

Vielen Dank für Ihre Aufmerksamkeit!

Source: https://habr.com/ru/post/de435094/


All Articles