Digital Research
This commit is contained in:
2020-11-06 18:50:37 +01:00
parent 621ed8ccaf
commit 31738079c4
8481 changed files with 1888323 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
all:
gcc -o exchange -g -fno-builtin -DRLI *c

View File

@@ -0,0 +1,84 @@
Greetings!
This is a utility that allows CP/M disk images to be manipulated under
Unix. It supports disk images in either the standard 8" SSSD format or
the P112 3.5" format. Disk images can be examined and files imported and
exported from them.
The source is a slightly hacked over copy of CP/M-68K which has
been worked over to allow compilation using GCC, to wit:
- A handful of typecasts have been dropped in.
- An assumption that an int is 16 bits has been fixed.
- An assumption that chars are signed has been fixed.
- The file diverge.h renames all of the globals to ensure they
don't collide with operating system globals.
- I changed the way the BDOS communicates with the BIOS; see
biosdef.h
- There are probably a couple of other minor changes I made that
I've forgotten (perhaps renaming a routine or two before I
decided to make diverge.h).
- A BIOS that allows the program to be run under Unix.
I've also added a couple of built-in commands:
- EXIT causes CP/M-68K to exit, returning to the host operating
system.
- IMPORT copies a file from the current directory of the host
operating system into the disk image.
- EXPORT copies a file from the disk image into the current
directory of the host operating system.
IMPORT and EXPORT do not accept wildcards. This is just a quickie hack
that turned out to be useful, not a snazzy disk image manipulation
program.
To build the program, execute make. This results in an executable called
exchange. The command-line syntax is:
exchange [-p112] file.img
-p112 This option tells the file to use the P112 3.5" disk format
for the image. By default, the the standard 8" SSSD format is
used.
file.img is the name of the disk image that should be used.
In this example, I copy the file BDOS.LST from an 8" SSSD image
containing CP/M 1.4 sources (obtained from http://cpm.z80.de/) to user 1
of the P112 boot disk image (obtained from
http://members.iinet.net.au/~daveb/p112/p112.html):
> mac> uname -a
> Linux mac.no.domain 2.4.22-2f #1 Sun Nov 9 16:49:49 EST 2003 ppc ...
> mac> ls
> bdosPLM.img bootdisk.img exchange
> mac> ./exchange bdosPLM.img
>
> A>dir
> A: BDOSI SRC : BDOS PLM : BDOS OBJ : BDOS LST
> A>export BDOS.LST
> export BDOS .LST -> BDOS.LST
> A>exit
> mac> ls
> BDOS.LST bdosPLM.img bootdisk.img exchange
> mac> ./exchange -p112 bootdisk.img
>
> A>user 1
>
> 1A>dir
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
> A: ROM PAS : ROM COM
> 1A>import bdos.lst
> import BDOS.LST -> BDOS .LST
> 1A>dir
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
> A: ROM PAS : ROM COM : BDOS LST
> 1A>exit
> mac>
Enjoy!
Roger Ivie
anachronda@hotmail.com

View File

@@ -0,0 +1,89 @@
Program by Roger Ivie. Exchange is a utility that allows CP/M disk images to be manipulated under Unix. It supports disk images in either the standard 8" SSSD format or the P112 3.5" format. Disk images can be examined and files imported and exported from them.
The source is a slightly hacked over copy of CP/M-68K BDOS and CCP which has been worked over to allow compilation using GCC.
/README
Greetings!
This is a utility that allows CP/M disk images to be manipulated under
Unix. It supports disk images in either the standard 8" SSSD format or
the P112 3.5" format. Disk images can be examined and files imported and
exported from them.
The source is a slightly hacked over copy of CP/M-68K which has
been worked over to allow compilation using GCC, to wit:
- A handful of typecasts have been dropped in.
- An assumption that an int is 16 bits has been fixed.
- An assumption that chars are signed has been fixed.
- The file diverge.h renames all of the globals to ensure they
don't collide with operating system globals.
- I changed the way the BDOS communicates with the BIOS; see
biosdef.h
- There are probably a couple of other minor changes I made that
I've forgotten (perhaps renaming a routine or two before I
decided to make diverge.h).
- A BIOS that allows the program to be run under Unix.
I've also added a couple of built-in commands:
- EXIT causes CP/M-68K to exit, returning to the host operating
system.
- IMPORT copies a file from the current directory of the host
operating system into the disk image.
- EXPORT copies a file from the disk image into the current
directory of the host operating system.
IMPORT and EXPORT do not accept wildcards. This is just a quickie hack
that turned out to be useful, not a snazzy disk image manipulation
program.
To build the program, execute make. This results in an executable called
exchange. The command-line syntax is:
exchange [-p112] file.img
-p112 This option tells the file to use the P112 3.5" disk format
for the image. By default, the the standard 8" SSSD format is
used.
file.img is the name of the disk image that should be used.
In this example, I copy the file BDOS.LST from an 8" SSSD image
containing CP/M 1.4 sources (obtained from http://cpm.z80.de/) to user 1
of the P112 boot disk image (obtained from
http://members.iinet.net.au/~daveb/p112/p112.html):
> mac> uname -a
> Linux mac.no.domain 2.4.22-2f #1 Sun Nov 9 16:49:49 EST 2003 ppc ...
> mac> ls
> bdosPLM.img bootdisk.img exchange
> mac> ./exchange bdosPLM.img
>
> A>dir
> A: BDOSI SRC : BDOS PLM : BDOS OBJ : BDOS LST
> A>export BDOS.LST
> export BDOS .LST -> BDOS.LST
> A>exit
> mac> ls
> BDOS.LST bdosPLM.img bootdisk.img exchange
> mac> ./exchange -p112 bootdisk.img
>
> A>user 1
>
> 1A>dir
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
> A: ROM PAS : ROM COM
> 1A>import bdos.lst
> import BDOS.LST -> BDOS .LST
> 1A>dir
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
> A: ROM PAS : ROM COM : BDOS LST
> 1A>exit
> mac>
Enjoy!
Roger Ivie
anachronda@hotmail.com

View File

@@ -0,0 +1,180 @@
/********************************************************
* *
* CP/M-68K header file *
* Copyright (c) 1982 by Digital Research, Inc. *
* Structure definitions for BDOS globals *
* and BDOS data structures *
* *
* Desecrated 6-Aug-83 (sw) for type-ahead *
* Again 17-Mar-84 (sw) for chaining *
* *
********************************************************/
/**************************************************************************
The BDOS data structures, especially those relating to global variables,
are structured in a way that hopefully will enable this BDOS, in the future,
to easily become a re-entrant multi-tasking file system. Consequently,
the BDOS global variables are divided into two classes. Those that are
truly global, even in the case of multiple tasks using the file system
concurrently, are simply declared as global variables in bdosmain.c.
Only a few "globals" are really global in this sense.
The majority of the "global" variables are actually state variables that
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 in a multi-thread model they're
not. This type of variables is put into a data structure, with the
intention that in the multi-task environment this structure will be based.
The following declarations take this philosophy into account, and define
a simple structure for the single thread environment while leaving the
possibilities open for the multi-thread environment.
****************************************************************************/
#define snglthrd TRUE
/* TRUE for single-thread environment
FALSE to create based structure for re-entrant model */
#if snglthrd
#define GBL gbls
/* In single thread case, GBL just names
the structure */
#define BSETUP EXTERN struct stvars gbls;
/* and BSETUP defines the extern structure */
#endif
#if ! snglthrd
#define GBL (*statep)
/* If multi-task, state vars are based */
#define BSETUP REG struct stvars *statep; \
statep = &gbls;
/* set up pointer to state variables */
/* This is intended as an example to show the intent */
#endif
/* Note that there are a few critical regions in the file system that must
execute without interruption. They pertain mostly to the manipulation of
the allocation vector. This isn't a problem in a single-thread model, but
must be provided for in a multi-tasking file system. Consequently, the
primitives LOCK and UNLOCK are defined and used where necessary in the
file system. For the single thread model, they are null routines */
#define LOCK /**/
#define UNLOCK /**/
/* Be sure LOCK and UNLOCK are implemented to allow recursive calls to LOCK.
That is, if a process that calls LOCK already owns the lock, let it proceed,
but remember that only the outer-most call to UNLOCK really releases the
file system. */
#define VERSION 0x2022 /* Version number for CP/M-68K */
#define robit 0 /* read-only bit in file type field of fcb */
#define arbit 2 /* archive bit in file type field of fcb */
#define SECLEN 128 /* length of a CP/M sector */
/* File Control Block definition */
struct fcb
{
UBYTE drvcode; /* 0 = default drive, 1..16 are drives A..P */
UBYTE fname[8]; /* File name (ASCII) */
UBYTE ftype[3]; /* File type (ASCII) */
UBYTE extent; /* Extent number (bits 0..4 used) */
UBYTE s1; /* Reserved */
UBYTE s2; /* Module field (bits 0..5), write flag (7) */
UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
union
{
UBYTE small[16]; /* 16 block numbers of 1 byte */
WORD big[8]; /* or 8 block numbers of 1 word */
} dskmap;
UBYTE cur_rec; /* current record field */
UBYTE ran0; /* random record field (3 bytes) */
UBYTE ran1;
UBYTE ran2;
};
/* Declaration of directory entry */
struct dirent
{
UBYTE entry; /* 0 - 15 for user numbers, E5 for empty */
/* the rest are reserved */
UBYTE fname[8]; /* File name (ASCII) */
UBYTE ftype[3]; /* File type (ASCII) */
UBYTE extent; /* Extent number (bits 0..4 used) */
UBYTE s1; /* Reserved */
UBYTE s2; /* Module field (bits 0..5), write flag (7) */
UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
union
{
UBYTE small[16]; /* 16 block numbers of 1 byte */
WORD big[8]; /* or 8 block numbers of 1 word */
} dskmap;
};
/* Declaration of disk parameter tables */
struct dpb /* disk parameter table */
{
UWORD spt; /* sectors per track */
UBYTE bsh; /* block shift factor */
UBYTE blm; /* block mask */
UBYTE exm; /* extent mask */
UBYTE dpbdum; /* dummy byte for fill */
UWORD dsm; /* max disk size in blocks */
UWORD drm; /* max directory entries */
UWORD dir_al; /* initial allocation for dir */
UWORD cks; /* number dir sectors to checksum */
UWORD trk_off; /* track offset */
};
struct dph /* disk parameter header */
{
UBYTE *xlt; /* pointer to sector translate table */
UWORD hiwater; /* high water mark for this disk */
UWORD dum1; /* dummy (unused) */
UWORD dum2;
UBYTE *dbufp; /* pointer to 128 byte directory buffer */
struct dpb *dpbp; /* pointer to disk parameter block */
UBYTE *csv; /* pointer to check vector */
UBYTE *alv; /* pointer to allocation vector */
};
/* Declaration of structure containing "global" state variables */
#define TBUFSIZ 126 /*sw # typed-ahead characters */
struct stvars
{
UBYTE kbchar; /* keyboard type-ahead buffer count */
UBYTE delim; /* Delimiter for function 9 */
BOOLEAN lstecho; /* True if echoing console output to lst: */
BOOLEAN echodel; /* Echo char when getting <del> ? */
UWORD column; /* CRT column number for expanding tabs */
UBYTE curdsk; /* Currently selected disk */
UBYTE dfltdsk; /* Default disk (last selected by fcn 14) */
UBYTE user; /* Current user number */
struct dph *dphp; /* pointer to disk parm hdr for cur disk */
struct dirent *dirbufp; /* pointer for directory buff for process */
/* stored here so that each process can */
/* have a separate dirbuf. */
struct dpb *parmp; /* pointer to disk parameter block for cur */
/* disk. Stored here to save ref calc */
UWORD srchpos; /* position in directory for search next */
UBYTE *dmaadr; /* Disk dma address */
struct fcb *srchp; /* Pointer to search FCB for function 17 */
UBYTE *excvec[18]; /* Array of exception vectors */
UBYTE *insptr; /*sw Insertion pointer for typeahead */
UBYTE *remptr; /*sw Removal pointer for typeahead */
UBYTE t_buff[TBUFSIZ]; /*sw Type-ahead buffer itself */
};
/*sw removed next line from structure */
UBYTE *chainp; /* Used for chain to program call */
/* Console buffer structure declaration */
struct conbuf
{
UBYTE maxlen; /* Maximum length from calling routine */
UBYTE retlen; /* Length actually found by BDOS */
UBYTE cbuf[0]; /* Console data */
};

View File

@@ -0,0 +1,68 @@
/*****************************************************************************
*
* C P / M C H E A D E R F I L E
* -----------------------------------
* Copyright 1982 by Digital Research Inc. All rights reserved.
*
* This is an include file for assisting the user to write portable
* programs for C.
*
*****************************************************************************/
#define ALCYON 1 /* using Alcyon compiler */
/*
* Standard type definitions
*/
/***************************/
#define BYTE signed char /* Signed byte */
#define BOOLEAN char /* 2 valued (true/false) */
#define WORD short /* Signed word (16 bits) */
#define UWORD unsigned short int /*** rli ***/ /* unsigned word */
#define LONG long /* signed long (32 bits) */
#define ULONG unsigned long /* Unsigned long */
#define REG register /* register variable */
#define LOCAL auto /* Local var on 68000 */
#define EXTERN extern /* External variable */
#define MLOCAL static /* Local to module */
#define GLOBAL /**/ /* Global variable */
#define VOID /**/ /* Void function return */
/***************************/
#ifdef ALCYON
#define UBYTE char
#define UBWORD(a) ((UWORD)a & 0xff)
/* Unsigned byte to word cast */
#else
#define UBYTE unsigned char /* Unsigned byte */
#define UBWORD(a) (UWORD)a
#endif
/****************************************************************************/
/* Miscellaneous Definitions: */
/****************************************************************************/
#define FAILURE (-1) /* Function failure return val */
#define SUCCESS (0) /* Function success return val */
#define YES 1 /* "TRUE" */
#define NO 0 /* "FALSE" */
#define FOREVER for(;;) /* Infinite loop declaration */
#define NULL (BYTE *)0 /* Null pointer value */
#define EOF (-1) /* EOF Value */
#define TRUE (1) /* Function TRUE value */
#define FALSE (0) /* Function FALSE value */
/****************************************************************************/
/* */
/* M A C R O S */
/* ----------- */
/* */
/* Define some stuff as macros .... */
/* */
/****************************************************************************/
#define abs(x) ((x) < 0 ? -(x) : (x)) /* Absolute value function */
#define max(x,y) (((x) > (y)) ? (x) : (y)) /* Max function */
#define min(x,y) (((x) < (y)) ? (x) : (y)) /* Min function */
/*************************** end of stdio.h *********************************/

View File

@@ -0,0 +1,307 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS Main Routine *
* *
* This is the main routine for the BDOS for CP/M-68K *
* It has one entry point, _bdos, which is called from *
* the assembly language trap handler found in bdosif.s. *
* The parameters are a function number (integer) and an *
* information parameter (which is passed from bdosif as *
* both an integer and a pointer). *
* The BDOS can potentially return a pointer, long word, *
* or word *
* *
* Configured for Alcyon C on the VAX *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "biosdef.h" /* Declarations of BIOS functions */
/* Declare EXTERN functions */
EXTERN warmboot(); /* Warm Boot function */
EXTERN BOOLEAN constat(); /* Console status */
EXTERN UBYTE conin(); /* Console Input function */
EXTERN tabout(); /* Console output with tab expansion */
EXTERN UBYTE rawconio(); /* Raw console I/O */
EXTERN prt_line(); /* Print line until delimiter */
EXTERN readline(); /* Buffered console read */
EXTERN seldsk(); /* Select disk */
EXTERN BOOLEAN openfile(); /* Open File */
EXTERN UWORD close_fi(); /* Close File */
EXTERN UWORD search(); /* Search first and next fcns */
EXTERN UWORD dirscan(); /* General directory scanning routine */
EXTERN UWORD bdosrw(); /* Sequential and Random disk read/write */
EXTERN BOOLEAN create(); /* Create file */
EXTERN BOOLEAN delete(); /* Delete file */
EXTERN BOOLEAN rename(); /* Rename file */
EXTERN BOOLEAN set_attr(); /* Set file attributes */
EXTERN getsize(); /* Get File Size */
EXTERN setran(); /* Set Random Record */
EXTERN free_sp(); /* Get Disk Free Space */
EXTERN UWORD flushit(); /* Flush Buffers */
EXTERN UWORD pgmld(); /* Program Load */
EXTERN UWORD setexc(); /* Set Exception Vector */
EXTERN set_tpa(); /* Get/Set TPA Limits */
EXTERN move(); /* general purpose byte mover */
/* Declare "true" global variables; i.e., those which will pertain to the
entire file system and thus will remain global even when this becomes
a multi-tasking file system */
GLOBAL UWORD log_dsk; /* 16-bit vector of logged in drives */
GLOBAL UWORD ro_dsk; /* 16-bit vector of read-only drives */
GLOBAL UWORD crit_dsk; /* 16-bit vector of drives in "critical"
state. Used to control dir checksums */
GLOBAL BYTE *tpa_lp; /* TPA lower boundary (permanent) */
GLOBAL BYTE *tpa_lt; /* TPA lower boundary (temporary) */
GLOBAL BYTE *tpa_hp; /* TPA upper boundary (permanent) */
GLOBAL BYTE *tpa_ht; /* TPA upper boundary (temporary) */
/* Declare the "state variables". These are globals for the single-thread
version of the file system, but are put in a structure so they can be
based, with a pointer coming from the calling process */
GLOBAL struct stvars gbls;
struct tempstr
{
UBYTE tempdisk;
BOOLEAN reselect;
struct fcb *fptr;
};
/****************************************************************
* *
* _bdos MAIN ROUTINE *
* *
* Called with _bdos(func, info, infop) *
* *
* Where: *
* func is the BDOS function number (d0.w) *
* info is the word parameter (d1.w) *
* infop is the pointer parameter (d1.l) *
* note that info is the word form of infop*
* *
****************************************************************/
UWORD _bdos(func,info,infop)
REG WORD func; /* BDOS function number */
REG UWORD info; /* d1.w word parameter */
REG UBYTE *infop; /* d1.l pointer parameter */
{
REG UWORD rtnval;
LOCAL struct tempstr temp;
BSETUP
temp.reselect = FALSE;
temp.fptr = (void *)infop;
rtnval = 0;
switch (func) /* switch on function number */
{
case 0: warmboot(0); /* warm boot function */
/* break; */
case 1: return((UWORD)conin()); /* console input function */
/* break; */
case 2: tabout((UBYTE)info); /* console output with */
break; /* tab expansion */
case 3: return((UWORD)brdr()); /* get reader from bios */
/* break; */
case 4: bpun((UBYTE)info); /* punch output to bios */
break;
case 5: blstout((UBYTE)info); /* list output from bios */
break;
case 6: return((UWORD)rawconio(info)); /* raw console I/O */
/* break; */
case 7: return(bgetiob()); /* get i/o byte */
/* break; */
case 8: bsetiob(info); /* set i/o byte function */
break;
case 9: prt_line(infop); /* print line function */
break;
case 10: readline(infop); /* read buffered con input */
break;
case 11: return((UWORD)constat()); /* console status */
/* break; */
case 12: return(VERSION); /* return version number */
/* break; */
case 13: log_dsk = 0; /* reset disk system */
ro_dsk = 0;
crit_dsk= 0;
GBL.curdsk = 0xff;
GBL.dfltdsk = 0;
break;
case 14: seldsk((UBYTE)info); /* select disk */
GBL.dfltdsk = (UBYTE)info;
break;
case 15: tmp_sel(&temp); /* open file */
((struct fcb *)infop)->extent = 0;
((struct fcb *)infop)->s2 = 0;
rtnval = dirscan(openfile, infop, 0);
break;
case 16: tmp_sel(&temp); /* close file */
rtnval = close_fi(infop);
break;
case 17: GBL.srchp = (void *)infop; /* search first */
rtnval = search(infop, 0, &temp);
break;
case 18: infop = (void *)GBL.srchp; /* search next */
temp.fptr = (void *)infop;
rtnval = search(infop, 1, &temp);
break;
case 19: tmp_sel(&temp); /* delete file */
rtnval = dirscan(delete, infop, 2);
break;
case 20: tmp_sel(&temp); /* read sequential */
rtnval = bdosrw(infop, TRUE, 0);
break;
case 21: tmp_sel(&temp); /* write sequential */
rtnval = bdosrw(infop, FALSE, 0);
break;
case 22: tmp_sel(&temp); /* create file */
((struct fcb *)infop)->extent = 0;
((struct fcb *)infop)->s1 = 0;
((struct fcb *)infop)->s2 = 0;
((struct fcb *)infop)->rcdcnt = 0;
/* Zero extent, S1, S2, rcrdcnt. create zeros rest */
rtnval = dirscan(create, infop, 8);
break;
case 23: tmp_sel(&temp); /* rename file */
rtnval = dirscan(rename, infop, 2);
break;
case 24: return(log_dsk); /* return login vector */
/* break; */
case 25: return(UBWORD(GBL.dfltdsk)); /* return current disk */
/* break; */
case 26: GBL.dmaadr = infop; /* set dma address */
break;
/* No function 27 -- Get Allocation Vector */
case 28: ro_dsk |= 1<<GBL.dfltdsk; /* set disk read-only */
break;
case 29: return(ro_dsk); /* get read-only vector */
/* break; */
case 30: tmp_sel(&temp); /* set file attributes */
rtnval = dirscan(set_attr, infop, 2);
break;
case 31: if (GBL.curdsk != GBL.dfltdsk) seldsk(GBL.dfltdsk);
move( (GBL.parmp), infop, sizeof *(GBL.parmp) );
break; /* return disk parameters */
case 32: if ( (info & 0xff) <= 15 ) /* get/set user number */
GBL.user = (UBYTE)info;
return(UBWORD(GBL.user));
/* break; */
case 33: tmp_sel(&temp); /* random read */
rtnval = bdosrw(infop, TRUE, 1);
break;
case 34: tmp_sel(&temp); /* random write */
rtnval = bdosrw(infop, FALSE, 1);
break;
case 35: tmp_sel(&temp); /* get file size */
getsize(infop);
break;
case 36: tmp_sel(&temp); /* set random record */
setran(infop);
break;
case 37: info = ~info; /* reset drive */
log_dsk &= info;
ro_dsk &= info;
crit_dsk &= info;
break;
case 40: tmp_sel(&temp); /* write random with 0 fill */
rtnval = bdosrw(infop, FALSE, 2);
break;
case 46: free_sp(info); /* get disk free space */
break;
case 47: chainp = GBL.dmaadr; /*sw chain to program */
warmboot(0); /* terminate calling program */
/* break; */
case 48: return( flushit() ); /* flush buffers */
/* break; */
case 59: return(pgmld(infop,GBL.dmaadr)); /* program load */
/* break; */
case 61: return(setexc(infop)); /* set exception vector */
/* break; */
case 63: set_tpa(infop); /* get/set TPA limits */
break;
default: return(-1); /* bad function number */
/* break; */
}; /* end of switch statement */
if (temp.reselect) ((struct fcb *)infop)->drvcode = temp.tempdisk;
/* if reselected disk, restore it now */
return(rtnval); /* return the BDOS return value */
} /* end _bdos */
tmp_sel(temptr) /* temporarily select disk pointed to by fcb */
REG struct tempstr *temptr;
{
REG struct fcb *fcbp;
REG UBYTE tmp_dsk;
BSETUP
fcbp = temptr->fptr; /* get local copy of fcb pointer */
tmp_dsk = (temptr->tempdisk = fcbp->drvcode);
seldsk( tmp_dsk ? tmp_dsk - 1 : GBL.dfltdsk );
fcbp->drvcode = GBL.user;
temptr->reselect = TRUE;
}

View File

@@ -0,0 +1,324 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS Miscellaneous Module *
* *
* This module contains miscellaneous loose ends for *
* CP/M-68K. Included are: *
* *
* bdosinit() - BDOS initialization routine *
* called from CCP for system init *
* warmboot() - BDOS warm boot exit routine *
* error() - BDOS error printing routine *
* ro_err() - BDOS read-only file error routine *
* setexc() - BDOS set exception vector *
* set_tpa() - BDOS get/set TPA limits *
* serial # and copyright notice, machine readable *
* *
* *
* Configured for Alcyon C on the VAX *
* *
* Modified 2/5/84 sw for ^C disk reset. *
* Again 3/17/84 for chain hack *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "biosdef.h" /* BIOS definitions, needed for bios wboot */
/* serial # and copyright notice */
char *copyrt="CP/M-68K(tm), Version 1.2, Copyright (c) 1984, Digital Research";
char *serial="XXXX-0000-654321";
/* Declare external functions */
EXTERN conout(); /* Console Output function */
EXTERN UBYTE conin(); /* Console Input function */
EXTERN prt_line(); /* Print String function */
EXTERN UWORD _bdos(); /* BDOS main routine */
EXTERN UBYTE *traphndl(); /* assembly language trap handler */
EXTERN initexc(); /* init the exception handler in */
/* exceptn.s */
EXTERN UWORD dirscan(); /* Directory scanning routine */
EXTERN BOOLEAN set_attr(); /* Set File attributes function */
EXTERN UWORD dir_rd(); /* Read directory sector routine */
/* Declare external variables */
EXTERN UWORD log_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; /* read-only disk vector */
EXTERN UWORD crit_dsk; /* vector of critical disks */
EXTERN BYTE *tpa_lt; /* TPA lower limit (temporary) */
EXTERN BYTE *tpa_lp; /* TPA lower limit (permanent) */
EXTERN BYTE *tpa_ht; /* TPA upper limit (temporary) */
EXTERN BYTE *tpa_hp; /* TPA upper limit (permanent) */
EXTERN BOOLEAN submit; /* external variables from CCP */
EXTERN BOOLEAN morecmds;
#define trap2v 34 /* trap 2 vector number */
#define ctrlc 3 /* control-c */
/********************************
* bdos initialization routine *
********************************/
bdosinit()
/* Initialize the File System */
{
REG struct
{
WORD nmbr;
BYTE *low;
LONG length;
} *segp;
BSETUP
bsetvec(trap2v, &traphndl); /* set up trap vector */
GBL.kbchar = 0; /* initialize the "global" variables */
GBL.insptr = GBL.remptr = &(GBL.t_buff[0]);
GBL.delim = '$';
GBL.lstecho = FALSE;
GBL.echodel = TRUE;
chainp = NULL; /*sw Used to be GBL.chainp */
_bdos(13); /* reset disk system function */
segp = (void *)bgetseg(); /* get pointer to memory segment table */
tpa_lt = tpa_lp = segp->low;
tpa_ht = tpa_hp = tpa_lp + segp->length;
initexc( &(GBL.excvec[0]) );
}
/************************
* warmboot entry point *
************************/
warmboot(parm)
/* Warm Boot the system */
WORD parm; /* 1 to reset submit flag */
{
BSETUP
if(parm != 2) /*sw Not ^C */
log_dsk &= ~ro_dsk; /* log off any disk marked read-only */
else
log_dsk &= (1 << GBL.curdsk); /*sw Log off all but current drive, as */
/* per manual. (^C only) */
/* note that this code is specifically for a single-
thread system. It won't work in a multi-task sys */
/*sw The above is still very much true */
ro_dsk = 0;
crit_dsk = 0;
if (parm)
submit = morecmds = FALSE;
GBL.curdsk = 0xff; /* set current disk to "unknown" */
tpa_lt = tpa_lp;
tpa_ht = tpa_hp;
initexc( &(GBL.excvec[0]) );
bwboot();
}
/*************************/
/* disk error handlers */
/*************************/
prt_err(p)
/* print the error message */
BYTE *p;
{
BSETUP
prt_line(p);
prt_line(" error on drive $");
conout(GBL.curdsk + 'A');
}
abrt_err(p)
/* print the error message and always abort */
BYTE *p;
{
prt_err(p);
warmboot(1);
}
char *warning = "\r\nWARNING -- Do not attempt to change disks$";
ext_err(cont,p)
/* print the error message, and allow for retry, abort, or ignore */
REG BOOLEAN cont; /* Boolean for whether continuing is allowed */
BYTE *p; /* pointer to error message */
{
REG UBYTE ch;
prt_err(p);
prt_line(warning);
do
{
prt_line("\n\rDo you want to: Abort (A), Retry (R)$");
if (cont) prt_line(", or Continue with bad data (C)$");
prt_line("? $");
ch = conin() & 0x5f;
prt_line("\r\n$");
switch ( ch )
{
case ctrlc: warmboot(1);
case 'A': warmboot(1);
case 'C': if (cont) return(1);
break;
case 'R': return(0);
}
} while (TRUE);
}
/********************************/
/* Read-only File Error Routine */
/********************************/
ro_err(fcbp,dirindx)
/* File R/O error */
REG struct fcb *fcbp;
WORD dirindx;
{
REG BYTE *p;
REG UWORD i;
REG UBYTE ch;
p = (BYTE *)fcbp;
prt_line("CP/M Disk file error: $");
i = 8;
do conout(*++p & 0x7f); while (--i);
conout('.');
i = 3;
do conout(*++p & 0x7f); while (--i);
prt_line(" is read-only.$");
prt_line(warning);
do
{
prt_line("\r\nDo you want to: Change it to read/write (C), or Abort (A)? $");
ch = conin() & 0x5f;
prt_line("\r\n$");
switch ( ch )
{
case ctrlc: warmboot(1);
case 'A': warmboot(1);
case 'C': fcbp->ftype[robit] &= 0x7f;
dirscan(set_attr, fcbp, 2);
return(dir_rd(dirindx >> 2));
} /* Reset the directory buffer !!!! */
} while (TRUE);
}
/************************
* error entry point *
************************/
error(errnum)
/* Print error message, do appropriate response */
UWORD errnum; /* error number */
{
BSETUP
prt_line("\r\nCP/M Disk $");
switch (errnum)
{
case 0: return( ext_err(TRUE,"read$") );
/* break; */
case 1: return( ext_err(TRUE,"write$") );
/* break; */
case 2: abrt_err("select$");
/* break; */
case 3: return( ext_err(FALSE,"select$") );
/* break; */
case 4: abrt_err("change$");
/* break; */
}
}
/*****************************
* set exception entry point *
*****************************/
struct setexc_struct {
WORD vecnum;
BYTE *newvec;
BYTE *oldvec;
};
setexc(epbp)
/* Set Exception Vector */
REG struct setexc_struct *epbp;
{
REG WORD i;
BSETUP
i = epbp->vecnum-2;
if ( i==32 || i==33) return(-1);
if ( (30 <= i) && (i <= 37) ) i -= 20;
else if ( (i < 0) || (i > 9) ) return(255);
epbp->oldvec = GBL.excvec[i];
GBL.excvec[i] = epbp->newvec;
return(0);
}
/*****************************
* get/set TPA entry point *
*****************************/
struct set_tpa_struct {
UWORD parms;
BYTE *low;
BYTE *high;
};
set_tpa(p)
/* Get/Set TPA Limits */
REG struct set_tpa_struct *p;
#define set 1
#define sticky 2
{
if (p->parms & set)
{
tpa_lt = p->low;
tpa_ht = p->high;
if (p->parms & sticky)
{
tpa_lp = tpa_lt;
tpa_hp = tpa_ht;
}
}
else
{
p->low = tpa_lt;
p->high = tpa_ht;
}
}

View File

@@ -0,0 +1,317 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS Disk Read/Write Module *
* *
* This module contains functions to perform sequential *
* or random access read or write to the disk for CP/M-68K *
* *
* It includes the following external functions: *
* *
* bdosrw() - sequential and random disk I/O *
* *
* *
* Compiled with Alcyon C on the VAX *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
/* External function definitions */
EXTERN UWORD rdwrt(); /* disk read/write routine */
EXTERN WORD getaloc(); /* allocate a block of disk space */
EXTERN WORD swap(); /* assembly language byte swapper */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN BOOLEAN openfile(); /* open file function passed to dirscan */
EXTERN UWORD close_fi(); /* close file function */
EXTERN BOOLEAN create(); /* create file function passed to dirscan */
EXTERN UWORD ro_err(); /* read-only file error handler */
/* External variable definitions */
EXTERN UWORD ro_dsk; /* read-only disk vector */
/**********************************************************/
/* First, some utility functions used by seqio and ranio */
/**********************************************************/
/******************************
* FCB block number routines *
******************************/
WORD blkindx(fcbp)
/* return index into fcb disk map */
REG struct fcb *fcbp; /* pointer to fcb */
{
REG struct dpb *dparmp; /* pointer to disk parameter block */
REG WORD i;
REG WORD blkshf;
BSETUP
dparmp = GBL.parmp;
blkshf = dparmp->bsh;
i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf);
return (i + (UBWORD(fcbp->cur_rec) >> blkshf) );
}
UWORD blknum(fcbp, index, wrdfcb)
/* return block number in fcb indicated by index */
REG struct fcb *fcbp; /* pointer to fcb */
REG WORD index; /* index into disk map of fcb */
WORD wrdfcb; /* boolean, fcb disk map of words */
{
if (wrdfcb)
return( swap(fcbp->dskmap.big[index]) );
else return( UBWORD(fcbp->dskmap.small[index]) );
}
setblk(fcbp, index, wrdfcb, block)
/* put block number into fcb */
REG struct fcb *fcbp; /* pointer to fcb */
REG WORD index; /* index into disk map of fcb */
WORD wrdfcb; /* boolean, fcb disk map of words */
REG UWORD block; /* block number */
{
fcbp->s2 &= 0x7f; /* set file write flag */
if (wrdfcb)
fcbp->dskmap.big[index] = swap(block);
else fcbp->dskmap.small[index] = (UBYTE)block;
}
/***************************
* disk read/write routine *
***************************/
UWORD do_io(block, rcrd, parm)
UWORD block; /* block number */
UBYTE rcrd; /* record number */
REG WORD parm; /* write parameter */
{
REG LONG lsec;
REG struct dpb *dparmp;
BSETUP
dparmp = GBL.parmp; /* init dpb pointer */
lsec = ((LONG)block << (dparmp->bsh)) +
(LONG)(rcrd & (dparmp->blm));
return( rdwrt(lsec, GBL.dmaadr, parm) );
}
/*******************************************
* routine for crossing extent boundaries *
*******************************************/
WORD new_ext(fcbp, reading, ran)
/* If sequential I/O, open the next extent */
/* If random I/O, compute new extent from random record field */
REG struct fcb *fcbp; /* pointer to fcb */
BOOLEAN reading; /* read/write flag */
WORD ran; /* random I/O flag */
{
REG UBYTE mod; /* module number */
REG UBYTE ext; /* extent number */
REG UBYTE t_mod; /* temp mod number */
REG UBYTE t_ext; /* temp extent */
BSETUP
if (ran)
{
mod = ( (fcbp->ran0) << 4) | ( (fcbp->ran1) >> 4);
ext = ( ((fcbp->ran1) & 0x0f) << 1);
if ((fcbp->ran2) & 0x80) ext |= 1;
/* the calculation of ext was coded this way because of a */
/* compiler bug from Alcyon */
}
else
{
mod = (fcbp->s2) & 0x3f;
ext = (fcbp->extent) + 1; /* for sequential, incr extent */
}
if (ext >= 32)
{
ext = 0;
mod += 1;
}
if (mod >= 64) return(6); /* past maximum file size */
if ( mod == ((fcbp->s2) & 0x3f) )
if ( ! ((ext ^ (fcbp->extent)) & ~((GBL.parmp)->exm) & 0x1f) )
{ /* we're in same logical extent */
fcbp->extent = ext;
return(0);
}
/* Extent or Module numbers don't match */
/* Close the old extent and open a one */
if ( close_fi(fcbp) >= 255 ) return(3);
/* can't close old extent */
t_mod = fcbp->s2;
t_ext = fcbp->extent;
fcbp->s2 = mod;
fcbp->extent = ext;
if ( dirscan(openfile, fcbp, 0) >= 255 ) /* open extent */
{
if (reading)
{ /* reading unwritten extent */
fcbp->s2 = t_mod;
fcbp->extent = t_ext;
return(4);
}
if ( dirscan(create, fcbp, 8) >= 255 )
return(5); /* can't create new extent */
}
return(0);
}
/************************************
* Routine to calculate the maximum *
* extent number of an FCB in a *
* extent-folded environment *
************************************/
UWORD calcext(fcbp)
REG struct fcb *fcbp;
{
REG UWORD i;
REG BYTE *p;
BSETUP
i = 15;
p = &(fcbp->dskmap.small[16]);
do
{
if (*--p) break;
i -= 1;
} while (i);
/* Now i contains the index of the last non-zero block in the FCB */
if ((GBL.parmp)->dsm > 255) i >>= 1;
i >>= 7 - ((GBL.parmp)->bsh);
return ( (fcbp->extent) & ~((GBL.parmp)->exm) & 0x1f | i );
}
/*********************************
* Routine to get the actual *
* record count of the currently *
* active logical extent of a FCB *
*********************************/
UWORD get_rc(fcbp)
REG struct fcb *fcbp;
{
REG UWORD ext;
ext = calcext(fcbp); /* find last active extent in fcb */
if (ext == fcbp->extent) return(UBWORD(fcbp->rcdcnt));
/* if this is the last active fcb, return fcb's rc */
else if (ext > fcbp->extent) return(128);
/* if the fcb has more extents past this one, then */
/* the current one is logically full */
else return (0);
/* if we seeked past the last active extent, rc = 0 */
}
/************************
* bdosrw entry point *
************************/
UWORD bdosrw(fcbp, reading, random)
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
REG BOOLEAN reading; /* boolean to tell whether to read or write */
WORD random; /* 0 = sequential, 1 = random (normal), */
/* 2 = random with zero fill */
{
REG UWORD block; /* block number from fcb */
REG WORD index; /* index into disk map of fcb */
REG BYTE *old_dma; /* temp holding spot for dmaadr */
REG WORD parm; /* parameter to do-io */
REG WORD bigfile; /* file system is in word mode */
REG UWORD rtn; /* return parameter */
REG UBYTE rc; /* temp storage for rcdcnt */
BSETUP
bigfile = ((GBL.parmp)->dsm) & ~0xff;
if ( ( ! reading) && (fcbp->ftype[robit] & 0x80) )
ro_err(fcbp,(((GBL.dphp)->dpbp))->drm); /*** rli ***/
/* check for read-only file */
if (random)
{
if ( rtn = new_ext(fcbp, reading, TRUE) ) return(rtn);
/* open new extent if necessary, return if error */
fcbp->cur_rec = (fcbp->ran2) & 0x7f;
}
else /* sequential */
if (fcbp->cur_rec == (UBYTE)128)
{ /* time to try next extent */
if ( new_ext(fcbp, reading, FALSE) )
return(1); /* if can't open new extent, error */
fcbp->cur_rec = 0; /* opened new extent, zero cur_rec */
}
/* record is now in active fcb */
rc = fcbp->rcdcnt;
if ( UBWORD(fcbp->cur_rec) >= get_rc(fcbp) )
{
if (reading) return(1); /* reading unwritten data */
fcbp->s2 &= 0x7f; /* set file write flag */
rc = fcbp->cur_rec + 1;
}
index = blkindx(fcbp); /* get index into fcb disk map */
block = blknum(fcbp, index, bigfile);
if (block) parm = (reading ? 0 : 1);
else /* if allocated block, parm is just read or write */
{ /* unallocated block */
if (reading) return(1); /* reading unwritten data */
/* Writing to new block */
/* The parm passed to getaloc is the previously allocated block */
/* or 0, if the previous block is not allocated */
block = getaloc(blknum(fcbp, (index ? (index - 1) : 0), bigfile));
if (block == (UWORD)~0) return(2); /* out of space */
setblk(fcbp, index, bigfile, block);
parm = 3;
if (random == 2)
{ /* Write random with zero fill */
old_dma = GBL.dmaadr;
GBL.dmaadr = (void *)GBL.dirbufp; /* Do DMA from dir_buf */
index = SECLEN;
do GBL.dmaadr[--index] = 0;
while (index); /* zero the dma buffer */
for (index = 0; index <= ((GBL.parmp)->blm); index++)
{
do_io(block, (UBYTE)index, parm);
/* write zeros to the block */
parm = 1; /* next write is not to new block */
}
GBL.dmaadr = old_dma; /* restore dma address */
}
}
rtn = do_io(block, fcbp->cur_rec, parm);
if ( rtn == 0 )
{
fcbp->rcdcnt = rc;
if ( ! random ) fcbp->cur_rec += 1;
}
return(rtn);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
/********************************************************
* *
* BIOS definitions for CP/M-68K *
* *
* Copyright (c) 1982 Digital Research, Inc. *
* *
* This include file simply defines the BIOS calls *
* *
********************************************************/
#if 0
EXTERN UBYTE bios1(); /* used for character I/O functions */
EXTERN bios2(); /* parm1 is word, no return value */
EXTERN bios3(); /* used for set dma only */
/* parm1 is a pointer, no return */
EXTERN UBYTE *bios4(); /* seldsk only, parm1 and parm2 are */
/* words, returns a pointer to dph */
EXTERN UWORD bios5(); /* for sectran and set exception */
EXTERN BYTE *bios6(); /* for get memory segment table */
#define bwboot() bios1(1) /* warm boot */
#define bconstat() bios1(2) /* console status */
#define bconin() bios1(3) /* console input */
#define bconout(parm) bios2(4,parm) /* console output parm */
#define blstout(parm) bios2(5,parm) /* list device output */
#define bpun(parm) bios2(6,parm) /* punch char output */
#define brdr() bios1(7) /* reader input */
#define bhome() bios1(8) /* recalibrate drive */
#define bseldsk(parm1,parm2) bios4(9,parm1,parm2)
/* select disk and return info */
#define bsettrk(parm) bios2(10,parm) /* set track on disk */
#define bsetsec(parm) bios2(11,parm) /* set sector for disk */
#define bsetdma(parm) bios3(12,parm) /* set dma address */
#define bread() bios1(13) /* read sector from disk */
#define bwrite(parm) bios2(14,parm) /* write sector to disk */
#define blistst() bios1(15) /* list device status */
#define bsectrn(parm1,parm2) bios5(16,parm1,parm2)
/* sector translate */
#define bgetseg() bios6(18) /* get memory segment tbl */
#define bgetiob() bios1(19) /* get I/O byte */
#define bsetiob(parm) bios2(20,parm) /* set I/O byte */
#define bflush() bios1(21) /* flush buffers */
#define bsetvec(parm1,parm2) bios5(22,parm1,parm2)
/* set exception vector */
#endif
extern void bios_wboot( void );
extern unsigned short int bios_const( void );
extern unsigned char bios_conin( void );
extern void bios_conout( unsigned char victim );
extern void bios_list( unsigned char victim );
extern void bios_punch( unsigned char victim );
extern unsigned char bios_reader( void );
extern void bios_home( void );
extern void *bios_seldsk( unsigned char drive, unsigned char logged );
extern void bios_settrk( unsigned short int track );
extern void bios_setsec( unsigned short int sector );
extern void bios_setdma( void *dmaaddress );
extern unsigned short int bios_read( void );
extern unsigned short int bios_write( unsigned short int typecode );
extern unsigned short int bios_listst( void );
extern unsigned short int bios_sectran( unsigned short int sector,
void *table );
extern void *bios_getmrt( void );
extern unsigned short int bios_getiobyte( void );
extern void bios_setiobyte( unsigned short int iobyte );
extern unsigned short int bios_flush( void );
void *bios_setexc( unsigned short int vector, void *handler );
#define bwboot() bios_wboot()
#define bconstat() bios_const()
#define bconin() bios_conin()
#define bconout(parm) bios_conout( parm )
#define blstout(parm) bios_list( parm )
#define bpun(parm) bios_punch( parm )
#define brdr() bios_reader()
#define bhome() bios_home()
#define bseldsk(parm1,parm2) bios_seldsk( parm1, parm2 )
#define bsettrk(parm) bios_settrk( parm )
#define bsetsec(parm) bios_setsec( parm )
#define bsetdma(parm) bios_setdma( parm )
#define bread() bios_read()
#define bwrite(parm) bios_write( parm )
#define blistst() bios_listst()
#define bsectrn(parm1,parm2) bios_sectran( parm1, parm2 )
#define bgetseg() bios_getmrt()
#define bgetiob() bios_getiobyte()
#define bsetiob(parm) bios_setiobyte( parm )
#define bflush() bios_flush()
#define bsetvec(parm1,parm2) bios_setexc( parm1, parm2 )

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/*--------------------------------------------------------------*\
| ccp_def.c DEFINES v1.0 |
| ======= |
| |
| CP/M 68k: A CP/M derived operating system |
| |
| File contents: |
| ------------- |
| This file contains all of the #defines |
| used by the console command processor. |
| |
| created by : Tom Saulpaugh Date: 7/13/82 |
| ---------- |
| last modified: 10/29/82 |
| ------------- |
| |
| (c) COPYRIGHT Digital Research 1982 |
| all rights reserved |
| |
\*--------------------------------------------------------------*/
/*-------------------------------------------*\
| CP/M Transient Commands |
\*-------------------------------------------*/
#define DIRCMD 0
#define TYPECMD 1
#define RENCMD 2
#define ERACMD 3
#define UCMD 4
#define CH_DISK 5
#define SUBCMD 6
#define SUB_FILE 7
#define FILE 8
#define DIRSCMD 9
#define SEARCH 10
#ifdef RLI
#define RLI_EXIT 11
#define RLI_IMPORT 12
#define RLI_EXPORT 13
#endif
/*-------------------------------------------*\
| Modes and Flags |
\*-------------------------------------------*/
#define ON 1
#define OFF 0
#define MATCH 0
#define GOOD 1
#define BAD 0
#define FILL 1
#define NOFILL 0
#define VOID /*no return value*/
#define NO_FILE 98
#define STOP 99
#define USER_ZERO 0
#define DISK_A 1
#define SOURCEDRIVE 88
#define DESTDRIVE 99
#define BYTE signed char
#define REG register
#define WORD short
#define UWORD unsigned short int /*** rli ***/
#define LONG long
#define ULONG unsigned long
#define GET_MEM_REG 18
#define ZERO 0
#define NULL '\0'
#define TRUE 1
#define FALSE 0
#define NO_READ 255
#define BLANK ' '
#define BACKSLH '\\'
#define EXLIMPT '!'
#define CMASK 0177
#define ONE (long)49
#define TAB 9
#define Cr 13
#define Lf 10
#define CR (long)13
#define LF (long)10
#define EOF 26
#define BLANKS (long)32
#define PERIOD (long)46
#define COLON (long)58
#define ARROW (long)62
/*-------------------------------------------*\
| Data Structure Size Constants |
\*-------------------------------------------*/
#define CMD_LEN 128
#define BIG_CMD_LEN 255
#define MAX_ARGS 4
#define ARG_LEN 30
#define NO_OF_DRIVES 16
#define NUMDELS 16
#define FCB_LEN 36
#define DMA_LEN 128
#define FILES_PER_LINE 5
#define SCR_HEIGHT 23
#define BIG_WIDTH 80
#define SMALL_WIDTH 40
/*-------------------------------------------*\
| BDOS Function Calls |
\*-------------------------------------------*/
#define WARMBOOT 0
#define CONIN 1
#define CONSOLE_OUTPUT 2
#define READER_INPUT 3
#define PUNCH_OUTPUT 4
#define LIST_OUTPUT 5
#define DIR_CONS_IO 6
#define GET_IO_BYTE 7
#define SET_IO_BYTE 8
#define PRINT_STRING 9
#define READ_CONS_BUF 10
#define GET_CONS_STAT 11
#define RET_VERSION_NO 12
#define RESET_DISK_SYS 13
#define SELECT_DISK 14
#define OPEN_FILE 15
#define CLOSE_FILE 16
#define SEARCH_FIRST 17
#define SEARCH_NEXT 18
#define DELETE_FILE 19
#define READ_SEQ 20
#define WRITE_SEQ 21
#define MAKE_FILE 22
#define RENAME_FILE 23
#define RET_LOGIN_VEC 24
#define RET_CUR_DISK 25
#define SET_DMA_ADDR 26
#define GET_ADDR(ALLOC) 27
#define WRITE_PROT_DISK 28
#define GET_READO_VEC 29
#define SET_FILE_ATTRIB 30
#define GET_ADDR_D_PARM 31
#define GET_USER_NO 32
#define READ_RANDOM 33
#define WRITE_RANDOM 34
#define COMP_FILE_SIZE 35
#define SET_RANDOM_REC 36
#define RESET_DRIVE 37
#define WRITE_RAN_ZERO 40
#define BIOS_CALL 50
#define LOAD_PROGRAM 59
/*----------------------------------------------*\
| MACROS |
\*----------------------------------------------*/
#define isalpha(c) (islower(c) || isupper(c))
#define islower(c) ('a' <= (c) && (c) <= 'z')
#define isupper(c) ('A' <= (c) && (c) <= 'Z')
#define tolower(c) (isupper(c) ? ((c)+040):(c))
#define toupper(c) (islower(c) ? ((c)-040):(c))
#define isdigit(c) ('0' <= (c) && (c) <= '9')

View File

@@ -0,0 +1,359 @@
#ifdef RLI
#include "diverge.h"
#endif
/********************************************************
* *
* CP/M-68K BDOS Character I/O Routines *
* *
* This module does BDOS functions 1 thru 11 *
* *
* It contains the following functions which *
* are called from the BDOS main routine: *
* constat(); *
* conin(); *
* tabout(); *
* rawconio(); *
* prt_line(); *
* readline(); *
* *
* Copyright (c) 1982 Digital Research, Inc. *
* *
* Modified 2/5/84 sw Allow typeahead *
* ^C warmboot modifications *
* Again 3/17/84 sw Chain hack *
* *
********************************************************/
#include "bdosinc.h"
#include "bdosdef.h"
#include "biosdef.h"
#define ctrlc 0x03
#define ctrle 0x05
#define ctrlp 0x10
#define ctrlq 0x11
#define ctrlr 0x12
#define ctrls 0x13
#define ctrlu 0x15
#define ctrlx 0x18
#define cr 0x0d
#define lf 0x0a
#define tab 0x09
#define rub 0x7f
#define bs 0x08
#define space 0x20
EXTERN warmboot(); /* External function definition */
/******************/
/* console status */
/******************/
BOOLEAN constat()
{
BSETUP
return( GBL.kbchar ? TRUE : bconstat() );
}
/********************/
/* check for ctrl/s */
/* used internally */
/********************/
conbrk()
{
REG UBYTE ch;
REG BOOLEAN stop;
BSETUP
stop = FALSE;
if ( bconstat() ) do
{
if ( (ch = bconin()) == ctrlc ) warmboot(2); /*sw from (1) */
if ( ch == ctrls ) stop = TRUE;
else if (ch == ctrlq) stop = FALSE;
else if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
/*sw What Follows is new... */
else /* Insert character in ring buffer */
{ /* */
if(GBL.kbchar < TBUFSIZ) /* Room? */
{ /************************************/
*GBL.insptr++ = ch; /* Yes, insert the character in buff*/
GBL.kbchar++; /* Up count */
} /************************************/
} /* Note if no room, character is */
/* Ignomiously discarded (!) */
/*sw End of new stuff */
/************************************/
} while (stop);
}
/******************/
/* console output */
/* used internally*/
/******************/
conout(ch)
REG UBYTE ch;
{
BSETUP
conbrk(); /* check for control-s break */
bconout(ch); /* output character to console */
if (GBL.lstecho) blstout(ch); /* if ctrl-p on, echo to list dev */
if ((UWORD)ch >= (UWORD)' ')
GBL.column++; /* keep track of screen column */
else if (ch == cr) GBL.column = 0;
else if (ch == bs) GBL.column--;
}
/*************************************/
/* console output with tab expansion */
/*************************************/
tabout(ch)
REG UBYTE ch; /* character to output to console */
{
BSETUP
if (ch == tab) do
conout(' ');
while (GBL.column & 7);
else conout(ch);
}
/*******************************/
/* console output with tab and */
/* control character expansion */
/*******************************/
cookdout(ch)
REG UBYTE ch; /* character to output to console */
{
if (ch == tab) tabout(ch); /* if tab, expand it */
else
{
if ( (UWORD)ch < (UWORD)' ' )
{
conout( '^' );
ch |= 0x40;
}
conout(ch); /* output the character */
}
}
/*****************/
/* console input */
/*****************/
UBYTE getch() /* Get char from buffer or bios */
/* For internal use only */
{
REG UBYTE temp;
BSETUP
if(GBL.kbchar)
{
temp = *GBL.remptr++; /* Fetch the character */
GBL.kbchar--; /* Decrement the count */
if(!GBL.kbchar) /* Gone to zero? */
GBL.remptr = GBL.insptr = &(GBL.t_buff[0]);
return(temp);
}
return( bconin() ); /* else get char from bios */
}
UBYTE conin() /* BDOS console input function */
{
REG UBYTE ch;
BSETUP
conout( ch = getch() );
if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
return(ch);
}
/******************
* raw console i/o *
******************/
UBYTE rawconio(parm) /* BDOS raw console I/O function */
REG UWORD parm;
{
BSETUP
if (parm == 0xff) return(getch());
else if (parm == 0xfe) return(constat());
else bconout(parm & 0xff);
}
/****************************************************/
/* print line up to delimiter($) with tab expansion */
/****************************************************/
prt_line(p)
REG UBYTE *p;
{
BSETUP
while( *p != GBL.delim ) tabout( *p++ );
}
/**********************************************/
/* read line with editing and bounds checking */
/**********************************************/
/* Two subroutines first */
newline(startcol)
REG UWORD startcol;
{
BSETUP
conout(cr); /* go to new line */
conout(lf);
while(startcol)
{
conout(' ');
startcol -= 1; /* start output at starting column */
}
}
backsp(bufp, col)
/* backspace one character position */
REG struct conbuf *bufp; /* pointer to console buffer */
REG WORD col; /* starting console column */
{
REG UBYTE ch; /* current character */
REG WORD i;
REG UBYTE *p; /* character pointer */
BSETUP
if (bufp->retlen) --(bufp->retlen);
/* if buffer non-empty, decrease it by 1 */
i = UBWORD(bufp->retlen); /* get new character count */
p = &(bufp->cbuf[0]); /* point to character buffer */
while (i--) /* calculate column position */
{ /* across entire char buffer */
ch = *p++; /* get next char */
if ( ch == tab )
{
col += 8;
col &= ~7; /* for tab, go to multiple of 8 */
}
else if ( (UWORD)ch < (UWORD)' ' ) col += 2;
/* control chars put out 2 printable chars */
else col += 1;
}
while (GBL.column > col)
{
conout(bs); /* backspace until we get to proper column */
conout(' ');
conout(bs);
}
}
readline(p) /* BDOS function 10 */
REG struct conbuf *p;
{
REG UBYTE ch;
REG UWORD i;
REG UWORD j;
REG UBYTE *q;
UWORD stcol;
BSETUP
stcol = GBL.column; /* set up starting column */
#ifdef NFG /*sw This didn't work for SUBMIT files...*/
if (GBL.chainp != NULL) /* chain to program code */
{
i = UBWORD(*(GBL.chainp++));
j = UBWORD(p->maxlen);
if (j < i) i = j; /* don't overflow console buffer! */
p->retlen = (UBYTE)i;
q = p->cbuf;
while (i)
{
cookdout( *q++ = *(GBL.chainp++) );
i -= 1;
}
GBL.chainp = NULL;
return;
}
#endif /*sw NFG chain code */
p->retlen = 0; /* start out with empty buffer */
while ( UBWORD(p->retlen) < UBWORD(p->maxlen) )
{ /* main loop for read console buffer */
if ( ((ch=getch()) == ctrlc) && !(p->retlen) )
{
cookdout(ctrlc);
warmboot(2); /*sw From warmboot(1) */
}
else if ( (ch == cr) || (ch == lf) )
{ /* if cr or lf, exit */
conout(cr);
break;
}
else if (ch == bs) backsp(p, stcol); /* backspace */
else if (ch == rub) /* delete character */
{
if (GBL.echodel)
{
if (p->retlen)
{
i = UBWORD(--(p->retlen));
conout( p->cbuf[i] );
}
}
else backsp(p, stcol);
}
else if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
/* control-p */
else if (ch == ctrlx) /* control-x */
do backsp(p,stcol); while (p->retlen);
else if (ch == ctrle) newline(stcol); /* control-e */
else if (ch == ctrlu) /* control-u */
{
conout('#');
newline(stcol);
p->retlen = 0;
}
else if (ch == ctrlr) /* control-r */
{
conout('#');
newline(stcol);
for (i=0; i < UBWORD(p->retlen); i++)
cookdout( p->cbuf[i] );
}
else /* normal character */
cookdout( p->cbuf[UBWORD((p->retlen)++)] = ch );
}
}

View File

@@ -0,0 +1,165 @@
/****
*
* This file forces internal CP/M names to diverge from those used
* by system library routines. It was automatically generated by
* massaging the output of nm.
*
****/
#define abrt_err cpm_abrt_err
#define alloc cpm_alloc
#define alltrue cpm_alltrue
#define autorom cpm_autorom
#define autost cpm_autost
#define backsp cpm_backsp
#define bdos cpm_bdos
#define _bdos cpm__bdos
#define bdosinit cpm_bdosinit
#define bdosrw cpm_bdosrw
#define blkindx cpm_blkindx
#define blknum cpm_blknum
#define calcext cpm_calcext
#define ccp cpm_ccp
#define chainp cpm_chainp
#define chain_sub cpm_chain_sub
#define check_cmd cpm_check_cmd
#define chkaloc cpm_chkaloc
#define chk_colon cpm_chk_colon
#define close cpm_close
#define close_fi cpm_close_fi
#define clraloc cpm_clraloc
#define cmdfcb cpm_cmdfcb
#define cmd_file cpm_cmd_file
#define cmd_tbl cpm_cmd_tbl
#define comments cpm_comments
#define conbrk cpm_conbrk
#define conin cpm_conin
#define conout cpm_conout
#define constat cpm_constat
#define cookdout cpm_cookdout
#define copy_cmd cpm_copy_cmd
#define copyrt cpm_copyrt
#define cpy cpm_cpy
#define create cpm_create
#define crit_dsk cpm_crit_dsk
#define cr_lf cpm_cr_lf
#define cur_disk cpm_cur_disk
#define dchksum cpm_dchksum
#define decode cpm_decode
#define del cpm_del
#define delete cpm_delete
#define delim cpm_delim
#define dir_cmd cpm_dir_cmd
#define dirflag cpm_dirflag
#define dir_rd cpm_dir_rd
#define dirscan cpm_dirscan
#define dir_wr cpm_dir_wr
#define dma cpm_dma
#define do_io cpm_do_io
#define dollar cpm_dollar
#define do_phio cpm_do_phio
#define echo_cmd cpm_echo_cmd
#define end_of_file cpm_end_of_file
#define era_cmd cpm_era_cmd
#define error cpm_error
#define execute_cmd cpm_execute_cmd
#define ext_err cpm_ext_err
#define extsize cpm_extsize
#define fill_fcb cpm_fill_fcb
#define find_colon cpm_find_colon
#define first_sub cpm_first_sub
#define flushit cpm_flushit
#define free_sp cpm_free_sp
#define fsize cpm_fsize
#define gbls cpm_gbls
#define getaloc cpm_getaloc
#define getch cpm_getch
#define get_cmd cpm_get_cmd
#define get_parms cpm_get_parms
#define get_rc cpm_get_rc
#define getsize cpm_getsize
#define glb_index cpm_glb_index
#define index cpm_index
#define initexc cpm_initexc
#define last_dsk cpm_last_dsk
#define lderr1 cpm_lderr1
#define lderr2 cpm_lderr2
#define lderr3 cpm_lderr3
#define lderror cpm_lderror
#define load68k cpm_load68k
#define load_tbl cpm_load_tbl
#define load_try cpm_load_try
#define log_dsk cpm_log_dsk
#define match cpm_match
#define matchit cpm_matchit
#define morecmds cpm_morecmds
#define move cpm_move
#define msg cpm_msg
#define msg10 cpm_msg10
#define msg11 cpm_msg11
#define msg12 cpm_msg12
#define msg13 cpm_msg13
#define msg2 cpm_msg2
#define msg3 cpm_msg3
#define msg4 cpm_msg4
#define msg5 cpm_msg5
#define msg6 cpm_msg6
#define msg7 cpm_msg7
#define msg8 cpm_msg8
#define msg9 cpm_msg9
#define new_ext cpm_new_ext
#define newline cpm_newline
#define openfile cpm_openfile
#define parm cpm_parm
#define pgmld cpm_pgmld
#define prompt cpm_prompt
#define prt_err cpm_prt_err
#define prt_line cpm_prt_line
#define rawconio cpm_rawconio
#define rdwrt cpm_rdwrt
#define readline cpm_readline
#define rename cpm_rename
#define ren_cmd cpm_ren_cmd
#define ro_dsk cpm_ro_dsk
#define ro_err cpm_ro_err
#define save_sub cpm_save_sub
#define scan_cmd cpm_scan_cmd
#define search cpm_search
#define seldsk cpm_seldsk
#define serial cpm_serial
#define setaloc cpm_setaloc
#define set_attr cpm_set_attr
#define setblk cpm_setblk
#define setexc cpm_setexc
#define setran cpm_setran
#define set_tpa cpm_set_tpa
#define strcmp cpm_strcmp
#define subcom cpm_subcom
#define subdma cpm_subdma
#define subfcb cpm_subfcb
#define sub_index cpm_sub_index
#define submit cpm_submit
#define submit_cmd cpm_submit_cmd
#define subprompt cpm_subprompt
#define sub_read cpm_sub_read
#define sub_user cpm_sub_user
#define swap cpm_swap
#define tabout cpm_tabout
#define tail cpm_tail
#define tmp_sel cpm_tmp_sel
#define too_many cpm_too_many
#define tpa_hp cpm_tpa_hp
#define tpa_ht cpm_tpa_ht
#define tpa_lp cpm_tpa_lp
#define tpa_lt cpm_tpa_lt
#define translate cpm_translate
#define traphndl cpm_traphndl
#define true_char cpm_true_char
#define type_cmd cpm_type_cmd
#define udiv cpm_udiv
#define user cpm_user
#define usercmd cpm_usercmd
#define user_cmd cpm_user_cmd
#define user_ptr cpm_user_ptr
#define warmboot cpm_warmboot
#define warning cpm_warning

View File

@@ -0,0 +1,304 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS Disk Utilities Module *
* *
* This module contains the miscellaneous utilities *
* for manipulating the disk in CP/M-68K. Included are: *
* *
* dirscan() - general purpose dir scanning *
* setaloc() - set bit in allocation vector *
* clraloc() - clear bit in allocation vector *
* getaloc() - get free allocation block *
* dchksum() - directory checksum calculator *
* dir_rd() - read directory sector *
* dir_wr() - write directory sector *
* rdwrt() - read/write disk sector *
* *
* *
* Configured for Alcyon C on the VAX *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
/* declare external functions and variables */
EXTERN UWORD do_phio(); /* external physical disk I/O routine */
EXTERN UWORD error(); /* external error routine */
EXTERN UWORD log_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; /* read-only disk vector */
EXTERN UWORD crit_dsk; /* critical disk vector */
UBYTE dchksum();
/**********************
* read/write routine *
**********************/
UWORD rdwrt(secnum, dma, parm)
/* General disk sector read/write routine */
/* It simply sets up a I/O packet and sends it to do_phio */
LONG secnum; /* logical sector number to read/write */
UBYTE *dma; /* dma address */
REG WORD parm; /* 0 for read, write parm + 1 for write */
{
struct iopb rwpkt;
BSETUP
rwpkt.devnum = GBL.curdsk; /* disk to read/write */
if (parm)
{
rwpkt.iofcn = (BYTE)write; /* if parm non-zero, we're doing a write */
rwpkt.ioflags = (BYTE)(parm-1); /* pass write parm */
if ( ro_dsk & (1 << (rwpkt.devnum)) ) error(4);
/* don't write on read-only disk */
}
else
{
rwpkt.iofcn = (BYTE)read;
rwpkt.ioflags = (BYTE)0;
}
rwpkt.devadr = secnum; /* sector number */
rwpkt.xferadr = dma; /* dma address */
/* parameters that are currently not used by do_phio
rwpkt.devtype = disk;
rwpkt.xferlen = 1;
*/
rwpkt.infop = GBL.dphp; /* pass ptr to dph */
while ( do_phio(&rwpkt) )
if ( error( parm ? 1 : 0 ) ) break;
return(0);
}
/***************************
* directory read routine *
***************************/
UWORD dir_rd(secnum)
WORD secnum;
{
BSETUP
return( rdwrt((LONG)secnum, GBL.dirbufp, 0) );
}
/****************************
* directory write routine *
****************************/
UWORD dir_wr(secnum)
REG WORD secnum;
{
REG UWORD rtn;
BSETUP
rtn = rdwrt( (LONG)secnum, GBL.dirbufp, 2);
if ( secnum < (GBL.parmp)->cks )
*((GBL.dphp)->csv + secnum) = dchksum();
return(rtn);
}
/*******************************
* directory checksum routine *
*******************************/
UBYTE dchksum()
/* Compute checksum over one directory sector */
/* Note that this implementation is dependant on the representation */
/* of a LONG and is therefore not very portable. But it's fast */
{
REG LONG *p; /* local temp variables */
REG LONG lsum;
REG WORD i;
BSETUP
p = (void *)GBL.dirbufp; /* point to directory buffer */
lsum = 0;
i = SECLEN / (sizeof lsum);
do
{
lsum += *p++; /* add next 4 bytes of directory */
i -= 1;
} while (i);
lsum += (lsum >> 16);
lsum += (lsum >> 8);
return( (UBYTE)(lsum & 0xff) );
}
/************************
* dirscan entry point *
************************/
UWORD dirscan(funcp, fcbp, parms)
BOOLEAN (*funcp)(); /* funcp is a pointer to a Boolean function */
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
REG UWORD parms; /* parms is 16 bit set of bit parameters */
/* Parms & 1 = 0 to start at beginning of dir, 1 to continue from last */
/* Parms & 2 = 0 to stop when *funcp is true, 1 to go until end */
/* Parms & 4 = 0 to check the dir checksum, 1 to store new checksum */
/* Parms & 8 = 0 to stop at hiwater, 1 to go until end of directory */
#define continue 1
#define full 2
#define initckv 4
#define pasthw 8
{
REG UWORD i; /* loop counter */
REG struct dpb *dparmp; /* pointer to disk parm block */
REG UWORD dirsec; /* sector number we're working on */
REG UWORD rtn; /* return value */
REG UBYTE *p; /* scratch pointer */
REG UWORD bitvec; /* disk nmbr represented as a vector */
BSETUP
dparmp = GBL.parmp; /* init ptr to dpb */
rtn = 255; /* assume it doesn't work */
i = ( (parms & continue) ? GBL.srchpos + 1 : 0 );
while ( (parms & pasthw) || (i <= ((GBL.dphp)->hiwater + 1)) )
{ /* main directory scanning loop */
if ( i > dparmp->drm ) break;
if ( ! (i & 3) )
{ /* inside loop happens when we need to
read another directory sector */
retry: dirsec = i >> 2;
dir_rd(dirsec); /* read the directory sector */
if ( dirsec < (dparmp->cks) ) /* checksumming on this sector? */
{
p = ((GBL.dphp)->csv) + dirsec;
/* point to checksum vector byte */
if (parms & initckv) *p = dchksum();
else if (*p != dchksum())
{ /* checksum error! */
(GBL.dphp)->hiwater = dparmp->drm; /* reset hi water */
bitvec = 1 << (GBL.curdsk);
if (crit_dsk & bitvec) /* if disk in critical mode */
ro_dsk |= bitvec; /* then set it to r/o */
else
{
log_dsk &= ~bitvec; /* else log it off */
seldsk(GBL.curdsk); /* and re-select it */
goto retry; /* and re-do current op */
}
}
}
}
GBL.srchpos = i;
if ( (*funcp)(fcbp, (GBL.dirbufp) + (i&3), i) )
/* call function with parms of (1) fcb ptr,
(2) pointer to directory entry, and
(3) directory index */
{
if (parms & full) rtn = 0; /* found a match, but keep going */
else return(i & 3); /* return directory code */
}
i += 1;
}
return(rtn);
}
/****************************************
* Routines to manage allocation vector *
* setaloc() *
* clraloc() *
* getaloc() *
****************************************/
setaloc(bitnum)
/* Set bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
#if 0
if (bitnum >= 0 && bitnum <= (GBL.parmp)->dsm)
#endif
if( bitnum <= (GBL.parmp)->dsm ) /* bitnum is unsigned */
*((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7);
}
clraloc(bitnum)
/* Clear bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
if (bitnum > 0 && bitnum <= (GBL.parmp)->dsm)
*((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7));
}
UWORD chkaloc(i)
/* Check bit i in allocation vector */
/* Return non-zero if block free, else return zero */
REG UWORD i;
{
BSETUP
return( ~(*( (GBL.dphp)->alv + (i >> 3) )) & (0x80 >> (i&7)) );
}
UWORD getaloc(leftblk)
/* Get a free block in the file system and set the bit in allocation vector */
/* It is passed the block number of the last block allocated to the file */
/* It tries to allocate the block closest to the block that was passed */
REG UWORD leftblk;
{
REG UWORD blk; /* block number to allocate */
REG UWORD rtblk; /* high block number to try */
REG UWORD diskmax; /* # bits in alv - 1 */
BSETUP
LOCK /* need to lock the file system while messing
with the allocation vector */
diskmax = (GBL.parmp)->dsm;
/* get disk max field from dpb */
rtblk = leftblk;
blk = ~0; /* -1 returned if no free block found */
while (leftblk || rtblk < diskmax)
{
if (leftblk)
if (chkaloc(--leftblk))
{
blk = leftblk;
break;
}
if (rtblk < diskmax)
if (chkaloc(++rtblk))
{
blk = rtblk;
break;
}
}
if (blk != (UWORD)~0) setaloc(blk);
UNLOCK
return(blk);
}

View File

@@ -0,0 +1,670 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS File I/O Module *
* *
* This module contains all file handling BDOS functions *
* except for read and write for CP/M-68K. Included are: *
* *
* seldsk() - select disk *
* openfile() - open file *
* close_fi() - close file *
* search() - search for first/next file match *
* create() - create file *
* delete() - delete file *
* rename() - rename file *
* set_attr() - set file attributes *
* getsize() - get file size *
* setran() - set random record field *
* free_sp() - get disk free space *
* move() - general purpose byte mover *
* *
* *
* Compiled with Alcyon C on the VAX *
* *
* Modified 2/5/84 sw Allow odd DMA on get free space *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
/* declare external fucntions */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN UWORD error(); /* disk error routine */
EXTERN UWORD ro_err(); /* read-only file error routine */
EXTERN UWORD do_phio(); /* packet disk i/o handler */
EXTERN clraloc(); /* clear bit in allocation vector */
EXTERN setaloc(); /* set bit in allocation vector */
EXTERN UWORD swap(); /* assembly language byte swapper */
EXTERN UWORD dir_wr(); /* directory write routine */
EXTERN tmp_sel(); /* temporary select disk routine */
EXTERN UWORD calcext(); /* calc max extent allocated for fcb */
EXTERN UWORD udiv(); /* unsigned divide routine */
/* declare external variables */
EXTERN UWORD log_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; /* read-only disk vector */
EXTERN UWORD crit_dsk; /* vector of disks in critical state */
/************************************
* This function passed to dirscan *
* from seldsk (below) *
************************************/
BOOLEAN alloc(fcbp, dirp, dirindx)
/* Set up allocation vector for directory entry pointed to by dirp */
struct fcb *fcbp; /* not used in this function */
REG struct dirent *dirp; /* pointer to directory entry */
WORD dirindx; /* index into directory for *dirp */
{
REG WORD i; /* loop counter */
BSETUP
if ( UBWORD(dirp->entry) < 0x10 ) /* skip MP/M 2.x and CP/M 3.x XFCBs */
{
(GBL.dphp)->hiwater = dirindx; /* set up high water mark for disk */
i = 0;
if ((GBL.parmp)->dsm < 256)
{
do setaloc( UBWORD(dirp->dskmap.small[i++]) );
while (i <= 15);
}
else
{
do setaloc(swap(dirp->dskmap.big[i++]));
while (i <= 7);
}
}
}
/************************
* seldsk entry point *
************************/
seldsk(dsknum)
REG UBYTE dsknum; /* disk number to select */
{
struct iopb selpkt;
REG WORD i;
UWORD j;
REG UBYTE logflag;
BSETUP
logflag = ~(log_dsk >> dsknum) & 1;
if ((GBL.curdsk != dsknum) || logflag)
{ /* if not last used disk or not logged on */
selpkt.iofcn = sel_info;
GBL.curdsk = (selpkt.devnum = dsknum);
if (UBWORD(dsknum) > 15) error(2);
selpkt.ioflags = logflag ^ 1;
do
{
do_phio(&selpkt); /* actually do the disk select */
if ( (void *)(GBL.dphp = selpkt.infop) != NULL ) break;
} while ( ! error(3) );
GBL.dirbufp = (void *)((GBL.dphp)->dbufp);
/* set up GBL copies of dir_buf and dpb ptrs */
GBL.parmp = (GBL.dphp)->dpbp;
}
if (logflag)
{ /* if disk not previously logged on, do it now */
LOCK /* must lock the file system while messing with alloc vec */
i = (GBL.parmp)->dsm;
do clraloc(i); while (i--); /* clear the allocation vector */
i = udiv( (LONG)(((GBL.parmp)->drm) + 1),
4 * (((GBL.parmp)->blm) + 1), &j);
/* calculate nmbr of directory blks */
if (j) i++; /* round up */
do setaloc(--i); while (i); /* alloc directory blocks */
dirscan(alloc, NULL, 0x0e); /* do directory scan & alloc blocks */
log_dsk |= 1 << dsknum; /* mark disk as logged in */
}
}
/*******************************
* General purpose byte mover *
*******************************/
move(p1, p2, i)
REG BYTE *p1;
REG BYTE *p2;
REG WORD i;
{
while (i--)
*p2++ = *p1++;
}
/*************************************
* General purpose filename matcher *
*************************************/
BOOLEAN match(p1, p2, chk_ext)
REG UBYTE *p1;
REG UBYTE *p2;
BOOLEAN chk_ext;
{
REG WORD i;
REG UBYTE temp;
BSETUP
i = 12;
do
{
temp = (*p1 ^ '?');
if ( ((*p1++ ^ *p2++) & 0x7f) && temp )
return(FALSE);
i -= 1;
} while (i);
if (chk_ext)
{
if ( (*p1 != '?') && ((*p1 ^ *p2) & ~((GBL.parmp)->exm)) )
return(FALSE);
p1 += 2;
p2 += 2;
if ((*p1 ^ *p2) & 0x3f) return(FALSE);
}
return(TRUE);
}
/************************
* openfile entry point *
************************/
BOOLEAN openfile(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to open */
struct dirent *dirp; /* pointer to directory entry */
WORD dirindx;
{
REG UBYTE fcb_ext; /* extent field from fcb */
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, TRUE) )
{
fcb_ext = fcbp->extent; /* save extent number from user's fcb */
move(dirp, fcbp, sizeof *dirp);
/* copy dir entry into user's fcb */
fcbp->extent = fcb_ext;
fcbp->s2 |= 0x80; /* set hi bit of S2 (write flag) */
crit_dsk |= 1 << (GBL.curdsk);
}
return(rtn);
}
/*************************/
/* flush buffers routine */
/*************************/
UWORD flushit()
{
REG UWORD rtn; /* return code from flush buffers call */
struct iopb flushpkt; /* I/O packet for flush buffers call */
flushpkt.iofcn = flush;
while ( rtn = do_phio(&flushpkt) )
if ( error(1) ) break;
return(rtn);
}
/*********************************
* file close routine for dirscan *
*********************************/
BOOLEAN close(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb */
REG struct dirent *dirp; /* pointer to directory entry */
WORD dirindx; /* index into directory */
{
REG WORD i;
REG UBYTE *fp;
REG UBYTE *dp;
REG UWORD fcb_ext;
REG UWORD dir_ext;
BSETUP
if ( match(fcbp, dirp, TRUE) )
{ /* Note that FCB merging is done here as a final
confirmation that disks haven't been swapped */
LOCK
fp = &(fcbp->dskmap.small[0]);
dp = &(dirp->dskmap.small[0]);
if ((GBL.parmp)->dsm < 256)
{ /* Small disk map merge routine */
i = 16;
do
{
if (*dp)
{
if (*fp)
{
if (*dp != *fp) goto badmerge;
}
else *fp = *dp;
}
else *dp = *fp;
fp += 1;
dp += 1;
i -= 1;
} while (i);
}
else
{ /* Large disk map merge routine */
i = 8;
do
{
if (*(UWORD *)dp)
{
if (*(UWORD *)fp)
{
if (*(UWORD *)dp != *(UWORD *)fp) goto badmerge;
}
else *(UWORD *)fp = *(UWORD *)dp;
}
else *(UWORD *)dp = *(UWORD *)fp;
(UWORD *)fp += 1;
(UWORD *)dp += 1;
i -= 1;
} while (i);
}
/* Disk map merging complete */
fcb_ext = calcext(fcbp); /* calc max extent for fcb */
dir_ext = (UWORD)(dirp->extent) & 0x1f;
if ( (fcb_ext > dir_ext) ||
((fcb_ext == dir_ext) &&
(UBWORD(fcbp->rcdcnt) > UBWORD(dirp->rcdcnt))) )
/* if fcb points to larger file than dirp */
{
dirp->rcdcnt = fcbp->rcdcnt; /* set up rc, ext from fcb */
dirp->extent = (BYTE)fcb_ext;
}
dirp->s1 = fcbp->s1;
if ( (dirp->ftype[robit]) & 0x80) ro_err(fcbp,dirindx);
/* read-only file error */
dirp->ftype[arbit] &= 0x7f; /* clear archive bit */
dir_wr(dirindx >> 2);
UNLOCK
return(TRUE);
badmerge:
UNLOCK
ro_dsk |= (1 << GBL.curdsk);
return(FALSE);
}
else return(FALSE);
}
/************************
* close_fi entry point *
************************/
UWORD close_fi(fcbp)
struct fcb *fcbp; /* pointer to fcb for file to close */
{
flushit(); /* first, flush the buffers */
if ((fcbp->s2) & 0x80) return(0); /* if file write flag not on,
don't need to do physical close */
return( dirscan(close, fcbp, 0)); /* call dirscan with close function */
}
/************************
* search entry point *
************************/
/* First two functions for dirscan */
BOOLEAN alltrue(p1, p2, i)
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(TRUE);
}
BOOLEAN matchit(p1, p2, i)
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(match(p1, p2, TRUE));
}
/* search entry point */
UWORD search(fcbp, dsparm, p)
REG struct fcb *fcbp; /* pointer to fcb for file to search */
REG UWORD dsparm; /* parameter to pass through to dirscan */
UBYTE *p; /* pointer to pass through to tmp_sel */
{
REG UWORD rtn; /* return value */
BSETUP
if (fcbp->drvcode == '?')
{
seldsk(GBL.dfltdsk);
rtn = dirscan(alltrue, fcbp, dsparm);
}
else
{
tmp_sel(p); /* temporarily select disk */
if (fcbp->extent != '?') fcbp->extent = 0;
fcbp->s2 = 0;
rtn = dirscan(matchit, fcbp, dsparm);
}
move( GBL.dirbufp, GBL.dmaadr, SECLEN);
return(rtn);
}
/************************
* create entry point *
************************/
BOOLEAN create(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to create */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index into directory */
{
REG BYTE *p;
REG WORD i;
REG BOOLEAN rtn;
BSETUP
if ( rtn = ((dirp->entry) == (UBYTE)0xe5) )
{
p = &(fcbp->rcdcnt);
i = 17;
do
{ /* clear fcb rcdcnt and disk map */
*p++ = 0;
i -= 1;
} while (i);
move(fcbp, dirp, sizeof *dirp); /* move the fcb to the directory */
dir_wr(dirindx >> 2); /* write the directory sector */
if ( dirindx > (GBL.dphp)->hiwater )
(GBL.dphp)->hiwater = dirindx;
crit_dsk |= 1 << (GBL.curdsk);
}
return(rtn);
}
/************************
* delete entry point *
************************/
BOOLEAN delete(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index into directory */
{
REG WORD i;
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx);
/* check for read-only file */
dirp->entry = 0xe5;
LOCK
dir_wr(dirindx >> 2);
/* Now free up the space in the allocation vector */
if ((GBL.parmp)->dsm < 256)
{
i = 16;
do clraloc(UBWORD(dirp->dskmap.small[--i]));
while (i);
}
else
{
i = 8;
do clraloc(swap(dirp->dskmap.big[--i]));
while (i);
}
UNLOCK
}
return(rtn);
}
/************************
* rename entry point *
************************/
BOOLEAN rename(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index into directory */
{
REG UWORD i;
REG BYTE *p; /* general purpose pointers */
REG BYTE *q;
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx);
/* check for read-only file */
p = &(fcbp->dskmap.small[1]);
q = &(dirp->fname[0]);
i = 11;
do
{
*q++ = *p++ & 0x7f;
i -= 1;
} while (i);
dir_wr(dirindx >> 2);
}
return(rtn);
}
/************************
* set_attr entry point *
************************/
BOOLEAN set_attr(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index into directory */
{
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
move(&fcbp->fname[0], &dirp->fname[0], 11);
dir_wr(dirindx >> 2);
}
return(rtn);
}
/****************************
* utility routine used by *
* setran and getsize *
****************************/
LONG extsize(fcbp)
/* Return size of extent pointed to by fcbp */
REG struct fcb *fcbp;
{
return( ((LONG)(fcbp->extent & 0x1f) << 7)
| ((LONG)(fcbp->s2 & 0x3f) << 12) );
}
/************************
* setran entry point *
************************/
setran(fcbp)
REG struct fcb *fcbp; /* pointer to fcb for file to set ran rec */
{
union {
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
} bytes;
LONG random;
} random;
random.random = (LONG)UBWORD(fcbp->cur_rec) + extsize(fcbp);
/* compute random record field */
fcbp->ran0 = random.bytes.b2;
fcbp->ran1 = random.bytes.b1;
fcbp->ran2 = random.bytes.b0;
}
/**********************************/
/* fsize is a funtion for dirscan */
/* passed from getsize */
/**********************************/
BOOLEAN fsize(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent *dirp; /* pointer to directory entry */
WORD dirindx; /* index into directory */
{
REG BOOLEAN rtn;
union {
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
} bytes;
LONG longs;
} temp;
if ( rtn = match(fcbp, dirp, FALSE) )
{
temp.longs = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp);
/* compute file size */
fcbp->ran0 = temp.bytes.b2;
fcbp->ran1 = temp.bytes.b1;
fcbp->ran2 = temp.bytes.b0;
}
return(rtn);
}
/************************
* getsize entry point *
************************/
getsize(fcbp)
/* get file size */
REG struct fcb *fcbp; /* pointer to fcb to get file size for */
{
REG WORD dsparm;
union {
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
} bytes;
LONG longs;
} maxrcd, temp;
maxrcd.longs = 0;
dsparm = 0;
temp.longs = 0;
while ( dirscan(fsize, fcbp, dsparm) < 255 )
{ /* loop until no more matches */
temp.bytes.b2 = fcbp->ran0;
temp.bytes.b1 = fcbp->ran1;
temp.bytes.b0 = fcbp->ran2;
if (temp.longs > maxrcd.longs ) maxrcd.longs = temp.longs;
dsparm = 1;
}
fcbp->ran0 = maxrcd.bytes.b2;
fcbp->ran1 = maxrcd.bytes.b1;
fcbp->ran2 = maxrcd.bytes.b0;
}
/************************
* free_sp entry point *
************************/
free_sp(dsknum)
UBYTE dsknum; /* disk number to get free space of */
{
REG LONG records;
REG UWORD *alvec;
REG UWORD bitmask;
REG UWORD alvword;
REG WORD i;
LONG temp; /*sw For DMA Odd problem */
BSETUP
seldsk(dsknum); /* select the disk */
records = (LONG)0; /* initialize the variables */
alvec = (void *)(GBL.dphp)->alv;
bitmask = 0;
for (i = 0; i <= (GBL.parmp)->dsm; i++) /* for loop to compute */
{
if ( ! bitmask)
{
bitmask = 0x8000;
alvword = ~(*alvec++);
}
if ( alvword & bitmask)
records += (LONG)( ((GBL.parmp)->blm) + 1 );
bitmask >>= 1;
}
temp = records; /*sw Put in memory */
move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */
}

