It is currently Sat Oct 21, 2017 11:42 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Wed Dec 04, 2013 2:40 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
Anyone knowledgeable with writing Game Boy emulators here?

Have a strange problem in Metroid II: Return of Samus.

Image

If you hold left and then switch to holding right, or right and then left, Samus gets stuck in the turning state between the two directions, and ends up sliding around like in the above picture with no animation.

This is *not* because of allowing left+right at the same time, I explicitly filtered that out and made certain that wasn't the case.

I think it might have something to do with slow decay/transition states of the real hardware buttons, but I'm not sure how to emulate that to prevent this behavior.

Any insight would be greatly appreciated.


Last edited by byuu on Thu Dec 05, 2013 8:30 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Wed Dec 04, 2013 2:47 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
Are you making sure to emulate the lack of an inverter on Game Boy, GBC, and GBA controllers (1=released, 0=pressed)?


Top
 Profile  
 
PostPosted: Wed Dec 04, 2013 6:04 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
Yeah you wouldn't be moving at all without that. Input seems fine other than this one issue.

Code:
void CPU::mmio_joyp_poll() {
  unsigned button = 0, dpad = 0;

  //inputPoll() returns 1 when pressed, 0 when released
  button |= interface->inputPoll(0, 0, (unsigned)Input::Start) << 3;
  button |= interface->inputPoll(0, 0, (unsigned)Input::Select) << 2;
  button |= interface->inputPoll(0, 0, (unsigned)Input::B) << 1;
  button |= interface->inputPoll(0, 0, (unsigned)Input::A) << 0;

  //hacky just to be 100% sure it wasn't allowing left+right at the same time
  if(interface->inputPoll(0, 0, (unsigned)Input::Up)) dpad |= 4;
  else if(interface->inputPoll(0, 0, (unsigned)Input::Down)) dpad |= 8;
  if(interface->inputPoll(0, 0, (unsigned)Input::Left)) dpad |= 2;
  else if(interface->inputPoll(0, 0, (unsigned)Input::Right)) dpad |= 1;

  status.joyp = 0x0f;
  //it's supposed to act wonky like this when p15 and p14 are both clear ... but I verified Metroid II isn't doing this
  if(status.p15 == 0) status.joyp &= button ^ 0x0f;
  if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;  //inversion is here
  if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
}


Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 1:31 pm 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 190
byuu wrote:
I think it might have something to do with slow decay/transition states of the real hardware buttons, but I'm not sure how to emulate that to prevent this behavior.
The only transition states that exist are between when you select a line and when you read out the button state. On a DMG, when you write a 0 to activate one of the lines, this signal is propagated through the ribbon cable up to the display board and back to the relevant input pin on the CPU. Because of capacitance and series resistance, it may take a couple of microseconds for the state to propagate. This is why you see games read out $FF00 multiple times. This is nothing more than a delay, and only the last read does anything. As you might have noticed, the button group usually has a longer delay in the readout routine than the D-pad group, likely because the start/select group has a longer propagation delay than the other buttons, especially if it's worn/dirty. (I've tested this.)

That said, the propagation delay never needs to be emulated for gameplay of licensed ROMs. The only time when it would matter is if a program is actively checking for it, as in reading the button input early and making sure the input hasn't propagated. Even then, GBC completely lacks this delay, as it has 8 input pins and this switching is handled in logic inside the chip, which means there's no propagation delay. However, I convinced beware to implement it into BGB, to discourage people from writing ROMs that don't work on real hardware. (As a primary use of BGB is as a development tool.)

One theory I had was that the problem might happen if only left was pressed in one frame, and then only right was pressed the next frame, a situation unlikely to occur on a real console as it would likely take a human more than one frame to pivot the D-pad from one side to the other. But this would be trivially reproducible in BGB by single frame stepping, and that's not it.

I tried to reproduce this in Higan 093 (the latest publicly available version as of writing this) and this game has another problem, which is the implementation of the priority sprite bit, which makes Samus almost invisible for the first screen. I don't know if you've fixed this in the beta you're working on or if this happens to me because of different settings.

