News for hackers. Stuff that matters.
Re:Implementing a NES Emulator in Rust by FartyMcFarter on Tuesday March 19, 2019 @10:06AM (#19430891)
It seems that unsafe references were used, so the advantages of Rust appear to have been somewhat relinquished in this case.
Re:Implementing a NES Emulator in Rust by bionicbits on Tuesday March 19, 2019 @10:22AM (#19431037)
I am not sure you can not use `unsafe` in an embedded type of project. `unsafe` isn't necessarily bad, but when used at least makes it very clear where extra attention should be paid.
Re:Implementing a NES Emulator in Rust by nukeop on Tuesday March 19, 2019 @10:24AM (#19431058)
I also wrote a NES emulator in Rust, and managed to do it without using a single unsafe block. I used SDL bindings for graphics, if that counts, but it can also run in headless mode (for testing) without SDL perfectly well.
Re:Implementing a NES Emulator in Rust by neurotrace on Tuesday March 19, 2019 @10:58AM (#19431375)
Do you have a link? I'd like to see how yours compares with OPs
Re:Implementing a NES Emulator in Rust by nukeop on Tuesday March 19, 2019 @11:10AM (#19431504)
Not finished, but for what it's worth: https://github.com/nukeop/mr-cool-nes
Re:Implementing a NES Emulator in Rust by SPD-13 on Tuesday March 19, 2019 @01:08PM (#19432864)
Is this named after Mr Cool Ice?
Re:Implementing a NES Emulator in Rust by nukeop on Tuesday March 19, 2019 @01:14PM (#19432944)
you know it
Re:Implementing a NES Emulator in Rust by simias on Tuesday March 19, 2019 @12:33PM (#19432426)
Writing an emulator is not really embedded programming (the target often qualifies as an embedded environment but the host can be any random desktop computer).

It's definitely possible to write an emulator without unsafe code. Here's a toy gameboy emulator I wrote a while ago in Rust without any unsafe code: https://github.com/simias/gb-rs

Here's a very incomplete PSX emulator with only a single unsafe (which might not even be necessary anymore, I haven't updated the code in a while): https://github.com/simias/rustation

Re:Implementing a NES Emulator in Rust by mzs on Tuesday March 19, 2019 @03:06PM (#19434418)
Re:Implementing a NES Emulator in Rust by simias on Wednesday March 20, 2019 @10:26AM (#19442524)
The SDL2 dependency? I don't understand what you mean by that.

Or are you saying that a dependency that I use happens to use unsafe code? In which case it's true but then by that definition it's effectively almost impossible to write 100% safe rust since the stdlib itself contains a non-negligible amount of unsafe code.

Re:Implementing a NES Emulator in Rust by steveklabnik on Wednesday March 20, 2019 @10:51AM (#19442776)
It’s always impossible, as you have to call into the OS at some point to do anything of use.
Re:Implementing a NES Emulator in Rust by hopler on Tuesday March 19, 2019 @11:18AM (#19431588)
Emulating a system of a few 2Mhz with a 4x3Ghz chipset ought to be doable using managed memory.
Re:Implementing a NES Emulator in Rust by flohofwoe on Tuesday March 19, 2019 @11:34AM (#19431775)
Nitpicking a bit, but there's not a lot of useful things that could be multithreaded in an 8-bit emulator, so it would be more like 1x3Ghz ;)

In those old 8- and 16-bit machines all components usually ran completely synchronous for each clock tick, for instance if the video emulation runs out of sync with the CPU emulation for a tick or two, a write from the CPU to a video hardware register might not make it in time and you get garbage video output.

Modern asynchronous systems may need less (relative) host system performance for emulation, because the timing requirements between the different hardware components are much more relaxed.

Re:Implementing a NES Emulator in Rust by jrockway on Tuesday March 19, 2019 @12:14PM (#19432214)
The original hardware was multithreaded... in the sense that there were several separate processing units.
Re:Implementing a NES Emulator in Rust by flohofwoe on Tuesday March 19, 2019 @12:57PM (#19432734)
Yes, but as far as I can glance from the NES spec, those still run from the same clock (with different dividers, but they're still locked to each other).

I haven't written an emulator for the NES yet, but on machines like the Amstrad CPC or C64, the CPU can reprogram video hardware registers (like color palette entries) at any time, for instance in the middle of a scanline. When this is off by a tick, you get the color palette change a couple of pixels late or early.

If CPU and video chip emulation would run on different threads, they would need to sync with each other a few million times per second, that doesn't sound like a good idea. If synchronization is only needed once per scanline, or even per frame that's an option of course. Often this is good enough to run some games which didn't go too close to the metal (again this is only from my experience with home computer emulators, haven't done NES stuff yet).

Parallelizing through SIMD might be an option though (one can pack a lot of 4- or 8-bit counters into a 512-bit register).

Re:Implementing a NES Emulator in Rust by boomlinde on Wednesday March 20, 2019 @09:11AM (#19441691)
Yes, but their emulation needs to be performed in lockstep, normally per clock tick or at least externally visible state change, to accurately model their interaction with respect to timing.

Threading in that case would likely mean several orders of magnitude of performance degradation.

Re:Implementing a NES Emulator in Rust by TheCoelacanth on Tuesday March 19, 2019 @11:30AM (#19431735)
Except that an explicit goal of the project was to run simulations much faster than real-time to train an AI to play the game, so they still wanted to squeeze the the maximum performance out of the program.
Re:Implementing a NES Emulator in Rust by bluejekyll on Tuesday March 19, 2019 @10:25AM (#19431078)
unsafe exists in Rust for when you need it. When it is used, it means nothing more than you’re writing code for which you must ensure the safety instead of the compiler.

The times when unsafe is poorly used are when it’s being abused to ignore safety related compilation issues, like lifetimes and/or mutability. Though, even in those cases it might be ok if you’re using lower level concurrency primitives to enforce those guarantees.

unsafe does not remove all advantages of Rust, it only removes a few restrictions. It should be avoided unless necessary.

Re:Implementing a NES Emulator in Rust by steveklabnik on Tuesday March 19, 2019 @12:17PM (#19432253)
It doesn’t remove restrictions, it adds unchecked constructs. Very different!
Re:Implementing a NES Emulator in Rust by bluejekyll on Tuesday March 19, 2019 @01:04PM (#19432814)
Hm, I’m not sure I see the difference between those concepts, but I do like your framing better.
Re:Implementing a NES Emulator in Rust by lmkg on Tuesday March 19, 2019 @01:21PM (#19433021)
The main point is that if you take safe code and put it inside an unsafe block, the meaning of the code doesn't change. So for example, array indexing is bounds-checked in safe code, and non-bounds-checked array access is only available in unsafe blocks. This does not mean that the call `a[i]` loses bounds-checking in an unsafe block. It has the same semantics regardless of context. Rather, the separate call `a.get_unchecked(i)` is available inside an unsafe block and cannot be called in safe code.
Re:Implementing a NES Emulator in Rust by steveklabnik on Tuesday March 19, 2019 @01:26PM (#19433080)
What my sibling said, but also, that unsafe doesn’t mean you’re free from rules; where safe and unsafe interact, your unsafe code is expected to uphold the safety guarantees that the safe code expects.

This matters because of stuff like the article; if you see the other thread, I’m pretty sure (though haven’t verified yet) that this code has UB, even though they’re using unsafe.

Re:Implementing a NES Emulator in Rust by bluejekyll on Tuesday March 19, 2019 @02:22PM (#19433862)
Right, which is why I phrased it as a “few restrictions”, I do understand the point you’re making.

I suppose the reason I consider it restrictions is due to things like “in safe code you can not work with raw pointers”. That seems like a restriction to me, but I can see why saying that way is less accurate.

Re:Implementing a NES Emulator in Rust by oconnor663 on Tuesday March 19, 2019 @07:32PM (#19437301)
If you use unsafe Rust, you do give up the advantage of being able to say, "Look at this code, no unsafe, therefore no UB." However, the lifetime and ownership model is still doing a lot for you. You get a lot of control over the way that your safe code (hopefully most of your program) can interact with your unsafe code. For example if I have this function (partially copied from listd):

    fn reverse_slice<T>(slice: &mut [T]) {
        let len = slice.len();
        for i in 0..len / 2 {
            // Unsafe swap to avoid the bounds check in safe swap.
            unsafe {
                let pa: *mut T = slice.get_unchecked_mut(i);
                let pb: *mut T = slice.get_unchecked_mut(len - 1 - i);
                std::ptr::swap_nonoverlapping(pa, pb);
            }
        }
    }
In theory, I could use those unsafe pointers to alias the same value and cause UB. Or I could stash them somewhere that outlives the lifetime of what they're pointing to, and cause UB later on that way. So I have to audit the function carefully to avoid doing those things. But at the same time (in the absence of other broken unsafe code in the caller), this function can rely on a lot of guarantees:

- The `slice` reference is guaranteed to be unique. No other code, on any thread, has read or write access to `slice` while this function is running.

- The length of `slice` is guaranteed to be correct. All of the memory it refers to has been properly initialized, and computing pointer offsets into it cannot overflow `usize` or otherwise cause UB. (This guarantee is surprisingly subtle, because it means the maximum length of a slice is `isize::MAX` rather than `usize::MAX`.)

- The type `T` is guaranteed to be safe to move. It doesn't contain any internal references to its own memory, which moving would invalidate.

All of this put together makes it possible to audit this function by itself, to make sure safe code can't use it to trigger UB.

Re:Implementing a NES Emulator in Rust by wyldfire on Tuesday March 19, 2019 @11:41AM (#19431848)
To declare the advantages reliquinshed requires some kind of discussion of the `unsafe` blocks' scope. How many, how much code?

Regardless, I'm not even sure I'd say that memory safety is Rust's biggest advantage. It's certainly the headliner and it's critically important. But it's a really appealing package overall IMO.

Re:Implementing a NES Emulator in Rust by Retra on Tuesday March 19, 2019 @12:15PM (#19432224)
One of Rust's advantages is that you can drop into unsafe to do this sort of thing.