View File

@@ -0,0 +1,81 @@
#ifdef RLI
#include "diverge.h"
#endif
/****************************************************************
* *
* CP/M-68K BDOS Disk I/O System Module *
* *
* This module translates from the packet oriented I/O *
* passed from the other BDOS modules into BIOS calls. *
* *
* It includes only one external entry point:
* do_phio() - do physical i/o *
* *
* *
* Configured for Alcyon C on the VAX *
* *
****************************************************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
#include "biosdef.h" /* Declarations for BIOS entry points */
EXTERN udiv(); /* Assembly language unsigned divide routine */
/* in bdosif.s. It's used because Alcyon C */
/* can't do / or % without an external */
/************************
* do_phio entry point *
************************/
UWORD do_phio(iop)
REG struct iopb *iop; /* iop is a pointer to a i/o parameter block */
{
MLOCAL UBYTE last_dsk; /* static variable to tell which disk
was last used, to avoid disk selects */
REG struct dph *hdrp; /* pointer to disk parameter header */
REG struct dpb *dparmp; /* pointer to disk parameter block */
REG UWORD rtn; /* return parameter */
UWORD iosect; /* sector number returned from divide rtn */
LOCK /* lock the disk system while doing physical i/o */
rtn = 0;
switch (iop->iofcn)
{
case sel_info:
last_dsk = iop->devnum;
iop->infop = (void *)bseldsk(last_dsk, iop->ioflags);
break;
case read:
case write:
if (last_dsk != iop->devnum)
bseldsk((last_dsk = iop->devnum), 0);
/* guaranteed disk is logged on, because temp_sel in
BDOSMAIN does it */
hdrp = iop->infop;
dparmp = hdrp->dpbp;
bsettrk( udiv( iop->devadr, dparmp->spt, &iosect )
+ dparmp->trk_off );
bsetsec( bsectrn( iosect, hdrp->xlt ) );
bsetdma(iop->xferadr);
if ((iop->iofcn) == read) rtn = bread();
else rtn = bwrite(iop->ioflags);
break;
case flush:
rtn = bflush();
}
UNLOCK
return(rtn);
}

