Jump to content

Under the OS in a VB

Recommended Posts

Hi all -

I'm starting to look at storing something under the OS. One slight difference from a lot of what I'm finding on the subject is that I *only* will be accessing it in a VB...both immediate and deferred. I think that actually makes it easier, but I'm not sure. I have some questions :


1. Am I right in saying that accessing only during VB will make it easier? I'm thinking I won't have to worry about VB's and DLI's.

2. What will I lose in terms of being able to run on various setups? I would like this to be as generally usable as possible.

3. What is the 'unused' portion between C000-D000. Is that really inaccessible?

Edited by danwinslow
Link to comment
Share on other sites

1. "Easier" - sort of. Stage 1 VB you don't have the risk of any other interrupts that the OS is absent to handle. Stage 2 though, the OS isn't there to handle interrupts (IRQs will be enabled) so you have potential for trouble. Stage 2 VB you don't have guarantee that it always occurs so think twice before using it anyway. Also a very long Stage 2 could potentially be interrupted by DLIs if the active display starts again.

Workaround for Stage 2 potential problems could be just do a SEI before swapping out the OS, CLI once the Rom is back in. There's potential for real problems if SIO is going on but just avoid doing any such thing while your routine is active.


2. Numerous Doses use the Ram under the OS. There's a patch for 2.5 that keeps Dup.sys and Mem.sav there. SpartaDos can be setup to enable using that memory. In general it's not easy to find out if something is already using that memory, you have to rely on the user to know well enough not to create a clash situation.


3. $C000-$CFFF - It was "unused" on the factory memory map of 400/800. Early Ram expansions sometimes used it for Ram. Modified OSes with Monitors generally used it to hold the monitor code.

The XL/later OS uses it, as such there is 14K which is swapped out in one hit if you disable the OS via PORTB setting.

Link to comment
Share on other sites

14k, wow. Yes, I was testing and the $C000 range does seem to be usable. Stage 2, with and without CIO running, works well with my stuff so far, although any kind of game that relies on heavy VB work won't be compatible. I hadn't thought about DLI's on overrun though, I'll have to test that.

Edited by danwinslow
Link to comment
Share on other sites

You could handle NMIs yourself. They're easy since only 2 types.

IRQs are totally different though. There's multiple sources and PBI devices can generate them too.

Best bet with IRQs is to just disable via SEI for the duration. Don't confuse CIO with SIO. CIO doesn't use interrupts so is mostly irrelevant.


But like I said before, using Stage 2 VB has no guarantees. All it takes is a keypress at the right time and it will be bypassed. Or disk IO taking place in which case almost all will be skipped.

Link to comment
Share on other sites

why not going the full mile and disable OS completly (except you need OS routines like text CIO etc). that's what I am doing since for ages. the 14k extra memory is a bonus why not use it? I mainly put there unrolled code or data/videoram/player missle stuff... fex. $dc00-$dfff for players, $e000- ... for double buffering video ram. $c000 for 4k lookup tables etc.

  • Like 1
Link to comment
Share on other sites

If you're doing stuff for Basic or need OS services then you generally want to keep the OS around.


Another thing I should mention. It's not good for your Stage 1 VB to go too long (the docs mention it). If you delay things too much, SIO will stop working properly, and screen corruption can occur if the shadow register copies are delayed too much... the problem there is that the DList pointer if reloaded during active display will restart the screen with 24 extra blank scanlines.

Link to comment
Share on other sites

Yes, that's the idea, I want the driver to be able to co-exist with as much normal programming stuff as possible, otherwise I surely would just punt the OS entirely. So far it works perfectly with SIO, and missing a few deferred stage 2's is no problem. But, sadly, I'm starting to run out of room in the single extended bank I'm using. Right now I have 4k of non-banked used by the CIO handler, which leaves BASIC with around 29k of usable space. I have about 2.8 k of space left in the single extended bank. The 4k for the handler is mostly buffer space, because the IO runs in the extended bank and it's handy to be able to have the buffers in real memory shared by the handler. It lets me dump bytes to the handler memory, directly accessible to user programs and skip the laborious extra copies from extended.

But I'd like to minimize the handler memory, leaving as much space as possible for user programs. I also don't know if the second half of the TCP code I have yet to write will fit into the extended bank. I'd like to get the handler usage down to 2k or less, and be able to fit the rest of the TCP code into the single extended bank. Careful use of the RAM under the OS would really help, as long as it wouldn't disturb things too much. I could just go ahead and use another extended bank, but as I said it introduces some issues with buffer copying speed.


Stage 1 all I do is increment some internal timers. Stage 2 is where the actual work happens, and missing up to 50% of them if IO is running doesn't seem to disturb much.

Link to comment
Share on other sites

