🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.computers.68k
Article #72

Source code for the background routines (long = 273 lines)

#72
From: Robert Royar
Date: Wed, 09 Jul 1986 19:06
273 lines
14320 bytes
* Below is the code for the background utility I have been writing about.
* I would appreciate someone's assmebling this code and integrating it into
* her own package to see whether it works for others.  The simple move to
* background operation, I have been using for three months without bugs. I
* posted that earlier.  This version, with its stack manipulations is new
* and has been tested for a week.  I cannot guarantee it.  At the end of the
* assembly code is the 'C' routine that interfaces to uEmacs, but any routine
* to output characters should work.  Also, this could be a stand alone program
* loaded in high memory.  If so add some lines of code to the conin routine to
* watch for an attention char that will begin the process, or patch your bios
* conin routine to call trap #1, after this is installed, whenever the
* attention character is typed.

* Known Gotcha's:
* 1) If a file is open in one process when you switch to the other which also
*    opens a file, the original DMA address is lost.  On return, your original
*    file will have an incorrect buffer.  Solution: write a getdma routine
*    to save the foreground DMA pointer and reset it on return.
* 2) If you have an open file in the foreground and when you go to background,
*    you change the logged disk drive, when you return to foreground, the
*    program cannot find the open file.  It should save the current disk value
*    on entry, and restore it on return.  Then it would also have to save the
*    background logged disk, and reset it when switching back to the background
*    task.  I'm too lazy right now.
* 3) This problem occurs frequently on my system with or without this
*    background stuff and is probably a problem with my system.  If you
*    are logged into one drive (say C:) and load ddt (only ddt) from another
*    (say B:) with a file to load on the command line (i.e. B:DDT FOO.BAR), ddt
*    goes to lunch, rather the drive does.  However, if you load ddt without
*    the filename on the command line and use the 'e' command, everthing works
*    fine.  Also, if ddt is on a RAMDRIVE, it will load successfully with the
*    filename on the command line.
* a technique for implementing sys() calls from inside a C program.
*       1) call initv() once at start-up.
*       2) oldhigh_add = hmem
*       3) trap #1 (_ccp routine)
*       4) reset trap #3 handler to capture warm boot and connin
*       5) on exit from background programs, loop to ccp (background)
*       6) on ^C reset tpa, trap #3, and return to suspended program
*       7) on <ESC> suspend background task and return to foreground
*       Comment field conventions
*       *     signifies code that runs in U mode
*       **    signifies code that runs in S mode
*       ***   signifies S code with interrupts disabled
*       * *** signifies U code with interrupts disabled

ssp:    =       $5a62           * address of SSP at pload
ccpmain:=       $234a           * cpmlib _main on HSC board (not _ccp)
log_dsk:=       $5abe           * address of log_dsk tbl on HSC system

        .globl  _initv
_initv: move.l  $8c,$80         * set up trap #0 from trap #3
        move.l  #_ccp,$84       * set up trap #1
        move.w  #$0,tpab        * request current values
        bsr     settpa
        move.l  high,hmem       * save original high memory
        move.w  #62,d0          * set supervisor state to get SSP value
        trap    #2              **
        move.l  #sstack,a0      ** address for new system stack
        move.l  #ssp,a1         ** default SSP
* This routine may not be necessary because in most cases the SSP at
* load is the same as the default value.
setstk: move.l  -(a1),-(a0)     ** copy current SSP contents to bg_ssp
        cmpa.l  a7,a1
        bhi     setstk          ** bra if a1 is higher than a7 (never?)
        move.l  a0,_ssp         ** default stack pointer for background
        move.w  #0,sr           ** back to user state
        rts                     *

* access to ccp through trap #1

_ccp:   movem.l d0-d7/a1-a7,regs1       ** save return environment
        move.l  usp,a0                  ** save USP for later return
        move.l  a0,_usp
        move.l  #bios_tr,$8c            ** set temporary trap #3 handler
        move.l  #$20000,high            ** set temporary high memory
        move.w  #$1,tpab                ** temporary set parameter
        bsr     settpa                  ** use temp. in case of crash
        cmp.w   #$0,inbg                ** has a background task been suspended?
        bne     restore                 ** yes, then return to it
