Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change SNES timings to specs #375

Conversation

stefan-b-jakobsson
Copy link
Collaborator

This is an attempt to follow SNES timing specs more closely.

In the current master branch, scanning the SNES controllers takes 1,473 clock cycles = 184 us.

This PR slows down the SNES controller latch and clock to about 12 us, according to specs. This increases the time needed to scan the controllers.

The SNES controller sends 16 bits of data. The current master branch reads another 8 bits, a total of 24 bits, where the last 8 bits are only used to check if a controller is present. This PR changes the controller detection by reading only one extra bit, reducing the duration of the scan.

After these two changes, scanning the SNES controllers takes 1,838 clock cycles = 230 us, i.e. 46 us more than the current master branch implementation.

It might be enough to get more SNES controller clones to work. If so, we need to decide if that is worth the extra 46 us.

… old check of controller presence. Reduce time needed to detect if controller present. Clean up comments.
@stefan-b-jakobsson
Copy link
Collaborator Author

Committed some improvements. The scan now takes 1,746 cycles = 218 us (+34 us compared to current master).

@stefan-b-jakobsson
Copy link
Collaborator Author

stefan-b-jakobsson commented Nov 23, 2024

I attempted to adjust the timing so that it's closer to how I think SNES consoles do it. Durations measured with the emulator.

  • After comment "Pulse latch for approx 12 us while clk=high": 97 cycles = 12.1 us from sta nes_data to stx nes_data
  • After comment "Wait 6 us after latch falling edge": 48 cycles = 6.0 us from jsr wait_6us until after clock is pulled low (stz nes_data) at beginning of l1 loop
  • l1 loop: 48 cycles = 6.0 us from pulling clock down (stz nes_data) until driving it high again (stx nes_data). l1 takes a total of 95 clock cycles (11.9 us)
  • l2 is identical from a timing perspective
  • joy_detect: 48 cycles (6.0 us) from pulling clock down (stz nes_data) until driving it high again (stx nes_data). After that the code doesn't interact anymore with the SNES controller.

If both my understanding and measurements are correct, we should be very close to the standard.

The joystick scan takes a total 1,769 cycles = 221 us (+37 us compared to the current master branch). The total duration measured from the start of the joystick scan method (before KVARS_START_TRASH_A_NZ) until the end of the method (after KVARS_END_TRASH_A_NZ).

The code works on my hardware (OtterX + original SNES controllers).

…,739 cycles = +33 us compared to current master
@stefan-b-jakobsson
Copy link
Collaborator Author

stefan-b-jakobsson commented Nov 23, 2024

I made some further changes to improve joystick scanning performance without breaking SNES timing.

In the latest code, joystick_scan reads the 17th bit from all controllers into .A and then stores that value holding the controller presence flags of all four controllers in the variable joycon. joycon bits 4..7 are 0 if the corresponding controller is present, and 1 if not.

The joystick_get function was changed to fetch the controller presence status from joycon, and return Y=$00 if connected, and Y=$FF if not. This means that joystick_get runs a bit slower than before, manually counted 10 cycles = 1.25 us. I assume it's better to push some of the increased processing time to joystick_get that is not part of the ISR.

The emulated keyboard joystick wasn't changed. It still uses joy0+2 to track whether connected or not.

joystick_scan is 217 us after this, +33 us compared to the current master. The scan takes about 1.3 % of the total VBLANK, compared to 1.1 % in the current master branch.

@stefan-b-jakobsson
Copy link
Collaborator Author

stefan-b-jakobsson commented Nov 23, 2024

SNES controller capture

Attached is a capture of the SNES port on my system (OtterX + original controller), made with a cheap logic analyzer (24 MHz). Results, compared to the real SNES console as described here: https://gamesx.com/controldata/snesdat.htm

  • Latch time: 12.0 us, diff +0.0 us
  • Delay after falling edge of latch, and before first clock: 5.9 us, diff -0.1 us
  • First clock, low duration: 5.8 us, diff -0.2 us
  • First clock, high duration: 5.9 us, diff -0.1 us
  • First clock, total duration: 11.8 us, diff -0.2 us
  • Duty cycle: 50.4 % (high), diff +0.4 % units
  • Following clock cycles run very close to the speed of the first clock cycle
  • Total duration of the first 16 clock cycles: 188 us, on average 11.75 us per clock cycle, diff -0.25 us

No button was pressed, and the first 16 bits are 1.

The 17th bit is 0, which tells that a controller is attached. The Data line went low about 1 us after the raising edge of Clock, that is 11 us before we need it.

@stefan-b-jakobsson
Copy link
Collaborator Author

I'm closing this PR as it is not clear it will actually support more SNES controllers.

The subject was discussed in depth here: https://discord.com/channels/547559626024157184/548715649065811989/1311825434794659911

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant