interrupts in dot commands

Discuss game and other programming topics not specifically covered in another forum

Moderator: Programming Moderators

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 6:31 am

I'm a bit perplexed. Working on a dot application, I'm setting up an interrupt routine, with these steps:

1. Interrupts disabled at my app startup
2. Allocate a bank of memory
3. Map memory to slot 0 (nextreg 0x50)
4. Write jp my_routine_address to 0x38
5. Enable interrupts
6. Busy loop reading keyboard
7. When space is pressed, continue
8. Disable interrupts
9. Map rom back to slot 0 (nextreg 0x50)
10. Free bank
11. Normal application cleanup

In the interrupt routine I write to the ula color page so I can see it's running. It's not. I figured I could press the nmi button to peek what the memory looks like to verify that my jp command got written correctly, but the nmi button doesn't pop up the menu. Pressing nmi+1 reboots the machine, though.

Are the interrupts disabled for dot commands? Why doesn't the nmi menu pop up?

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 7:07 am

Okay, found in the "NextZXOS_and_esxDOS_APIs.pdf" that the dot commands:
• writing to Next registers MMU0/1 will have no effect
• needing to continue to use RST $8 hooks as if the dot command was running
• inability to run any further dot commands
• standard IM1 interrupt routine (including ROM keyscanning) unavailable
• NMI unavailable, so Multiface replacement can't be activated
Writing to mmu0 seems to at least change the mmu0 value, so it has some effect. Whether the memory actually gets rerouted is a different matter. I understand that the standard im1 interrupt isn't available because, well, the standard rom isn't loaded. Does that also mean that raster interrupt is disabled via nextreg 0x22? It says there that nmi is unavailable which is what I noticed, why is this? Is the nmi menu code in the standard rom or something?

What extra steps do I need to do in order to get interrupts going in a dot application *and* be able to return cleanly after I'm finished? (i.e, I can't do RST 0x20 because that seems like a one-way street)

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 8:45 am

However, enabling 128 special paging mode (AllRam mode) mode will override the Next MMU. The bank selections from the AllRam mode table will override the set pages in the Next registers. The MMU registers can still be changed, but they will have no effect until special paging mode is disabled.
Okay, this is probably what I'm seeing. So next up: where's "allram mode table" and whether I can modify it and whether modifying that helps..

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 8:55 am

I suppose I could do the interrupts in the old school fashion, but I'd rather not.. =)

Ped7g
Posts: 256
Joined: Mon Jul 16, 2018 7:11 pm

Re: interrupts in dot commands

Postby Ped7g » Mon Apr 27, 2020 9:03 am

Not sure about all of this, but I can answer some:

raster interrupt in 0x22 -> this does just raise the regular /INT signal on the CPU pin, so the normal IM0/IM1/IM2 interrupt handler is executed. If you set for example from BASIC raster interrupt to line 40, and enable both raster+ULA, the regular ROM IM1 handler will run twice per frame (at line 40, and at line around 255 or where the regular ULA interrupt triggers). (also "di/ei" instructions disable/enable handling of /INT signal in the CPU, so it doesn't matter whether the /INT is raised by ULA or raster line, the Z80N doesn't know+care which event raised the signal)

to get interrupts going -> how about using "im 2", map the newly allocated bank to C000 or E000 and put your interrupt handler there.

But if all you need is just simple keyboard handler in spin-loops, I would probably avoid interrupts completely and just read the keyboard directly in the loop.

I guess the rst 0x20 is one-way to close the dot-command environment, but very likely there's some way to return back to NextZXOS (as long as you preserve all the other memory except your allocated bank, where you need to move into, before rst 0x20). But I find this non-trivial, as the stack can be anywhere (depends on CLEAR in BASIC), so makes me wonder if it's more reasonable to use your own stack all the time and fixed mapping and do some magic upon return (maybe putting a small piece of return code into VRAM into basic input area, where it will become overdrawn soon, or if there is some sysvar area similar to printer buffer on zx48 where you could temporarily put code handling the exit), or if it's more reasonable to have two possible mapping and relocatable code, and pick the mapping outside of current system stack and keep using that one (and I'm not sure if you can deallocate + return in one call, so maybe again some small piece of exit code needed somewhere).

But in the end, this needs basically some strict and precise definition from Garry, because whatever we hack now on current NextZXOS may become invalid later in future, so in my personal view it's not worth the effort at this moment, until it is well defined.

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 9:24 am

Ped7g wrote:
Mon Apr 27, 2020 9:03 am
Not sure about all of this, but I can answer some:
Yeah, that pretty much covers the way I see things at the moment. The current application is just a test, not the final thing I'm working towards, so I do need that screen-refresh interrupt.

So basically what I want is a way to just map something to mmu0 in dot command and then have a way to return back. That would be the simplest implementation for me. Exiting and entering the allram mode (assuming that's what we're dealing with here) does look confusing, though. Peripheral 4 has "reset mapram bit in DivMMC" bit which may be related but I have no idea what that actuall does.

Workaround 1 would be to do the interrupts in old school way, which I'd rather not do unless I have to.

Workaround 2 would be to use the rst 0x20 which would require quite a few changes to how I've done things so far, but would lead to a more "clean" system state, I suppose.

The biggest drawback with workaround 1 (apart from being annoying) is that mmu0 wouldn't be remappable to usable memory and I'd have one mmu slot dedicated to the interrupt jump table, so I couldn't remap it on the fly, which would limit the amount of contiguous resident memory I could use.

The biggest drawback with workaround 2 is that it would require quite a bit of work before I knew if I can cleanly exit at all.

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 9:36 am

On subject of rst 0x20, here's all the information I can find about it:
The recommended way to start your game/application after loading from within a dot command is to use RST $20 with HL=address. This will cleanly terminate your dot command, and return to the address provided in HL.
Note that this still leaves your dot command file open (as well as any other files you may have opened), so you may continue to load further assets from it if desired.
So I suppose I could do:
- Store current mmu register values
- Allocate page, map to, say, mmu3
- Copy the current 8k of code (located at mmu1) to mmu3
- Also map the allocated page to mmu1, value which is ignored in allram mode
- RST $20 with HL at current address, which will swap control to mmu1
- Assume application life starts from this point (except that mmu1 and 3 have changed and I have one allocated page), so store all registers from this point
- Do the application stuff
- Restore registers and mmu state, free allocated pages and return

..except that the last bit is a bit problematic because where are we executing stuff when the mmu registers are restored? I guess I could do it in the ULA display memory..

All that assuming the rst 0x20 starts from a clean state, i.e, if hl points at 'ret' the system will be fine.

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 5:15 pm

I went with the workaround 1, implementing the IM 2 interrupt hop table. And... it's not triggering. Looks like the frame interrupt is disabled for dot commands?

User avatar
sol_hsa
Posts: 273
Joined: Fri Jun 02, 2017 10:10 am
Location: Finland
Contact:

Re: interrupts in dot commands

Postby sol_hsa » Mon Apr 27, 2020 5:44 pm

nextreg 0x34 is 0, which means the ULA interrupt should be firing. Reg 0x6 is 0xac, which says nmi by m1 is enabled.

I presume there's some system in play that disables these in the special mode, and the nextreg values don't matter.

So I guess this is a dead end and the rst 0x20 is the only way to go, unless I've missed something obvious (or have made a mistake that has not, for some reason, crashed the whole system)

User avatar
SevenFFF
Posts: 565
Joined: Mon Jun 05, 2017 5:30 pm
Location: USA

Re: interrupts in dot commands

Postby SevenFFF » Mon Apr 27, 2020 7:18 pm

I think you're making it much more complicated that it needs to be. Dot commands already run with the fixed esxDOS ROM bank at 0000-1FFF, and your command at 2000-3FFF.

On entry to the dot command, IM1 will normally be in effect, and the already-paged-in esxDOS ROM will handle it perfectly with its own ISR. If you want to switch to a mode 2 interrupt, the natural place to put your 257 byte table and handler is in some free space between 2000-3FFF. You can move this anywhere else between 4000-FFFF, but then you will need to deal with allocating banks using IDE_BANK, and then freeing them up and restoring the original memory arrangement before exiting.

Bear in mind that the IM1 interrupt handler may already be chaining driver calls, so you should consider whether you want these to run inside your dot command or not. Is there any particular reason you need an interrupt handler at all? Most dot commands don't need them. Echoing what Ped days, you can run a main loop and poll keys inside them, and the screen doesn't need interrupts to be on in order to redraw itself.

You should only very rarely need to exit dot commands with rst $20 - that's really for something like .nexload, which loads a user program then exits straight into it. For regular dot commands, you almost always want to exit back to BASIC with ret.

Dot commands are complicated enough when done simply, so I really would strongly recommend to stick to the standard simple pattern rather than going off reservation because you think your complicated way sounds simpler. Same thing as with sdcc vs z88dk, really. You're making a rod for your own back by trying to reinvent the wheel with your own more complicated techniques.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins


Who is online

Users browsing this forum: No registered users and 2 guests