I cannot reproduce the reported problem in Higan 093, however. If you stand against a wall facing right, and press right+left, Samus' animation gets stuck in the turning state, which is consistent with BGB, and probably hardware if you could press left+right. But not when walking freely.

Maybe you should consider the possibility that this bug is due to something other than the joypad input, for example that the sprites are not getting updated properly in the rendering pipeline, or in the ROM, for whatever reason, and that the turning animation that is normally visible for two frames sticks. Try firing a shot and see if that animates normally while Samus is in this state.


Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 2:52 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
Thank you for the help!

Yes, Samus being invisible was a huge bug, too. I was relying on BG-over-OAM mode allowing OAM only when the pixel color was 0. But it's supposed to be only when the palette color is 0. Really wish we had better GB docs than pandocs :(

And very, very, very weird. You're right, this bug doesn't happen on Windows. It only happens on Linux (even with v093 official, so no WIP modifications are at fault.)

Per your question, I can't shoot while walking straight, but I can shoot after jumping.

Image

Now I am really terrified. What kind of insane bug would cause an emulation input bug, but only on Linux?
Again, I am 100% certain that JOYP is never returning left+right set at the same time.

Side question: I noticed in gambatte that it was re-reading the keyboard/gamepad inputs every time you read $ff00 (JOYP), rather than latching them on write like the SNES. Is that correct behavior? (I trust gambatte 100x more than anything I've done, so I'll go with gambatte's method unless you know that's wrong.)


Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 3:22 pm 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 190
When you say you can't shoot, is this true only graphically speaking, ie. do you hear the shooting sound even if you can't see the the shot? My hypothesis was that this was a purely graphical bug where the sprites are not being updated while (perhaps) the CPU continues to be emulated normally.

As for your question about reading input. $FF00 is literally a 2 out, 4 in digital IO port, so what you're reading back is immediate. (Subject only to the microsecond delays explained above.)

The SNES controller readout is not immediate like that, as data has to be shifted in from a shift register in the controller. This is done by sending a number of clock pulses to read out one bit at a time. And then there's the automatic mode to read out the controller on VBlank, but you probably know that better than I do considering you've written a SNES emulator and I haven't touched SNES. I only know this process from the hardware side. (I've interfaced a SNES controller from the Gameboy's link port for example.)


Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 8:14 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
Man, it gets even weirder.

This happens on both of my development machine OSes, but not on my laptop.

Both the dev machine and laptop are Windows 7, running the stock v093 official release 64-bit balanced binary.
Game Boy binary hash is identical on both machines, so it's not a corrupted game image.

Looks like my only option is going to be to create an input playback and run trace logs against both machines to see where the code is branching differently. That'll be a treat.

Craziest bug ever.


Last edited by byuu on Thu Dec 05, 2013 8:31 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 8:24 pm 
Offline
User avatar

Joined: Mon Sep 27, 2004 8:33 am
Posts: 3715
Location: Central Texas, USA
Do the config files for the emulator differ across the machines?


Top
 Profile  
 
PostPosted: Thu Dec 05, 2013 8:31 pm 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1338
Just figured it out.

I didn't realize that I had a "multi-jump" cheat code active still on my dev machine. Obviously I know cheat codes screw games up, just didn't realize it was on because it's not an obvious one unless you try it. Dev machine shares the same cheat file for both OSes.

Apparently this code has the side-effect of making Samus moonwalk.

Well I feel stupid now. Sorry for the trouble :(


Top
 Profile  
 
PostPosted: Mon Dec 09, 2013 11:45 am 
Offline

Joined: Sat Aug 28, 2010 9:01 am
Posts: 190
Just an addendum of the input latency question, since you asked. As far as the GB CPU is concerned, it's instant. On a SGB it is, of course, dependent on the SNES CPU. Data will only arrive at the SGB CPU when the SNES CPU propagates it to the cartridge, through the controller chip, however that works exactly from the SNES side.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group