View File

@@ -0,0 +1,56 @@
/********************************************************
* *
* CP/M-68K header file *
* Copyright (c) 1982 by Digital Research, Inc. *
* Structure definitions for doing I/O in packets *
* *
********************************************************/
/* May use this information structure instead of disk parameter header and
disk parameter block in future, but for now it's unused
struct dskinfo
{
UBYTE *dbuffp;
UBYTE *csv;
UBYTE *alv;
UBYTE blksize;
UBYTE didummy;
UWORD dskmax;
UWORD dirmax;
UWORD chksize;
};
*/
struct iopb
{
UBYTE iofcn; /* function number, see defines below */
UBYTE ioflags; /* used for login flag and write flag */
UBYTE devtype; /* device type, see defines below */
/* currently unused */
UBYTE devnum; /* device number, or, devtype and devnum
taken together form int device number */
LONG devadr; /* item nmbr on device to start xfer at */
/* note -- item is sector for disks, byte for char devs */
UWORD xferlen; /* number items to transfer */
UBYTE *xferadr; /* memory address to xfer to/from */
struct dph *infop; /* pointer to disk parameter header */
/* return parm for fcn 0, input for rest */
};
/* Definitions for iofcn, the function number */
#define sel_info 0 /* select and return info on device */
#define read 1
#define write 2
#define flush 3
#define status 4 /* not currently used */
/* Definitions for devtype, the device type */
/* This field not currently used */
#define console 0
#define printer 1
#define disk 2
#define memory 3 /* gets TPA boundaries */
#define redir 4 /* read/write IOByte */
#define exc_vec 5 /* set exception vector */