ccp:    move.l  _ssp,a7                 ** set default ssp
        jsr     ccpmain                 ** address of _ccpmain on HSC board
        bra     ccp                     ** loop forever (until ^C)
fix:    move.l  $80,$8c                 ** reset the original trap #3 handler
        move.w  #$3,tpab                ** reset tpa permanently
        move.l  hmem,high               ** back to original value
        bsr     settpa
        bsr     reset                   ** reset disks
        movem.l regs1,d0-d7/a1-a7       ** reset old environment
        move.l  _usp,a0                 ** replace user stack pointer
        move.l  a0,usp
        rte

* Bios trap handler takes over when in background.  Passes through all
* commands except conin and warm start.  Captures these to enable return
* to suspended program.  Trapping warm start allows the bdos to reinitialize
* everything as usual and return on end to background ccp.  This routine
* assumes the patch to CPM _initexc has been made so that traps #0 and #1
* are left alone by the system, as should be.  This routine is borrowed from
* the system bios in that it always disables interrupts.  Most background
* tasks, except during program execution, operate with interrupts disabled.
* Could this be a problem on some systems?

        .globl  _outchar
bios_tr:
        move.w  #$2700,sr       *** disable interrupts
        cmp.w   #4,d0           *** console out request?
        beq     conout          *** put char in buffer
        cmp.w   #3,d0           *** was it a conin request?
        beq     conin           *** check for return to editor
        cmp.w   #1,d0           *** was it a warm boot?
        beq     wboot           *** return to calling program
        trap    #0              *** no, process the request
        rte                     *** return
conin:  trap    #0              *** get the character
        cmp     #3,d0           *** was it a ^C?
        beq     fix             *** yes, go back to calling program
        cmp     #$7f,d0         *** delete?
        beq     bsp             *** change to backspace
        cmp     #2,d0           *** left arrow?
        beq     bsp             *** change to backspace
        cmp     #$1b,d0         *** suspend background task command?
        beq     suspend         *** save this environment
        rte                     *** send char through
bsp:    move.w  #8,d0           *** put ^H in d0
        rte                     *** return
* Each running (suspended) program needs its own stacks to avoid interference.
* But the editor must use its own stack to allocate text in the [Command]
* buffer.  That's the reason for the stack manipulation in this routine.
conout: link    a6,#-6          ***
        move    d1,-2(a6)       ***
        move.w  #$0700,sr       * *** set user mode without interrupts
        move.l  a7,ra7u         * *** save user (sp)
        move.l  _usp,a7         * *** replace old usp
        move    -2(a6),(a7)     * *** put char on stack
        jsr     _outchar        * *** goto 'C' code to handle allocation
        move.l  ra7u,a7         * *** replace background USP
        move.l  d0,rd0          * *** save return from _outchar
        move.w  #62,d0          * *** back to superviser state
        trap    #2              ***
        move.l  rd0,d0          *** replace _outchar's returned value
        cmp     #$ff,d0         *** -1 means allocation error
        beq     fix             *** if so cleanup and leave
        unlk    a6              ***
        rte                     ***
wboot:  move.w  #$0,log_dsk     *** address of disk select word
        moveq.l #$d,d0          *** warm boot request to z80
        bsr     append          *** HSC dependent routines to deal with
        bsr     extract         *** I/O server
        move.w  #$1,tpab        *** temporarily reset tpa to protect editor
        jsr     settpa          ***
        bra     ccp             *** remain in background
* These two routines should probably save and restore the current DMA address
* and current logged disk for each process, then restore them on exit.
suspend:                        *** save all environment variables
        movem.l d1-a7,bgregs
        move.l  usp,a0
        move.l  a0,bgusp        *** save current USP value
        move.w  #$ffff,inbg     *** set switch
        bra     fix             *** return to editor
restore:                        *** return to suspended task
        move.w  #$2700,sr       *** restore SR to trap #3 state
        move.l  bgusp,a0        *** restore all environment variables
        move.l  a0,usp          *** restore background USP
        movem.l bgregs,d1-a7
        clr.w   inbg            *** set up for next time through
        bra     bsp             *** return to suspended program
reset:  move.w  #$25,d0         ** reset disks A-C to R/W
        move.w  #$3,d1
        trap    #2
        rts

