5 ms·
I'd be very interested to know how preemptive (rather than cooperative) multi-tasking is implemented. It's been a while but I don't remember the Z80 having any
by andyjohnson0 3y ago
I'd be very interested to know how preemptive (rather than cooperative) multi-tasking is implemented. It's been a while but I don't remember the Z80 having any suitable primitives upon which to implement preemption.
I poked around the website but it seems light on implementation details. Super-impressive piece of work though.
Edit to say: thank you to the responders who've backfilled the gaps in my memory. Interesting what you forget given enough time.
- dfawcus 3y agoEven DRI's MP/M from 1979 had preemptive multi-tasking, as long as the platform supported an clock interrupt. You can find the documents on bitsavers, the binaries may well be there and/or on Gaby's site.
- becurious 3y agoThere was a program called Switcha published as a listing in Your Sinclair. You could make a 48K Sinclair Spectrum appear as three 16K machines. It installed an interrupt mode 2 handler and checked for a key combination to swap out the lower 16K of RAM. No reason it couldn’t have time sliced them.
- JNRowe 3y agoWhat a time to be alive, 1980s pdf at your fingertip¹. The tool is described on page 84 of the linked doc. ¹ https://ia903206.us.archive.org/19/items/Your_Sinclair_003/Your_Sinclair_003.pdf https://ia903206.us.archive.org/19/items/Your_Sinclair_003/Y...
- becurious 3y agoThanks! I remember that cover now! The article has both the hex and the asm listing. I think I did an update to it to use the bank switched memory on the 128K to get 8 16K Spectrums. Of course with something like a MGT +D with the 8K ROM and 8K SRAM it would have been possible to use the NMI button to switch between two 48K Spectrums on a 128K and have them run a game in one and BASIC in the other.
- actionfromafar 3y agoTimer interrupt
- actionfromafar 3y agoZ80 has two sets of all registers: https://retrocomputing.stackexchange.com/questions/7794/did-anyone-ever-use-the-extra-set-of-registers-on-the-z80 https://retrocomputing.stackexchange.com/questions/7794/did-...
- guenthert 3y agoWhich is neither required nor sufficient for preemptive multitasking, which the OP was asking about. The 2nd set can speed up interrupt handling though (and was used this way in the BIOS/BASIC of Amstrad CPC).
- actionfromafar 3y agoI don’t understand. What would you need? You can look at the registers, save them, populate them with another tasks contents, rinse, repeat
- guenthert 3y agoOthers have already correctly pointed out that you'll need a (periodic) interrupt source and facility to handle such. As the Z80 doesn't provide a protected or system mode, it needs to be a non-maskable interrupt, which the Z80 fortunately does provide (iirc, that wasn't used in the Amstrad computers though). Sure you'll need to save the registers, but you could do that using the stack as well. The second register set just makes it quicker.
- actionfromafar 3y agoBut if the processes don’t mask the timer interrupt, it could be used instead of NMI?
- sedatk 3y agoZ80 has a mirror register set that can be swapped immediately. That makes task switching faster.
- CodeWriter23 3y agoFor up to two tasks
- sedatk 3y agoNo, for kernel code that handles the switching.
- CodeWriter23 3y agoEXX doesn’t transfer to RAM, only to the ‘ register set. Great for ISRs (as long as you can single-thread the interrupts) but you’re not going to track task state using it.
- sedatk 3y agoThat's what I said. You can make the kernel's code that handles the task switching faster that way.
- CodeWriter23 3y ago> Z80 has a mirror register set that can be swapped immediately. That makes task switching faster. Your original statement is sufficiently ambiguous that non-mind reading people might interpret it to mean “all tasks”.
- cornholio 3y agoZ80 has a non-maskable (NMI) interrupt line that will break whatever code is currently executing without allowing the software to opt out (EI/DI instructions), and then jump to a hardcoded page zero location, I believe it is address 0x66. This line is typically tied in popular Z80 machines to the vertical blanking generator (frame refresh - 50/60Hz). Presumably, the OS would then schedule the tasks in a round robin fashion and most tasks will cooperate and yield control quicker to allow a not too choppy experience.
- baz00 3y agoAs other people have said, there's an NMI line. But that's not usually how it's implemented because you tend to want to mask it if the thing is doing a real time or time critical task. The Z80 CTC was the canonical solution. Back in the dark ages had an "OS" which had a simple "task table". This was a circular linked list with enough space after each pointer to store the CPU state for a task and some stack. There was one element per task. The task interrupt would fire every 100ms, the registers/stack pointer/PC would be dumped to that, the list followed and the next task picked up and loaded into the CPU, then it'd return from interrupt and off it'd go again. You could call YIELD at any point if you didn't want the rest of your time slice. If you had something that needed to handle an interrupt from the CTC or an NMI, it would disable interrupts until it was done. Notably you didn't tend to create new tasks. They were hard coded in at assembly time! Edit: we also had an 8031 version as well.
- andyjohnson0 3y agoThanks. Back when I last wrote an z80 asm I didn't have access to an environment with anything like an os. > Notably you didn't tend to create new tasks. They were hard coded in at assembly time! Reminiscent of the "executive" in the Apollo lunar module computer.
- epcoa 3y ago> Z80 having any suitable primitives upon which to implement preemption. In general the only thing needed is an external interrupt (which the Z80 has). All but the cheapest deeply embedded 8 bit micros will have one and therefore can support preemption.
- stephc_int13 3y agoI once implemented a pre-emptive kernel and OS on a very crude hardware, the Hewlett-Packard Graphing Calculator HP48GX, running a Saturn CPU (4Bits with 64bits registers, a weird beast). It can still be downloaded here : https://www.hpcalc.org/hp48/apps/shell/ https://www.hpcalc.org/hp48/apps/shell/ You don't need MMU or anything of the sort. The only thing you need is programmable interrupts. My implementation was using a 64Hz timer, that was also synchronized on the LCD screen "vsync" as it had to be serviced for kernel-level double buffering and different modes of simulated multiple grey levels. It is much less difficult than it seems, save registers, save context, load context, load registers, return to the current process. Optimizing the code is just a good knowledge of the CPU constraints and bit of juggling with registers. It was a simpler time, you could benchmark code by counting cycles, instruction by instruction. No cache, no branch predictors, no throttling.
- GlenTheMachine 3y agoI did something similar on the C64 (6502). Programmatically user code could mask interrupts, but as long as it didn’t it worked fine. It saved all the registers and restored them prior to switching execution threads. The unified memory space required that each thread ask for an absolute memory offset to be allocated and then voluntarily stay in that space.
- OnlyMortal 3y agoThe vertical blank interrupt was how many games did their screen updates and played music. Those were good days writing demos and crack intros.
- CodeWriter23 3y agoThey’re not claiming protected mode multitasking.
- tyingq 3y agoThe bank switching seems to provide a similar thing though.
- CodeWriter23 3y agoSomewhat isolated, yes. Not protected because there are no privileged instructions on a Z80. Bank switching requires part of the address space to be common amongst all banks (never switchable) so code to manage the switching can execute. In that part of the address space you can do things like monkey patch the OS and driver entry points, or switch banks and collect or patch all the RAM.
- jbverschoor 3y agoYeah they don't have protected mode. They are working on a language+toolkit to create windowed applications. I guess something like Visual Basic.