This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Pre-emptive thread scheduling using MMC3 irqs?

Pre-emptive thread scheduling using MMC3 irqs?
by on (#209304)
My current game uses coroutines, which are kind of like threads that pre-empt themselves, but how hard would it be to fully implement threads on an NES? I was wondering in the context of this conversation whether such a technique could be used to implement 300hz animation updates and then adjust how often the animation threads are updated on PAL or NTSC.

I don't personally feel motivated to go as far as implementing threading myself, but as I have spotted "threads" mentioned in some games' source code and by some homebrewers, it is making me wonder what the possibilities are. Note I'm well aware one often refers to the "main thread" and the "nmi thread," and I fully understand why that terminology was adopted, since these do behave like threads and you have to deal with concurrency issues, but I'm specifically asking about implementing a general pre-emptive threading scheme.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209306)
Context switches are expensive; when one uses coroutines there's much less state to save and restore. I'd be worried about the overhead overwhelming the benefits...
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209307)
lidnariq wrote:
Context switches are expensive; when one uses coroutines there's much less state to save and restore. I'd be worried about the overhead overwhelming the benefits...

Good point, one would have to have a full copy of all cpu registers at the time a thread is pre-empted, whereas with coroutines all I need is the state associated with the coroutine (in my game's case, just the current entity's state)...(and the PC)

Given that, I'm guessing any time I've seen the word "thread" used in an NES game's source code, it is probably really a coroutine or similar idea...
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209316)
I don't see why you need threads for this or what benefit they would have.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209318)
pubby wrote:
I don't see why you need threads for this or what benefit they would have.

I don't; but I am accustomed to discovering that many folks here do things in ways I would have never thought of so I thought I'd ask and see if it's something anybody has done or is doing. Especially since I've seen it in source code and mentioned more than once.

If anything; it'd be a fun demo to write...
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209334)
Interrupts (NMI and other IRQs) are already multiple threads that can preempt a main thread.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209375)
http://codebase64.org/doku.php?id=base: ... n_the_6502

However what you are probably thinking of is best left for a C128 or a 65816 based system.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209376)
At the risk of angering you for not answering the question, there is absolutely zero reason to do such a thing in the first place. The point of pre-emptive multitasking is that if a program crashes, the whole system does not crash. If I'm not mistaking this was introduced rather late in the history of computers - perhaps with Windows 95. So that if an application crashed it was possible to resume computer usage without hard rebooting.

In the case of an embedded video game console where no 3rd party software you don't control is used, there is zero reason to do such a thing. Basically you're trying to solve a problem that doesn't even exist in your case. If one of your thread crashes, you should fix it - you should not hope it'll go unnoticed and hide it with pre-emptive thread switching.

Now if you're asking if this is possible technically, then the answer is probably yes - but does it make any sense in the case of a NES platform, the answer is no.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209378)
Sinclair QDos of 84 had it, but that machine had a lot of issues. It's main announcement to the world was the A1000 of 85. Windows kind of had it since 2.1 but yeah not really. 95 was when it got it for real. MacOS got it in 2001 when they ditched the old OS and used NextStep. There were some DOS hacks that added it as well I think, but none really took off.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209379)
lidnariq wrote:
Context switches are expensive; when one uses coroutines there's much less state to save and restore. I'd be worried about the overhead overwhelming the benefits...

Hmm, what would a context switch look like here? Something like:

IRQ, save registers, some IRQ upkeep, move stack pointer, restore registers, return from IRQ.

I wonder if bankable WRAM could help here too, you could let the different threads independently use memory that way.


Though, aside from running a multitasking operating system with independent programs that come and go, I don't really understand the use for threads on a 6502. For multi-core systems threads are a very important way to parallelize. On a single core system, they can't do that.

In a game... the first situation that comes to mind is running AI for a chess game, where you want to let that run independently and keep doing user interface updates for the player in the meanwhile. For that, though, you only need one more thread... a single IRQ is already good enough to do that (if not just the NMI by itself).

Threads were also common for things like background loading, or background decompression, but the NES doesn't really have enough RAM for decompression to ever take that long, and its only loading device is the FDS... but again even for this kind of thing a single IRQ is already enough for this case too?

So I'd be quite curious to know of a good use case for it, as I can't think of anything, myself.


Coroutines on the other hand do make a lot of interesting code structures possible, especially for AI, but we're not talking about interrupts anymore with that. Coroutines aren't to be confused with "threads", at least in my understanding of them; it's a very different paradigm.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209386)
Bregalad wrote:
At the risk of angering you for not answering the question, there is absolutely zero reason to do such a thing in the first place. The point of pre-emptive multitasking is that if a program crashes, the whole system does not crash.


Preemptive multithreading also lets a single task do something that takes a long time, while doing something else at the same time. So if you have something like a long pathfinding sequence, you can interrupt it for something else.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209388)
If I recall, Tepples, or some other person here, made a "Sprite" demo where each sprite was its own thread. So a demo has been made.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209390)
Dwedit wrote:
Preemptive multithreading also lets a single task do something that takes a long time, while doing something else at the same time. So if you have something like a long pathfinding sequence, you can interrupt it for something else.

True, I see some applications for that such as chess game AI or whatever, but then it could just be a specialized implementation for one specific CPU-intensive task, rather than general purpose pre-emptive multithreading.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209392)
...so what really prompted my thread was that the word "Thread" is present in the old Neotoxin source code. I also have heard at least one fellow homebrewer refer to things as "threads" in his code. I was just curious what these things actually were. Probably not "real" threads.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209400)
rainwarrior wrote:
Threads were also common for things like background loading, or background decompression, but the NES doesn't really have enough RAM for decompression to ever take that long, and its only loading device is the FDS

NOR flash prices began to rise half a year ago, as I mentioned earlier. If this trend continues, there'll be more pressure to store the majority of the program on a serial flash (SPI, eMMC, microSD, etc.) and load the rest to a bankable 128Kx8 PRG RAM during the copyright screen, between levels, or even in the background if you can structure the level stream that way.

rainwarrior wrote:
... but again even for this kind of thing a single IRQ is already enough for this case too?

True. On 8- and 16-bit consoles, I don't see a use for more than three preemptive contexts in a game: video memory updates and music, game logic, and graphics decompression, software rendering, or heavyweight AI.

ccovell wrote:
If I recall, Tepples, or some other person here, made a "Sprite" demo where each sprite was its own thread.

It wasn't me. Neither the old version nor the 2011 version of the Sprite Cans demo uses anything thread-like. In fact, it probably uses the simplest possible NMI handler.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209404)
ccovell wrote:
If I recall, Tepples, or some other person here, made a "Sprite" demo where each sprite was its own thread. So a demo has been made.

I think that was blargg. IIRC, the demo consisted basically in giving each object its own PC, that was restored before its logic ran, and then backed up for next time. No interrupts were used, each object was responsible for transferring control to the next.
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209412)
tokumaru wrote:
ccovell wrote:
If I recall, Tepples, or some other person here, made a "Sprite" demo where each sprite was its own thread. So a demo has been made.

I think that was blargg. IIRC, the demo consisted basically in giving each object its own PC, that was restored before its logic ran, and then backed up for next time. No interrupts were used, each object was responsible for transferring control to the next.

So basically coroutines then?
Re: Pre-emptive thread scheduling using MMC3 irqs?
by on (#209416)
Ideally coroutines would/should save/restore the stack as well.

I implemented a coroutine system for my Game Boy game but ultimately scrapped it because it didn't win me much, and there were costs in terms of performance and complexity and flexibility (I had to be really conscious of my stack height because each routine had such a small one allocated to it).

My favourite thing to use coroutines for is scripting - in an RPG or something, you can write scripts right in assembly, no need for a separate bytecode or managing a state machine or anything.

On a more powerful platform with more spare RAM it might be worthwhile - you could have larger stacks and more memory per process, and you wouldn't take such a large performance hit. You could have tons of different tasks handling different things - collision detection, scripting, animation, physics, etc.