REAR SUBEXCEPTN S K BDOSDEF H L CONBDOS C S !MAKE SUBFILEIO C FILEIO C FILETYPSS 1 $2 l.o fileio.o bdosrw.o bdosmain.o $2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o BDOSMISCC K"#$%&'()*+CCPLOAD S B,-./01234MAKE SUB5BDOSIF S (6789:IOSYS C PGMLD S PGMLD S PKTIO H  $2 l.o fileio.o bdosrw.o bdosmain.o $2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o BDOSINC H ";<=>?BDOSMAINC g@ABCDEFGHIJKLBDOSRW C ^MNOPQRSTUVWXBIOSDEF H YZ[\************************************************* * * * CP/M-68k Basic Disk Operating System * * Exception Handling MoSTACK S LOADR S >OVHDLR S MACHINE 68K $2 l.o fileio.o bdosrw.o bdosmain.o $2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o CCP C ]^_`abcdefghijklCCP C mnopqrstuvwxyz{|CCP C $}~CCPBDOS S era cpmlib $2ar68 rf $1 cpmlib ccpif.o except10.o ccpbdos.o ccpload.o ccp.o bdosif.o $2ar68 rf $1 cpmlib conbdos.o bdosmisc.odule * * * * Version 0.0 -- July 21, 1982 * * Version 0.1 -- July 25, 1982 * * Version 0.2 -- October 6, 1982 MACHINE VAXMACHINE H CCPDEF H $CCPIF S CPMC DOC DSKUTIL C B dskutil.o fileio.o bdosrw.o bdosmain.o $2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o era *.o user 3!make $ * * Version 0.3 -- December 21, 1982 * * * * Modified 2/15/84 sw for 68010 support * * * ***********************f M68010 bsr.w except * 2 Buserr excrtn0: bsr.w except * 3 Addressing error bsr.w except * 4 Illegal Instruction #d4 = new high TPA limit move #17,d0 movea.l 4(sp),a0 move.l a0,evec_adr * save exception vector address init4: cmp.l (adef M68010 * * Here if the exception in question was a buserr/addressing error. * We reformat the stack to look like a 68000.dq #1,d1 add.l #4,d2 cmpi #spurious,d1 bne init3 move #trap0,d1 init3: cmpi #trap2,d1 beq init2 * don't init trap 2 r.w except * 16 bsr.w except * 17 bsr.w except * 18 bsr.w except * 19 bsr.w except * 20 bsr.w except * 21 bsr.************************** .globl _initexc .globl _tpa_lp .globl _tpa_hp .globl gouser *sw RTE routine bgetsegelse .globl m68010 * Note case difference! m68010: * For build process bsr.w berr * 2 Buserr excrtn0: bsr.w berr 0),d1 bhi do_init * if old exception outside orig TPA, clear it cmp.l (a0),d2 bls do_init * current exception array entr * * Entered with a standard 68010 exception stack frame with a return * address on top (at 0(sp)). * berr: move.l $0(sp)or trap 3 cmpi #trap3,d1 beq init2 cmpi #endvec,d1 blt init1 * initialize the exception vector array moveq #bgetw except * 22 bsr.w except * 23 bsr.w except * 24 bsr.w except * 25 bsr.w except * 26 bsr.w except * 27 bsr.w = 18 bsetexc = 22 buserr = 2 spurious = 24 trap0 = 32 trap2 = 34 trap3 = 35 endvec = 48 _initexc: * Initialize Excep* 3 Addressing error bsr.w except * 4 Illegal Instruction #endif bsr.w except * 5 bsr.w except * 6 bsr.w except y is in original TPA cmp.l (a0),d3 bhi dontinit * if old exception in old TPA but outside new cmp.l (a0),d4 * TPA, don't ,$2a(sp) * Move return address move.w $0c(sp),$2e(sp) * Move Status word andi.w #7,$2e(sp) * Clear all but FC0-2 movseg,d0 trap #3 * get the original TPA limits movea.l d0,a0 tst.w (a0)+ move.l (a0)+,d1 * d1 = original low TPA limit except * 28 bsr.w except * 29 bsr.w except * 30 bsr.w except * 31 bsr.w except * 32 bsr.w except * 33 bsr.w extion Vector Handlers * It has 1 passed parameter: the address of the exception vector array move #bsetexc,d0 moveq #2,d1 * 7 #ifndef M68010 bsr.w except * 8 #else * Privilege violation bsr.w privviol * 8 #endif bsr.w except * 9 clear it bls dontinit do_init: clr.l (a0) dontinit: tst.l (a0)+ dbf d0,init4 rts .page exchndl:.equ * #ifndee.l $0e(sp),$30(sp) * Copy Fault address move.w $1c(sp),$34(sp) * Move IR move.w $4(sp),$36(sp) * Move SR move.l $6(move.l d1,d2 add.l (a0),d2 * d2 = original high TPA limit move.l _tpa_lp,d3 * d3 = new low TPA limit move.l _tpa_hp,d4 * cept * 34 bsr.w except * 35 bsr.w except * 36 bsr.w except * 37 bsr.w except * 38 bsr.w except * 39 .page #ifmove.l #exchndl,d2 init1: movem.l d0-d2,-(sp) trap #3 * BIOS call to set exception vector movem.l (sp)+,d0-d2 init2: adbsr.w except * 10 bsr.w except * 11 bsr.w except * 12 bsr.w except * 13 bsr.w except * 14 bsr.w except * 15 bssp),$38(sp) * Move PC move.w $0a(sp),$3c(sp) * Move format word adda.l #$2a,sp * Make sp -> new frame bra except format word)| move.l 10(sp),d0 * get return address from above array sub.l #excrtn0,d0 * d0 now has 4 * (encoded excptn nmbrsr: movem.l (sp)+,d0/a0 * Abandon hope, all ye .. .page #endif except: clr.w -(sp) movem.l a0/d0,-(sp) * 10 (11) wordsi #2,d0 cmpi #23,d0 * get back real excptn nmbr in [2..23,32..47] ble lowexc addi #8,d0 lowexc: move d0,-(sp) * save excruction exception. * ****************************************************************************** privviol: movem.l ected bne usrexc * not redirected, do default handler supexc: * Here for supervisor state cmpi #40,d0 blt dfltexc * Merge ****************************************************************************** * Here we make up for a faux pas in th), where * encoded excptn nmbr is in [0..21,22..37] * representing [2..23,32..47] cmpi #36,d0 * if d0/4 is now on stack in following order * _______________________________ * |____________D0.L_______________| * |_________ptn nmbr lea excmsg1,a0 bsr print * print default exception message move (sp)+,d0 bsr prtbyte lea excmsg2, a0 bsr pd0/a0,-(sp) * Save some regs move.l $0e(sp),a0 * A0 -> Instruction move.w (a0),d0 * d0 = Instruction andi.w #$FFC0 addi #48,d0 * add 4*12 that was sub'd above dfltexc: adda #14,sp * throw away 7 words that we added to stack asr #2,d0 e C compiler. Change all * * move from SR instructions ($40CX) to move from CCR ($42CX). * * Precludes executin [0..9,22..29] then ble chkredir * the exception may be redirected cmpi #88,d0 blt dfltexc cmpi #116,d0 bgt dflt___A0.L_______________| * |____0000______|________________ * |_______Handler Return__________| * If bus error, extrarint move.l (sp)+,d0 bsr prtlong lea excmsg3, a0 bsr print clr.l d0 trap #2 * warm boot rte usrexc: * Call us,d0 * Mask off field cmpi.w #$40C0,d0 * Move from SR? bne notsr * No, handle normally ori.w #$0200,(a0) * Ch * divide d0 by 4 * now d0 is in [0..21,22..37] * to represent [2..23,32..47] cmpi #2,d0 * bus or address error? bging 68000 programs in ROM on a 68010. * * exc * in range of redirected exceptions subi #48,d0 * subtract 4*12 to normalize [0..9,22..29] * into [0..9,10..17 2 longs are here * ______________ * |__Status Reg__|________________ * |_____Exception Return__________| * |_(er exception handler * make sure exception information is on his stack cmpi #8,d0 * address or bus error? blt addrexc * iange to move from CCR movem.l (sp)+,d0/a0 * Restore regs tst.l (sp)+ * Pop return address rte * Try it again note nobusexc movem.l (sp)+,a0-a1 * if yes, throw away 4 words from stack nobusexc: tst.w (sp)+ * throw away stacked SR add * * Relies on the fact that the exception PC (Stack offset 0E below) * * points to the instruction on an illegal inst] chkredir: movea.l evec_adr,a0 adda d0,a0 * index into exception vector array tst.l (a0) * if 00000000, then not redirf yes, skip btst #13,14(sp) * exception occured in user state? bne supexc *sw if no, go to supervisor handler move.l (a0)M68010 clr.w -(sp) * Push format word #endif move.l a0,-(sp) * Push epa clr.w -(sp) * and SR rte * Do it. Iove address of user handler to excptn rtn #ifdef M68010 clr.w 20(sp) *sw Clear format word #endif adda #14,sp * clear judler addrexc: btst #13,22(sp) * exception occured in user state? bne supexc *sw if no, go to supervisor handler move.l (9'-1,d0 lt10: addi.b #'0',d0 move d0,d1 move #2,d0 trap #2 rts .data excmsg1: .dc.b 13,10,10,'Exception $',10(sp) * put user handler address on our stack move.l usp,a0 * user stack pointer to a0 move.l 16(sp),-(a0) * put exceptionto user program. .page * * Subroutines * print: clr.l d1 move.b (a0)+, d1 beq prtdone move #2, d0 trap #2 bnk from stack andi #$7fff,(sp) * clear trace bit rte * go to user handler .page *************************************a0),10(sp) * put user handler address on our stack move.l usp,a0 * user stack pointer to a0 move.l 24(sp),-(a0) * put excep,0 excmsg2: .dc.b ' at user address $',0 excmsg3: .dc.b '. Aborted.',0 .bss evec_adr: .ds.l 1 .end n return on user stack move.w 14(sp),-(a0) * put SR on user stack move.l a0,usp * update user stack pointer movem.l (sp)+ra print prtdone: rts prtlong: * Print d0.l in hex format move d0,-(sp) swap d0 bsr prtword move (sp)+,d0 prt****************************************** * * gouser routine. This routine performs an RTE to go to the user program * Ution return on user stack move.w 22(sp),-(a0) * put SR on user stack move.l 18(sp),-(a0) * put extra 2 longs on user stack 0 excmsg2: .dc.b ' at user address $',0 excmsg3: .dc.b '. Aborted.',0 .bss evec_adr: .ds.l 1 .end ,a0/d0 * restore regs move.l 2(sp),8(sp) * move address of user handler to excptn rtn #ifdef M68010 clr.w 12(sp) *sw Clearword: * Print d0.w in hex format move d0,-(sp) lsr #8,d0 bsr prtbyte move (sp)+,d0 prtbyte: * Print d0.b in hex fser EPA is passed in A0.L. * ******************************************************************************* gouser: #ifdef move.l 14(sp),-(a0) move.l a0,usp * update user stack pointer movem.l (sp)+,a0/d0 * restore regs move.l 2(sp),16(sp) * m out the format word #endif addq #6,sp * clear junk from stack andi #$7fff,(sp) * clear trace bit rte * go to user hanormat move d0,-(sp) lsr #4,d0 bsr prtnib move (sp)+,d0 prtnib: andi #$f,d0 cmpi #10,d0 blt lt10 addi.b #'A'-'/******************************************************** * * * imple structure for the single thread environment while leaving the possibilities open for the multi-thread environment. ***** Only a few "globals" are really global in this sense. The majority of the "global" variables are actually state variables th to the manipulation of the allocation vector. This isn't a problem in a single-thread model, but must be provided for ********************************************************************* The BDOS data structures, especially those relating to gltern structure */ #endif #if ! snglthrd #define GBL (*statep) /* If multi-task, state vars CP/M-68K header file * * Copyright (c) 1982 by Digital Research, Inc. * * Structure defin***********************************************************************/ #define snglthrd TRUE /* TRat relate to the state of the task using the file system. In CP/M-68K, these are "global", since there's only one task, but iin a multi-tasking file system. Consequently, the primitives LOCK and UNLOCK are defined and used where necessary in the obal variables, are structured in a way that hopefully will enable this BDOS, in the future, to easily become a re-entrant mu are based */ #define BSETUP REG struct stvars *statep; \ statep = &gbls; /* set uitions for BDOS globals * * and BDOS data structures * * UE for single-thread environment FALSE to create based structure for re-entrant model */ #if snglthrd n a multi-thread model they're not. This type of variables is put into a data structure, with the intention that in the multi file system. For the single thread model, they are null routines */ #define LOCK /**/ #define UNLOCK /**/ /*lti-tasking file system. Consequently, the BDOS global variables are divided into two classes. Those that are truly global,p pointer to state variables */ /* This is intended as an example to show the intent */ #endif /* * * Desecrated 6-Aug-83 (sw) for type-ahead * * Again 17-Mar-84 (sw) for chaining * #define GBL gbls /* In single thread case, GBL just names -task environment this structure will be based. The following declarations take this philosophy into account, and define a s Be sure LOCK and UNLOCK are implemented to allow recursive calls to LOCK. That is, if a process that calls LOCK already own even in the case of multiple tasks using the file system concurrently, are simply declared as global variables in bdosmain.c. Note that there are a few critical regions in the file system that must execute without interruption. They pertain mostly * * ********************************************************/ /***** the structure */ #define BSETUP EXTERN struct stvars gbls; /* and BSETUP defines the exs the lock, let it proceed, but remember that only the outer-most call to UNLOCK really releases the file system. */ UBYTE fname[8]; /* File name (ASCII) */ UBYTE ftype[3]; /* File t WORD big[8]; /* or 8 block numbers of 1 word */ } dskmap; UBYTE cur_rec; UWORD dsm; /* max disk size in blocks */ UWORD drm; /* max directory entries */ II) */ UBYTE ftype[3]; /* File type (ASCII) */ UBYTE extent; */ } dskmap; }; /* Declaration of disk parameter tables */ struct dpb /* */ #define VERSION 0x2022 /* Version number for CP/M-68K */ #define robit 0 /* reaype (ASCII) */ UBYTE extent; /* Extent number (bits 0..4 used) */ UBYTE s /* current record field */ UBYTE ran0; /* random record field (3 bytes) */ UWORD dir_al; /* initial allocation for dir */ UWORD cks; /* number dir sectors to ch /* Extent number (bits 0..4 used) */ UBYTE s1; /* Reserved */ disk parameter table */ { UWORD spt; /* sectors per track */ UBYTE bsh; d-only bit in file type field of fcb */ #define arbit 2 /* archive bit in file type field of fcb */ #define 1; /* Reserved */ UBYTE s2; /* Module field (bits 0..5), write fl UBYTE ran1; UBYTE ran2; }; /* Declaration of directory entry */ struct dirent { UBYTE ecksum */ UWORD trk_off; /* track offset */ }; struct dph /* disk par UBYTE s2; /* Module field (bits 0..5), write flag (7) */ UBYTE rcdcnt; /* Nmbr rcrds in /* block shift factor */ UBYTE blm; /* block mask */ UBYTE SECLEN 128 /* length of a CP/M sector */ /* File Control Block definition */ struct fcb { ag (7) */ UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */ union { UBYTE entry; /* 0 - 15 for user numbers, E5 for empty */ /* the rest are reserved ameter header */ { UBYTE *xlt; /* pointer to sector translate table */ UWORD hiwater;last block, 0..128 */ union { UBYTE small[16]; /* 16 block numbers of 1 byte */ exm; /* extent mask */ UBYTE dpbdum; /* dummy byte for fill */ UBYTE drvcode; /* 0 = default drive, 1..16 are drives A..P */ UBYTE fname[8]; /* File name (ASC small[16]; /* 16 block numbers of 1 byte */ WORD big[8]; /* or 8 block numbers of 1 word /* high water mark for this disk */ UWORD dum1; /* dummy (unused) */ /* disk. Stored here to save ref calc */ UWORD srchpos; /* position in directory fast selected by fcn 14) */ UBYTE user; /* Current user number */ struct dph * */ }; E kbchar; /* keyboard type-ahead buffer count */ UBYTE delim; /* Delimiter for function 9 ved next line from structure */ UBYTE *chainp; /* Used for chain to program call */ /* Consol UWORD dum2; UBYTE *dbufp; /* pointer to 128 byte directory buffer */ struct dpb *dpbp; or search next */ UBYTE *dmaadr; /* Disk dma address */ struct fcb *srchp; dphp; /* pointer to disk parm hdr for cur disk */ struct dirent *dirbufp; /* pointer for directory buff for pro */ };  */ BOOLEAN lstecho; /* True if echoing console output to lst: */ BOOLEAN echodel; e buffer structure declaration */ struct conbuf { UBYTE maxlen; /* Maximum length from calling routine */ /* pointer to disk parameter block */ UBYTE *csv; /* pointer to check vector */ /* Pointer to search FCB for function 17 */ UBYTE *excvec[18]; /* Array of exception vectors */cess */ /* stored here so that each process can */ /* have /* Echo char when getting ? */ UWORD column; /* CRT column number for expanding tabs */ UBYTE retlen; /* Length actually found by BDOS */ UBYTE cbuf[]; /* Console data UBYTE *alv; /* pointer to allocation vector */ }; /* Declaration of structure containing "global" s UBYTE *insptr; /*sw Insertion pointer for typeahead */ UBYTE *remptr; /*sw Removal po a separate dirbuf. */ struct dpb *parmp; /* pointer to disk parameter block for cur */ UBYTE curdsk; /* Currently selected disk */ UBYTE dfltdsk; /* Default disk (l */ }; tate variables */ #define TBUFSIZ 126 /*sw # typed-ahead characters */ struct stvars { UBYTinter for typeahead */ UBYTE t_buff[TBUFSIZ]; /*sw Type-ahead buffer itself */ }; /*sw remofine ctrlr 0x12 #define ctrls 0x13 #define ctrlu 0x15 #define ctrlx 0x18 #define cr 0x0d #define lf yright (c) 1982 Digital Research, Inc. * * * * Modified 2/5/84 sw */ { /************************************/ *GBL.ing functions which * * are called from the BDOS main routine: * * constat(); op = FALSE; if ( bconstat() ) do { if ( (ch = bconin()) == ctrlc ) warmboot(2); /*sw from (1) */ if 0x0a #define tab 0x09 #define rub 0x7f #define bs 0x08 #define space 0x20 EXTERN warmbooAllow typeahead * * ^C warmboot modifications * * Again 3/17/84 sw Chain hack * * insptr++ = ch; /* Yes, insert the character in buff*/ GBL.kbchar++; /* Up count * * conin(); * * tabout(); ( ch == ctrls ) stop = TRUE; else if (ch == ctrlq) stop = FALSE; else if (ch == ctrlp) GBL.lstecho = !GBL.lste/******************************************************** * * * CPt(); /* External function definition */ /******************/ /* console status */ /******************/ BOO * ********************************************************/ #include "bdosinc.h" #include "bdosdef */ } /************************************/ } * * rawconio(); * * prt_line(); * *cho; /*sw What Follows is new... */ else /* Insert character in ring buffer */ /M-68K BDOS Character I/O Routines * * * * This module LEAN constat() { BSETUP return( GBL.kbchar ? TRUE : bconstat() ); } /********************/ /* check for ctrl/s.h" #include "biosdef.h" #define ctrlc 0x03 #define ctrle 0x05 #define ctrlp 0x10 #define ctrlq 0x11 #de /* Note if no room, character is */ /* Ignomiously discarded (!) */ readline(); * * * * Cop { /* */ if(GBL.kbchar < TBUFSIZ) /* Room? does BDOS functions 1 thru 11 * * * * It contains the follow */ /* used internally */ /********************/ conbrk() { REG UBYTE ch; REG BOOLEAN stop; BSETUP st /*sw End of new stuff */ /************************************/ } while ( REG UBYTE temp; BSETUP if(GBL.kbchar) { temp = *GBL.remptr++; /* Fetch the character */ /* character to output to console */ { if (ch == tab) tabout(ch); /* if tab, expand it */ else p != GBL.delim ) tabout( *p++ ); } /**********************************************/ /* read line with editing and bounds .column--; } /*************************************/ /* console output with tab expansion */ /****************************************** * raw console i/o * ******************/ UBYTE rawconio(parm) /* BDOS raw console I/O function */ REGstop); } /******************/ /* console output */ /* used internally*/ /******************/ conout(ch) REG UBYTE c GBL.kbchar--; /* Decrement the count */ if(!GBL.kbchar) /* Gone to zero? { if ( (UWORD)ch < (UWORD)' ' ) { conout( '^' ); ch |= 0x40; } conochecking */ /**********************************************/ /* Two subroutines first */ newline(startcol) REG UWORD sta***********/ tabout(ch) REG UBYTE ch; /* character to output to console */ { BSETUP if (ch == t UWORD parm; { BSETUP if (parm == 0xff) return(getch()); else if (parm == 0xfe) return(constat()); else bh; { BSETUP conbrk(); /* check for control-s break */ bconout(ch); /* output */ GBL.remptr = GBL.insptr = &(GBL.t_buff[0]); return(temp); } return( bconin() );ut(ch); /* output the character */ } } /*****************/ /* console input */ /*****************/ rtcol; { BSETUP conout(cr); /* go to new line */ conout(lf); while(startcol) { ab) do conout(' '); while (GBL.column & 7); else conout(ch); } /*******************************/ /* consconout(parm & 0xff); } /****************************************************/ /* print line up to delimiter($) with tab echaracter to console */ if (GBL.lstecho) blstout(ch); /* if ctrl-p on, echo to list dev */ if ((UWORD)ch >= (UWO /* else get char from bios */ } UBYTE conin() /* BDOS console input function */ { REG U UBYTE getch() /* Get char from buffer or bios */ /* For internal use only */ { conout(' '); startcol -= 1; /* start output at starting column */ } } backsp(bufp, col) /* bacole output with tab and */ /* control character expansion */ /*******************************/ cookdout(ch) REG UBYTE ch; xpansion */ /****************************************************/ prt_line(p) REG UBYTE *p; { BSETUP while( *RD)' ') GBL.column++; /* keep track of screen column */ else if (ch == cr) GBL.column = 0; else if (ch == bs) GBLBYTE ch; BSETUP conout( ch = getch() ); if (ch == ctrlp) GBL.lstecho = !GBL.lstecho; return(ch); } /**kspace one character position */ REG struct conbuf *bufp; /* pointer to console buffer */ REG WORD col; { i = UBWORD(*(GBL.chainp++)); j = UBWORD(p->maxlen); if (j < i) i = j; /* don't o conout(bs); /* backspace until we get to proper column */ conout(' '); conout(bs); } } >retlen) { i = UBWORD(--(p->retlen)); conout( p->cbuf[i] ); ulate column position */ { /* across entire char buffer */ ch = *p++; && !(p->retlen) ) { cookdout(ctrlc); warmboot(2); /*sw From warmboot(1) */ } /* starting console column */ { REG UBYTE ch; /* current character */ REG WORverflow console buffer! */ p->retlen = (UBYTE)i; q = p->cbuf; while (i) { cookd readline(p) /* BDOS function 10 */ REG struct conbuf *p; { REG UBYTE ch; REG UWORD i; } } else backsp(p, stcol); } else if (ch == ctrlp) GBL.lstecho = !GBL.lste /* get next char */ if ( ch == tab ) { col += 8; col &= ~7; else if ( (ch == cr) || (ch == lf) ) { /* if cr or lf, exit */ conout(D i; REG UBYTE *p; /* character pointer */ BSETUP if (bufp->retlen) --(bufp->retlenout( *q++ = *(GBL.chainp++) ); i -= 1; } GBL.chainp = NULL; return; } #endif /* REG UWORD j; REG UBYTE *q; UWORD stcol; BSETUP stcol = GBL.column; /* set up starting colucho; /* control-p */ else if (ch == ctrlx) /* contro /* for tab, go to multiple of 8 */ } else if ( (UWORD)ch < (UWORD)' ' ) col += 2; cr); break; } else if (ch == bs) backsp(p, stcol); /* backspace */ else if (ch ==); /* if buffer non-empty, decrease it by 1 */ i = UBWORD(bufp->retlen); /* get new charsw NFG chain code */ p->retlen = 0; /* start out with empty buffer */ while ( UBWORD(p->retlen) < UBWOmn */ #ifdef NFG /*sw This didn't work for SUBMIT files...*/ if (GBL.chainp != NULL) /* chain to program code */ l-x */ do backsp(p,stcol); while (p->retlen); else if (ch == ctrle) newline(stcol); /* control-e */ /* control chars put out 2 printable chars */ else col += 1; } while (GBL.column > col) { rub) /* delete character */ { if (GBL.echodel) { if (p-acter count */ p = &(bufp->cbuf[0]); /* point to character buffer */ while (i--) /* calcRD(p->maxlen) ) { /* main loop for read console buffer */ if ( ((ch=getch()) == ctrlc) else if (ch == ctrlu) /* control-u */ { conout('#'); newline(stco * * CP/M-68K BDOS Miscellaneous Module * * ied 2/5/84 sw for ^C disk reset. * * Again 3/17/84 for chain hack * * * *************************************uf[UBWORD((p->retlen)++)] = ch ); } } DOS read-only file error routine * * setexc() - BDOS set exception vector * * set_tpa()l); p->retlen = 0; } else if (ch == ctrlr) /* control-r */ { * * This module contains miscellaneous loose ends for * * CP/M-68K. Included are: ***************************/ #include "bdosinc.h" /* Standard I/O declarations */ #include "bdosdef.h" uf[UBWORD((p->retlen)++)] = ch ); } }  - BDOS get/set TPA limits * * serial # and copyright notice, machine readable * * conout('#'); newline(stcol); for (i=0; i < UBWORD(p->retlen); i++) cookdout * * * * bdosinit() - BDOS initiali /* Type and structure declarations for BDOS */ #include "biosdef.h" /* BIOS definitions, needed for bios wboot * * * * Confi( p->cbuf[i] ); } else /* normal character */ cookdout( p->czation routine * * called from CCP for system init * * warmboot() - BDOS wa/**************************************************************** * */ /* serial # and copyright notice */ char *copyrt="CP/M-68K(tm), Version 1.2, Copyright (c) 1984, Digital Research"; gured for Alcyon C on the VAX * * * * Modifbuf[UBWORD((p->retlen)++)] = ch ); } } rm boot exit routine * * error() - BDOS error printing routine * * ro_err() - Bchar *serial="XXXX-0000-654321"; /* Declare external functions */ EXTERN conout(); /* Console Ou************************* * bdos initialization routine * ********************************/ bdosinit() /* Initialize thelower limit (temporary) */ EXTERN BYTE *tpa_lp; /* TPA lower limit (permanent) */ EXTERN BYTE *tpa_ht else log_dsk &= (1 << GBL.curdsk); /*sw Log off all but current drive, as */ /* per manual. (^C only) * /* Directory scanning routine */ EXTERN BOOLEAN set_attr(); /* Set File attributes function */ EXTER segp = bgetseg(); /* get pointer to memory segment table */ tpa_lt = tpa_lp = segp->low; tpa_ht = tpa_tput function */ EXTERN UBYTE conin(); /* Console Input function */ EXTERN prt_line(); File System */ { REG struct { WORD nmbr; BYTE *low; LONG length; } *segp; ; /* TPA upper limit (temporary) */ EXTERN BYTE *tpa_hp; /* TPA upper limit (permanent) */ / /* note that this code is specifically for a single- thread system. ItN UWORD dir_rd(); /* Read directory sector routine */ /* Declare external variables */ EXTERN UWORD loghp = tpa_lp + segp->length; initexc( &(GBL.excvec[0]) ); } /************************ * warmboot entry point * **** /* Print String function */ EXTERN UWORD _bdos(); /* BDOS main routine */ EXTER BSETUP bsetvec(trap2v, &traphndl); /* set up trap vector */ GBL.kbchar = 0; /* initialize the "globa EXTERN BOOLEAN submit; /* external variables from CCP */ EXTERN BOOLEAN morecmds; #define trap2v 34 won't work in a multi-task sys */ /*sw The above is still very much true */ ro_dsk = 0; crit_dsk = 0; if (pa_dsk; /* logged-on disk vector */ EXTERN UWORD ro_dsk; /* read-only disk vector ********************/ warmboot(parm) /* Warm Boot the system */ WORD parm; /* 1 to reset submit flag *N UBYTE *traphndl(); /* assembly language trap handler */ EXTERN initexc(); /* init the excl" variables */ GBL.insptr = GBL.remptr = &(GBL.t_buff[0]); GBL.delim = '$'; GBL.lstecho = FALSE; GBL.echod /* trap 2 vector number */ #define ctrlc 3 /* control-c */ /*******rm) submit = morecmds = FALSE; GBL.curdsk = 0xff; /* set current disk to "unknown" */ tpa_lt */ EXTERN UWORD crit_dsk; /* vector of critical disks */ EXTERN BYTE *tpa_lt; /* TPA / { BSETUP if(parm != 2) /*sw Not ^C */ log_dsk &= ~ro_dsk; /* log off any disk marked read-only */ eption handler in */ /* exceptn.s */ EXTERN UWORD dirscan(); el = TRUE; chainp = NULL; /*sw Used to be GBL.chainp */ _bdos(13); /* reset disk system function */ = tpa_lp; tpa_ht = tpa_hp; initexc( &(GBL.excvec[0]) ); bwboot(); } /*************************/ /* disk = 8; do conout(*++p & 0x7f); while (--i); conout('.'); i = 3; do conout(*++p & 0x7f); while (--i); prt_: warmboot(1); case 'C': if (cont) return(1); break; case 'R': return(0/ case 2: abrt_err("select$"); /* break; */ case 3: return( ext_err(FALSE,"select$") ) /* Boolean for whether continuing is allowed */ BYTE *p; /* pointer to error message */ { eset the directory buffer !!!! */ } while (TRUE); } /************************ * error entry point * *********error handlers */ /*************************/ prt_err(p) /* print the error message */ BYTE *p; { BSETUP line(" is read-only.$"); prt_line(warning); do { prt_line("\r\nDo you want to: Change it to read/write (C), or ); } } while (TRUE); } /********************************/ /* Read-only File Error Routine */ /**********; /* break; */ case 4: abrt_err("change$"); /* break; */ } } /***** REG UBYTE ch; prt_err(p); prt_line(warning); do { prt_line("\n\rDo you want to: Abort (A), Re***************/ error(errnum) /* Print error message, do appropriate response */ UWORD errnum; /* erro prt_line(p); prt_line(" error on drive $"); conout(GBL.curdsk + 'A'); } abrt_err(p) /* print the error messaAbort (A)? $"); ch = conin() & 0x5f; prt_line("\r\n$"); switch ( ch ) { case **********************/ ro_err(fcbp,dirindx) /* File R/O error */ REG struct fcb *fcbp; WORD dirindx; { ************************ * set exception entry point * *****************************/ setexc(epbp) /* Set Exception Vectotry (R)$"); if (cont) prt_line(", or Continue with bad data (C)$"); prt_line("? $"); ch = conin() & 0r number */ { BSETUP prt_line("\r\nCP/M Disk $"); switch (errnum) { case 0: return( ext_err(TRUge and always abort */ BYTE *p; { prt_err(p); warmboot(1); } char *warning = "\r\nWARNING -- Do not attempt tctrlc: warmboot(1); case 'A': warmboot(1); case 'C': fcbp->ftype[robit] &= 0x7f; REG BYTE *p; REG UWORD i; REG UBYTE ch; p = (BYTE *)fcbp; prt_line("CP/M Disk file error: $"); i r */ REG struct { WORD vecnum; BYTE *newvec; BYTE *oldvec; } *epbp; { REG WORD i; BSETUP ix5f; prt_line("\r\n$"); switch ( ch ) { case ctrlc: warmboot(1); case 'A'E,"read$") ); /* break; */ case 1: return( ext_err(TRUE,"write$") ); /* break; *o change disks$"; ext_err(cont,p) /* print the error message, and allow for retry, abort, or ignore */ REG BOOLEAN cont; dirscan(set_attr, fcbp, 2); return(dir_rd(dirindx >> 2)); } /* R = epbp->vecnum-2; if ( i==32 || i==33) return(-1); if ( (30 <= i) && (i <= 37) ) i -= 20; else if ( (i < 0) || ( call the BDOS to obtain the boundries * * of the TPA. The load parameter block * * a_lp = tpa_lt; tpa_hp = tpa_ht; } } else { p->low = tpa_lt; p->high = tpa * * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM * * =============================i > 9) ) return(255); epbp->oldvec = GBL.excvec[i]; GBL.excvec[i] = epbp->newvec; return(0); } /**************************************************************************** * defined in this loader holds all the * * memory size and location details. * * _ht; } } ===================== * * * * Description: ****************** * get/set TPA entry point * *****************************/ set_tpa(p) /* Get/Set TPA Limits */ REG * * COMMAND FILE LOADER FOR CPM68K * * ============================== Next the loader returns the system to * * its original user #. The CCP might * *ht; } }  * * ----------- The command file loader is envoked by * * tstruct { UWORD parms; BYTE *low; BYTE *high; } *p; #define set 1 #define sticky 2 { if (p->par * * * * (c) COPYRIGHT Digital Research 1983 have switched to user zero during its * * search for the file. Next the defaultht; } } he CCP after the CCP has successfully * * opened that file. The loader must * * ms & set) { tpa_lt = p->low; tpa_ht = p->high; if (p->parms & sticky) { tp * * all rights reserved * * * * dma address is set for the loaded * * program. Next the command tail ------- * .text move.l #TPAB,d1 * move in address of tpa parameter block move.w #gettpa, .globl _cmdfcb * parsed fcb .globl _tail * global pointer to command tail .globl _fill_ #$80,d1 * d1 points to default dma in base page movea.l d1,a1 * save it for later use mov * * Created by: Tom Saulpaugh * * err * if not print error message and return * * return to original user # * ------------------------- is * * placed,along with the first two parsed * * fcb's,into the user basepad0 * get function number trap #2 * get the tpa limits move.l low,lowadr * put it ifcb * procedure to fill fcb's .globl flags * ROM SYSTEM INITIALIZATION .globl TPAB e #setdma,d0 * move in bdos function no trap #2 * set the default dma address * * move * * Last Modified: 2/17/84 sw 68010 support * * move.w _user,d1 * put user # to switch to in d1 move.l #chuser,d0 * put bdos func # in d0 ge. * * Lastly the user stack pointer is set up * * and the return addren the lpb move.l high,hiadr * put high tpa addr in lpb move.l #_cmdfcb,LPB * get address of opened f * ROM SYSTEM INITIALIZATION .globl gouser *sw 68000/68010 rte routine reboot = 0 printstr = 9 setdma = 26 chusin the command tail * ------------------------ move.l a1,a2 * save a pointer to the count field * ***************************************************************** trap #2 * do the user # change * * set the default dma address * --------------------------- ss is put on the * * user stack. An RTE transferes control. * * If a load was cb move.l #pgmldf,d0 * move in bdos function no move.l #LPB,d1 * d1 points to load block er = 32 pgmldf = 59 gettpa = 63 _load68k: * * Load the 68k file into the TPA * ----------------------- add.l #$01,a1 * point past count field move.l _tail,a0 * point to command tail clr.l d.globl _load68k * make this procedure public .globl _user * global user # before load occured clr.l d1 * clear d1 register move.l baspag,d1 * d1 points to user base page add not successfull, the * * appropriate error message is printed. * * trap #2 * do the program load tst d0 * was the load successful? bne ld0 * clear out d0 mvtail: cmpi.b #$00,(a0) * check for a NULL ending byte beq done * move.l baspag,a1 * get basepage address *sw move.l 8(a1),-(sp) * push address we want to jump to *sw ck move.w #2,-(sp) * put 2 on stack(parm2) jsr _fill_fcb * jump to 'C' code & fill cmdfcb wive a byte into the basepage dbf d0,mov1 * if not done branch to mov1 rts move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack move.w #1,-(sp) * put 1 on stack(parm1) rror * ---------- lderr: rts * return with error code in d0 cmdrtn: move #rebo NULL byte terminates command cmpi.b #$21,(a0) * check for an '!' beq done * '!' ends th move sr,d0 * get the status register in d0 *sw andi #$5f00,d0 * mask trace,system bits,user flags th parm2 add.l #6,sp * clean off the stack clr.l d0 * clear register d0 mo.bss .even * * LOAD PARAMETER BLOCK * LPB: .ds.l 1 lowadr: .ds.l 1 hiadr: .ds.l 1 baspag: .ds.l jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm1 add.l #6,sp * clean off the stot,d0 * reboot CPM trap #2 movfcb: add.l baspag,d0 * get offset into basepage move.e command move.b (a0)+,(a1)+ * move a byte of the command tail addq #1,d0 * bump up the char*sw move.w d0,-(sp) * push it on stack move.l a1,-(a0) * push addr of basepage onto user stack veq #$38,d0 * put basepage address of fcb1 in d0 bsr movfcb * put fcb2 in the basepage * * 1 usrstk: .ds.l 1 flags: .ds.w 1 * * TPA Parameter Block * .even TPAB: .ds.w 1 low: .ds.l 1 ack clr.l d0 * clear register d0 moveq #$5c,d0 * put basepage address of fcb1 in d0 l d0,a0 * move address into a0 move.l #_cmdfcb,a1 * a1 points to fcb to be moved clr.l d0 acter count bra mvtail * continue byte move done: move.b d0,(a2) * put in the character count move.l #cmdrtn,-(a0) * push return address onto user stack move.l a0,usp * set up user stack pointer now push rte stuff on stack * --------------------------- movea.l usrstk,a0 * get user stack pointer high: .ds.l 1 .end  bsr movfcb * put fcb1 in the basepage move.l #_cmdfcb,-(sp) * put address of fcb buffer onto sta * clear register d0 moveq #35,d0 * get length of fcb mov1: move.b (a1)+,(a0)+ * mo move.b #$00,(a1) * terminate cmd tail with a NULL byte * * fill fcb1 & fcb2 * ---------------- move.l 8(a1),a0 *sw a0 -> User program epa jmp gouser *sw Jump to exit routine in exceptn.s *sw rte * * load ehigh: .ds.l 1 .end proc.o lnkmess.o 0$2clib era *.o $2as68 -s 0$1 -f $1 -l -u loadr.s $2as68 -s 0$1 -f $1 -l -u ovhdlr.s user 4!make $1 $.s era $1x.1 era $1x.2 $2as68 -s 0$1 -f $1 -l -u link68.s era link68.s $2cp68 -i 0$1 lnkmess.c $1x.i $2c068 $1x.i $1x.1 .globl _bios2 .globl _bios3 .globl _bios4 .globl _bios5 .globl _bios6 . * * * * Copyright (c) 1982 Digital Research, Inc.high: .ds.l 1 .end 2 $1x.2 $1x.3 era $1x.i $2c168 $1x.1 $1x.2 lnkmess.s era $1x.1 era $1x.2 $2as68 -s 0$1 -f $1 -l -u lnkmess.s era lnkmess.s globl _traphnd * trap #2 handler .globl _swap * byte swapper .globl _udiv * unsi * * * * Version 0.2 -- September 22, 1982   $2cp68 -i 0$1 preproc.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 era $1x.i $2c168 $1x.1 $1x.2 preproc.s era $1x.1 era $1x.2 gned divide routine * Declare external routines .globl __bdos * BDOS entry point in bdosmain * The foll * * * ****************************************************************************************************** * $2as68 -s 0$1 -f $1 -l -u preproc.s era preproc.s $2lo68 -s -u_nofloat -u_nowildc -r -o link68.rel -f $1 0$1s.o link68.o preowing external references were put in just to make sure that all * the BDOS modules were referenced, so we could put them$2pip machine.h=machine.68k $2cp68 -i 0$1 link68.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 era $1x.i $2c168 $1x.1 $1x.2 link68**************************** * Declare Public Routines .globl _bios1 * 6 BIOS entry points from BDOS * * CP/M-68K Basic Disk Operating System interface module * * For "C" version of CP/M-68K in a library .globl _constat * references conbdos.o .globl _dirscan * references dskutil.o long word move.l 8(sp),d2 * get 2nd parameter (long word) bra _bios2 * join common routi move.w (a0)+,d0 movem.l (a0)+,d1-d2 trap #3 bra bdone * * Set supervisor mode pr bytes of a word, return swapped value in d0 move.b 5(sp),d0 lsl #8,d0 movD1.W * address parameters are passed in D1.L * move.l d1,-(a7) move.w d1,-(a7) move.w d0,-mber move.w 6(sp),d1 * get 1st parameter (word) _bios6: _bios1: * For all BIOS functions that have no para .globl _create * references fileio.o .globl _bdosrw * references bdosrw.o biosf =ne _bios4: * For BIOS function seldsk * Has function number followed by 2 word parameters move.w 8(sp),d2 ocedure * setsup: ori #$2000,(sp) * turn on supervisor bit in SR rte * * BIOS Interface Routinese.b 4(sp),d0 rts _udiv: * Unsigned divide routine * returns unsigned quotient in D0.W * UWORD udiv( divisor,(a7) jsr __bdos * call BDOS * * now restore the regs * ext.l d0 addq meter other than function number move.w 4(sp),d0 * get function number movem.l d3-d7/a3-a6,-(sp) * 50 setsupf = 62 _traphnd: * * first save the registers and * check for functions handled by assembly* get 2nd parameter (word) bra _bios2 * join common routine _bios3: * For BIOS function set dma * Has * * * Note - there are 6 BIOS entry points from the BDOS, labelled BIOS1 - * BIOS6, depending on the parameters passed. dividend, remp ) * * REG LONG divisor; * UWORD dividend; * UWORD *remp /* pointer to remainder (re #8,sp * fix up the stack bdone: movem.l (sp)+,a0-a6/d1-d7 rte * save C register variables trap #3 * do BIOS call * language routines * cmpi #setsupf,d0 beq setsup movem.l d1-d7/a0-a6,-(sp) cmpi # function number followed by 1 long parameter move.l 6(sp),d1 * get long word parameter bra _bios1 _bios5: * For BIOS functions sectran and set exception vector * Has function number and 2 parameters, a word followed by aturned) */ move.l 4(sp), d0 * get dividend divu 8(sp), d0 * do the divide movea.l 1 * return from trap call * * direct BIOS call function * bioscall: move.l d1,a0 * get address of CPB * returns value in d0 movem.l (sp)+,d3-d7/a3-a6 rts * * Utility Subroutines * _swap: * Swapbiosf,d0 beq bioscall * * function number is passed in D0 * byte and word pararmeters are passed in * join common routine _bios2: * For all BIOS functions with a word parameter * Word parameter follows function nu0(sp),a0 swap d0 move.w d0, (a0) * store remainder clr.w d0 swap d0 r /* register variable */ #define LOCAL auto /* Local var on 68000 ************/ #define BYTE char /* Signed byte */ #define BOOLEAN char /* Function success return val */ #define YES 1 /* "TRUE" */ #define F I L E * ----------------------------------- * Copyright 1982 by Digital Research Inc. All rightsbyte to word cast */ #else #define UBYTE unsigned char /* Unsigned byte */ #define UBWORD(a) * word quotient in d0 rts .end  */ #define EXTERN extern /* External variable */ #define MLOCAL static /* 2 valued (true/false) */ #define WORD short /* Signed word (16 bits) */ #defNO 0 /* "FALSE" */ #define FOREVER for(;;) /* Infinite reserved. * * This is an include file for assisting the user to write portable * programs for C. * ***********(UWORD)a #endif /****************************************************************************/ /* Miscellaneous De * word quotient in d0 rts .end  /* Local to module */ #define GLOBAL /**/ /* Global variable */ #define VOIDine UWORD unsigned int /* unsigned word */ #define LONG long /* si loop declaration */ #define NULL (BYTE *)0 /* Null pointer value */ #define EOF (-1) ******************************************************************/ #define ALCYON 1 /* using Alfinitions: */ /*********************************************************************** * word quotient in d0 rts .end  /**/ /* Void function return */ /************gned long (32 bits) */ #define ULONG unsigned long /* Unsigned long */ #define REG registe /* EOF Value */ #define TRUE (1) /* Function TRUE value cyon compiler */ /* * Standard type definitions */ /********************/ #define FAILURE (-1) /* Function failure return val */ #define SUCCESS (0) /***************************************************************************** * * C P / M C H E A D E R***************/ #ifdef ALCYON #define UBYTE char #define UBWORD(a) ((UWORD)a & 0xff) /* Unsigned */ #define FALSE (0) /* Function FALSE value */ /*****************************************************************/ r (integer) and an * * information parameter (which is passed from bdosif as * * both an integer and a pointer */ /****************************************************************************/ #define abs(x) ((x) < 0 ? -(x) : /**************************************************************** * *****************************************/ /* */ /* ******************************/ ). * * The BDOS can potentially return a pointer, long word, * * or word (x)) /* Absolute value function */ #define max(x,y) (((x) > (y)) ? (x) : (y)) /* Max function */ * * CP/M-68K BDOS Main Routine * * M A C R O S */ /* ----------- ******************************/  * * * * Configured for Alcyon C on the VAX #define min(x,y) (((x) < (y)) ? (x) : (y)) /* Min function */ /*************************** end of stdio.h ** * * This is the main routine for the BDOS for CP/M-68K * * It has one entry point, _bdos, which is */ /* */ /* Define some * * * ***********************************************************************/ called from * * the assembly language trap handler found in bdosif.s. * * The parameters are a function numbestuff as macros .... */ /* ************************/ #include "bdosinc.h" /* Standard I/O declarations */ #include "bdosdef.h" EXTERN UWORD flushit(); /* Flush Buffers */ EXTERN UWORD pgmld(); /* Program Load ntial and Random disk read/write */ EXTERN BOOLEAN create(); /* Create file */ EXTERN BOOLEAN delete(he "state variables". These are globals for the single-thread version of the file system, but are put in a structure so th prt_line(); /* Print line until delimiter */ EXTERN readline(); /* Buffered console read */ EX* 16-bit vector of read-only drives */ GLOBAL UWORD crit_dsk; /* 16-bit vector of drives in "critical" /* Type and structure declarations for BDOS */ #include "biosdef.h" /* Declarations of BIOS functions */ /* De */ EXTERN UWORD setexc(); /* Set Exception Vector */ EXTERN set_tpa(); /* Get/Set TPA Limi); /* Delete file */ EXTERN BOOLEAN rename(); /* Rename file */ EXTERN BOOLEAN ey can be based, with a pointer coming from the calling process */ GLOBAL struct stvars gbls; struct teTERN seldsk(); /* Select disk */ EXTERN BOOLEAN openfile(); /* Open File state. Used to control dir checksums */ GLOBAL BYTE *tpa_lp; /* TPA lower boundary (permanent)clare EXTERN functions */ EXTERN warmboot(); /* Warm Boot function */ EXTERN BOOLEAN constat(); ts */ EXTERN move(); /* general purpose byte mover */ /* Declare "true" global variables; i. set_attr(); /* Set file attributes */ EXTERN getsize(); /* Get File Size */ EXTERN mpstr { UBYTE tempdisk; BOOLEAN reselect; struct fcb *fptr; }; /******************************** */ EXTERN UWORD close_fi(); /* Close File */ EXTERN UWORD search(); /* Search first and ne */ GLOBAL BYTE *tpa_lt; /* TPA lower boundary (temporary) */ GLOBAL BYTE *tpa_hp; /* TPA up /* Console status */ EXTERN UBYTE conin(); /* Console Input function */ EXTERN tabout(e., those which will pertain to the entire file system and thus will remain global even when this becomes a multi-task setran(); /* Set Random Record */ EXTERN free_sp(); /* Get Disk Free Space */ ******************************** * * * _bdos MAIN xt fcns */ EXTERN UWORD dirscan(); /* General directory scanning routine */ EXTERN UWORD bdosrw(); /* Sequeper boundary (permanent) */ GLOBAL BYTE *tpa_ht; /* TPA upper boundary (temporary) */ /* Declare t); /* Console output with tab expansion */ EXTERN UBYTE rawconio(); /* Raw console I/O */ EXTERN ing file system */ GLOBAL UWORD log_dsk; /* 16-bit vector of logged in drives */ GLOBAL UWORD ro_dsk; /ROUTINE * * * * Called with /* punch output to bios */ break; case 5: blstout((UBYTE)info); /* list output fwarmboot(0); /* warm boot function */ /* break; */ case 1: return((UWORD)coni break; case 14: seldsk((UBYTE)info); /* select disk */ GBL.dfltdsk = (UBYT * ****************************************************************/ UWORD _bdos(func,info,infop) REG WORD func; /* read buffered con input */ break; case 11: return((UWORD)constat()); /* console sta_bdos(func, info, infop) * * * * rom bios */ break; case 6: return((UWORD)rawconio(info)); /* raw console I/O */ n()); /* console input function */ /* break; */ case 2: tabout((UBYTE)info); /* cE)info; break; case 15: tmp_sel(&temp); /* open file */ info /* BDOS function number */ REG UWORD info; /* d1.w word parameter */ REG UBYTE *infop; /* d1.l pointer ptus */ /* break; */ case 12: return(VERSION); /* return version number */ Where: * * func is the BDOS function number (d0.w) * * /* break; */ case 7: return(bgetiob()); /* get i/o byte */ /* break; */ onsole output with */ break; /* tab expansion */ case 3: returnp->extent = 0; infop->s2 = 0; rtnval = dirscan(openfile, infop, 0); arameter */ { REG UWORD rtnval; LOCAL struct tempstr temp; BSETUP temp.reselect = FALSE; tem /* break; */ case 13: log_dsk = 0; /* reset disk system */ ro_dsk info is the word parameter (d1.w) * * infop is the pointer parameter (d1.l) case 8: bsetiob(info); /* set i/o byte function */ break; case 9: ((UWORD)brdr()); /* get reader from bios */ /* break; */ case 4: bpun((UBYTE)info); break; case 16: tmp_sel(&temp); /* close file */ rtnval = close_fi(infop); p.fptr = infop; rtnval = 0; switch (func) /* switch on function number */ { case 0: = 0; crit_dsk= 0; GBL.curdsk = 0xff; GBL.dfltdsk = 0; * * note that info is the word form of infop* * prt_line(infop); /* print line function */ break; case 10: readline(infop); break; case 17: GBL.srchp = infop; /* search first */ rtnval = seaess */ break; /* No function 27 -- Get Allocation Vector */ case 28: ro_dsk |= 1 rtnval = dirscan(create, infop, 8); break; case 23: tmp_sel(&temp); /* renamw(infop, FALSE, 1); break; case 35: tmp_sel(&temp); /* get file size */ TRUE, 0); break; case 21: tmp_sel(&temp); /* write sequential */ break; /* return disk parameters */ case 32: if ( (info & 0xff) <= 15 ) /* get/set user number */ rch(infop, 0, &temp); break; case 18: infop = GBL.srchp; /* search next */ <extent = 0; infop->s1 = 0; infop->s2 = 0; case 33: tmp_sel(&temp); /* random read */ rtnval = bdosrw(infop, TRUE, 1); ase 19: tmp_sel(&temp); /* delete file */ rtnval = dirscan(delete, infop, 2); */ rtnval = dirscan(set_attr, infop, 2); break; case 31: if (GBL.curdsk ; /* return current disk */ /* break; */ case 26: GBL.dmaadr = infop; /* set dma addrrive */ log_dsk &= info; ro_dsk &= info; crit_dsk &= info; infop->rcdcnt = 0; /* Zero extent, S1, S2, rcrdcnt. create zeros rest */ break; case 34: tmp_sel(&temp); /* random write */ rtnval = bdosr break; case 20: tmp_sel(&temp); /* read sequential */ rtnval = bdosrw(infop,!= GBL.dfltdsk) seldsk(GBL.dfltdsk); move( (GBL.parmp), infop, sizeof *(GBL.parmp) ); break; case 40: tmp_sel(&temp); /* write random with 0 fill */ rtmpdisk = fcbp->drvcode); seldsk( tmp_dsk ? tmp_dsk - 1 : GBL.dfltdsk ); fcbp->drvcode = GBL.user; temptr->reselode = temp.tempdisk; /* if reselected disk, restore it now */ return(rtnval); functions: * * * * bdosrw() - sequenmaadr)); /* program load */ /* break; */ case 61: return(setexc(infop)); /* set excepti /**************************************************************** * nval = bdosrw(infop, FALSE, 2); break; case 46: free_sp(info); /* get disk free ect = TRUE; }  /* return the BDOS return value */ } /* end _bdos */ tmp_sel(temptr) tial and random disk I/O * * * * on vector */ /* break; */ case 63: set_tpa(infop); /* get/set TPA limits */ * * CP/M-68K BDOS Disk Read/Write Module * * space */ break; case 47: chainp = GBL.dmaadr; /*sw chain to program */ ct = TRUE; }  /* temporarily select disk pointed to by fcb */ REG struct tempstr *temptr; { REG struct fcb *fcbp; REG U * * Compiled with Alcyon C on the VAX * * break; default: return(-1); /* bad function number */ /* br * * This module contains functions to perform sequential * * or random access read or write to the di warmboot(0); /* terminate calling program */ /* break; */ case 48: return( ct = TRUE; } BYTE tmp_dsk; BSETUP fcbp = temptr->fptr; /* get local copy of fcb pointer */ tmp_dsk = (temptr->te * ****************************************************************/ #include "bdosineak; */ }; /* end of switch statement */ if (temp.reselect) infop->drvcsk for CP/M-68K * * * * It includes the following externalflushit() ); /* flush buffers */ /* break; */ case 59: return(pgmld(infop,GBL.dc.h" /* Standard I/O declarations */ #include "bdosdef.h" /* Type and structure declarationsm(fcbp, index, wrdfcb) /* return block number in fcb indicated by index */ REG struct fcb *fcbp; /* pointer to fcb routines * ******************************/ WORD blkindx(fcbp) /* return index into fcb disk map */ REG structlock; /* block number */ UBYTE rcrd; /* record number */ REG WORD parm; /* write XTERN BOOLEAN create(); /* create file function passed to dirscan */ EXTERN UWORD ro_err(); /* read-only file e of fcb */ WORD wrdfcb; /* boolean, fcb disk map of words */ REG UWORD block; for BDOS */ /* External function definitions */ EXTERN UWORD rdwrt(); /* disk read/write routine * */ REG WORD index; /* index into disk map of fcb */ WORD wrdfcb; fcb *fcbp; /* pointer to fcb */ { REG struct dpb *dparmp; /* pointer to disk parameter */ { REG LONG lsec; REG struct dpb *dparmp; BSETUP dparmp = GBL.parmp; rror handler */ /* External variable definitions */ EXTERN UWORD ro_dsk; /* read-only disk vector /* block number */ { fcbp->s2 &= 0x7f; /* set file write flag */ / EXTERN WORD getaloc(); /* allocate a block of disk space */ EXTERN WORD swap(); /* assembly langu /* boolean, fcb disk map of words */ { if (wrdfcb) return( swap(fcbp->dskmap.big[index]) ); elsparameter block */ REG WORD i; REG WORD blkshf; BSETUP dparmp = GBL.parmp; blkshf = dparmp->bsh; /* init dpb pointer */ lsec = ((LONG)block << (dparmp->bsh)) + (LONG)(rcrd & (dparmp->blm)); ret */ /**********************************************************/ /* First, some utility functions used by seqio an if (wrdfcb) fcbp->dskmap.big[index] = swap(block); else fcbp->dskmap.small[index] = (UBYTE)block; } /******age byte swapper */ EXTERN UWORD dirscan(); /* directory scanning routine */ EXTERN BOOLEAN openfile(e return( UBWORD(fcbp->dskmap.small[index]) ); } setblk(fcbp, index, wrdfcb, block) /* put block number into fcb */ RE i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf); return (i + (UBWORD(fcbp->cur_rec) >> blkshf) ); } UWORD blknuurn( rdwrt(lsec, GBL.dmaadr, parm) ); } /******************************************* * routine for crossing extent boundd ranio */ /**********************************************************/ /****************************** * FCB block number********************* * disk read/write routine * ***************************/ UWORD do_io(block, rcrd, parm) UWORD b); /* open file function passed to dirscan */ EXTERN UWORD close_fi(); /* close file function */ EG struct fcb *fcbp; /* pointer to fcb */ REG WORD index; /* index into disk maparies * *******************************************/ WORD new_ext(fcbp, reading, ran) /* If sequential I/O, open the nextclose old extent */ t_mod = fcbp->s2; t_ext = fcbp->extent; fcbp->s2 = mod; fcbp->extent = ext; if ( di >= 64) return(6); /* past maximum file size */ if ( mod == ((fcbp->s2) & 0x3f) ) if ( ! ((ext ^ (fcbp->) & 0x1f | i ); } /********************************* * Routine to get the actual * * record count of the currently ran) { mod = ( (fcbp->ran0) << 4) | ( (fcbp->ran1) >> 4); ext = ( ((fcbp->ran1) & 0x0f) << 1); i a * * extent-folded environment * ************************************/ UWORD calcext(fcbp) REG struct fcb extent */ /* If random I/O, compute new extent from random record field */ REG struct fcb *fcbp; rscan(openfile, fcbp, 0) >= 255 ) /* open extent */ { if (reading) { /* rextent)) & ~((GBL.parmp)->exm) & 0x1f) ) { /* we're in same logical extent */ * * active logical extent of a FCB * *********************************/ UWORD get_rc(fcbp) REG struct fcb *fcbp; { f ((fcbp->ran2) & 0x80) ext |= 1; /* the calculation of ext was coded this way because of a */ *fcbp; { REG UWORD i; REG BYTE *p; BSETUP i = 15; p = &(fcbp->dskmap.small[16]); do { /* pointer to fcb */ BOOLEAN reading; /* read/write flag */ WORD ran; /* random I/eading unwritten extent */ fcbp->s2 = t_mod; fcbp->extent = t_ext; return(4); } fcbp->extent = ext; return(0); } /* Extent or Module numbers don't match */ /* Close the o REG UWORD ext; ext = calcext(fcbp); /* find last active extent in fcb */ if (ext == fcbp->extent) return( /* compiler bug from Alcyon */ } else { mod = (fcbp->s2) & 0x3f; ext = (fcbp->extent) + 1; if (*--p) break; i -= 1; } while (i); /* Now i contains the index of the last non-zero block in the FCB *O flag */ { REG UBYTE mod; /* module number */ REG UBYTE ext; /* extent number */ if ( dirscan(create, fcbp, 8) >= 255 ) return(5); /* can't create new extent */ } ld extent and open a one */ if ( close_fi(fcbp) >= 255 ) return(3); /* can't UBWORD(fcbp->rcdcnt)); /* if this is the last active fcb, return fcb's rc */ else if (ext > fcbp-> /* for sequential, incr extent */ } if (ext >= 32) { ext = 0; mod += 1; } if (mod/ if ((GBL.parmp)->dsm > 255) i >>= 1; i >>= 7 - ((GBL.parmp)->bsh); return ( (fcbp->extent) & ~((GBL.parmp)->exmREG UBYTE t_mod; /* temp mod number */ REG UBYTE t_ext; /* temp extent */ BSETUP if ( return(0); } /************************************ * Routine to calculate the maximum * * extent number of an FCB inextent) return(128); /* if the fcb has more extents past this one, then */ /* if (fcbp->cur_rec == 128) { /* time to try next extent */ if ( new_ext(fcbp, r rcdcnt */ BSETUP bigfile = ((GBL.parmp)->dsm) & ~0xff; if ( ( ! reading) && (fcbp->ftype[robit] & 0x80) */ block = getaloc(blknum(fcbp, (index ? (index - 1) : 0), bigfile)); if (block == ~0) return(2); /* 2 = random with zero fill */ { REG UWORD block; /* block number from fcb */ RE* get index into fcb disk map */ block = blknum(fcbp, index, bigfile); if (block) parm = (reading ? 0 : 1); else the current one is logically full */ else return (0); /* if we seeked past the last active extereading, FALSE) ) return(1); /* if can't open new extent, error */ fcbp->cur_rec = 0; /* ope) ro_err(fcbp,((GBL.dpbp)->dpbp)->drm); /* check for read-only file */ i /* out of space */ setblk(fcbp, index, bigfile, block); parm = 3; if (random == 2) { G WORD index; /* index into disk map of fcb */ REG BYTE *old_dma; /* temp holding spot for dmaadr */ /* if allocated block, parm is just read or write */ { /* unallocated blocnt, rc = 0 */ } /************************ * bdosrw entry point * ************************/ UWORD bdosrw(fcbp, readned new extent, zero cur_rec */ } /* record is now in active fcb */ rc = fcbp->rcdcnt; if ( UBWORD(fcbf (random) { if ( rtn = new_ext(fcbp, reading, TRUE) ) return(rtn); /* open new extent if /* Write random with zero fill */ old_dma = GBL.dmaadr; GBL.dmaadr = GBL.di REG WORD parm; /* parameter to do-io */ REG WORD bigfile; /* file system is in word k */ if (reading) return(1); /* reading unwritten data */ /* Writing to new block */ /* ing, random) REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */ REG BOOLEAN reading; /* boolean to p->cur_rec) >= get_rc(fcbp) ) { if (reading) return(1); /* reading unwritten data */ fcbp->s2 &= necessary, return if error */ fcbp->cur_rec = (fcbp->ran2) & 0x7f; } else /* sequential */ rbufp; /* Do DMA from dir_buf */ index = SECLEN; do GBL.dmaadr[--index] = 0; while mode */ REG UWORD rtn; /* return parameter */ REG UBYTE rc; /* temp storage foThe parm passed to getaloc is the previously allocated block */ /* or 0, if the previous block is not allocated tell whether to read or write */ WORD random; /* 0 = sequential, 1 = random (normal), */ 0x7f; /* set file write flag */ rc = fcbp->cur_rec + 1; } index = blkindx(fcbp); /(index); /* zero the dma buffer */ for (index = 0; index <= ((GBL.parmp)->blm); index++) { ply defines the BIOS calls * * * *************************************** brdr() bios1(7) /* reader input */ #define bhome() bios1(8) /* recalibrate drive */ bp->rcdcnt = rc; if ( ! random ) fcbp->cur_rec += 1; } return(rtn); } ception */ EXTERN BYTE *bios6(); /* for get memory segment table */ #define bwboot() bios1(1) do_io(block, (UBYTE)index, parm); /* write zeros to the block */ *****************/ EXTERN UBYTE bios1(); /* used for character I/O functions */ EXTERN bios2(); /* /******************************************************** * * * B #define bseldsk(parm1,parm2) bios4(9,parm1,parm2) /* select disk and return info */ #bp->rcdcnt = rc; if ( ! random ) fcbp->cur_rec += 1; } return(rtn); }  /* warm boot */ #define bconstat() bios1(2) /* console status */ #define bconin() parm = 1; /* next write is not to new block */ } GBL.dmaadr = old_dma; / parm1 is word, no return value */ EXTERN bios3(); /* used for set dma only */ IOS definitions for CP/M-68K * * * * Copyright (define bsettrk(parm) bios2(10,parm) /* set track on disk */ #define bsetsec(parm) bios2(11,parm) /* set sector for disbp->rcdcnt = rc; if ( ! random ) fcbp->cur_rec += 1; } return(rtn); }  bios1(3) /* console input */ #define bconout(parm) bios2(4,parm) /* console output parm */ #define blstout* restore dma address */ } } rtn = do_io(block, fcbp->cur_rec, parm); if ( rtn == 0 ) { f /* parm1 is a pointer, no return */ EXTERN UBYTE *bios4(); /* seldsk only, parm1 and parm2 are */ c) 1982 Digital Research, Inc. * * * * This include file simk */ #define bsetdma(parm) bios3(12,parm) /* set dma address */ #define bread() bios1(13) /* read secto(parm) bios2(5,parm) /* list device output */ #define bpun(parm) bios2(6,parm) /* punch char output */ #definecbp->rcdcnt = rc; if ( ! random ) fcbp->cur_rec += 1; } return(rtn); }  /* words, returns a pointer to dph */ EXTERN UWORD bios5(); /* for sectran and set exr from disk */ #define bwrite(parm) bios2(14,parm) /* write sector to disk */ #define blistst() bios1(15) /* liented | | interface for the console user to the | | information maintained by the BDOS on | | disk storage. * set exception vector */  *==================================================* | | *==================================================* | | *ist device status */ #define bsectrn(parm1,parm2) bios5(16,parm1,parm2) /* sector tr | | | | created by : Tom Saulpaugh Date created: 7/13/82 | | ---------- ------------ | | last modif set exception vector */ THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM* | | *==================================================* | | *==anslate */ #define bgetseg() bios6(18) /* get memory segment tbl */ #define bgetiob() bios1(19) /ied: 03/17/84 sw St. Patrick's Day!!! | | ------------- Chain hack -------------------- | | | | (c) COPY set exception vector */ ================================================* | | | | Description: | | ----------- | | * get I/O byte */ #define bsetiob(parm) bios2(20,parm) /* set I/O byte */ #define bflush() bios1(21)/*--------------------------------------------------------------*\ | ccp.c CONSOLE COMMAND PROCESSOR v1.1 | RIGHT Digital Research 1983, 1984 | | all rights reserved | | | \*------------------------------- set exception vector */  The Console Command Processor is a | | distinct program which references | | the BDOS to provide a human-or /* flush buffers */ #define bsetvec(parm1,parm2) bios5(22,parm1,parm2) / | ========================= | | | | CP/M 68k: A CP/M derived operating system | | | | -------------------------------*/ /*--------------------------------------------------------------*\ | CCP Macro D BYTE msg12[] = "User # range is [0-15]$"; BYTE msg13[] = "Too many arguments: $"; BYTE lderr1[] = "Insufficient memory oPrompts and Messages | \*--------------------------------------------------------------*/ BYTE msg[] = "NON-SYSTEM FILE(S) Ent default disk drive */ BYTE subcom[CMD_LEN+1]; /* submit command buffer */ BYTE subdma[CMD_LEN]; /* buffer to fill from ,DIRSCMD, "TYPE",TYPECMD, "REN",RENCMD, "ERA",ERACMD, "USER",UCMD, "SUBMIT",SUBCMD, NULL,-1 }; chaining flag */ extern BYTE submit; /* submit file flag */ BYTE end_of_file; /* submit end of file flag */ BYTE dirflagefinitions | \*--------------------------------------------------------------*/ #include "ccpdef.h" /* include CCP definesr bad file header$"; BYTE lderr2[] = "Read error on program load$"; BYTE lderr3[] = "Bad relocation information bits$"; BYTXIST$"; BYTE msg2[] = "Enter Filename: $"; BYTE msg3[] = "Enter Old Name: $"; BYTE msg4[] = "Enter New Name: $"; BYTE msg5[]sub file */ extern BYTE usercmd[CMD_LEN+2]; /* user command buffer */ BYTE *user_ptr; /* next user command to execute */ B/*--------------------------------------------------------------*\ | CP/M-68K COMMAND FILE LOADER TABLE | \*---------------; /* used by fill_fcb(? or blanks)*/ BYTE subprompt; /* submit file was prompted for */ extern BYTE morecmds; /* command */ /*--------------------------------------------------------------*\ | CP/M Builtin Command Table | \*------E lderror[] = "Program load error$"; /*--------------------------------------------------------------*\ | Global Arrays = "File already exists$"; BYTE msg6[] = "No file$"; BYTE msg7[] = "No wildcard filenames$"; BYTE msg8[] = "Syntax: REN NewfiYTE *glb_index; /* points to current command */ BYTE save_sub[CMD_LEN+1]; /* saves cur cmd line for submit*/ BYTE subfcb[FCB_-----------------------------------------------*/ extern struct _filetyps { BYTE *typ; UWORD (*loader) (); BYTE user_c; after warmboot flag */ UWORD sub_index; /* index for subdma buffer */ UWORD index; /* index into cmd argument array*/ UW--------------------------------------------------------*/ struct _cmd_tbl { BYTE *ident; /* command identifer field */ U& Variables | \*--------------------------------------------------------------*/ /********************************/ Ble=Oldfile$"; BYTE msg9[] = "Confirm(Y/N)? $"; BYTE msg10[] = "Enter User No: $"; BYTE msg11[] = ".SUB file not found$"; LEN]; /* global fcb for sub files */ BYTE cmdfcb[FCB_LEN]; /* global fcb for 68k files */ BYTE *tail; /* pointer to comman BYTE user_0; } load_tbl[]; /*--------------------------------------------------------------*\ | Table of User ORD sub_user; /* submit file user number */ UWORD user; /* current default user number */ UWORD cur_disk; /* curreWORD cmd_code; /* command code field */ } cmd_tbl[8] = /* declare CP/M built-in table */ { "DIR",DIRCMD, "DIRS"YTE load_try; /* flag to mark a load try */ BYTE first_sub; /* flag to save current cmd ptr */ BYTE chain_sub; /* submitd tail */ extern BYTE autost; /* autostart flag */ BYTE autorom; /* needed for ROM system autost */ BYTE dma[DMA_LENCONSOLE_OUTPUT,CR); bdos(CONSOLE_OUTPUT,LF); } /********************************/ VOID cpy(source,dest) /* copy sourcWORD chk_colon(); /* this returns a word */ UWORD user_cmd(); /* this returns a word */ UWORD cmd_file(); /* this returns NULL; } /********************************/ VOID prompt() /* print the CCP prompt */ /*********************/ extern UWORD bdos(); /* this returns a word */ extern UWORD load68k(); /* this returns a word(1-3) */ e command which */ /* started a submit file */ /* Parameter substituion will */ /* need this command ta+3]; /* 128 byte dma buffer */ BYTE parm[MAX_ARGS][ARG_LEN]; /* cmd argument array */ BYTE *chainp; /*sw -> User-specifiee to destination */ /********************************/ REG BYTE *source; REG BYTE *dest; { while(*dest++ = *source++) a word */ UWORD sub_read(); /* this returns a word */ UWORD dollar(); /* this returns a word */ UWORD comments(); /* *********************/ { REG UWORD cur_drive,cur_user_no; BYTE buffer[3]; cur_user_no = bdos(GET_USER_NO,(long)255BYTE *scan_cmd(); /* this returns a ptr to a byte */ UWORD strcmp(); /* this returns a word */ UWORD decode(); /* this ril. */ /* The buffer save_sub is used */ /* to store the command. */ /********************************/ REG Bd command */ BYTE del[] = /* CP/M-68K set of delimeters */ {'>','<','.',',','=','[',']',';','|','&','/','(',')','+','-',; } /********************************/ UWORD strcmp(s1,s2) /* compare 2 char strings */ /*****************this returns a word */ UWORD submit_cmd(); /* this returns a word */ /********************************/ /******); cur_drive = bdos(RET_CUR_DISK,(long)0); cur_drive += 'A'; cr_lf(); if(cur_user_no) { if(cur_user_no >= 10) eturns a word */ UWORD delim(); /* this returns a word */ BYTE true_char(); /* this returns a byte */ UWORD fill_fcb();YTE *com_index; { REG BYTE *t1,*temp; temp = save_sub; if(subprompt) { t1 = parm; while(*t1) *temp++ = *t1+'\\'}; /********************************/ /*--------------------------------------------------------------*\ | ***************/ REG BYTE *s1,*s2; { while(*s1) { if(*s1 > *s2) return(1); if(*s1 < *s2) return(-1); s1**************************/ VOID cr_lf() /* print a CR and a Linefeed */ /********************************/ { bdos( { buffer[0] = '1'; buffer[1] = ((cur_user_no-10) + '0'); buffer[2] = '$'; } else { buffer[0] = (cur_us /* this returns a word */ UWORD too_many(); /* this returns a word */ UWORD find_colon(); /* this returns a word */ U+; *temp++ = ' '; subprompt = FALSE; } while(*com_index && *com_index != EXLIMPT) *temp++ = *com_index++; *temp = Function Definitions | \*--------------------------------------------------------------*/ /**********************++; s2++; } return((*s2 == NULL) ? 0 : -1); } /********************************/ VOID copy_cmd(com_index) /* Save ther_no + '0'); buffer[1] = '$'; } bdos(PRINT_STRING,buffer); } bdos(CONSOLE_OUTPUT,(long)cur_drive); bdos(CONSOLEDelimeter */ /*****************************************************/ if(fill_fcb(0,cmdfcb) > 0) return(-1); if(iand */ /********************************************************/ i = 0; while(i < (ARG_LEN-1) && parm[0][i] != ':') i+ if(*user_ptr) morecmds = TRUE; } } else morecmds = FALSE; } /************************/ VOcognize the command as: */ /* --------- */ /* 1. Builtin */ /* 2. File */ /***************************a warmboot */ /*----------------------------*/ if(*tcmd++ == EXLIMPT && *tcmd) { morecmds = TRUE; while(*tcmd ==_OUTPUT,ARROW); } /********************************/ VOID echo_cmd(cmd,mode) /* echo any multiple commands */ == 1) i = 2; else i = 0; if(delim(&parm[0][i])) return(-1); for(n = 0;n < ARG_LEN-1 && parm[0][n];n++) if(par+; if(i == 1 && parm[0][2] == NULL && parm[1][0] == NULL) if((parm[0][0] >= 'A') && (parm[0][0] <= 'P')) return(CH_DIID get_cmd(cmd,max_chars) /* Read in a command */ /*Strip off extra blanks*/ /************************/ *****/ REG BYTE *cmd; { REG UWORD i,n; /****************************************/ /* Check for a CP/M builtin comman ' ') tcmd++; user_ptr = tcmd; } else if(submit) /* check original cmd line */ { if(!(end_of_file)) mo /* or any illegal commands */ /********************************/ REG BYTE *cmd; REG UWORD mode; { if(mode == GOOD &m[0][n] < ' ') return(-1); return(FILE); } /************************/ VOID check_cmd(tcmd) /* Check end of cSK); if(i == 1 && ((parm[0][0] < 'A') || (parm[0][0] > 'P'))) return(-1); if(i != 1 && parm[0][i] == ':') return(-1); REG BYTE *cmd; REG long max_chars; { REG BYTE *c; max_chars += (cmd - 1); dma[0] = CMD_LEN; /* set maximum chars tod */ /****************************************/ for(i = 0; i < 7;i++) if (strcmp(cmd,cmd_tbl[i].ident) == MATCH) returecmds = TRUE; /*--------------------------*/ else /* restore cmd to where user*/ /* ptr points to. User_ptr */ & (!(autost && autorom))) prompt(); while(*cmd && *cmd != EXLIMPT) bdos(CONSOLE_OUTPUT,(long)*cmd++); if(mode == BAD) md */ /* for an '!' which */ /* starts another cmd */ REG BYTE *tcmd; /************************/ { whil /*****************************************************/ /* Check for Wildcard Filenames */ /* Check Filename for a read */ bdos(READ_CONS_BUF,dma); /* then read console */ if(dma[1] != 0 && dma[2] != ';') cr_lf(); dma[((UWORD)dma[rn(cmd_tbl[i].cmd_code); /********************************************************/ /* Check for a change of disk drive comm /* always points to next */ /* console command to exec */ { /*--------------------------*/ submit = FALSE; bdos(CONSOLE_OUTPUT,(long)'?'); else cr_lf(); } /********************************/ UWORD decode(cmd) /* Ree(*tcmd && *tcmd != EXLIMPT) tcmd++; /*----------------------------*/ /* check for multiple command */ /* in case of 1] & 0xFF)+2] = '\n'; /* tack on end of line char */ if(dma[2] == ';') /* ';' denotes a comment */ dma[2] = '\n'; c***************/ /* separate command line at blanks,exlimation pts */ /***************************************************// /* parmeters associated with the command are put*/ /* in in sequential order in parm[1],parm[2], */ /* and parm[3]. A return(*ch); } return(' '); /* pad field with blank */ } /************************/ UWORD fill_fcb(which_parmcom_index++; while(*com_index == EXLIMPT || *com_index == ' ' || *com_index == TAB) com_index++; return(com_indexa delimeter */ /************************/ REG BYTE *ch; { REG UWORD i; if(*ch <= ' ') return(TRUE); for(i = = &dma[2]; while(*c == ' ' || *c == TAB) c++; while(*c != '\n' && cmd < max_chars) { *cmd++ = toupper(*c); if while(*cmd != NULL && *cmd != EXLIMPT && i < MAX_ARGS) { j = 0; while(*cmd != EXLIMPT && command ends at a NULL or */ /* an exlimation point. */ /************************************************/ REG B,fcb) /* fill the fields of */ /* the file control blk */ /************************/ REG UWORD which_parm; REG ); } /************************/ VOID get_parms(cmd) /* extract cmd arguments*/ /* from command line */ REG0;i < sizeof (del);i++) if(*ch == del[i]) return(TRUE); return(FALSE); } /************************/ BYTE true(*c == ' ' || *c == TAB) while(*++c == ' ' || *c == TAB); else c++; } *cmd = NULL; /* tack a null character *cmd != ' ' && *cmd != TAB && *cmd) { if(j < (ARG_LEN-1)) parm[i][j++] = *cmd; YTE *line; /* pointer to parm array */ REG UWORD i; /* Row Index */ REG UWORD j; /* Column Index */ BYTE *fcb; { REG BYTE *ptr; REG BYTE fillch; REG UWORD j,k; *fcb = 0; for(k = 12;k <= 35; k++) /* fill fc BYTE *cmd; /************************/ { /************************************************/ /* This function parse_char(ch) /* return the desired */ /* character for fcb */ /************************/ REG BYTE *ch; { if(*chon the end*/ } /************************/ BYTE *scan_cmd(com_index) /* move ptr to next cmd */ /* in the command cmd++; } parm[i++][j] = NULL; if(*cmd == ' ' || *cmd == TAB) cmd++; if(i == 1) tail = cmd; /* mark the be line = parm; for(i = 0; i < (MAX_ARGS * ARG_LEN); i++) *line++ = NULL; i = 0; /************************************b with zero */ fcb[k] = ZERO; for(k = 1;k <= 11;k++) fcb[k] = BLANK; /* blank filename+type */ /******************s the command line */ /* read in by get_cmd(). The expected command */ /* from that line is put into parm[0]. All * == '*') return('?'); /* wildcard */ if(!delim(ch)) /* ascii character */ { index++; /* increment cmd index */ line */ /************************/ REG BYTE *com_index; { while((*com_index != EXLIMPT) && (*com_index)) ginning of the tail */ } } /************************/ UWORD delim(ch) /* check ch to see */ /* if it's *************************/ /* extract drivecode,filename and filetype */ /* from parmeter blk */ /*******************colon */ { /************************/ REG UWORD i; i = 0; while(parm[1][i] && parm[1][i] != ':') i++; return(i); 3;j++) /* get extension */ *ptr++ = true_char(&parm[which_parm][index]); } k = 0; for(j = 1;j <= 11;j++) if(fcbnt = 0; while(dir_index != 255) { if(((attrib) && (dma[save+9] & 0x80)) || (!(attrib) && (!(dma[save+9] & 0x 1;j <= 11;j++) *ptr++ = fillch; if(dirflag) return(11); else return(0); } } else /* fill d/ /* attrib->1 (sysfiles) */ /* attrib->0 (dirfiles) */ /************************/ REG UWORD attrib; { BYT************************/ if(dirflag) fillch = '?'; else fillch = ' '; index = ZERO; ptr = fcb; if(parm[whic } /************************/ UWORD chk_colon(j) /* check the position of*/ UWORD j; /* the colon and for */ {[j] == '?') k++; return(k); /* return the number of question marks */ } /************************/ UWORD too_many() 80)))) { if(needcr_lf) { cr_lf(); needcr_lf = FALSE; } if(file_cnt == 0) bdos(CONSOLE_Orivecode with the default disk */ *fcb = (bdos(RET_CUR_DISK,(long)0) + 1); ptr = fcb; ptr++; /* set poiE needcr_lf; REG UWORD dir_index,file_cnt; REG UWORD save,j,k,curdrive,exist; exist = FALSE; needcr_lf = FALSE; if(th_parm][index] == NULL) /* no parmemters */ { ptr++; for(j = 1;j <= 11;j++) *ptr++ = fillch; *fcb = (bdos(RET_C /* a legal drive letter */ if(parm[1][j] == ':') /************************/ { if(j != 1 || parm[1][0] < 'A' || parm /* too many args ? */ { /************************/ if(parm[2][0]) { bdos(PRINT_STRING,msg13); echo_cmd(&paUTPUT,(long)curdrive); } else { exist = TRUE; dir_index = bdos(SEARCH_NEXT); save = (32 * dir_indnter to fcb filename */ for(j = 1;j <= 8;j++) /* get filename */ *ptr++ = true_char(&parm[which_parm][index]); while((!(oo_many()) return; j = find_colon(); if(!chk_colon(j)) return; fill_fcb(1,cmdfcb); curdrive = (cmdfcb[0] + 'A' - 1); dUR_DISK,(long)0)+1); if(dirflag) return(11); else return(0); } if(parm[which_parm][index+1] == ':') { *pt[1][0] > 'P') { echo_cmd(&parm[1][0],BAD); return(FALSE); } } return(TRUE); } /***************rm[2][0],BAD); return(TRUE); } return(FALSE); } /************************/ UWORD find_colon() /* search for a ex) + 1; continue; } dir_index = (32 * dir_index) + 1; bdos(CONSOLE_OUTPUT,COLON); bdos(CONSOLE_OUTPUT,BLANKS)delim(&parm[which_parm][index])))) index++; if(parm[which_parm][index] == PERIOD) { index++; for(j = 1;j <=ir_index = bdos(SEARCH_FIRST,cmdfcb); if(dir_index == 255) bdos(PRINT_STRING,msg6); save = (32 * dir_index) + 1; file_cr = parm[which_parm][index] - 'A' + 1; index += 2; if(parm[which_parm][index] == NULL) { ptr = &fcb[1]; for(j =*********/ VOID dir_cmd(attrib) /* print out a */ /* directory listing */ /*----------------------*; j = 1; while(j <= 11) { if(j == 9) bdos(CONSOLE_OUTPUT,BLANKS); bdos(CONSOLE_OUTPUT,(long)(dma[dir_index*/ VOID ren_cmd() /* rename a file */ /************************/ { BYTE new_fcb[FCB_LEN]; REG UWOR if(!chk_colon(i)) return; i = fill_fcb(1,cmdfcb); /*fill a file control block*/ if(i == 0 && parm[1][0] && (bdos(OPEN_FIL while(parm[j][k] != ':' && parm[j][k]) k++; if(k > 1 && parm[j][k] == ':') bad_cmd = TRUE; for(i = 0;i < sizeof e */ { /*----------------------------------------*/ cr_lf(); if(attrib) bdos(PRINT_STRING,msg); else bdos(------------*/ i = 0; while(parm[1][i] != '=' && parm[1][i]) i++; if(parm[1][i] == '=') { if(!(i > 0 && parm[1][++] & CMASK)); j++; } bdos(CONSOLE_OUTPUT,BLANKS); dir_index = bdos(SEARCH_NEXT); if(dir_index == 255) breakD i,j,k,bad_cmd; bad_cmd = FALSE; /*-------------------------*/ if(parm[1][0] == NULL) /*prompt user for fiE,cmdfcb) <= 3)) { while(bdos(READ_SEQ,cmdfcb) == 0) { for(i = 0;i <= 127;i++) if(dma[i] != EOF) bdos(del;i++) if(parm[j][0] == del[i]) { echo_cmd(&parm[j][0],BAD); return; } } if(!bad_cmd && parm[1][0] &PRINT_STRING,&msg[4]); } } /************************/ VOID type_cmd() /* type out a file */ /* i+1] && parm[2][0] == NULL)) bad_cmd = TRUE; } else if(!(parm[2][0] == '=' && parm[2][1] == NU; file_cnt++; save = (32 * dir_index) + 1; if(file_cnt == 5) { file_cnt = 0; if((attrib && (dma[save+9] & 0xlenames*/ { /*-------------------------*/ bdos(PRINT_STRING,msg3); get_cmd(&parm[3][0],(long)(ARG_LEN-1)); CONSOLE_OUTPUT,(long)dma[i]); else break; } bdos(RESET_DRIVE,(long)cmdfcb[0]); } else if(parm[1][0]) { & parm[3][0]) { i = fill_fcb(1,new_fcb); j = fill_fcb(3,cmdfcb); if(i == 0 && j == 0) { if(new_fcb[0] != cmdfc to the console */ /************************/ { REG UWORD i; if(parm[1][0] == NULL) /*prompt user for filename*/LL && parm[3][0])) bad_cmd = TRUE; if(!bad_cmd && parm[1][i] == '=') { parm[1][i] = NULL; i++; j80)) || (!(attrib) && (!(dma[save+9] & 0x80)))) cr_lf(); else needcr_lf = TRUE; } } /*------------ if(parm[3][0] == NULL) return; bdos(PRINT_STRING,msg4); get_cmd(&parm[1][0],(long)(ARG_LEN-1)); parm[2][0] = '=' if(i > 0) bdos(PRINT_STRING,msg7); else bdos(PRINT_STRING,msg6); } } /***********************b[0]) { if(parm[1][1] == ':' && parm[3][1] != ':') cmdfcb[0] = new_fcb[0]; else if(parm[1][1] != ':' && { bdos(PRINT_STRING,msg2); get_cmd(&parm[1][0],(long)(ARG_LEN-1)); } if(too_many()) return; i = find_colon(); = 0; while((parm[3][j++] = parm[1][i++]) != NULL); parm[2][0] = '='; } } for(j = 1;j < 4;j += 2) { k = 0; ----------------------------*/ if(exist) /* if files exist that were not displayed */ /* print out a message to the consol; } /*--------------------------------*/ else /*check for correct command syntax*/ { /*-------------------- parm[3][1] == ':') new_fcb[0] = cmdfcb[0]; else bad_cmd = TRUE; } if(new_fcb[0] < 1 || new_fcb[0] > 16)********/ { REG UWORD i; if(parm[1][0] == NULL) /* prompt for a number */ { bdos(PRINT_STRING,msg10); get_cmd( return; } i = fill_fcb(1,cmdfcb); /* fill an fcb */ if(i > 0 && !(submit)) /* no confirmation */ { /* if subm /* search the current */ /* user # then user 0 */ /* */ /************************/ UWORD mode; { BYerase a file from */ /* the directory */ /************************/ { REG UWORD i; /*-------======== */ /* */ /* 1. 68K type on the */ /* current user # */ /* 2. BLANK type on */ bad_cmd = TRUE; if(!(bad_cmd) && bdos(SEARCH_FIRST,new_fcb) != 255) bdos(PRINT_STRING,msg5); else{ k = 0&parm[1][0],(long)(ARG_LEN-1)); } if(parm[1][0] == NULL) return(TRUE); if(too_many()) return(TRUE); if(parm[1][0] it file */ bdos(PRINT_STRING,msg9); parm[2][0] = bdos(CONIN,(long)0); parm[2][0] = toupper(parm[2][0]); cr_lf(); TE done,open,sub_open; BYTE found; REG UWORD i,n; UWORD (*ldrpgm) (); REG BYTE *top; REG struct _filetyps *p; dirf---------------*/ if(parm[1][0] == NULL) /* prompt for a file */ { /*----------------------*/ bdos(PRINT_STRING,msg2)/* current user # */ /* 3. SUB type on the */ /* current user # */ /* 4. 68K type on */ /* us; for(i = 16;i <= 35;i++) cmdfcb[i] = new_fcb[k++]; if(cmdfcb[0] < 0 || cmdfcb[0] > 15) bad_cmd = TRUE; < '0' || parm[1][0] > '9') return(FALSE); i = (parm[1][0] - '0'); if(i > 9) return(FALSE); if(parm[1][1]) i = ((i if(parm[2][0] != 'N' && parm[2][0] != 'Y') return; } if(parm[2][0] != 'N') if(bdos(DELETE_FILE,cmdfcb) > 0) bdoslag = FALSE; load_try = TRUE; done = FALSE; found = FALSE; sub_open = FALSE; open = FALSE; user = bdos(GET_USER_NO; get_cmd(&parm[1][0],(long)(ARG_LEN-1)); } if(parm[1][0] == NULL) return; if(too_many()) return; i = find_coloer 0 */ /* 5. BLANK type on the */ /* user 0 */ /* 6. SUB type on */ /* user 0 */ if(!(bad_cmd) && bdos(RENAME_FILE,cmdfcb) > 0) bdos(PRINT_STRING,msg6); } } else bdos(PRINT_STRI * 10) + (parm[1][1] - '0')); if(i < 16 && parm[1][2] == NULL) bdos(GET_USER_NO,(long)i); else return(FALSE); return(PRINT_STRING,msg6); } /************************/ UWORD user_cmd() /* change user number */ /****************,(long)255); cur_disk = bdos(RET_CUR_DISK,(long)0); if(mode == SEARCH) i = 0; else i = 1; i = fill_fcb(i,cmdfcb); if(i >n(); if(!chk_colon(i)) return; else if(parm[1][1] == ':' && parm[1][2] == NULL) { echo_cmd(&parm[1][0],BAD); /* */ /*----------------------*/ /* */ /* If a filetype is */ /* specified then I */ NG,msg7); } if(bad_cmd) bdos(PRINT_STRING,msg8); } /************************/ VOID era_cmd() /* (TRUE); } UWORD cmd_file(mode) /************************/ /* */ /* SEARCH ORDER */ /* ==== 0) { bdos(PRINT_STRING,msg7); return(FALSE); } p = &load_tbl; top = p->typ; if(cmdfcb[9] == ' ') { whilemdfcb[11] == 'B') { sub_open = TRUE; sub_user = bdos(GET_USER_NO,(long)255); if(submit) chain_sub = TRUE; fill_fcb(1,cmdfcb); p = &load_tbl; while(*(p->typ)) { if(p->user_c || p->user_0) { if(mode == SEARd_try = FALSE; morecmds = FALSE; return((sub_open || open)); } /************************/ UWORD sub_read() /* R MATCH) { found = TRUE; if(dma[i] == user) p->user_c = TRUE; else p->user_0 = TRUE; if(m else p++; } if(*(p->typ)) ldrpgm = p->loader; else ldrpgm = load68k; /* default */ /* ATTEMP(*(p->typ)) /* clear flags in table */ { p->user_c = p->user_0 = FALSE; p++; } bdos(SELECT_DISK,(long)(cmdf else first_sub = TRUE; for(i = 0;i < FCB_LEN;i++) subfcb[i] = cmdfcb[i]; if(mode == SEARCH) subpromptCH) break; if(strcmp(p->typ,"SUB") == MATCH) break; } p++; } if(*(p->typ)) { if(!(p->user_c)) bead the submit file */ { /************************/ if(bdos(READ_SEQ,subfcb)) { end_of_file = TRUE; return(FALSE)ode == SEARCH && strcmp(p->typ,top) == MATCH && p->user_c) done = TRUE; } p++; } } i =T THE PROGRAM LOAD */ switch( (*ldrpgm) (glb_index) ) { case 1: bdos(PRINT_STRING,lderr1); break; case 2: bdoscb[0]-1)); cmdfcb[0] = '?'; cmdfcb[12] = NULL; i = bdos(SEARCH_FIRST,cmdfcb); while(i != 255 && !(done)) { = FALSE; submit = TRUE; end_of_file = FALSE; } else if(mode != SUB_FILE) open = TRUE; break; } dos(GET_USER_NO,(long)0); cpy(p->typ,&cmdfcb[9]); } } bdos(SELECT_DISK,(long)cur_disk); while(1) { if(bd; } return(TRUE); } /************************/ UWORD dollar(k,mode,com_index) /* Translate $n to */ bdos(SEARCH_NEXT); } if(!(found)) { if(mode == SUB_FILE) bdos(PRINT_STRING,msg11); dirflag = TRUE; load_tr(PRINT_STRING,lderr2); break; case 3: bdos(PRINT_STRING,lderr3); break; default : bdos(PRINT_STRING,lderror); } i *= 32; if(dma[i] == 0 || dma[i] == user) { for(n = 9;n <= 11;n++) dma[i+n] &= CMASK; dma[i+12] = NULL; else if(bdos(GET_USER_NO,(long)255) == 0) break; else bdos(GET_USER_NO,(long)0); } if(open) { check_cmos(OPEN_FILE,cmdfcb) <= 3) { for(n = 9;n <= 11;n++) cmdfcb[n] &= CMASK; if(cmdfcb[9] == 'S' && cmdfcb[10] == 'U' && c /* nth argument on the */ /* command line */ /************************/ REG UWORD k; REG UWORD mode; REG By = FALSE; bdos(SELECT_DISK,(long)cur_disk); return(FALSE); } if(mode == SEARCH) fill_fcb(0,cmdfcb); else } if(!(sub_open) && mode == SUB_FILE) bdos(PRINT_STRING,msg11); bdos(GET_USER_NO,(long)user); dirflag = TRUE; loa p = &load_tbl; while(*(p->typ)) { cpy(p->typ,&cmdfcb[9]); if(strcmp(&cmdfcb[1],&dma[i+1]) ==d(glb_index); if(!(found)) { p = &load_tbl; while(*(p->typ)) if(strcmp(p->typ,&cmdfcb[9]) == MATCH) break;YTE *com_index; { REG UWORD n,j,p_index; REG BYTE *p1; j = sub_index; if(k >= CMD_LEN) { k = 0; if(!sub_refile = TRUE; done = TRUE; } }while(!(done)); return(k); } /************************/ VOID translate(com_inprompt(); do { while(k < CMD_LEN && subdma[k] != EOF && subdma[k] != Cr) { if(subdma[k] == '$(k >= CMD_LEN) { k = 0; sub_read(); } } } /*--------------------------------------------p1++; else bdos(CONSOLE_OUTPUT,(long)*p1++); k++; } else { if(mode == FILL) subcom[j++] = '$'; else dma[k] == TAB)) k++; if(k >= CMD_LEN) { k = 0; if(!sub_read()); else goto blankoutad()) return(k); } if((subdma[k] >= '0') && (subdma[k] <= '9')) { p_index = (subdma[k] - '0'); p1 = com_index; dex) /* TRANSLATE the subfile*/ /* and fill sub buffer. */ /************************/ REG BYTE *com_index; { RE') { k++; k = dollar(k,NOFILL,com_index); } else bdos(CONSOLE_OUTPUT,(long)subdma[k++]); } if(k----------------------*/ /* TRANSLATION OF A COMMAND IS COMPLETE */ /* -Now move sub_index to next comman bdos(CONSOLE_OUTPUT,(long)'$'); if(subdma[k] == '$') k++; } sub_index = j; if(k >= CMD_LEN) { k = 0; su; } break; case '$': k++; sub_index = j; k = dollar(k,FILL,com_index); j = sub_index; if(*p1++ == 'S' && *p1++ == 'U' && *p1++ == 'B' && *p1++ == 'M' && *p1++ == 'I' && *p1++ == 'TG BYTE *p1; REG UWORD j,n,k,p_index; j = 0; k = sub_index; while(!(end_of_file) && j < CMD_LEN && subdma[k] != Cr & == CMD_LEN && subdma[k] != EOF && subdma[k] != Cr) { k = 0; if(!sub_read()) done = TRUE; } else { if(sud- */ /*------------------------------------------------------------------*/ if(subdma[k] == Cr || sub_read(); } return(k); } /************************/ UWORD comments(k,com_index) /* Strip and echo submit*/ /* break; case Lf: k++; if(k >= CMD_LEN) { k = 0; sub_read(); } break;' && *p1 == ' ') p_index++; p1 = com_index; for(n = 1; n <= p_index; n++) { while(*p1 != ' ' && *p1) & subdma[k] != EXLIMPT) { switch(subdma[k]) { case ';': k = comments(k,com_index); break; case TAB: bdma[k] == Cr) { k += 2; if(k >= CMD_LEN) { k = 0; sub_read(); } } else end_of_bdma[k] == EXLIMPT) do { while(k < CMD_LEN && (subdma[k] == Cr || subdma[k] == Lf || subdma[k] file comments */ /************************/ REG UWORD k; REG BYTE *com_index; { REG UWORD done; done = FALSE; case EOF: end_of_file = TRUE; break; default: subcom[j++] = subdma[k++]; if p1++; if(*p1 == ' ') p1++; } while(*p1 != ' ' && *p1 && j < CMD_LEN) if(mode == FILL) subcom[j++] = *case ' ': if(j > 0) subcom[j++] = subdma[k++]; blankout: while(k < CMD_LEN && (subdma[k] == ' ' || sub == EXLIMPT)) k++; if(k == CMD_LEN) { k = 0; if(!sub_read()) break; } else { if(subdma[k] /************************/ VOID execute_cmd(cmd) /* branch to */ /* appropriate routine */ /********/ REG BYTE *com_index; { REG UWORD i,cur_user; for(i = 0;i <= CMD_LEN;i++) subcom[i] = NULL; cur_user = bdos(GET main() { /*---------------------*/ REG BYTE *com_index; /* cmd execution ptr */ /*--------------------ng submit_cmd,the variable | | sub_index points to the beginning of the next command | | to translate and execute. The { bdos(PRINT_STRING,msg2); get_cmd(subdma,(long)(CMD_LEN-1)); i = 0; while(subdma[i] != ' ' && == EOF) end_of_file = TRUE; break; } }while(TRUE); sub_index = k; } /************************/ UWORD *****************/ REG BYTE *cmd; { REG UWORD i,flag; switch( decode(cmd) ) { case DIRCMD: dir_cmd(0); brea_USER_NO,(long)255); bdos(GET_USER_NO,(long)sub_user); bdos(SET_DMA_ADDR,subdma); if(first_sub || chain_sub) { for(i -*/ dirflag = TRUE; /* init fcb fill flag */ bdos(SET_DMA_ADDR,dma); /* set system dma addr */ /* buffer subdma is used | | to hold the UN-translated submit file contents. | | The buffer subcom holds a translate subdma[i] && i < ARG_LEN-1 ) parm[1][i] = subdma[i++]; parm[1][i] = NULL; if(i != 0) subpromsubmit_cmd(com_index) /* fill up the subcom */ /* buffer */ /************************/ /*----------------k; case DIRSCMD: dir_cmd(1); break; case TYPECMD: type_cmd(); break; case RENCMD: ren_cmd(); break; = 0;i < CMD_LEN;i++) subdma[i] = NULL; sub_read(); sub_index = 0; } if(!(end_of_file)) translate(com_index); ---------------------*/ if(load_try) { bdos(SELECT_DISK,(long)cur_disk); bdos(GET_USER_NO,(long)user); load_try = Fd command. | | Comments are echoed to the screen by the procedure | | "comments". Parameters are substituted in commept = TRUE; else break; } else subprompt = FALSE; goto gosub; case FILE: flag = SEARCH; gosu----------------------------------------------*\ | | | Submit_Cmd is a Procedure that returns exactly | | one commcase ERACMD: era_cmd(); break; case UCMD: if(!(user_cmd())) bdos(PRINT_STRING,msg12); break; case CH_Dfor(i = 0;i < CMD_LEN;i++) subcom[i] = toupper(subcom[i]); bdos(SET_DMA_ADDR,dma); bdos(GET_USER_NO,(long)cur_user); } ALSE; } if(chainp) /*sw Chain? */ { /*sw Yes. */ com_index = chainp + 1; /*sw Set-um pointer */ com_indents | | as well as command lines. | | | \*--------------------------------------------------------------b: if(cmd_file(flag)) break; if(flag == SUB_FILE) break; default : echo_cmd(parm,BAD); } } and from the submit file. Submit_Cmd is | | called only when the end of file marker has not | | been read yet. Upon leaviISK: bdos(SELECT_DISK,(long)(parm[0][0]-'A')); break; case SUBCMD: flag = SUB_FILE; if(parm[1][0] == NULL) x[((WORD)(*chainp))&0xff] = NULL; /*sw Add null*/ chainp = NULL; /*sw Clear chain flag */ } /*sw *******************e */ if(parm[0][0] && parm[0][0] != ';')/*-----------*/ execute_cmd(parm); /* execute command */ /*---------************************/ } /*sw if(chainp) */ /************************/ /*------------------------------------- if(*com_index) echo_cmd(com_index,GOOD); } else { /*----------------------*/ prompt(); /* pFALSE; break; } else submit_cmd(save_sub); } } if(*com_index) echo_cmd(com_index,GOOD); / else /*sw Submit or normal */ { /*---------------------*/ if(morecmds) /* if a warmboot */ { /*-----------*/ if(!(submit)) com_index = scan_cmd(com_index);/* inc pointer */ else { com_index = subcom;-------------------------*\ | | | MAIN CCP PARSE LOOP | | =================== | | | \rompt for command */ com_index = usercmd; /* set execution pointer*/ if(autost && autorom) /* check for COLD} }  occurred & there were*/ /* more cmds to do */ if(submit) /*---------------------*/ { com_index = subcom; if(first_sub || chain_sub) { if(subprompt) copy_cmd(subdma); else copy_cmd(glb_index); if(fi*--------------------------------------------------------------*/ while(*com_index) { /*--------------------*/ BOOT cm*/ { /* */ echo_cmd(usercmd,GOOD); /* echo the command */ autorom = FALSE; /* turn off .bss flag  }  submit_cmd(save_sub); while(!*com_index) { if(end_of_file) { com_index = user_ptr; submit = Frst_sub) user_ptr = scan_cmd(glb_index); submit_cmd(save_sub); first_sub = chain_sub = FALSE; } else glb_index = com_index; /* save for use in */ /* check_cmd call */ get_parms(com_index); /* parse command lin */ } /* */ else /* otherwise....... */ get_cmd(usercmd,(long)(CMD_LEN));/*read a cmd */ } / } ALSE; break; } else submit_cmd(save_sub); } } else com_index = user_ptr; morecmds = FALSE; *com_index = NULL; while(*com_index == NULL) { if(end_of_file) { com_index = user_ptr; submit = ************************************************************************* * * * INTERFACE MODULE BETWEEN * * | \*--------------------------------------------------------------*/ /*-------------------------------------------*\ ======= | | | | CP/M 68k: A CP/M derived operating system | | | | File contents: | ine NO_READ 255 #define BLANK ' ' #define BACKSLH '\\' #define EXLIMPT '!' #define CMASK 0177 #define ONE (long)49 (sp),d0 move.l 6(sp),d1 trap #2 rts  OFF 0 #define MATCH 0 #define GOOD 1 #define BAD 0 #define FILL 1 #define NOFILL 0 #define VOID /*no return valu CCP and THE BDOS * * * * * * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM * * ========== | CP/M Transient Commands | \*-------------------------------------------*/ #define DIRCMD 0 #def | ------------- | | This file contains all of the #defines | | used by the console command processor. | | #define TAB 9 #define Cr 13 #define Lf 10 #define CR (long)13 #define LF (long)10 #define EOF 26 #define BLAN(sp),d0 move.l 6(sp),d1 trap #2 rts e*/ #define NO_FILE 98 #define STOP 99 #define USER_ZERO 0 #define DISK_A 1 #define SOURCEDRIVE 88 #define DESTDR======================================== * * * * (C) Copyright Digital Research 1983 all rights reserved * ine TYPECMD 1 #define RENCMD 2 #define ERACMD 3 #define UCMD 4 #define CH_DISK 5 #define SUBCMD 6 #defi | | created by : Tom Saulpaugh Date: 7/13/82 | | ---------- | | last modified: 10/29/82 KS (long)32 #define PERIOD (long)46 #define COLON (long)58 #define ARROW (long)62 /*----------------------------(sp),d0 move.l 6(sp),d1 trap #2 rts IVE 99 #define BYTE char #define REG register #define WORD short #define UWORD unsigned int #define LONG long #defi * * ************************************************************************* .globl _bdos _bdos: move.w ne SUB_FILE 7 #define FILE 8 #define DIRSCMD 9 #define SEARCH 10 /*-------------------------------------- | | ------------- | | | | (c) COPYRIGHT Digital Research 1982 | | all rights reserved | | ---------------*\ | Data Structure Size Constants | \*-------------------------------------------*/ #define CMD_/*--------------------------------------------------------------*\ | ccp_def.c DEFINES v1.0 | | ne ULONG unsigned long #define GET_MEM_REG 18 #define ZERO 0 #define NULL '\0' #define TRUE 1 #define FALSE 0 #def4(sp),d0 move.l 6(sp),d1 trap #2 rts -----*\ | Modes and Flags | \*-------------------------------------------*/ #define ON 1 #define LEN 128 #define BIG_CMD_LEN 255 #define MAX_ARGS 4 #define ARG_LEN 30 #define NO_OF_DRIVES 16 #define NUMDELS 16supper(c)) #define islower(c) ('a' <= (c) && (c) <= 'z') #define isupper(c) ('A' <= (c) && (c) <= 'Z') #define tolower(c) PROT_DISK 28 #define GET_READ/O_VEC 29 #define SET_FILE_ATTRIB 30 #define GET_ADDR_D_PARM 31 #define GET_USER_NO 32************************************************************************* * * * CPM68K INTERFACE MO/O_BYTE 8 #define PRINT_STRING 9 #define READ_CONS_BUF 10 #define GET_CONS_STAT 11 #define RET_VERSION_NO 12 #define R #define FCB_LEN 36 #define DMA_LEN 128 #define FILES_PER_LINE 5 #define SCR_HEIGHT 23 #define BIG_WIDTH 80 (isupper(c) ? ((c)+040):(c)) #define toupper(c) (islower(c) ? ((c)-040):(c)) #define isdigit(c) ('0' <= (c) && (c) <= '9') #define READ_RANDOM 33 #define WRITE_RANDOM 34 #define COMP_FILE-SIZE 35 #define SET_RANDOM_REC 36 #define RESET_DRIVDULE FOR * * THE CONSOLE COMMAND PROCESSOR * * * * THIS IS THE DUAL-PROCESSOR,ROMABLE CP/M-68K SYSTEM ESET_DISK_SYS 13 #define SELECT_DISK 14 #define OPEN_FILE 15 #define CLOSE_FILE 16 #define SEARCH_FIRST 17 #define SEA #define SMALL_WIDTH 40 /*-------------------------------------------*\ | BDOS Function Calls | E 37 #define WRITE_RAN_ZERO 40 #define BIOS_CALL 50 #define LOAD_PROGRAM 59 /*------------------------------------* * ================================================== * * * * (C) Copyright Digital Research 1983 all rigRCH_NEXT 18 #define DELETE_FILE 19 #define READ_SEQ 20 #define WRITE_SEQ 21 #define MAKE_FILE 22 #define RENAME_FILE 2\*-------------------------------------------*/ #define WARMBOOT 0 #define CONIN 1 #define CONSOLE_OUTPUT 2 #define R ----------*\ | MACROS | \*----------------------------------------------*/ #define isalpha(c) (islower(c) || ihts reserved * * * ************************************************************************* .globl _bios1 .3 #define RET_LOGIN_VEC 24 #define RET_CUR_DISK 25 #define SET_DMA_ADDR 26 #define GET_ADDR(ALLOC) 27 #define WRITE_EADER_INPUT 3 #define PUNCH_OUTPUT 4 #define LIST_OUTPUT 5 #define DIR_CONS_I/O 6 #define GET_I/O_BYTE 7 #define SET_I globl _bdos .globl _load68k .globl _load_tbl .globl init_tbl .globl _load_try .globl _autorom .globl flags .gluser: .ds.w 1 .even _submit: .ds.b 1 .even _morecmds: .ds.b 1 .even _patch .ds.l 25 .end d1 move.b dskuser,d1 * get the user # trap #2 * set the user number clr.l d0 * clear d0 move.w #14,d0 * select func BDOS functions 1 thru 11 (console functions) bdosmisc.c - BDOS initialization, warmboot, error handler, set exception, t ccpclear: clr.b _autost * clear the autostart flag ccpstart: lea stack,sp * set up the stack pointer clr.b _autosobl TPAB .globl stack .globl _bdosini .globl _main .globl _submit .globl _morecmds .globl _autost .globl _ususer: .ds.w 1 .even _submit: .ds.b 1 .even _morecmds: .ds.b 1 .even _patch .ds.l 25 .end tion clr.l d1 * clear d1 move.w dskuser,d1 * get disk to be selected andi #$0ff,d1 * mask off the user # trap #2 * (used for miscellaneous BDOS routines) dskutil.c - bit map handlers, directory read & write, dirscan t * clear the auto start flag jsr _init * call bios init move.w d0,dskuser * save user # & disk * * * ROM SYSTEM INITIAercmd .globl _init .globl _ccp .globl _patch .globl cpm .text cpm: jmp.l ccpstart * start ccp with possible inselect the disk _ccp: lea stack,sp * set up the stack pointer jsr _main * call the CCP bra _ccp .bss .even ds (miscellaneous disk handling utilities) fileio.c - all file handling calls except read & write LIZATION * OF BSS VARIABLES * * clr.b _load_try clr.b _submit clr.b _morecmds move.b #$1,_autorom clr.w flags The following is a list of the modules that form the BDOS for the C language version of CP/M-68K: SOURCE FILES bdosif.sitial command jmp.l ccpclear * clear auto start flag .bss _autost: .ds.b 1 * autostart command flag _usercmd: .kuser: .ds.w 1 .even _submit: .ds.b 1 .even _morecmds: .ds.b 1 .even _patch .ds.l 25 .end includes open, close, delete, rename, etc. bdosrw.c - sequential and random read & write bdosmain.c - the BDOS case clr.w TPAB jsr init_tbl jsr _bdosini * do bdos init move.w #32,d0 * get user bdos func # clr.l d1 * clear out - assembly language interface, trap handler, BIOS caller, function 62 (set supervisor) conbdos.c - ds.b 130 * user command buffer .text copy: .dc.b ' CP/M-68K V1.2 COPYRIGHT (C) 1982,1984, Digital Research ' .texstatement, global variable declarations iosys.c - packet I/O to BIOS interface pgmld.s - program load (function t in allocation vector * * getaloc() - get free allocation block * * dchksum() - directory checksum calculator * * diecnum; /* logical sector number to read/write */ UBYTE *dma; /* dma address */ REG WORD parm; /* 0 for read, write pation of data structure for packet I/O WORD do_phio(); /* external physical disk I/O routine */ EXTERN UWORD error(); /* external error routine */ EXTERN UWORD log59) exceptn.s - exception handler INCLUDE FILES bdosinc.h - standard i/o stuff, universal declarations bdosdr_rd() - read directory sector * * dir_wr() - write directory sector * * rdwrt() - read/write disk sector * * /**************************************************************** * * * CP/M-68K BDOS Disk Utilities Module * * rm + 1 for write */ { struct iopb rwpkt; BSETUP rwpkt.devnum = GBL.curdsk; /* disk to read/write */ iftion of data structure for packet I/O _dsk; /* logged-on disk vector */ EXTERN UWORD ro_dsk; /* read-only disk vector */ EXTERN UWORD crit_dsk; /* critical disk veef.h - BDOS data structure declarations biosdef.h - procedure declarations to interface to BIOS pktio.h - defin * * * * Configured for Alcyon C on the VAX * * * **************************************************** * * This module contains the miscellaneous utilities * * for manipulating the disk in CP/M-68K. Included are: * * (parm) { rwpkt.iofcn = (BYTE)write; /* if parm non-zero, we're doing a write */ rwpkt.ioflags = (BYTE)(parm-1); /* pasctor */ UBYTE dchksum(); /********************** * read/write routine * **********************/ UWORD rdwrt(secnum, ition of data structure for packet I/O ************/ #include "bdosinc.h" /* Standard I/O declarations */ #include "bdosdef.h" /* Type and structure declaratio * * dirscan() - general purpose dir scanning * * setaloc() - set bit in allocation vector * * clraloc() - clear bis write parm */ if ( ro_dsk & (1 << (rwpkt.devnum)) ) error(4); /* don't write on read-only disk */ } eldma, parm) /* General disk sector read/write routine */ /* It simply sets up a I/O packet and sends it to do_phio */ LONG stion of data structure for packet I/O ns for BDOS */ #include "pktio.h" /* Packet I/O definitions */ /* declare external functions and variables */ EXTERN Use { rwpkt.iofcn = (BYTE)read; rwpkt.ioflags = (BYTE)0; } rwpkt.devadr = secnum; /* sector number */ rxff) ); } /************************ * dirscan entry point * ************************/ UWORD dirscan(funcp, fcbp, parhis implementation is dependant on the representation */ /* of a LONG and is therefore not very portable. But it's fast */tinue) ? GBL.srchpos + 1 : 0 ); while ( (parms & pasthw) || (i <= ((GBL.dphp)->hiwater + 1)) ) { /* main directory *************************** * directory write routine * ****************************/ UWORD dir_wr(secnum) REG WORD sedefine full 2 #define initckv 4 #define pasthw 8 { REG UWORD i; /* loop counter */ REG struct dpb *dparmp;wpkt.xferadr = dma; /* dma address */ /* parameters that are currently not used by do_phio rwpkt.devtype = disk; ms) BOOLEAN (*funcp)(); /* funcp is a pointer to a Boolean function */ REG struct fcb *fcbp; /* fcbp is a pointer to a fcb { REG LONG *p; /* local temp variables */ REG LONG lsum; REG WORD i; BSETUP p = GBL.dirbufp; /*scanning loop */ if ( i > dparmp->drm ) break; if ( ! (i & 3) ) { /* inside loop happens when we need to read cnum; { REG UWORD rtn; BSETUP rtn = rdwrt( (LONG)secnum, GBL.dirbufp, 2); if ( secnum < (GBL.parmp)->cks /* pointer to disk parm block */ REG UWORD dirsec; /* sector number we're working on */ REG UWORD rtn; /* return rwpkt.xferlen = 1; */ rwpkt.infop = GBL.dphp; /* pass ptr to dph */ while ( do_phio(&rwpkt) ) if ( error( p */ REG UWORD parms; /* parms is 16 bit set of bit parameters */ /* Parms & 1 = 0 to start at beginning of dir, 1 to conti point to directory buffer */ lsum = 0; i = SECLEN / (sizeof lsum); do { lsum += *p++; /* add next 4 byteanother directory sector */ retry: dirsec = i >> 2; dir_rd(dirsec); /* read the directory sector */ if ( dirsec) *((GBL.dphp)->csv + secnum) = dchksum(); return(rtn); } /******************************* * directory checksum r value */ REG UBYTE *p; /* scratch pointer */ REG UWORD bitvec; /* disk nmbr represented as a vector */ BSETarm ? 1 : 0 ) ) break; return(0); } /*************************** * directory read routine * ********************nue from last */ /* Parms & 2 = 0 to stop when *funcp is true, 1 to go until end */ /* Parms & 4 = 0 to check the dir checkss of directory */ i -= 1; } while (i); lsum += (lsum >> 16); lsum += (lsum >> 8); return( (UBYTE)(lsum & 0 < (dparmp->cks) ) /* checksumming on this sector? */ { p = ((GBL.dphp)->csv) + dirsec; /* point to checksum vecoutine * *******************************/ UBYTE dchksum() /* Compute checksum over one directory sector */ /* Note that tUP dparmp = GBL.parmp; /* init ptr to dpb */ rtn = 255; /* assume it doesn't work */ i = ( (parms & con*******/ UWORD dir_rd(secnum) WORD secnum; { BSETUP return( rdwrt((LONG)secnum, GBL.dirbufp, 0) ); } /*um, 1 to store new checksum */ /* Parms & 8 = 0 to stop at hiwater, 1 to go until end of directory */ #define continue 1 #tor byte */ if (parms & initckv) *p = dchksum(); else if (*p != dchksum()) { /* checksum error! */ (GBL.dphp)v + (i >> 3) )) & (0x80 >> (i&7)) ); } UWORD getaloc(leftblk) /* Get a free block in the file system and set the bit in a if (bitnum >= 0 && bitnum <= (GBL.parmp)->dsm) *((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7); } clral UNLOCK return(blk); }  to directory entry, and (3) directory index */ { if (parms & full) rtn = 0; /* found a match, but keep goet disk max field from dpb */ rtblk = leftblk; blk = ~0; /* -1 returned if no free block found */ while (leftb->hiwater = dparmp->drm; /* reset hi water */ bitvec = 1 << (GBL.curdsk); if (crit_dsk & bitvec) /* if disk in crllocation vector */ /* It is passed the block number of the last block allocated to the file */ /* It tries to allocate theoc(bitnum) /* Clear bit in allocation vector */ REG UWORD bitnum; { BSETUP if (bitnum > 0 && bitnum <= (GBL.parmp UNLOCK return(blk); } ing */ else return(i & 3); /* return directory code */ } i += 1; } return(rtn); } /******************lk || rtblk < diskmax) { if (leftblk) if (chkaloc(--leftblk)) { blk = leftblk; break; } if (rtbitical mode */ ro_dsk |= bitvec; /* then set it to r/o */ else { log_dsk &= ~bitvec; /* else log it off * block closest to the block that was passed */ REG UWORD leftblk; { REG UWORD blk; /* block number to allocate */ )->dsm) *((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7)); } UWORD chkaloc(i) /* Check bit i in allocation ve********************** * Routines to manage allocation vector * * setaloc() * * clraloc() * * getaloc() * **********lk < diskmax) if (chkaloc(++rtblk)) { blk = rtblk; break; } } if (blk != ~0) setaloc(blk); / seldsk(GBL.curdsk); /* and re-select it */ goto retry; /* and re-do current op */ } } } } GBL.s REG UWORD rtblk; /* high block number to try */ REG UWORD diskmax; /* # bits in alv - 1 */ BSETUP LOCK /ctor */ /* Return non-zero if block free, else return zero */ REG UWORD i; { BSETUP return( ~(*( (GBL.dphp)->al******************************/ setaloc(bitnum) /* Set bit in allocation vector */ REG UWORD bitnum; { BSETUP UNLOCK return(blk); } rchpos = i; if ( (*funcp)(fcbp, (GBL.dirbufp) + (i&3), i) ) /* call function with parms of (1) fcb ptr, (2) pointer* need to lock the file system while messing with the allocation vector */ diskmax = (GBL.parmp)->dsm; /* gera $1x.1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 iosys.s era iosys.s $2cp68 ccp.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f e1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 conbdos.s era conbdos.s $2cp68 dskutil.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f e68 -s 0$1 -l -u -f $1 bdosmain.s era bdosmain.s $2cp68 bdosmisc.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c16f $1 stack.s rear $1 $2 ra $1x.i $2c168 $1x.1 $1x.2 ccp.s era $1x.1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 ccp.s era ccp.s $2as68 -s 0$1 -l -u -f $ra $1x.i $2c168 $1x.1 $1x.2 dskutil.s era $1x.1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 dskutil.s era dskutil.s $2cp68 filei8 $1x.1 $1x.2 bdosmisc.s era $1x.1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 bdosmisc.s era bdosmisc.s $2cp68 bdosrw.c $1x.i $ $1 stack.s rear $1 $2 1 bdosif.s $2cp68 exceptn.s except.s $2as68 -s 0$1 -f $1 -l -n except.s era except.s $2cp68 -dm68010 exceptn.s except10.s $o.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c168 $1x.1 $1x.2 fileio.s era $1x.1 era $1x.2 $2as68 -s 0$1 -l -u 2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c168 $1x.1 $1x.2 bdosrw.s era $1x.1 era $1x.2 $2as68 -s 0$1 -l -u -f $1 bdosrw $1 stack.s rear $1 $2 2as68 -s 0$1 -f $1 -l -n except10.s era except10.s $2as68 -s 0$1 -l -u -f $1 pgmld.s $2as68 -s 0$1 -l -u -f $1 ccpbdos.s $2a-f $1 fileio.s era fileio.s $2cp68 iosys.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c168 $1x.1 $1x.2 iosys.s .s era bdosrw.s $2cp68 conbdos.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c168 $1x.1 $1x.2 conbdos.s era $1x.$2cp68 bdosmain.c $1x.i $2c068 $1x.i $1x.1 $1x.2 $1x.3 -f era $1x.i $2c168 $1x.1 $1x.2 bdosmain.s era $1x.1 era $1x.2 $2ass68 -s 0$1 -l -u -f $1 ccpif.s $2as68 -s 0$1 -l -u -f $1 ccpload.s $2as68 -s 0$1 -l -u -f $1 filetyps.s $2as68 -s 0$1 -l -u - Compiled with Alcyon C on the VAX * * - rename file * * set_attr() - set file attributes * * get(); /* calc max extent allocated for fcb */ EXTERN UWORD udiv(); /* unsigned divide routine */ /* decIncluded are: * * * * seldsk() - select disk */ EXTERN UWORD ro_err(); /* read-only file error routine */ EXTERN UWORD do_phio(); /* packet disk * * Modified 2/5/84 sw Allow odd DMA on get free space * * * *******************************************************size() - get file size * * setran() - set random record field * * lare external variables */ EXTERN UWORD log_dsk; /* logged-on disk vector */ EXTERN UWORD ro_dsk; * * openfile() - open file * * close_fi() - close fi/o handler */ EXTERN clraloc(); /* clear bit in allocation vector */ EXTERN setaloc(); /* se/**************************************************************** * *********/ #include "bdosinc.h" /* Standard I/O declarations */ #include "bdosdef.h" /* Type and str free_sp() - get disk free space * * move() - general purpose byte mover * * /* read-only disk vector */ EXTERN UWORD crit_dsk; /* vector of disks in critical state */ /***********ile * * search() - search for first/next file match * * create() - ct bit in allocation vector */ EXTERN UWORD swap(); /* assembly language byte swapper */ EXTERN UWORD dir_wr(); * * CP/M-68K BDOS File I/O Module * * ucture declarations for BDOS */ #include "pktio.h" /* Packet I/O definitions */ /* declare external fucntions * * * ************************** * This function passed to dirscan * * from seldsk (below) * ***********************reate file * * delete() - delete file * * rename() /* directory write routine */ EXTERN tmp_sel(); /* temporary select disk routine */ EXTERN UWORD calcext * * This module contains all file handling BDOS functions * * except for read and write for CP/M-68K. */ EXTERN UWORD dirscan(); /* directory scanning routine */ EXTERN UWORD error(); /* disk error routine *************/ BOOLEAN alloc(fcbp, dirp, dirindx) /* Set up allocation vector for directory entry pointed to by dirp */ s GBL.dirbufp = (GBL.dphp)->dbufp; /* set up GBL copies of dir_buf and dpb ptrs */ GBL.parmgflag = ~(log_dsk >> dsknum) & 1; if ((GBL.curdsk != dsknum) || logflag) { /* if not last us************* * General purpose filename matcher * *************************************/ BOOLEAN match(p1, p2, chk_ext) do setaloc( UBWORD(dirp->dskmap.small[i++]) ); while (i <= 15); } else { /* round up */ do setaloc(--i); while (i); /* alloc directory blocks */ dirscan(alloc, NULL, truct fcb *fcbp; /* not used in this function */ REG struct dirent *dirp; /* pointer to directory entryp = (GBL.dphp)->dpbp; } if (logflag) { /* if disk not previously logged on, do it now */ LOCK ed disk or not logged on */ selpkt.iofcn = sel_info; GBL.curdsk = (selpkt.devnum = dsknum); if (UBWOR REG UBYTE *p1; REG UBYTE *p2; BOOLEAN chk_ext; { REG WORD i; REG UBYTE temp; BSETUP i = 12; do setaloc(swap(dirp->dskmap.big[i++])); while (i <= 7); } } } /*********************0x0e); /* do directory scan & alloc blocks */ log_dsk |= 1 << dsknum; /* mark disk as logged in */ */ WORD dirindx; /* index into directory for *dirp */ { REG WORD i; /* loop counter /* must lock the file system while messing with alloc vec */ i = (GBL.parmp)->dsm; do clraloc(i); while (i-D(dsknum) > 15) error(2); selpkt.ioflags = logflag ^ 1; do { do_phio(&selpkt); /* actu do { temp = (*p1 ^ '?'); if ( ((*p1++ ^ *p2++) & 0x7f) && temp ) return(FALSE); i *** * seldsk entry point * ************************/ seldsk(dsknum) REG UBYTE dsknum; /* disk number to } } /******************************* * General purpose byte mover * *******************************/ move(p1, p2*/ BSETUP if ( UBWORD(dirp->entry) < 0x10 ) /* skip MP/M 2.x and CP/M 3.x XFCBs */ { (GBL.dphp)->hiw-); /* clear the allocation vector */ i = udiv( (LONG)(((GBL.parmp)->drm) + 1), 4 * (((GBL.parmally do the disk select */ if ( (GBL.dphp = selpkt.infop) != NULL ) break; } while ( ! error(3) ); -= 1; } while (i); if (chk_ext) { if ( (*p1 != '?') && ((*p1 ^ *p2) & ~((GBL.parmp)->exm)) ) select */ { struct iopb selpkt; REG WORD i; UWORD j; REG UBYTE logflag; BSETUP lo, i) REG BYTE *p1; REG BYTE *p2; REG WORD i; { while (i--) *p2++ = *p1++; } /************************ater = dirindx; /* set up high water mark for disk */ i = 0; if ((GBL.parmp)->dsm < 256) { p)->blm) + 1), &j); /* calculate nmbr of directory blks */ if (j) i++; return(FALSE); p1 += 2; p2 += 2; if ((*p1 ^ *p2) & 0x3f) return(FALSE); } return(TRUE); EG WORD i; REG UBYTE *fp; REG UBYTE *dp; REG UWORD fcb_ext; REG UWORD dir_ext; BSETUP if ( matc /* I/O packet for flush buffers call */ flushpkt.iofcn = flush; while ( rtn = do_phio(&flushpkt) ) if { if (*(UWORD *)dp != *(UWORD *)fp) goto badmerge; } fcb */ move(dirp, fcbp, sizeof *dirp); /* copy dir entry into user's fcb */ { if (*dp != *fp) goto badmerge; } else *fp = *dp; } /************************ * openfile entry point * ************************/ BOOLEAN openfile(fcbp, dirp, dirindx) h(fcbp, dirp, TRUE) ) { /* Note that FCB merging is done here as a final conf( error(1) ) break; return(rtn); } /********************************* * file close routine for dirscan * ********** else *(UWORD *)fp = *(UWORD *)dp; } else *(UWORD *)dp = *(UWORD *)fp; (UWO fcbp->extent = fcb_ext; fcbp->s2 |= 0x80; /* set hi bit of S2 (write flag) */ crit_dsk |= 1 << ( } else *dp = *fp; fp += 1; dp += 1; i -= 1; REG struct fcb *fcbp; /* pointer to fcb for file to open */ struct dirent *dirp; /* pointer to directorirmation that disks haven't been swapped */ LOCK fp = &(fcbp->dskmap.small[0]); dp = &(dirp->dskmap.s***********************/ BOOLEAN close(fcbp, dirp, dirindx) REG struct fcb *fcbp; /* pointer to fcb */ REG struRD *)fp += 1; (UWORD *)dp += 1; i -= 1; } while (i); } /* Disk GBL.curdsk); } return(rtn); } /*************************/ /* flush buffers routine */ /************************ } while (i); } else { /* Large disk map merge routine */ i = 8; y entry */ WORD dirindx; { REG UBYTE fcb_ext; /* extent field from fcb */ REG BOOLEAN rtn; mall[0]); if ((GBL.parmp)->dsm < 256) { /* Small disk map merge routine */ i = 16;ct dirent *dirp; /* pointer to directory entry */ WORD dirindx; /* index into directory */ { Rmap merging complete */ fcb_ext = calcext(fcbp); /* calc max extent for fcb */ dir_ext = (UWORD)(dirp->*/ UWORD flushit() { REG UWORD rtn; /* return code from flush buffers call */ struct iopb flushpkt; do { if (*(UWORD *)dp) { if (*(UWORD *)fp) BSETUP if ( rtn = match(fcbp, dirp, TRUE) ) { fcb_ext = fcbp->extent; /* save extent number from user's do { if (*dp) { if (*fp) extent) & 0x1f; if ( (fcb_ext > dir_ext) || ((fcb_ext == dir_ext) && (UBWORD(fcbp->rcdctry point */ UWORD search(fcbp, dsparm, p) REG struct fcb *fcbp; /* pointer to fcb for file to search */ REG UWO don't need to do physical close */ return( dirscan(close, fcbp, 0)); /* call if ( rtn = ((dirp->entry) == 0xe5) ) { p = &(fcbp->rcdcnt); i = 17; do { dirindx >> 2); UNLOCK return(TRUE); badmerge: UNLOCK ro_dsk |= (1 << GBL.curdsk); an(matchit, fcbp, dsparm); } move( GBL.dirbufp, GBL.dmaadr, SECLEN); return(rtn); } /**********************nt) > UBWORD(dirp->rcdcnt))) ) /* if fcb points to larger file than dirp */ { dirRD dsparm; /* parameter to pass through to dirscan */ UBYTE *p; /* pointer to pass through dirscan with close function */ } /************************ * search entry point * ************************/ /* Fi /* clear fcb rcdcnt and disk map */ *p++ = 0; i -= 1; } while (i); move( return(FALSE); } else return(FALSE); } /************************ * close_fi entry point * ******************* * create entry point * ************************/ BOOLEAN create(fcbp, dirp, dirindx) REG struct fcb *fcbp; p->rcdcnt = fcbp->rcdcnt; /* set up rc, ext from fcb */ dirp->extent = (BYTE)fcb_ext; } dito tmp_sel */ { REG UWORD rtn; /* return value */ BSETUP if (fcbp->drvcode == '?') { rst two functions for dirscan */ BOOLEAN alltrue(p1, p2, i) UBYTE *p1; UBYTE *p2; WORD i; { return(TRUE); } fcbp, dirp, sizeof *dirp); /* move the fcb to the directory */ dir_wr(dirindx >> 2); /* write the directory s*******/ UWORD close_fi(fcbp) struct fcb *fcbp; /* pointer to fcb for file to close */ { flushit(); /* pointer to fcb for file to create */ REG struct dirent *dirp; /* pointer to directory entry */ REG WORD dirindxrp->s1 = fcbp->s1; if ( (dirp->ftype[robit]) & 0x80) ro_err(fcbp,dirindx); seldsk(GBL.dfltdsk); rtn = dirscan(alltrue, fcbp, dsparm); } else { tmp_sel(p); BOOLEAN matchit(p1, p2, i) UBYTE *p1; UBYTE *p2; WORD i; { return(match(p1, p2, TRUE)); } /* search enector */ if ( dirindx > (GBL.dphp)->hiwater ) (GBL.dphp)->hiwater = dirindx; crit_dsk |= 1 << (GB /* first, flush the buffers */ if ((fcbp->s2) & 0x80) return(0); /* if file write flag not on,; /* index into directory */ { REG BYTE *p; REG WORD i; REG BOOLEAN rtn; BSETUP /* read-only file error */ dirp->ftype[arbit] &= 0x7f; /* clear archive bit */ dir_wr( /* temporarily select disk */ if (fcbp->extent != '?') fcbp->extent = 0; fcbp->s2 = 0; rtn = dirscL.curdsk); } return(rtn); } /************************ * delete entry point * ************************/ B ) ro_err(fcbp,dirindx); /* check for read-only file */ p = &(fcbp->dskmap.small[1]); * ************************/ BOOLEAN rename(fcbp, dirp, dirindx) REG struct fcb *fcbp; /* pointer to fcb for fil | ((LONG)(fcbp->s2 & 0x3f) << 12) ); } /************************ * setran entry point * *************** LOCK dir_wr(dirindx >> 2); /* Now free up the space in the allocation vector */ if ((GBL.paindex into directory */ { REG BOOLEAN rtn; BSETUP if ( rtn = match(fcbp, dirp, FALSE) ) { OOLEAN delete(fcbp, dirp, dirindx) REG struct fcb *fcbp; /* pointer to fcb for file to delete */ REG struct dirent q = &(dirp->fname[0]); i = 11; do { *q++ = *p++ & 0x7f; i -= 1; e to delete */ REG struct dirent *dirp; /* pointer to directory entry */ REG WORD dirindx; /* index int*********/ setran(fcbp) REG struct fcb *fcbp; /* pointer to fcb for file to set ran rec */ { struct rmp)->dsm < 256) { i = 16; do clraloc(UBWORD(dirp->dskmap.small[--i])); whil move(&fcbp->fname[0], &dirp->fname[0], 11); dir_wr(dirindx >> 2); } return(rtn); } /*************** *dirp; /* pointer to directory entry */ REG WORD dirindx; /* index into directory */ { } while (i); dir_wr(dirindx >> 2); } return(rtn); } /************************ * set_attr entryo directory */ { REG UWORD i; REG BYTE *p; /* general purpose pointers */ REG BYTE *q; { BYTE b3; BYTE b2; BYTE b1; BYTE b0; }; LONG random; random = (LONG)UBWORe (i); } else { i = 8; do clraloc(swap(dirp->dskmap.big[--i])); ************* * utility routine used by * * setran and getsize * ****************************/ LONG extsize(fcbp)REG WORD i; REG BOOLEAN rtn; BSETUP if ( rtn = match(fcbp, dirp, FALSE) ) { if ( (dirp->ftype[rob point * ************************/ BOOLEAN set_attr(fcbp, dirp, dirindx) REG struct fcb *fcbp; /* pointer to fc REG BOOLEAN rtn; BSETUP if ( rtn = match(fcbp, dirp, FALSE) ) { if ( (dirp->ftype[robit]) & 0x80D(fcbp->cur_rec) + extsize(fcbp); /* compute random record field */ fcbp->ran0 = random.b while (i); } UNLOCK } return(rtn); } /************************ * rename entry point /* Return size of extent pointed to by fcbp */ REG struct fcb *fcbp; { return( ((LONG)(fcbp->extent & 0x1f) << 7) it]) & 0x80 ) ro_err(fcbp,dirindx); /* check for read-only file */ dirp->entry = 0xe5;b for file to delete */ REG struct dirent *dirp; /* pointer to directory entry */ REG WORD dirindx; /* 2; fcbp->ran1 = random.b1; fcbp->ran2 = random.b0; } /**********************************/ /* fsize is a funtionp->ran2 = maxrcd.b0; } /************************ * free_sp entry point * ************************/ free_sp(dsknum) EG WORD dsparm; struct { BYTE b3; BYTE b2; BYTE b1; BYTE b0; }; maxrcdory */ move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */ }  dirp, FALSE) ) { temp = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp); /* compute ftmask) { bitmask = 0x8000; alvword = ~(*alvec++); } if ( alvword & bitmask) for dirscan */ /* passed from getsize */ /**********************************/ BOOLEAN fsize(fcbp, dirp, dirindx UBYTE dsknum; /* disk number to get free space of */ { REG LONG records; REG UWORD *alvec; REG UW = 0; dsparm = 0; temp = 0; while ( dirscan(fsize, fcbp, dsparm) < 255 ) { /* loopile size */ fcbp->ran0 = temp.b2; fcbp->ran1 = temp.b1; fcbp->ran2 = temp.b0; } return(r records += (LONG)( ((GBL.parmp)->blm) + 1 ); bitmask >>= 1; } temp = records; /*sw Put in me) REG struct fcb *fcbp; /* pointer to fcb for file to delete */ REG struct dirent *dirp; /* pointer to direORD bitmask; REG UWORD alvword; REG WORD i; LONG temp; /*sw For DMA Odd problem */ BSETUP seldsk until no more matches */ temp.b2 = fcbp->ran0; temp.b1 = fcbp->ran1; temp.b0 = fcbp->ran2; * * CP/M-68K table driven file search module * ======================================== * * GLOBALS tn); } /************************ * getsize entry point * ************************/ getsize(fcbp) /* get file size mory */ move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */ } ctory entry */ WORD dirindx; /* index into directory */ { REG BOOLEAN rtn; struct (dsknum); /* select the disk */ records = (LONG)0; /* initialize the variables */ alvec = (GBL.dpif (temp > maxrcd) maxrcd = temp; dsparm = 1; } fcbp->ran0 = maxrcd.b2; fcbp->ran1 = maxrcd.b1; fcb .globl _load_tbl * loader table .globl _load68k * default load program */ REG struct fcb *fcbp; /* pointer to fcb to get file size for */ { LONG maxrcd; LONG temp; Rory */ move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */ }  { BYTE b3; BYTE b2; BYTE b1; BYTE b0; }; LONG temp; if ( rtn = match(fcbp,hp)->alv; bitmask = 0; for (i = 0; i <= (GBL.parmp)->dsm; i++) /* for loop to compute */ { if ( ! bi .globl init_tbl * initializes table on COLD BOOT .text ******************************************* * *-----------------------------------------------------------------------* * ointers to the loaders move.l #_load68k,pgld3 move.l #_load68k,pgld4 rts .bss . ***************************************** * * * FILETYPE TABLE * ************************************************************************* * * * * * ******************************************* * * * This is the D * * STRUCTURE OF A LOADER TABLE ENTRY: * * ==================even .page ************************************************************************* * * * ============== * * * *************************************** The following code allows CP/M-68K to be ROM-able. * ------------------------------------------------- * init_tb************************************************************ _load_tbl: typ1p: .ds.l 1 pgld1: .ds.l 1 .ds.UAL PROCESSOR,ROMABLE version of CP/M-68K * * ====================================================== * =============== * * * * * * CP/M-68K LOADER TABLE * * ** .data .even typ1: .dc.b '68K',0 .even typ2: .dc.b ' ',0 .even typ3: .dl: move.l #typ1,typ1p move.l #typ2,typ2p * init the pointers to the filetypes move.l #b 1 .ds.b 1 typ2p: .ds.l 1 pgld2: .ds.l 1 .ds.b 1 .ds.b 1 typ3p: .ds.l 1 pgld3: * * * (c) Copyright Digital Research 1983 (1) LONG WORD pointer to a filetype * * (2) LONG WORD address of the program loader for ===================== * * c.b 'SUB',0 .even null: .dc.l 0 .end typ3,typ3p move.l #null,typ4p move.l #_load68k,pgld1 move.l #_load68k,pgld2 * init the p .ds.l 1 .ds.b 1 .ds.b 1 typ4p: .ds.l 1 pgld4: .ds.l 1 .ds.b 1 .ds.b 1 * * all rights reserved * * the above type * * (3) BYTE flag #1 * * (4) BYTE flag #2 .b 'SUB',0 .even null: .dc.l 0 .end def.h" /* Declarations for BIOS entry points */ EXTERN udiv(); /* Assembly language unsigned divi * * * * Configured for Alcyon C on the VAX iop->infop = bseldsk(last_dsk, iop->ioflags); break; case read: case write: * * CP/M-68K BDOS Disk I/O System Module * * REG struct dph *hdrp; /* pointer to disk parameter header */ REG struct dpb *dparmp; /* pointer to dis.b 'SUB',0 .even null: .dc.l 0 .end de routine */ /* in bdosif.s. It's used because Alcyon C */ * * * **************************************** if (last_dsk != iop->devnum) bseldsk((last_dsk = iop->devnum), 0); /* guarant * * This module translates from the packet oriented I/O * * passed from the other BDOS modules into Bk parameter block */ REG UWORD rtn; /* return parameter */ UWORD iosect; /* can't do / or % without an external */ /************************ * do_phio entry point * ************************/ ************************/ #include "bdosinc.h" /* Standard I/O declarations */ #include "bdosdef.h" eed disk is logged on, because temp_sel in BDOSMAIN does it */ hdrp = iop->infoIOS calls. * * * * It includes only one external entry /* sector number returned from divide rtn */ LOCK /* lock the disk system while doing physical i/o UWORD do_phio(iop) REG struct iopb *iop; /* iop is a pointer to a i/o parameter block */ { MLOCAL UBYTE las/* Type and structure declarations for BDOS */ #include "pktio.h" /* Packet I/O definitions */ #include "biosp; dparmp = hdrp->dpbp; bsettrk( udiv( iop->devadr, dparmp->spt, &iosect ) point: * do_phio() - do physical i/o * * */ rtn = 0; switch (iop->iofcn) { case sel_info: last_dsk = iop->devnum; /**************************************************************** * t_dsk; /* static variable to tell which disk was last used, to avoid disk selects */ + dparmp->trk_off ); bsetsec( bsectrn( iosect, hdrp->xlt ) ); bsetdma(iop->xferadr); 0 always contains the return parameter from pgmld * d1 is the return register from local subroutines * a0 contains the pointerlocation if necessary noreloc: tst d0 bne lddone bsr setrtn * set up return park; case flush: rtn = bflush(); } UNLOCK return(rtn); } r * get header tst d0 bne lddone * if unsuccessful, return bsr setaddr if ((iop->iofcn) == read) rtn = bread(); else rtn = bwrite(iop->ioflags); bre to the Load Parm Block passed to pgmld * Return parameters in d0 are: * 00 - function successful * 01 - insuff ********************************* * * * Function 59 -- Program Load * * Assembly language ameters lddone: move.l 64(sp), d1 bsr setdma * restore dma address movem.l (sp)+,d1-d7 * set up load addresses tst d0 bne lddone * if unsuccessful, return bsr ak; case flush: rtn = bflush(); } UNLOCK return(rtn); } icient memory or bad header in file * 02 - read error on file * 03 - bad relocation information in file * Entversion * * * * June 8, 1982 * * * **********/a0-a6 rts * Subroutines readseq: * CP/M read sequential function move.l d0,-(sp) * save returnrdtxt * read code and data text segments into mem tst d0 bne lddone * if unsuccessfk; case flush: rtn = bflush(); } UNLOCK return(rtn); } ry point for Program Load routine _pgmld: movem.l d1-d7/a0-a6, -(sp) * save everything, just to be safe move.*********************** .globl _pgmld * this routine is public secsize = 128 * CP/M sector size * d parm move.l FCBPtr(a0),d1 moveq #20,d0 * read seq function trap #2 * calul, return move.l tstart,d7 cmp.l cseg,d7 beq noreloc bsr reloc * do rek; case flush: rtn = bflush(); } UNLOCK return(rtn); } l 60(sp),a0 * get pointer to LPB clr.l d0 * start with return parm cleared bsr gethdl bdos move.l d0,d1 * return parm in d1 move.l (sp)+,d0 rts setdma: * CP/M set dma st seg? ble confgd * if no, we're ok confbd: moveq.l #1,d1 confgd: rts trymemtp: * entry: d2 is a move.l 0(a2,d2),d7 * get 1st seg start cmp.l 0(a2,d3),d7 * is 1st seg above 2nd seg? bge l #4,d3 tst.l d1 * conflict with this seg? dbne d6,chk1 * if no, try next ovea.l #hdr,a6 geth1: move.w (a5)+,(a6)+ * move header into hdr dbf d7,geth1 rts badhdr: moveq #eturn 0 in d1 if no conflicts, else d1 = 1 * uses d3, a5, a6 movea.l #cseg,a5 movea.l #csize,a6 sub.function move.l d0,-(sp) * save return parm moveq #26,d0 * set dma function trap segment nmbr [0..4] * try to fit it at top of memory * uses d3, d6, d7, a5, a6 * returns 0 in d1 if ok move.l d2,d6 conf1 add.l 0(a3,d2),d7 * yes, find top of 1st seg cmp.l 0(a2,d3),d7 * above start of 2nd seg? rts fndseg: * entry: d2 is a segment nmbr [0..4] * try to fit segment d2 directly below segments 0..(d2-1) * uses d3-d7,2,d0 rts conflict: * input parms: d2, d3 = 4 * segment nmbr * if segment d2/4 overlaps segment d3/4, then returnl 0(a6,d2),d7 * subtract size of segment to try bclr #0,d7 * make it even address move.l d #2 * call bdos move.l (sp)+,d0 * restore d0 rts gethdr: * Get header into buffer * d6 is loop counter for chksegs subq #1,d6 lsl #2,d2 * multiply d2 by 4 bgt confbd * if yes, we have a conflict rts * else, return good conf1: a5, a6 move.l d2,d5 * d5 is loop counter to find fit subq.l #1,d5 move.l d5,temp 1 in d1 * else return 0 in d1 * uses d7, a2, a3 clr.l d1 * assume it will work movea.l #cseg7,0(a5,d2) * insert address in segment table cmp.l LoAdr(a0),d7 * check for conflict with low memory in data segment move.l LoAdr(a0),d1 bsr setdma bsr readseq tst d1 move.l HiAdr(a0),d7 * top of mem to d7 chksegs: * entry: d2 = 4 * (segment nmbr to try) * d6 = (d2/4) - 1 (loop move.l 0(a2,d3),d7 add.l 0(a3,d3),d7 * find top of 2nd seg cmp.l 0(a2,d2),d7 * above start of 1 lsl.l #2,d2 * multiply segment by 4 clr.l d4 * d4 is segment to try to fit below fnd1: ,a2 * a2 points to start of segment addresses movea.l #csize,a3 * a3 points to start of segment lengths blt confbd clr.l d3 * check for conflicts with 0..d6 chk1: bsr conflict addq.* read ok? bne badhdr * if no, return bad moveq #18,d7 movea.l LoAdr(a0),a5 m counter) * d7 = address below which to try it * check for conflicts with segments [0..d6] and low memory boundary * r move.l temp,d6 * d6 is loop counter for chksegs movea.l #cseg,a5 move.l 0(a5,d4),d7 * sedseg, bseg cmpi.w #$601b,magic bne set3 * if magic # = 601b, take addr from hdr move.l dstart, #$101,d7 * leave room for base page bclr #0,d7 move.l d7,cseg * cseg is bottom of mem + adr set6: * now check all segments for conflicts with low and high memory boundaries movea.l #cseg,a5 movea.e page is 256 bytes lea stksize,a2 cmp (a2),d7 blt set0 * if stack size < 256, tst.l d1 beq set5 * if found, skip moveq.l #3,d2 bsr trymemtp * gment address to d7 bsr chksegs * check for conflicts addq.l #4,d4 tst.l d1 ddseg move.l bstart,bseg bra set4 set3: * if short header, dseg and bseg follow cseg move.l cs$100 (even boundary) bra set2 sldhi: * relocatable, load high move.l HiAdr(a0),d7 sub.l csizl #csize,a6 clr.l d2 moveq #4,d3 * loop counter set7: move.l 0(a5,d2),d7 * get segment b set to 256 move.l d7,(a2) set0: cmpi.w #$601b,magic beq seta tst.w rlbflg beq else, try top of memory tst.l d1 bne badadr * if fail, exit set5: moveq.l #4,d2 bsrbeq d5,fnd1 * if conflict, try next rts setaddr: * Set up load addresses for cseg, dseg, bss, basepg, eg,d7 add.l csize,d7 addq.l #1,d7 bclr #0,d7 move.l d7,dseg add.l dsize,d7e,d7 sub.l dsize,d7 sub.l bsize,d7 subq.l #4,d7 bclr #0,d7 * put cseg at nase cmp.l LoAdr(a0),d7 * above bottom of memory? blt badadr add.l 0(a6,d2),d7 * find t set1 seta: move.l tstart,cseg * if not relocatable or hdr = $601b, bra set2 * cseg starts at t trymemtp * try to fit stack at top of memory tst.l d1 beq set6 * if ok, skip and stack move.w magic,d6 andi.w #$fffe,d6 cmpi.w #$601a,d6 bne badadr * if addq.l #1,d7 bclr #0,d7 move.l d7,bseg set4: * cseg, dseg, bseg set up * now find a place foext even address below move.l d7,cseg * high memory - (sum of sizes) set2: * Cseg has been set up. Now do op of segment cmp.l HiAdr(a0),d7 * below top of memory? bgt badadr addq.l #4,d2 *start set1: btst #0,Flags(a0) bne sldhi * relocatable, load low move.l LoAdr(a0),d7 add.l moveq.l #4,d2 bsr fndseg * else, try to fit below other segs tst.l d1 bne badmagic nmbr <> 601a or 601b, skip move.l bpsize,symsize move.l #256,d7 move.l d7,bpsize * basr the base page and stack moveq.l #3,d2 bsr fndseg * try to fit base page below cseg, dseg, bseg point to next segment dbf d3,set7 rts badadr: moveq.l #1,d0 rts movebuf: * move (d3) byted3 = secsize fo following loop rdtxt5: cmp.l d3,d2 * have at least one more full sector? blt ,a2 * start at cseg move.l csize,d2 * for csize bytes rdtxt3: clr.l d3 move.w buf clr.b (a2)+ subq.l #1,d2 bne rdtxt7 rdtxt8: rts rdbad: moveq.l #2,d0 rts relocword: d2 is number of bytes left to load moveq #63,d7 movea.l LoAdr(a0),a5 movea.l b readseq * if yes, read into base page tst.w d1 bne rdbad move.w d3,bufbyts *s from the base page buffer to (a2) * uses d6 movea.l basepg,a1 move.l #secsize,d6 sub.w bufbyts,rdtxt6 move.l a2,d1 bsr setdma * if yes, set up dma address bsr readseq * rbyts,d3 cmp.l d2,d3 * # bytes in buffer >= # bytes to load? blt rdtxt4 move.l d2,d3 * relocate word at (a2) based on reloc bits at (a3) * lsb of d2 indicates whether previous word was 1st half of long-word asepg,a6 rdtxt1: move.w (a5)+,(a6)+ * move header sector to base page dbf d7,rdtxt1 move.w #secsize indicate that we've buffered a sector move.l d2,d3 bsr movebuf * move remainder of segment finrd6 * address to move from = adda.w d6,a1 * (basepg) + secsize - (bufbyts) sub.w d3,bufead next sector tst.w d1 bne rdbad * if no good, exit sub.l d3,d2 * decre bsr movebuf * if yes, move # bytes to load bra finrd rdtxt4: sub.l d3,d2 move.w (a3)+,d7 * get relocation info andi.w #7,d7 * strip off symbol table bits lsl -28,d7 cmpi.w #$601a,magic * short header? beq rdtxt2 subq.w #8,d7 rdtxt2: move.w d7,bufbyd: move.l dseg,a2 * set up to load data segment move.l dsize,d2 sub.w #1,loop bnbyts * update # bytes buffered bra moveb2 moveb1: move.b (a1)+,(a2)+ * do the move moveb2: dbf d3,mment # bytes to load adda.l #secsize,a2 * increment dma address bra rdtxt5 rdtxt6: tst.l * if no, update # bytes to load bsr movebuf * move remainder of buffer move.l #secsize,d3 * #1,d7 * multiply by 2 jmp 2(pc,d7) bra relabs bra reldata bra ts * indicate # bytes of text in buffer move.w #2,loop * do for code, data segments move.l csege rdtxt3 move.l bseg,a2 * clear the bss segment move.l bsize,d2 beq rdtxt8 rdtxt7:oveb1 rts rdtxt: * Read code and data text into memory * during this routine, a2 is always the load address, * d2 * any more bytes to read? beq finrd move.l basepg,d1 bsr setdma bsr relcode bra relbss bra relbad bra rellong bra relbad bra relod7,d6 * d6 is nmbr sectors to skip swap d7 * d7 is nmbr bytes to skip move.w bufbytcation word in basepg * lsb of d2 is long word flag (set on reloc type 5, reset on next word) * d3 is # words in relocation bu * make d4 indicate # words bra reloc4 reloc2: subq.w #1,d3 bpl reloc3 bsr reag set? bne relc1 * if yes, skip move.w (a2),d6 add.w d5,d6 move.w d6,(a2)+ tst.w d1 bne rdbad skip3: dbf d6,skip2 * we got past symbol table * a3, d3 are set up move.l p relbad: move.l (sp)+,d0 * pop return address moveq #3,d0 * return bad relocation to main routis,d3 sub.w d7,d3 * subtract bytes to skip from buffer bge skip1 addi #secsize,d3 ffer * d4 is nmbr of words left to relocate * d5 is relocation offset move.l basepg,d1 bsr setdma dseq * if no more words in buffer, refill it tst.w d1 bne rdbad move.l basepg,a3 rts relc1: tst.w -(a2) * point to first word of long move.l (a2),d6 add.l d5,d6 cseg,d5 move.l d5,a2 * relocate cseg first sub.l tstart,d5 * d5 contains the relocation offne rts relabs: relop: bclr #0,d2 * reset long word flag tst.w (a2)+ * point to n *if amt in buffer < # bytes to skip, addq #1,d6 * read in 1 extra sector skip1: move.l basepg,a3 * we will always read into base page * skip past the symbol table move.l symsize,d7 divu #secsize,d move.w #(secsize/2)-1,d3 reloc3: bsr relocword * relocate one word subq.l #1,d4 reloc4: move.l d6,(a2)+ * note that a2 points past long word rts reloc: * Modify address references of coset move.l csize,d4 * nmbr of bytes to relocate move.w #2,loop * we're going to relocate 2 seext word of segment rts rellong: bset #0,d2 * set long word flag tst.w (a2)+ adda #secsize,a3 suba.w d3,a3 * set up a3 to point to buffer lsr #1,d3 * d37 * calculate how many sectors to skip * note that max # symbols is 8k, which is 896 sectors of 128 bytes move.w tst.l d4 * any more to relocate in this segment? bne reloc2 * if yes, do it mde and data segments based on relocation bits * During this routine, * a2 points to text file to relocate * a3 points to relogments reloc1: * relocate one segment clr.l d2 * clear long word flag lsr.l #1,d4 * point to next word of segment rts reldata: relbss: relcode: bclr #0,d2 * long word fla is nmbr words in buffer bra skip3 skip2: bsr readseq * read next symbol table sector ove.l dseg,a2 * else, set up for dseg move.l dsize,d4 sub.w #1,loop bne reloc1 trap #2 * get default disk addq #1,d0 * we want it in range of 1..16 setb3: move.b ds it below previous? bls setb2 move.l (a6),d7 setb2: tst.l (a6)+ * point to next segment w 1 bufbyts: .ds.w 1 .end  after bss segment move.l HiAdr(a0),d7 * d7 contains next segment above bss move.l -4(a1),d6 addsize is swapped with base page size stksize: .ds.l 1 tstart: .ds.l 1 rlbflg: .ds.w 1 dstart: rts setrtn: * Set up the return parameters in Ld Parm Blk and Base Page move.l basepg,BasPage(a0) mo0,(a1)+ * move disk number into base page clr.l d0 * function OK rts .bss dbf d5,setb1 sub.l d6,d7 * diff between bss top and next segment abv move.l d7,(a1)+ w 1 bufbyts: .ds.w 1 .end .l (a1)+,d6 * d6 points to start of free mem after bss movea.l #cseg,a6 * a6 points to segment to try .ds.l 1 bstart: .ds.l 1 cseg: .ds.l 1 dseg: .ds.l 1 bseg: .ds.l 1 bve.l stk,d7 add.l stksize,d7 bclr #0,d7 move.l d7,Stack(a0) move.l basepg,a1 * offsets from start of parameter block FCBPtr = 0 LoAdr = 4 HiAdr = 8 BasPage = 12 * return parameters S* now put disk number that we loaded from into base page movea.l FCBPtr(a0),a2 move.b (w 1 bufbyts: .ds.w 1 .end  moveq #4,d5 * try for all segments clr.l bseg * but force bss not to appear setb1:asepg: .ds.l 1 stk: .ds.l 1 symsize: .ds.l 1 temp: .ds.l 1 loop: .ds move.l LoAdr(a0),(a1)+ move.l HiAdr(a0),(a1)+ move.l cseg,(a1)+ move.l csize,(a1)+ movtack = 16 Flags = 21 hdr: * load file header is read into here magic: .ds.w a2),d0 * get disk select byte bne setb3 * if not auto-select, skip move #25,d0 cmp.l (a6),d6 * segment above bss? bhi setb2 cmp.l (a6),d7 * segment is above bss. I.w 1 bufbyts: .ds.w 1 .end e.l dseg,(a1)+ move.l dsize,(a1)+ move.l bseg,(a1)+ move.l bsize,(a1) * find size of free memory 1 csize: .ds.l 1 dsize: .ds.l 1 bsize: .ds.l 1 bpsize: .ds.l 1 * symb tbl mber */ LONG devadr; /* item nmbr on device to start xfer at */ /* note -- item is sector for disks, byte for char devs *uture, but for now it's unused struct dskinfo { UBYTE *dbuffp; UBYTE *csv; UBYTE *alv; UBYTE blksize; UBYTE didummy;#define redir 4 /* read/write IOByte */ #define exc_vec 5 /* set exception vector */ ot currently used */ #define console 0 #define printer 1 #define disk 2 #define memory 3 /* gets TPA boundaries */ / UWORD xferlen; /* number items to transfer */ UBYTE *xferadr; /* memory address to xfer to/from */ struct dph *infop; UWORD dskmax; UWORD dirmax; UWORD chksize; }; */ struct iopb { UBYTE iofcn; /* function number, see defines /******************************************************** * * * CP/M-68K header file * * Copyright (c) 1982 by D #define redir 4 /* read/write IOByte */ #define exc_vec 5 /* set exception vector */  /* pointer to disk parameter header */ /* return parm for fcn 0, input for rest */ }; /* Definitions for iofcn, tbelow */ UBYTE ioflags; /* used for login flag and write flag */ UBYTE devtype; /* device type, see defines below */ igital Research, Inc. * * Structure definitions for doing I/O in packets * * * *************************************#define redir 4 /* read/write IOByte */ #define exc_vec 5 /* set exception vector */ he function number */ #define sel_info 0 /* select and return info on device */ #define read 1 #define write 2 #define /* currently unused */ UBYTE devnum; /* device number, or, devtype and devnum taken together form int device nu*******************/ /* May use this information structure instead of disk parameter header and disk parameter block in f#define redir 4 /* read/write IOByte */ #define exc_vec 5 /* set exception vector */  flush 3 #define status 4 /* not currently used */ /* Definitions for devtype, the device type */ /* This field nam Load * * * * March 17, 1983 * * * * Does not load program root. * * Leaves base page and stack as * * set0 stack: .ds.w 1 .end es readseq: * CP/M read sequential function move.l d0,-(sp) * save return parm move.l FCBPtr(a0),d1 moveq #20,d0 * re* * * * * * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM * * ==================================ntry point for Program Load routine _loadr: clr.l d0 * start with return parm cleared bsr gethdr * get header tst d0 up by actual BDOS 59 * * * ********************************* .globl _loadr * this routine is public secsize = 128 0 stack: .ds.w 1 .end ad seq function trap #2 * call bdos move.l d0,d1 * return parm in d1 move.l (sp)+,d0 rts setdma: * CP/M set dma ================ * ************************************************************************* .globl stack .bss .ds.l 4bne lddone * if unsuccessful, return bsr setaddr * set up load addresses tst d0 bne lddone * if unsuccessful, return * CP/M sector size * d0 always contains the return parameter from pgmld * d1 is the return register from local subroutines function move.l d0,-(sp) * save return parm moveq #26,d0 * set dma function trap #2 * call bdos move.l (sp)+,d0 * rest00 stack: .ds.w 1 .end bsr rdtxt * read code and data text segments into mem tst d0 bne lddone * if unsuccessful, return move.l tstart,d7 cmp * a0 contains the pointer to the Load Parm Block passed to pgmld * Return parameters in d0 are: * 00 - function successful ********************************* * * * Relocating overlay loader * * modified from * * Function 59 -- Progrore d0 rts gethdr: * Get header into buffer in data segment move.l BasPage(a0),d1 move.l d1,basepg bsr setdma bs0 stack: .ds.w 1 .end .l cseg,d7 beq noreloc bsr reloc * do relocation if necessary noreloc: tst d0 bne lddone lddone: rts * Subroutin************************************************************************* * * * THIS IS THE SYSTEM STACK AREA * 01 - insufficient memory or bad header in file * 02 - read error on file * 03 - bad relocation information in file * Er readseq tst d1 * read ok? bne badhdr * if no, return bad moveq #18,d7 movea.l BasPage(a0),a5 movea.l #hdr,a6 geth cmp.l d3,d2 * have at least one more full sector? blt rdtxt6 move.l a2,d1 bsr setdma * if yes, set up dma address bsve.w d7,bufbyts * indicate # bytes of text in buffer move.w #2,loop * do for code, data segments move.l cseg,a2 * start atrelcode bra relbss bra relbad bra rellong bra relbad bra relop relbad: move.l (sp)+,d0 * pop return address moveqbuf: * move (d3) bytes from the base page buffer to (a2) * uses d6 movea.l basepg,a1 move.l #secsize,d6 sub.w bufbyts,d6e.l dsize,d2 sub.w #1,loop bne rdtxt3 move.l bseg,a2 * clear the bss segment move.l bsize,d2 beq rdtxt8 rdtxt7: clr.1: move.w (a5)+,(a6)+ * move header into hdr dbf d7,geth1 rts badhdr: moveq #2,d0 rts setaddr: * Set up load addresr readseq * read next sector tst.w d1 bne rdbad * if no good, exit sub.l d3,d2 * decrement # bytes to load adda.l #se cseg move.l csize,d2 * for csize bytes rdtxt3: clr.l d3 move.w bufbyts,d3 cmp.l d2,d3 * # bytes in buffer >= # bytes #3,d0 * return bad relocation to main routine rts relabs: relop: bclr #0,d2 * reset long word flag tst.w (a2)+ * poi * address to move from = adda.w d6,a1 * (basepg) + secsize - (bufbyts) sub.w d3,bufbyts * update # bytes buffered bra mob (a2)+ subq.l #1,d2 bne rdtxt7 rdtxt8: rts rdbad: moveq.l #2,d0 rts relocword: * relocate word at (a2) based onses for cseg, dseg, bss, basepg, and stack move.w magic,d6 cmpi.w #$601a,d6 bne badadr * if magic nmbr <> 601a, skip mocsize,a2 * increment dma address bra rdtxt5 rdtxt6: tst.l d2 * any more bytes to read? beq finrd move.l basepg,d1 bsto load? blt rdtxt4 move.l d2,d3 bsr movebuf * if yes, move # bytes to load bra finrd rdtxt4: sub.l d3,d2 * if no, nt to next word of segment rts rellong: bset #0,d2 * set long word flag tst.w (a2)+ * point to next word of segment veb2 moveb1: move.b (a1)+,(a2)+ * do the move moveb2: dbf d3,moveb1 rts rdtxt: * Read code and data text into memory reloc bits at (a3) * lsb of d2 indicates whether previous word was 1st half of long-word move.w (a3)+,d7 * get relocation inve.l bpsize,symsize move.l LoAdr(a0),cseg move.l cseg,d7 add.l csize,d7 addq.l #1,d7 bclr #0,d7 move.l d7,dseg addr setdma bsr readseq * if yes, read into base page tst.w d1 bne rdbad move.w d3,bufbyts * indicate that we've buffered update # bytes to load bsr movebuf * move remainder of buffer move.l #secsize,d3 * d3 = secsize fo following loop rdtxt5: rts reldata: relbss: relcode: bclr #0,d2 * long word flag set? bne relc1 * if yes, skip move.w (a2),d6 add.w d5,* during this routine, a2 is always the load address, * d2 is number of bytes left to load move.w #secsize-28,d7 mofo andi.w #7,d7 * strip off symbol table bits lsl #1,d7 * multiply by 2 jmp 2(pc,d7) bra relabs bra reldata bra .l dsize,d7 addq.l #1,d7 bclr #0,d7 move.l d7,bseg * cseg, dseg, bseg set up rts badadr: moveq.l #1,d0 rts movea sector move.l d2,d3 bsr movebuf * move remainder of segment finrd: move.l dseg,a2 * set up to load data segment movd6 move.w d6,(a2)+ rts relc1: tst.w -(a2) * point to first word of long move.l (a2),d6 add.l d5,d6 move.l d6,(a2)+s bra reloc4 reloc2: subq.w #1,d3 bpl reloc3 bsr readseq * if no more words in buffer, refill it tst.w d1 bne rdba#1,d3 * d3 is nmbr words in buffer bra skip3 skip2: bsr readseq * read next symbol table sector tst.w d1 bne rdbad sl table move.l symsize,d7 divu #secsize,d7 * calculate how many sectors to skip * note that max # symbols is 8k, which is 8ize: .ds.l 1 * symb tbl size is swapped with base page size stksize: .ds.l 1 tstart: .ds.l 1 rlbflg: .ds.w 1 dstart: .ds * note that a2 points past long word rts reloc: * Modify address references of code and data segments based on relocatid move.l basepg,a3 move.w #(secsize/2)-1,d3 reloc3: bsr relocword * relocate one word subq.l #1,d4 reloc4: tst.l d4 kip3: dbf d6,skip2 * we got past symbol table * a3, d3 are set up move.l cseg,d5 move.l d5,a2 * relocate cseg first sub96 sectors of 128 bytes move.w d7,d6 * d6 is nmbr sectors to skip swap d7 * d7 is nmbr bytes to skip move.w bufbyts,d3 .l 1 bstart: .ds.l 1 cseg: .ds.l 1 dseg: .ds.l 1 bseg: .ds.l 1 basepg: .ds.l 1 symsize: .ds.l 1 temp: .ds.l 1 on bits * During this routine, * a2 points to text file to relocate * a3 points to relocation word in basepg * lsb of d2 is * any more to relocate in this segment? bne reloc2 * if yes, do it move.l dseg,a2 * else, set up for dseg move.l dsize,.l tstart,d5 * d5 contains the relocation offset move.l csize,d4 * nmbr of bytes to relocate move.w #2,loop * we're going t* * BDOS Function Definitions * reboot = 0 printstr = 9 open = 15 setdma = 26 pgmldf = 59 gettpa sub.w d7,d3 * subtract bytes to skip from buffer bge skip1 addi #secsize,d3 *if amt in buffer < # bytes to skip, addq #1loop: .ds.w 1 bufbyts: .ds.w 1 .end long word flag (set on reloc type 5, reset on next word) * d3 is # words in relocation buffer * d4 is nmbr of words left to red4 sub.w #1,loop bne reloc1 rts .bss * offsets from start of parameter block FCBPtr = 0 LoAdr = 4 BasPageo relocate 2 segments reloc1: * relocate one segment clr.l d2 * clear long word flag lsr #1,d4 * make d4 indicate # word = 63 * .globl _ovhdlr .xdef _loadr .text * _ovhdlr:move sr,savecc * save condition codes movem.l d1-d7/a0-a6,saver,d6 * read in 1 extra sector skip1: move.l basepg,a3 adda #secsize,a3 suba.w d3,a3 * set up a3 to point to buffer lsr oop: .ds.w 1 bufbyts: .ds.w 1 .end locate * d5 is relocation offset move.l basepg,d1 bsr setdma * we will always read into base page * skip past the symbo = 12 hdr: * load file header is read into here magic: .ds.w 1 csize: .ds.l 1 dsize: .ds.l 1 bsize: .ds.l 1 bps * save all registers movea.l (a7)+,a6 * pop pointer to inline parameter move.l #4,d6 * adjust return address add.l a6,#printstr,d0 *get BDOS function number trap #2 *print the message move.b #36,ex *mark end of filename move.linto register a0 jsr _loadr *load the module tst d0 *was the load successful? bne lderr *if not then print error messag *Base page address of loaded program usrstk: .ds.l 1 *Loaded program's initial stack pointer flags: .ds.w 1 *int address * * OPEN OVERLAY FILE * move.l #fcb,d1 movea.l d1,a1 move.w #open,d0 *put BDOS function number in register.ds.w 64 * input buffer (like basepage) for loadr * * FILE CONTROL BLOCK * .even fcb: .ds.b 1 * file control block fnamd6 * to skip over table pointer move.l d6,-(a7) * push return address * * GET FILE NAME AND LOAD PT * movea.l (a6),a6 #fname,d1 *get address of filename move.w #printstr,d0 *set up for BDOS call trap #2 *print the filename cmdrtn: move.w #e * * RESTORE AND RETURN * done: movem.l saver,d1-d7/a0-a6 * restore all registers move savecc,ccr * restore condition coLoad program function control flags .end  d0 trap #2 *try to open the file to be loaded cmpi #255,d0 *test d0 for BDOS error return code beq openerr *if d0 = 25e: .ds.b 11 ex: .ds.b 1 sysjnk: .ds.b 19 cr: .ds.b 1 * * LOAD PARAMETER BLOCK * .even LPB: .ds.l 1 *FCB address * get ovl table address move.l a6,d5 * check address with last loaded cmp.l oldadd,d5 * if it's the same, beq donereboot,d0 *get BDOS function number trap #2 *warmboot and return to the CCP * * DATA * .data * * ERROR Mdes rts * * PRINT ERROR MESSAGE * openerr: move.l #openmsg,d1 *get address of error message * oad program function control flags .end 5 then goto openerr move.b #0,cr *zero record number in fcb * * FILL THE LPB * lea ovbspg,a3 * get address of input buff of program file lowadr: .ds.l 1 *Low boundary of area in which * *to load program hiad * file is already loaded. move.l a6,oldadd * save address for next time lea.l fname,a5 * get address of name in fcb ESSAGE STRINGS * .even loaderr: .dc.b 13,10,'Error Loading Overlay File $' openmsg: .dc.b 13,10,'Unable to Open Overlay F *to be printed bra print lderr: move.l #loaderr,d1 *get address of error message to * *be printed print: move.w er move.l a3,baspag * put it in LPB move.l a1,LPB *put address of open FCB into LPB move.l #LPB,a0 *put address of LPB r: .ds.l 1 *High boundary of area in which to * *to load program baspag: .ds.l 1 move.l #11,d5 * set up loop counter (l2 cycles) gfnm: move.b (a6)+,(a5)+ dbf d5,gfnm move.l (a6),lowadr * store load poile $' * * BSS * .bss .even oldadd: .ds.l 1 * table for last loaded overlay savecc: .ds.w 1 saver: .ds.l 14 ovbspg: / /* 68000 version */ #define VAX 1 /* VAX Version */ /*#define PDP11 1*/ /* PDP-11 Version*/ /*#define CPM 1*/ /* CP/M Ope FOOBAZ2$' .end  System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ /*#define VMS 1*/ /* VMS Operating System*/ 8000 version */ /*#define VAX 1*/ /* VAX Version */ /*#define PDP11 1*/ /* PDP-11 Version*/ #define CPM 1 /* CP/M Operatingrating System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ #define VMS 1 /* VMS Operating System*/ System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ /*#define VMS 1*/ /* VMS Operating System*/  System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ /*#define VMS 1*/ /* VMS Operating System*/ ating System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ #define VMS 1 /* VMS Operating System*/ System*/ /*#define UNIX 1*/ /* UNIX Operating System*/ /*#define VMS 1*/ /* VMS Operating System*/ /* * Use this file to determine what kind of machine you want the * Alcyon stuff to run on .... */ #define MC68000 1 /* 6 /* * Use this file to determine what kind of machine you want the * Alcyon stuff to run on .... */ /*#define MC68000 1*M FOOBAZ2$' .end 8000 version */ /*#define VAX 1*/ /* VAX Version */ /*#define PDP11 1*/ /* PDP-11 Version*/ #define CPM 1 /* CP/M Operating/* * Use this file to determine what kind of machine you want the * Alcyon stuff to run on .... */ #define MC68000 1 /* 6