So, I've been looking at this code, as a means to enable IRQ and NMI protection when the OS is swapped out. Can anyone explain what the deal with the DFB $24 is? Is that just a fancy way of skipping the CLC if it's entered at the NMI address, or is there something else going on there? Wouldn't a BCS accomplish the same thing?

NMI     SEC       ;Set carry-flag, and
        DFB  $24  ;skip the next byte
                  ;(BIT has opcode $24)
IRQ     CLC        ;Clear carry-flag
        PHA         ;Save A and X, and
        TXA         ;copy the stack
        TSX         ;pointer into X
        LDA  $D301   ;Swith the ROM on,
        PHA          ;and save the old
        ORA  #1      ;value
        STA  $D301
        LDA  #BACK:H  ;Set the adress
        PHA           ;where RTI will
        LDA  #BACK:L  ;jump
        INX            ;Transfer state
        INX            ;of flags before
        LDA  $100,X    ;interrupt
        BCC  IRQJUMP  ;Which interrupt?
        JMP  ($FFFA)   ;Run NMI in ROM!
               ;When the routine in ROM
               ;finished its work:
BACK    PLA           ;Return ROM into
        STA  $D301    ;original state
        PLA          ;End of interrupt!
Note that we need to initialize it first - in this way:
INIT    LDA  #0      ;Disable all the
        STA  $D40E   ;interrupts
        LDA  #$FE     ;ROM OFF!
        STA  $D301
        LDA  #NMI:L  ;Set NMI adress!
        STA  $FFFA
        LDA  #NMI:H
        STA  $FFFB
        LDA  #IRQ:L  ;Set IRQ adress!
        STA  $FFFE
        LDA  #IRQ:H
        STA  $FFFF
        INC  $D301    ;ROM ON!
        CLI          ;Enable interrupts
        LDA  #$40
        STA  $D40E
        RTS           ;That's all!
Edited by danwinslow
Link to comment
Share on other sites

The techique of using that BIT as a sort of NOP/skip next instruction is a memory and cycle saving exercise. Yes, it makes the program harder to understand.


The sort of interrupt handling being done here can have problems. It'll add way too much overhead to practically any DLI. For IRQs it should be OK but SIO at anything over stock speeds might have trouble.

Personally, I'd probably just use the Immediate VBlank, leave IRQs masked while the OS is swapped out. Do the shadow register copy stuff that the OS Stage 2 VBlank would otherwise have done.

Then return with the OS swapped back in, ie JMP $E462.


The thing to be careful of though is don't let the routine run into normal display time.

Alternatively, handle the NMI case differently. DLIs generally won't have dependancy on the OS Rom being present. Though if you're doing a driver or some program that's in an otherwise unknown environment, e.g. might execute with a word processor loaded or something - then you can't depend on that being the case.

Edited by Rybags
Link to comment
Share on other sites

Yeah, it's not looking like this is going to work out very well. Since I want to support at least some DLI activity, I really can't swap the OS much if I'm not in the VB, plus Sparta and RealDos both steal those vectors themselves and put code under the OS, so it's probably not practical anyway. I really need about 4k more buffer space though. I can probably move it into another ext bank but that leads to unfortunate amounts of copying. Maybe I can put the buffers in low mem and move the actual CIO device handler into another bank. It's important to be able to write the packet directly into the user space, which means the driver needs to write the buffers in a spot that can be directly accessible to user code that probably will be in the bank window. Learned some stuff from looking at that code, though, it's pretty cool.

Edited by danwinslow
Link to comment
Share on other sites

You could just do a proper NMI handler in Ram. The critical thing though is that any DLI would have to not need the OS Rom in place.

Generally that's the case anyway.

The other thing, probably already covered - in the active display it's probably a good idea to have an exact copy of the character set in Ram at $E000

Link to comment
Share on other sites

You know, on top of fit all, this code I used just doesn't seem right. The sequence followed when an IRQ occurs screws up the stack. The first RTI does not return whence it came from. It goes off somewhere else in the rom and eventually RTS's, but the stack is screwed up so I wind up jumping right in the middle of some unrelated code and crashing. I think they are trying to jimmy the stack to get the RTI come back to the intercept routine right after the indirect JMP, but it's not doing it right.

Link to comment
Share on other sites

Looks like the issue with code may be an OS version thing...the ROM IRQ I have is pulling the y,x, and a regs off before doing the RTI, and they did not allow for that.


FJC : not really, but if the driver is to stay 'running' while no program is executing it needs a interrupt thread so it can poll for packets, answer pings, etc., as in a regular ethernet stack. Plus it allows user programs, such as BASIC, to not have to worry about continuously calling some 'poll()' routine. I do plan a version of the stack that would be linked into a user program, and that program would have the responsibility to call it often enough.


I don't think the problem, at least right now, is that I'm in a VB at the time, its that the code I copied from (above) is either bad or at least out of date from my ROM.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...