Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I recently wrote a NES emulator in Rust aswell. It was one of the most fulfilling side projects I've done. I did a brief write-up too: https://ltriant.github.io/2019/11/22/nes-emulator.html

Kudos to getting to this point. Adding support for more mappers is a nice incremental thing that can be done at your leisure, and once you get save states implemented, playing games at your own pace is super fun :)



Thanks! Mapper 1 is since done as well as battery-backed RAM support, and I'll be implementing mappers 2-4 in the next couple days. I just read your blog post and the audio section caught my eye: I went through the exact same struggles with trying to queue 44,100Hz to SDL, including trying to implement dynamic sampling, but it was never quite right and I got quite frustrated with it. So eventually I took another pass at using the callback method instead, which I thought wasn't possible as you can't exfiltrate a reference to the struct that you give the audio device, but I got it to work this time with an Arc<Mutex<Vec<u8>>> and it's wayyy better.

The APU sends all of its samples to a staging buffer, then between video frames, the Mutex for the SDL buffer is locked and the staging buffer is emptied into it. The SDL callback also locks the Mutex 60 times per second, takes evenly spaced samples from the raw data, and truncates what it consumed if it had more than it needed. Now the audio keeps perfect pace with the emulator, whether it slows to 58 FPS or goes too fast, and there's no popping and clicking. If you're curious, here are the relevant spots in the code now:

https://github.com/spieglt/nestur/blob/master/src/audio.rs https://github.com/spieglt/nestur/blob/e49921541d493b3616352...

I just beat the first Zelda dungeon last night, saving the file afterwards, and it was indeed really satisfying.


ADC = A + V + C

SBC = A - V - (1 - C)

SBC = A + (-1 * (V - (1 - C)))

SBC = A + (-V + (1 - C))

SBC = A + -V + 1 + C

I am not able to follow the mathemagic behind the third line. Is it normal algebra or its in 1's complement?


I think it looks odd, too. If you go with this:

    ADC = A + V + C
    SBC = A - V - (1 - C)
    SBC = A + (-1 * (V - (C - 1)))
    SBC = A + (-V + (C - 1))
    SBC = A + -(V + 1) + C
"The SBC instruction subtracts a value from the accumulator register, with an extra 1 subtracted from the result if the carry flag is NOT set."

The explanation fits though. If the carry flag is not set (C == 0) then you subtract an extra 1. If C == 1 then it's A-V.


Wow, yeah, that's a bit off. And incorrect. It should end up being equivalent to:

SBC = A - V - 1 + C

Thanks. I'll fix this up :)


> but the - 1 is taken care of because of the fact that ADC and SBC do the opposite thing with the carry flag.

Also, this line is bothersome, they do opposite things but that's why you have already done (1 - C).

Maybe the fact that -V is actually (!V + 1) (in 2's complement) that eats up the extra -1 is the correct explanation?

So,

  SBC = A - V - 1 + C

  SBC = A + !V + 1 - 1 + C

  SBC = A + !V + C


Ah yeah you’re right. I had a brain fart and got my -V and !V confused.

At the time of writing I was sure I had it right too!

I’ll fix that up. Thanks :)


That’s an excellent write up and some well written code! I might use this as a reference if I ever try to write an emulator in Rust :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: