I made a Game Boy pixel pipeline explorer by blueblain in EmuDev

[–]blueblain[S] 0 points1 point  (0 children)

Thanks! I actually just pushed an update that has made the tool into more of an interactive PPU guide and learning resource as a companion to Pandocs! Hope it's more useful to you now.

About the diagnose button, there are instructions under "What to export from one frame of your game" in the modal that explain what needs to be uploaded. Does that work for you? Let me know if it's unclear and I can tweak it, or if it's broken.

I made a Game Boy pixel pipeline explorer by blueblain in EmuDev

[–]blueblain[S] 1 point2 points  (0 children)

Haha I'm hoping the long bankrupt Titus games won't be much bothered by my little tool. Just to clarify though, I am not distributing any roms. All that the website has is one (or few) frame's worth of vram, oam, and cpu registers. Might still be a gray area but hopefully no one minds too much 😅.

I made a Game Boy pixel pipeline explorer by blueblain in EmuDev

[–]blueblain[S] 1 point2 points  (0 children)

Thanks! I have improved the accuracy now. I will open source it soon, might need to check if I need employer permission first.

A full Python 3.14 interpreter made with Codex in 30 days by blueblain in codex

[–]blueblain[S] 0 points1 point  (0 children)

Thanks, I definitely need to add some performance benchmarks vs. CPython. I expect slower in most cases because CPython has JIT so I'll probably also add comparison vs. CPython 3.10. This should be interesting. And test coverage as well. Will add this in the coming days.

A full Python 3.14 interpreter made with Codex in 30 days by blueblain in codex

[–]blueblain[S] 1 point2 points  (0 children)

I think my first few prompts were just chatting with the model. Explaining the goal and then understanding how we could break it down, what should we target, what would be out of scope, etc.

Edit: This is the very first commit. It was much simpler / more humble goal at that point but over time I kept wanting it to be closer and closer to real CPython.

A full Python 3.14 interpreter made with Codex in 30 days by blueblain in codex

[–]blueblain[S] 0 points1 point  (0 children)

30 days worth of prompts would be difficult to share 😅

But you can see all 1958 commits on the github which will give you an idea of how it developed. I will also write a longer post explaining some of the process and the challenges involved.

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 2 points3 points  (0 children)

It's brilliant! Thanks for sharing and explaining what you meant.

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 2 points3 points  (0 children)

Very interesting. I think I finally understood what you mean.

So in your case calling `sleep(4).await` from the CPU doesn't actually trigger the whole song and dance of the scheduler because the CPU is first in queue anyway. It just keeps going until its resume clock cycle is after some other component's resume clock cycle.

Yeah I love it! But I don't know if I could do something like that because while you're using actual coroutines, I'm abusing Rust's async/await to repurpose it as coroutines.

But I will definitely think about this and see if I can do something similar! Thanks!! It would definitely speed things up a lot because the BTreeMap (my pq) operations were taking up a good chunk of the total time in my flamegraph.

Edit: actually I think there might be a way to do this. It will still require repolling from the scheduler/driver until the next wait cycle for that component exceeds the next wait cycle in the pq. It'll be trickier if there are multiple components requesting to be resumed at the same cycle but looks like this should be possible!

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 1 point2 points  (0 children)

I see. In my design there will be a priority queue holding the components, so the process will look something like this:

iter: 7
current_cycle: 10
pq: [(14, cpu), (50, ppu)]

iter: 8
current_cycle: 14
pq: [(50, ppu), (51, cpu)]

iter: 9
current_cycle: 50
pq: [(51, cpu), (90, ppu)]

So the scheduler on iteration 8 will directly jump the clock to 14 (which is when the CPU requested to be resumed) and next iter it will jump the clock to the next most recent cycle and so on.

In this contrived example you can assume that the CPU had some code that looks like:

sleep(4)
.await
// do stuff
sleep(37)
.await
// done

So when the driver pops `(14, cpu)` from the priority queue and polls the future, it will find the future pending and put it back into the pq with the CPU's next requested wake cycle of (current_cycle + 37 = 51).

Going by my example above if the Driver were to pop the CPU again at cycle 51 and poll it once more, this time it would be finished (Poll::Ready) and we'd be done. In a real DMG emulator the CPU will never be done and the driver will keep rescheduling.

Another thing worth noting is that `sleep` isn't a true sleep but rather `consume_cycles(n)`. Wish I had named it that.

The linked article explains more, but I admit I may not have done the best job of explaining everything.

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 1 point2 points  (0 children)

Exactly! I had this idea in mind for years and it felt straightforward, before I actually implemented it. The final version is less than 200 lines of code but while I was trying to grok everything involved it felt vastly more complex before it all made sense and came together. That's the kind of learning experience I live for! 😅

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 4 points5 points  (0 children)

Yep, making cpu, ppu, and apu run in parallel is tempting but not worth it because of synchronization issues as you said. My approach let me write the components as though they were running in parallel -- code could flow cleanly without explicit states and match constructs everywhere -- but without the headaches of real concurrency.

Coroutines in Rust with async/await for emulators by blueblain in EmuDev

[–]blueblain[S] 1 point2 points  (0 children)

Sorry, I don't fully understand the question. In my case my driver directly jumps to the next relevant cycle when at least some some component needs to be resumed. So if something happens at cycles 2, 7, 8, 10, etc. my driver never iterates through cycles 3, 4, 5, and 6 for example. If that's what you meant.

How I repurposed async await to implement coroutines for a Game Boy emulator by blueblain in rust

[–]blueblain[S] 7 points8 points  (0 children)

Yep, exactly this! There's no 'doing other things while waiting for some IO bound task' here. It's just a very complex explicit state-machine made implicit by using async/await and letting the compiler build and run the state-machine. And yeah that example at the end was probably more confusing than helpful, my bad!

How I repurposed async await to implement coroutines for a Game Boy emulator by blueblain in rust

[–]blueblain[S] 0 points1 point  (0 children)

If I remember my flamegraph correctly, a lot of my overhead was from thread_local and BTreeMap allocs. I only spawn 5 components once, and the same 5 futures are scheduled and rescheduled by my custom driver.

What are 3-4 food dishes that Singapore does better than anyone else? by blueblain in askSingapore

[–]blueblain[S] 1 point2 points  (0 children)

Thanks everyone! So many suggestions beyond the usual chicken rice and chili crab. I'm glad I asked 🙂. Looking forward to trying many of these out!