* Sets tpa limits using values in tpab.  Use to set TPA before beginning
* a background task.  On return from task call the function again to
* set the high TPA back to the temporary value.  This way a crash during
* a background task will not leave the memory permanently truncated.  On
* exit from background, restore original value stored in hmem.  The
* calling function stores the TPAB parameter at tpab before calling this
* function.  The tpab should be 1 to set the memory temporarily or 3 for
* permanent setting.

settpa:
        movem.l d0-d7/a0-a6,regs2       * not presently necessary
        move.w  #$3f,d0
        move.l  #tpab,d1
        trap    #2
        movem.l regs2,d0-d7/a0-a6
        rts

        .even
        .data
inbg:   dc.w    0               * 0 = no bg task running
                                * $FFFF = bg task active
        .even
        .bss
tpab:   ds.w    1               * parameter for tpa set
low:    ds.l    1               * storage for low mem value
high:   ds.l    1               * storage for high mem value
        .even
hmem:   ds.l    1               * permanent highmem
rd0:    ds.l    1
ra7u:   ds.l    1               * storage for register user a7 in conout
regs1:  ds.l    15              * register storage for _ccp and fix
regs2:  ds.l    15              * register storage for settpa
_usp:   ds.l    1               * value of USP for _ccp and fix
_ssp:   ds.l    1               * pointer to stack location in background
bgregs: ds.l    15              * register storage for suspended task two
bgusp:  ds.l    1               * value of USP for for suspended task
        .even
        ds.l    300             * space for stack probably overkill
sstack:=*
        .end

----------------- cut -- here -------------------------------------------------
/* Some sample 'C' code */
/* minimum initiation.  This assumes you have patched _initexc in CPM.SYS
 * to work as DRI claims it does, i.e. leaves traps 0 & 1 alone on warm
 * boot.
 */
main()
{
        initv();
}
        /* 'C' code fragment to call installed program */
        /* All functions are part of uEmacs */
                case 0x03:      /* start a ccp subjob */
                        if ((f=onlywind(NULL, TRUE)) != TRUE)
                                return(f);
                        if ((f=combuf()) != TRUE)/* open [Command] window */
                                return(f);
                        if ((f=prevwind(NULL, TRUE)) != TRUE)
                                return(f);
                        setmark(NULL,TRUE);
                        gotoeob(NULL,TRUE);
                        update();
                        asm("trap #1");
                        return(prevwind(NULL,TRUE));

/* this routine is only necessary for uEmacs interface; otherwise could
 * be in the assembly code.
 */
outchar(c)
register int c;
{

        switch(c)
                {
                case '\r':
                        return(NULL);
                case '\n':              /* newline */
                        c = newline(NULL,TRUE);
                        break;
                case CTRL|'X':          /* delete line */
                        c = mdeleln(NULL,TRUE);
                        break;
                case '\b':      /* back delete */
                        c = backdel(NULL, TRUE);
                        break;
                default:        /* simple insert */
                        c = linsert(1, c);
                }
        if(c==NULL)
                c = 0xff;       /* failed functions return 0, but conout
                                   expects -1 for failure
                                 */
        else
                {
                update();
                c=NULL;
                }
        return(c);
}
Technical Details
Message-ID: <8607091809.AA13815@ucbjade.Berkeley.Edu>
Path: arc1-ca.pugleaf.net!utzoo!decvax!ittatc!dcdwest!sdcsvax!ucbvax!ULKYVX.BITNET!RDROYA01

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site ucbvax.BERKELEY.EDU
Path: arc1-ca.pugleaf.net!utzoo!decvax!ittatc!dcdwest!sdcsvax!ucbvax!ULKYVX.BITNET!RDROYA01
From: RDROYA01@ULKYVX.BITNET (Robert Royar)
Newsgroups: mod.computers.68k
Subject: Source code for the background routines (long = 273 lines)
Message-ID: <8607091809.AA13815@ucbjade.Berkeley.Edu>
Date: Wed, 9-Jul-86 15:06:00 EDT
Article-I.D.: ucbjade.8607091809.AA13815
Posted: Wed Jul  9 15:06:00 1986
Date-Received: Thu, 10-Jul-86 21:00:48 EDT
Sender: mwm@ucbvax.BERKELEY.EDU
Organization: University of Louisville
Lines: 273
Approved: info-68k@ucbvax.berkeley.edu