> I would love to get some input on what API functions would make it possible to expose required interrupt functionality outside of the ROM itself. I did look at MP/M a while back and understand that it wants to hook a timer interrupt. Is there anything more required? If anyone has thoughts on this, please speak up!
Brain dump... not entirely thought through so caveat emptor etc.
The important document is The MPM II Operating System System
Implementor's Guide, which is around but not so easy to find and I
think historically only available to licensees.
http://www.retroarchive.org/cpm/archive/unofficial/drilib.html
Most BIOS support for MP/M is there I think including support for
multiple consoles and the ability to ask if a console write would
block.
MP/M wants an interrupt, but it also needs to control the exit from
that interrupt as it doesn't finish interrupt handling with EI RET but
your BIOS jumps to an address supplied by MP/M which does magic. The
reason for this is that you are quite likely to go into an interrupt
from one task and come out in another. Fuzix has similar needs for the
same reason.
So for the interrupt I'd think something like
CHAIN_INTERRUPT
HL = address in common area to jump to at the end of BIOS interrupt processing
or 0 to unchain
Return OK or BUSY (already chained)
Which would just replace the final EI RETI with JP xxxx, or put back
the EI RET(I)
The called routine is then responsible for saving any register it
uses, doing any RETI, switching banks back if it moves them etc. It
also needs to be responsible for RETI because in many cases you have
code doing
LD HL,#foo
PUSH HL
RETI
foo: DI
as it needs to generate the RETI cycle before task switching but
whilst still in the interrupt handler with interrupts blocked.
MP/M does also want a timer interrupt, and it needs to know if the
interrupt is a timer event or not so I guess there would need to be a
variable/method to report the interrupt causes or similar. If you've
got a real RTC it likes to turn the interrupt off when it doesn't need
it but that's an optimzation detal. It likes 10Hz but obviously a
7.3MHz Z80 is a bit different to the 1MHZ 8080 it anticipated.
So I'd guess
SET_TIMER A = 1 / 0
Start or stop timer. Returns the timer frequency in HZ. Errors
NO_TIMER, NO_TIMER_STOP
Other than that it wants to be able to disk I/O into the currently
selected bank or common space.
What I don't know enough about is how the memory management would
work. In the conventional model MP/M has multiple banks (usually 48K)
and a 16K fixed common. That bit is easy but the 'what happens if
ROMWBW is paged and you take an interrupt' question is trickier. I
guess the MP/M BIOS knows if it's calling ROMWBW so could just defer
the event until after ROMWBW returns (and count timer ticks if need
be). For N8VEM Mark 2 you are stuck with 32/32 so you'd need to
generate different MP/M or I guess just recognize MP/M isn't that
useful on it.
I guess you'd need a way to query/set the banking arrangement but that
also changes the bank allocation logic because presumably all your
bank numbers change if you do it. That to me seems the hairy bit for
MP/M. Fuzix wants to control the 16K banks independently if they are
present although to be honest with 512K of RAM a 48K/16K faked banking
setup wouldn't be much worse.
SET_BANK_BOUNDARY 32K | 48K | ?? (I guess with Z180 anywhere
OK | NOT SUPPORTED
but I have no idea how the allocation API would then behave.
The re-entrancy question is a more tricky one. MP/M needs to be able
to test if there is character I/O pending or room for writes from
within an interrupt. Fuzix is slightly more antisocial and also wants
to be able to read/write characters in one (blame the designers of
Unix not me). In both cases it's not quite as bad as it could be.
Re-entrancy to ROMWBW could be avoided, and the cases where it calls
ROMWBW from an interrupt will be after the chained interrupt so I
guess to ROMWBW after an interrupt. If need be the caller could just
defer any action on an interrupt during a ROMWBW call.
Beyond that MP/M is pretty isolated from real interrupt structure. It
provides methods to have your code called regularly to poll for
events, or you can wait for and clear a flag (from 1-32) and provides
an interrupt callable routine that sets the flag. It's otherwise
oblivious to real interrupt goings on in the BIOS and below.
Disk I/O is serialized. MP/M has a single threaded disk I/O system so
while it can do clever stuff like run another task during a disk DMA
it doesn't re-enter the disk I/O code, and I don't think that matters
because AFAIK no ROMWBW system can actually do asynchronous disk I/O
anyway can it ?
Alan