Article View: mod.computers.68k
Article #72Source code for the background routines (long = 273 lines)
From: Robert Royar
Date: Wed, 09 Jul 1986 19:06
Date: Wed, 09 Jul 1986 19:06
273 lines
14320 bytes
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!RDROYA01Show 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