Recording controller input [SOLVED]

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Recording controller input [SOLVED]
by on (#58149)
I thought it might be fun to take a quick little detour from my APU development and make a simple little input recorder for my emulator. Then I could playback the input as my test cases so I don't always have to play the games myself. Is there any particular way I should go about doing this?

I think it would be as easy as simply watching the $4016 read/write strobes and recording data as appropriate. I'm just talking about single player with the original joypad for right now.

Any tips are appreciated!

Thanks!! :)

Jonathon

by on (#58153)
Watch out for the DMC bug doing extra controller reads.
hmmm
by on (#58156)
Hmmm...this sound very interesting. I know that the APU DMC can read samples from memory but I thought the lowest possible address it could read from was $8000. This would not effect $4016/$4017....I'm obviously missing something. Would you mind elaborating a bit more? :-D

Thanks Dwedit!

Jonathon

by on (#58158)
If the sample channel fetches a byte of compressed sample data at the exact same time that the program reads $4016 or $4017, it causes an extra pulse on the clock line, which from the CPU's point of view causes a bit to get deleted from the data stream.
wow
by on (#58168)
WOW, that's awesome! You guys never cease to amaze me. And to think, I was considering not even asking this question. LOL

THANKS A LOT!

Jonathon :)

by on (#58183)
Same thing happens on $2007 read
cool!
by on (#58315)
Hey guys!

I got the first revision of my input recorder working! It was so awesome to see Mario running all over the screen without me pressing a single button! LOL. I think it's like 95% correct, but I believe that I'm running into one of these bugs because after a while of "playback" the movements get more and more off and then I die. :(

Specifically I think I am running into the $2007 bug that Disch mentioned because Super Mario Bros. doesn't use the DMC channel. I will need to iron out this bug - still, I'm very excited! :)

Pz!

Jonathon
Re: cool!
by on (#58327)
jwdonal wrote:
Specifically I think I am running into the $2007 bug that Disch mentioned because Super Mario Bros. doesn't use the DMC channel.

When Disch said that the "Same thing happens on $2007 read" he didn't mean that $2007 reads clock the controller, he meant that if a DMC fetch and a $2007 read occur at the same time the VRAM address may be incremented twice (which has nothing to do with the controllers). So I don't think this is the problem.

by on (#58344)
This probably goes without saying, but I'd also highly recommend that you make sure your save states are as close to 100% ironclad as possible when working on input recording (assuming you save the state as the beginning of your movie.) I wasn't properly saving every last bit of the APU state in early versions of my emulator and that led to a lot of heartache down the line with movie files.

by on (#58359)
If you don't want controller glitches just log the raw button input (I'm assuming you're emulating the controller too).
Re: cool!
by on (#58360)
tokumaru wrote:
When Disch said that the "Same thing happens on $2007 read" he didn't mean that $2007 reads clock the controller, he meant that if a DMC fetch and a $2007 read occur at the same time the VRAM address may be incremented twice (which has nothing to do with the controllers). So I don't think this is the problem.


Ohhh, I see now. I was confused then. Thanks for the clarification! Well, that kind of really stinks then because it must be something else. Haha. I don't see how I could be missing any bits in my recorder. Hmmm....I have a feeling this one is not going to be fun to debug! :-/ Haha.

by on (#58361)
kyuusaku wrote:
If you don't want controller glitches just log the raw button input (I'm assuming you're emulating the controller too).


Nope, I'm not emulating the controller, I'm recording the raw controller input directly from an original joypad connected to my dev board.

by on (#58362)
Then you could do what I do: oversample the controller with a module, then emulate the pad from the output of that :P

by on (#58363)
kyuusaku wrote:
Then you could do what I do: oversample the controller with a module, then emulate the pad from the output of that :P


That's a reasonable solution. I'm kind of already doing that, but not in quite the same way you are.

I actually just discovered something _very_ interesting. When I playback the same sample 2 or more times in a row the playback gets screwed up in different places! Sometimes it will get messed up 1/4 of the way through the game, sometimes it'll mess up 3/4 of the way and sometimes it makes it all the way through the level. (Note the 1/4 and 3/4 are not exact numbers, just examples).

So this leads me more to believe that the recording aspect is working well but there is something wrong with the playback mechanism. This should be easier to debug than the external joypad interface.

by on (#58370)
The original Super Mario Bros. has two demos with the same keypress content: Mario dies in one and survives in the other. The difference has to do with how the time of level start aligns with one of the internal tasks that executes only once every few frames.

by on (#58374)
NO WAY! So maybe this has something to do with it as well.... Hmmm...so how do software emulators deal with this phenomena? That is, how do you correct for it?

That is actually really cool. I always just thought they were 2 different demos that ran pseudo-randomly. Neat. Thanks tepples!

by on (#58385)
jwdonal wrote:
Hmmm...so how do software emulators deal with this phenomena?

They save the whole state of the machine, including all the internal timers that the game maintains. An emulator can do this; a controller port peripheral cannot.

by on (#58397)
Well that stinks... :'(

Guess I'll just need to put this off until I can save the entire state of my emulator to an external memory. Thanks for your help though! I'll tuck these notes away until next time....
hmm
by on (#58422)
Tepples, so in reading your post more closely:

Quote:
An emulator can do this; a controller port peripheral cannot.


If you could clarify....Do you actually think it is not even possible to properly save the state of a system and make a good recording of input using a hardware-based emulator? In other words, you only think it's possible in a software-based emulator?

I don't see why that would be the case, but if that's what you're saying that really stinks! Haha.

Please advise.

Pz!

Jonathon
Re: cool!
by on (#58425)
jwdonal wrote:
Hey guys!

I got the first revision of my input recorder working! It was so awesome to see Mario running all over the screen without me pressing a single button! LOL. I think it's like 95% correct, but I believe that I'm running into one of these bugs because after a while of "playback" the movements get more and more off and then I die. :(

Specifically I think I am running into the $2007 bug that Disch mentioned because Super Mario Bros. doesn't use the DMC channel. I will need to iron out this bug - still, I'm very excited! :)

Pz!

Jonathon


I had this same issue in the Joypad Logger I implemented in the original Windows-only NESICIDE. Mario would eventually die. If you figure it out I'd love to hear.

One thing I thought it could possibly be is randomness injected into the game by design. Say for example an enemy is not where he was when you recorded which causes your played-back Mario not to get that extra "I just stomped a guy now I can make it onto that platform" boost. I'm not sure whether or not this is possible on the NES and knowing exactly where the enemies are going to pop into frame in SMB1 seems to suggest that it is not.

It was pretty cool to see though, like you say. I implemented a control like a player-piano where you could watch the playback head scroll over eight varying dot patterns. You could even change the dot patterns and replay. The idea there was to be able to "cheat".

It is here if you're at all interested. I had relegated the Joypad Logger to 'novelty' status since it didn't quite work and there were bigger things to work on.
Re: hmm
by on (#58438)
jwdonal wrote:
Do you actually think it is not even possible to properly save the state of a system and make a good recording of input using a hardware-based emulator?

To make a saved state, you have to be able to pause emulation, and you have to give all internal registers a second read port that doesn't cause side effects. Usually, saved states are taken at the start of line 240 so that you don't have to deal with most of the PPU's internal state. (NMI happens on 241.)

by on (#58445)
If you look at the Hori Game Repeater (controller recorder/replayer for the Famicom - I don't know exactly how well it works) you would see that the only extra control it has over the hardware is that it passes the power connector through. So by that it is able to reset the system with some degree of accuracy, hopefully repeating any seeds that were made for the random # generator.

I don't think all the save state stuff is really needed, if you are OK with controlling reset and always starting from the beginning.
Re: cool!
by on (#58562)
Hello all! I'm so sorry for not replying to this sooner. You guys are kind enough to answer my questions and I don't even reply! What's up with that?! Haha, I just got caught up with work and have been making some much needed miscellaneous upgrades to my NES and regression testing after all my mods for the APU DMC module. I think I'm pretty much good to go now and I will probably start working on the Noise channel next. But back to the joypad input recorder...

NESICIDE wrote:
It is here if you're at all interested.


Cool! Thanks! I'll have to check that out.

tepples wrote:
To make a saved state, you have to be able to pause emulation, and you have to give all internal registers a second read port that doesn't cause side effects. Usually, saved states are taken at the start of line 240 so that you don't have to deal with most of the PPU's internal state. (NMI happens on 241.)


Okay, that makes me feel better. Adding an additional read port (and write port to restore the state) to each register is definitely possible. An EXTREMELY tedious task for a hardware implementation, but certainly possible. I was gonna be all sad if you said it was only possible with software. LOL.

Memblers wrote:
If you look at the Hori Game Repeater...I don't think all the save state stuff is really needed, if you are OK with controlling reset and always starting from the beginning.


Now that is REALLY interesting!! Maybe I don't absolutely HAVE to save the entire state of the NES (although it's certainly the best and most versatile way) if I control the reset like this thing does. I could have two options for my emulator, one that only allows playback from full reset and one that is a complete save-state feature. I'm going to look for some documentation on this. Is there much to be found though?? :-/

So if I reset Super Mario Bros. every single time before I playback my recording then should that make it work every time? Seems so....IF this Hori thing actually works. I've never even heard of it before. :)

THANKS EVERYONE! :)
still doesn't work
by on (#58671)
Okay, so I modified my joypad input reocrder to work just like the Hori game repeater (i.e. when I hit the record button it resets the system and starts recording immediately from reset, and when i hit the playback button it resets the system and starts feeding input samples to the game immediately). However, it still doesn't work. I tried a different game this time, the original Mario Bros. (not Super Mario). And each time I playback the input the first enemy comes out of a different pipe. So it's one of two things as far as I can tell:

1) My playback method is screwed up - which is possible, but hard to believe because it's such a simple state machine.

2) The game is seeding its randomness off of something in the system (a register/memory location?) that is not being reset properly (or not at all) when I reset the system on record/playback.

If anyone has any more ideas let me know. I'm really disappointed I couldn't get it to work from a full reset. If I don't hear back from anyone I'm going to get back on working on my APU - I was having a lot more fun doing that! LOL.

Pz!

Jonathon :)

UPDATE: I was just about to shut my dev board off when I thought of a test to try. I toggled the CPU/PPU reset line (the _exact_ same line that my input recorder uses to reset the system) *while holding down the Start button*. Holding down the start button guarantees that the time the game is started following a reset will always be exactly the same (I'm still talking original Mario Bros. here). And wouldn't you know, the first enemy always came out of the left pipe no matter how many times I toggled the reset line!!! Believe it or not I'm very excited about this since it means that option #2 above is less likely - which is good because trying to track down some register or memory that is not being reset properly is like searching for a needle in a haystack. So there must still be something wrong with my playback state machine...GRRRRR!! I don't know how much longer I want to keep messing around with this. I would much rather finish the APU so I can start working on MAPPERS!!! :-D But just wanted to give you guys an update. Again, any ideas, let me know. THANKS!
!!!!SOLVED!!!!
by on (#58692)
BOO-YAH!!!! IT'S WORKING!!!! I TOTALLY FIXED IT!!! IT WORKS EVERY TIME NOW!!! AWESOME!!!

I can't even describe how excited I am!!! I made a few small changes to my playback state machine (mostly timing-related), and BAM! (Chef Emeril style baby!) - it worked!!!

I can record/play Super Mario Bros. every single time without fail, I've also tried the original Mario Bros., Defender 2, and Galaga, and everything syncs up and plays back perfectly!!! KICK ASS!!

So this proves that as long as you start recording and playing back *immediately* from a system reset you do not need to save the state of the entire system (this is obviously how the Hori game repeater works as well). Of course, this method is not as versatile or feature-rich as saving the full state but it's a good interim (and less resource intensive) solution.

Thanks so much to everyone that helped - especially Memblers for telling me about the Hori.

I'm going to post some vids of the record and playback mechanism - just for fun. I'm also going to add a neat little feature...but I'm gonna keep that quiet until I post the vids. ;)

Pz!!

Jonathon :)