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,37 @@
/****************************************************************************/
/* */
/* B A S E P A G E . H */
/* ------------------- */
/* */
/* This file contains a definition of the CP/M basepage structure, */
/* b_page. */
/* */
/* NOTE: In the portable CP/M environment, it is NOT guaranteed */
/* that the location of the base page is known at link-edit time */
/* (as it is, for example, in CP/M-80 and CP/M-86.) Instead, a */
/* pointer to the current basepage is delivered by the BDOS */
/* to each new program which is run. This pointer, _base, is */
/* initialized by the C startup function (startup.s) and is */
/* available to C programs as an external. */
/* */
/* This file has been modified to live with the BDOS definitions. */
/* */
/****************************************************************************/
struct b_page
{
XADDR ltpa; /* Low TPA address */
XADDR htpa; /* High TPA address */
XADDR lcode; /* Start address of code seg*/
long codelen; /* Code segment length */
XADDR ldata; /* Start address of data seg*/
long datalen; /* Data segment length */
XADDR lbss; /* Start address of bss seg */
long bsslen; /* Bss segment length */
long freelen; /* Free segment length */
char resvd1[20]; /* Reserved area */
struct fcb fcb2; /* Second basepage FCB */
struct fcb fcb1; /* First basepage FCB */
char buff[128]; /* Default DMA buffer, */
/* command line tail */
};

View File

@@ -0,0 +1,171 @@
/********************************************************
* *
* P-CP/M header file *
* Copyright (c) 1982 by Digital Research, Inc. *
* Structure definitions for BDOS globals *
* and BDOS data structures *
* *
********************************************************/
/**************************************************************************
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. These type of variables are 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
undefined to create based structure for re-entrant model */
#ifdef 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 */
#else
#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 */
union smallbig
{
UBYTE small[16]; /* 16 block numbers of 1 byte */
WORD big[8]; /* or 8 block numbers of 1 word */
};
/* 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 smallbig 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 smallbig 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 */
struct stvars
{
UBYTE kbchar; /* One byte keyboard type-ahead buffer */
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 */
XADDR chainp; /* Used for chain to program call */
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 */
XADDR dmaadr; /* Disk dma address */
XADDR srchp; /* Pointer to search FCB for function 17 */
UBYTE *excvec[18]; /* Array of exception vectors */
};
/* Console buffer structure declaration */
struct conbuf
{
UBYTE maxlen; /* Maximum length from calling routine */
UBYTE retlen; /* Length actually found by BDOS */
UBYTE cbuf[1]; /* Console data */
};

View File

@@ -0,0 +1,249 @@
;****************************************************************
;* *
;* CP/M-Z8K Basic Disk Operating System interface module *
;* For "C" version of CP/M-Z8K *
;* *
;* Copyright (c) 1982 Digital Research, Inc. *
;* *
;* Version 0.2 -- September 22, 1982 *
;* Z8000 version -- 821014 *
;* *
;****************************************************************
__text: .sect
;****************************************************
;*
;* Globals
;*
;****************************************************
.global _bios1 ; 6 BIOS entry points from BDOS
.global _bios2
.global _bios3
.global _bios4
.global _bios5
.global _bios6
.global _traphnd ; trap #2 handler
.global _swap ; byte swapper
.global _udiv ; unsigned divide routine
;****************************************************
;*
;* Externals and Constants
;*
;****************************************************
.global __bdos ; BDOS entry point in bdosmain
;* The following were put in so that all BDOS modules were
;* referenced, so they could be put in a library
.global _constat ; references conbdos.o
.global _dirscan ; references dskutil.o
.global _create ; references fileio.o
.global _bdosrw ; references bdosrw.o
biosf .equ 50
setsupf .equ 62
;****************************************************
;*
;* Trap Handler
;*
;* rcode = bdos(command, (long)parameter)
;*
;* rr6: parameter
;* r5: command
;* returns
;* r7: result
;*
;* called SEGMENTED with caller's registers
;* saved on stack, and all but rr0 intact in
;* registers.
;*
;* Calls __bdos(cmd, (word)param, (addr)param)
;*
;****************************************************
_traphnd:
ldctl r0,FCW ;go non-segmented
res r0,#15
ldctl FCW,r0
;
; check for functions handled by assembly
; language routines
;
cp r5,#setsupf ; set system mode
jr eq setsup
cp r5,#biosf ; call bios direct
jr eq bioscall
;
; If caller was non-segmented user program,
; get segment number from his program counter
;
ldl rr2,rr6
ld r0,34+4(r15) ;caller's fcw
bit r0,#15
jr nz callC ; segmented
bit r0,#14
jr nz callC ; system
ld r2,36+4(r15) ; user nonseg.
; set seg from PC
;
; Call C main routine
;
callC:
pushl @r15,rr2 ; xaddr param.
push @r15,r7 ; word param
push @r15,r5 ; command
call __bdos
add r15,#8
;
; Return result in caller's r7.
; Restore segmented mode and return
;
ld 14+4(r15),r7
ldctl r0,FCW ;go segmented
set r0,#15
ldctl FCW,r0
ret
;
; direct BIOS call function
;
bioscall:
;
; If caller was non-segmented user program,
; get segment number from his program counter
;
ld r0,34+4(r15) ;caller's fcw
bit r0,#15
jr nz callBios ; segmented
bit r0,#14
jr nz callBios ; system
ld r6,36+4(r15) ; user nonseg.
ld r2,r6 ; set seg from PC
; save in r2, also
ldctl r0,FCW ;go segmented
set r0,#15
ldctl FCW,r0
ldm r3,@r6,#5 ;get parameters
ld r4,r2 ;set segments
ld r6,r2
sc #3 ;call BIOS
ret ;done
callBios:
ldctl r0,FCW ;go segmented
set r0,#15
ldctl FCW,r0
ldm r3,@r6,#5 ;get parameters
sc #3 ;call BIOS
ret ;done
;
; Set supervisor mode procedure -- VERY DANGEROUS
;
; Status is set to SYSTEM, SEGMENTED.
; Interrupt status will be that at the time
; of the call.
;
setsup:
ld r0,34+4(r15)
set r0,#14 ;set system
set r0,#15 ; and segmented
ld 34+4(r15),r0 ; in user FCW
ldctl r0,FCW ;go segmented
set r0,#15
ldctl FCW,r0
ret ;return
;****************************************************
;*
;* BIOS Interface Routines
;*
;* Note - there are 6 BIOS entry points from the BDOS,
;* labelled BIOS1 - BIOS6, depending on the
;* parameters passed.
;*
;****************************************************
_bios5:
; For BIOS functions sectran and set exception vector
; (funct, word, long) offsets 2, 4, 6
ldl rr6,6(r15) ; get 2nd param (long)
jp _bios2 ; join common routine
_bios4:
; For BIOS function seldsk
; (func, word, word) offsets 2, 4, 6
ld r7,6(r15) ; get 2nd param (word)
clr r6 ; extend to ulong
jp _bios2 ; join common routine
_bios3:
; For BIOS function set dma
; (func, long) offsets 2, 4
ldl rr4,4(r15) ; get 1st param (long)
subl rr6,rr6 ; clear second
jp _bios1 ; join common routine
_bios2:
; For all BIOS functions with a word parameter
; (func, word) offsets 2, 4
ld r5,4(r15) ; get 1st param (word)
clr r4 ; extend to ulong
_bios6:
_bios1:
; For all BIOS functions that have no parameter
; other than function number
ld r3,2(r15) ; get function number
sc #3 ; do BIOS call
ret ; returns value in rr7
;****************************************************
;*
;* Utility Subroutines
;*
;* swap(word) swap bytes of a word
;*
;* uword udiv((long) dividend,
;* (uword) divisor,
;* (uword *)rem )
;*
;****************************************************
_swap:
ld r7,2(r15)
exb rh7,rl7
ret
_udiv:
ldl rr2,2(r15) ;long dividend
subl rr0,rr0 ; as unsigned quad
ld r5,6(r15) ;word divisor
clr r4 ; as unsigned long
ldl rr6,8(r15) ;->result
divl rq0,rr4
ld @r7,r1 ; store remainder
ld r7,r3 ; return quotient
clr r6
ret

View File

@@ -0,0 +1,379 @@
/****************************************************************
* *
* P-CP/M BDOS Main Routine *
* *
* This is the main routine for the BDOS for P-CP/M. *
* 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, (passed as both an integer and *
* a pointer) *
* The BDOS can potentially return a pointer, long word, *
* or word *
* *
* Memory management for Z8000, etc. added 821018 by SS. *
* One non-obvious change is using tmp_sel to copy in the *
* user's FCB, and copying it out again if changed. *
* Tmp_sel now handles '?' in the drive field, so it need *
* not be called from search (the only place outside of *
* this module where it is called) *
* *
****************************************************************/
#include "stdio.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 cookdout(); /* Cooked console output routine */
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 = 0; /* 16-bit vector of logged in drives */
GLOBAL UWORD ro_dsk = 0; /* 16-bit vector of read-only drives */
GLOBAL UWORD crit_dsk = 0; /* 16-bit vector of drives in "critical"
state. Used to control dir checksums */
GLOBAL XADDR tpa_lp; /* TPA lower boundary (permanent) */
GLOBAL XADDR tpa_lt; /* TPA lower boundary (temporary) */
GLOBAL XADDR tpa_hp; /* TPA upper boundary (permanent) */
GLOBAL XADDR 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;
XADDR fxptr; /* xaddr of caller's FCB */
struct fcb tempfcb; /* added for memory management */
/* because caller's fcb may not */
/* be directly accessible */
};
/****************************************************************
* *
* _bdos MAIN ROUTINE *
* *
* Called with _bdos(func, info, infop) *
* *
* Where: *
* func is the BDOS function number (d0.w) *
* info is the parameter as a word *
* infop is the parameter as a segmented pointer *
* note that info is the word form of infop*
* *
****************************************************************/
UWORD _bdos(func,info,infop)
REG WORD func; /* BDOS function number */
REG UWORD info; /* parameter as word */
REG XADDR infop; /* parameter as (segmented) pointer */
{
REG UWORD rtnval;
LOCAL struct tempstr temp;
BSETUP
temp.reselect = FALSE;
temp.fxptr = 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: cookdout((UBYTE)info,FALSE);/* "cooked" console output */
break;
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: uprt_line(infop); /* print line function */
break;
case 10: ureadline(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 */
temp.fptr->extent = 0;
temp.fptr->s2 = 0;
rtnval = dirscan(openfile, temp.fptr, 0);
break;
case 16: tmp_sel(&temp); /* close file */
rtnval = close_fi(temp.fptr);
break;
case 17: GBL.srchp = infop; /* search first */
tmp_sel(&temp);
rtnval = search(temp.fptr, 0, &temp);
break;
case 18: infop = GBL.srchp; /* search next */
temp.fxptr = infop;
tmp_sel(&temp);
rtnval = search(temp.fptr, 1, &temp);
break;
case 19: tmp_sel(&temp); /* delete file */
rtnval = dirscan(delete, temp.fptr, 2);
break;
case 20: tmp_sel(&temp); /* read sequential */
rtnval = bdosrw(temp.fptr, TRUE, 0);
break;
case 21: tmp_sel(&temp); /* write sequential */
rtnval = bdosrw(temp.fptr, FALSE, 0);
break;
case 22: tmp_sel(&temp); /* create file */
temp.fptr->extent = 0;
temp.fptr->s1 = 0;
temp.fptr->s2 = 0;
temp.fptr->rcdcnt = 0;
/* Zero extent, S1, S2, rcrdcnt. create zeros rest */
rtnval = dirscan(create, temp.fptr, 8);
break;
case 23: tmp_sel(&temp); /* rename file */
rtnval = dirscan(rename, temp.fptr, 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, temp.fptr, 2);
break;
case 31: if (GBL.curdsk != GBL.dfltdsk) seldsk(GBL.dfltdsk);
cpy_out( (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(temp.fptr, TRUE, 1);
break;
case 34: tmp_sel(&temp); /* random write */
rtnval = bdosrw(temp.fptr, FALSE, 1);
break;
case 35: tmp_sel(&temp); /* get file size */
getsize(temp.fptr);
break;
case 36: tmp_sel(&temp); /* set random record */
setran(temp.fptr);
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(temp.fptr, FALSE, 2);
break;
case 46: free_sp(info); /* get disk free space */
break;
case 47: GBL.chainp = GBL.dmaadr; /* chain to program */
warmboot(0); /* terminate calling program */
/* break; */
case 48: return( flushit() ); /* flush buffers */
/* break; */
case 59: return(pgmld(infop)); /* 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){ /* if reselected disk, restore it now */
temp.fptr->drvcode = temp.tempdisk;
cpy_out(temp.fptr, infop, sizeof *temp.fptr);
}
return(rtnval); /* return the BDOS return value */
} /* end _bdos */
/*****************************************************
**
** tmp_sel(temptr) -- temporarily select disk
** pointed to by temptr->fptr.
**
** make local copy of FCB in caller's space.
**
*****************************************************/
tmp_sel(temptr) /* temporarily select disk pointed to by fcb */
/* also copy fcb into temp structure */
REG struct tempstr *temptr;
{
REG struct fcb *fcbp;
REG UBYTE tmp_dsk;
BSETUP
/* get local copy of caller's FCB, */
/* and point temptr->fptr at it */
cpy_in(temptr->fxptr, &temptr->tempfcb, sizeof(struct fcb));
temptr->fptr = &temptr->tempfcb;
/* get local copy of fcb pointer */
fcbp = temptr->fptr;
/* select disk if necessary */
tmp_dsk = fcbp->drvcode;
if (tmp_dsk == '?') { /* -- drive '?' for search */
seldsk( GBL.dfltdsk);
} else { /* -- drive 0 or disk+1 */
temptr->tempdisk = tmp_dsk;
seldsk( tmp_dsk ? tmp_dsk - 1 : GBL.dfltdsk );
fcbp->drvcode = GBL.user;
temptr->reselect = TRUE;
}
}
/*****************************************************
**
** uprt_line(ptr) -- print line in user space
** ureadline(ptr) -- read line into user space
**
** The pointer parameter is passed as a long,
** since it may be in the user's memory space.
**
*****************************************************/
uprt_line(ptr)
XADDR ptr;
{
UBYTE c;
XADDR caddr;
/* At one system-call per byte, this is VERY inefficient. */
caddr = map_adr((XADDR)&c, 0);
while (mem_cpy(ptr++, caddr, 1L), c != GBL.delim)
cookdout( c, FALSE);
}
ureadline(ptr)
XADDR ptr;
{
char buf[258];
cpy_in(ptr, buf, 1); /* copy in user's buffer */
readline(buf); /* read line */
cpy_out(buf, ptr, 2+(255&(int)buf[1])); /* copy out result */
}

View File

@@ -0,0 +1,327 @@
/****************************************************************
* *
* P-CP/M BDOS Miscellaneous Module *
* *
* This module contains miscellaneous loose ends for *
* P-CP/M. Included are: *
* *
* bdosinit() - BDOS initialization routine *
* called from CCP for system init *
* warmboot() - BDOS warm boot exit routine *
* error() - BDOS error printing routine *
* setexc() - BDOS set exception vector *
* set_tpa() - BDOS get/set TPA limits *
* cpy_bi() - copy byte in *
* *
* *
* Modified for memory management on the Z8000 *
* *
****************************************************************/
#include "stdio.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "biosdef.h" /* BIOS definitions, needed for bios wboot */
/* 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 *traphnd(); /* 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 */
/* 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 XADDR tpa_lt; /* TPA lower limit (temporary) */
EXTERN XADDR tpa_lp; /* TPA lower limit (permanent) */
EXTERN XADDR tpa_ht; /* TPA upper limit (temporary) */
EXTERN XADDR 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;
XADDR low;
LONG length;
} *segp;
BSETUP
bsetvec(trap2v, map_adr((long)traphnd, 257)); /* set up trap vector */
/* (inst. space addr) */
GBL.kbchar = 0; /* initialize the "global" variables */
GBL.delim = '$';
GBL.lstecho = FALSE;
GBL.echodel = TRUE;
GBL.chainp = XNULL;
GBL.user = 0;
_bdos(13,0, XNULL); /* reset disk system function */
prt_line("
\r\nCPM-Z8000 Version 1.2 03/14/83$");
prt_line("\r\nCopyright 1982 Digital Research Inc., Zilog Inc.$");
segp = 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
log_dsk &= ~ro_dsk; /* log off any disk marked read-only */
/* note that this code is specifically for a single-
thread system. It won't work in a multi-task sys */
ro_dsk = 0;
crit_dsk = 0;
if (parm)
submit = morecmds = FALSE;
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);
}
ext_err(p)
/* print the error message, and allow for retry, abort, or ignore */
BYTE *p;
{
REG UBYTE ch;
prt_err(p);
do
{
prt_line("\n\rDo you want to: Abort (A), Retry (R),$");
prt_line(" or Continue with bad data (C)? $");
ch = conin() & 0x5f;
prt_line("\r\n$");
switch ( ch )
{
case ctrlc: warmboot(1);
case 'A': warmboot(1);
case 'C': return(1);
case 'R': return(0);
}
} while (TRUE);
}
filero(fcbp)
/* File R/O error */
REG struct fcb *fcbp;
{
REG BYTE *p;
REG UWORD i;
REG UBYTE ch;
p = (BYTE *)fcbp;
prt_line("file error: $");
i = 8;
do conout(*++p); while (--i);
conout('.');
i = 3;
do conout(*++p); while (--i);
prt_line(" is read-only.$");
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;
return( dirscan(set_attr, fcbp, 2) );
}
} while (TRUE);
}
/************************
* error entry point *
************************/
error(errnum, fcbp) /* VARARGS */
/* Print error message, do appropriate response */
UWORD errnum; /* error number */
struct fcb *fcbp; /* pointer to fcb */
{
BSETUP
prt_line("\r\nCP/M Disk $");
switch (errnum)
{
case 0: return( ext_err("read$") );
/* break; */
case 1: return( ext_err("write$") );
/* break; */
case 2: abrt_err("select$");
/* break; */
case 3: return( ext_err("select$") );
/* break; */
case 4: abrt_err("change$");
/* break; */
case 5: return filero(fcbp);
/* break; */
}
}
/*****************************
* set exception entry point *
*****************************/
setexc(xepbp)
/* Set Exception Vector */
REG XADDR xepbp;
{
REG WORD i;
REG struct
{
WORD vecnum;
UBYTE *newvec;
UBYTE *oldvec;
} epb;
BSETUP
cpy_in(xepbp, &epb, sizeof epb); /* copy in param block */
i = epb.vecnum-2;
if ( i==32 || i==33) return(-1);
if ( (30 <= i) && (i <= 37) ) i -= 20;
else if ( (i < 0) || (i > 9) ) return(-1);
epb.oldvec = GBL.excvec[i];
GBL.excvec[i] = epb.newvec;
cpy_out(&epb, xepbp, sizeof epb); /* copy out param block */
return(0);
}
/*****************************
* get/set TPA entry point *
*****************************/
set_tpa(xp)
/* Get/Set TPA Limits */
REG XADDR xp;
#define set 1
#define sticky 2
{
struct
{
UWORD parms;
XADDR low;
XADDR high;
} p;
cpy_in(xp, &p, sizeof p); /* copy in param block */
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;
}
cpy_out(&p, xp, sizeof p); /* copy out param block */
}
/*****************************************************
**
** ubyte = cpy_bi(xaddr)-- copy byte in
**
*****************************************************/
UBYTE cpy_bi(addr)
XADDR addr;
{
UBYTE b;
cpy_in(addr, &b, 1);
return b;
}

View File

@@ -0,0 +1,302 @@
/****************************************************************
* *
* P-CP/M BDOS Disk Read/Write Module *
* *
* This module contains functions to perform sequential *
* or random access read or write to the disk for P-CP/M *
* *
* It includes the following external functions: *
* *
* bdosrw() - sequential and random disk I/O *
* *
* *
* Modified for memory management on the Z8000 *
* *
****************************************************************/
#include "stdio.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 UWORD 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 error(); /* 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 */
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 new one */
if ( close_fi(fcbp) >= 255 ) return(3);
/* can't close old extent */
fcbp->s2 = mod;
fcbp->extent = ext;
if ( dirscan(openfile, fcbp, 0) >= 255 ) /* open new extent */
{
if (reading) return(4); /* reading unwritten extent */
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 XADDR old_dma; /* temp holding spot for dmaadr */
REG UBYTE *buf; /* type compatibility kludge */
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) ) error(5,fcbp);
/* 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 == 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 */
block = getaloc();
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 = map_adr((XADDR)GBL.dirbufp,0);/* Do DMA from dir_buf */
index = SECLEN;
buf = (UBYTE *)GBL.dirbufp; /* fix type incompatibility */
do buf[--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);
}

View File

@@ -0,0 +1,64 @@
/********************************************************
* *
* BIOS definitions for P-CP/M *
* *
* Copyright (c) 1982 Digital Research, Inc. *
* *
* This include file simply defines the BIOS calls *
* *
* Memory management added 821018 by SS at Zilog *
* *
********************************************************/
EXTERN long bios(); /* main BIOS entry point */
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,(XADDR)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,(XADDR)parm2)
/* set exception vector */
/************************/
/* MEMORY MANAGEMENT */
/*----------------------*/
EXTERN XADDR map_adr(); /*(laddr, space)->paddr */
EXTERN VOID mem_cpy(); /*(src, dst, len) */
/*----------------------*/
/* copy in, out (s,d,l) */
/* */
#define cpy_in(s,d,l) mem_cpy((XADDR)s, map_adr((XADDR)d, 0), (long)l)
#define cpy_out(s,d,l) mem_cpy(map_adr((XADDR)s, 0), (XADDR)d, (long)l)
/* */
/************************/

View File

@@ -0,0 +1,322 @@
/********************************************************
* *
* P-CP/M 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(); *
* cookdout(); *
* rawconio(); *
* prt_line(); *
* readline(); *
* *
* Copyright (c) 1982 Digital Research, Inc. *
* *
********************************************************/
#include "stdio.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 */
EXTERN UBYTE cpy_bi(); /* copy byte in from user space */
/******************/
/* 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(1);
if ( ch == ctrls ) stop = TRUE;
else if (ch == ctrlq) stop = FALSE;
else if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
else GBL.kbchar = ch;
} 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 (ch >= ' ') 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 */
/*************************************/
cookdout(ch, ctlout)
REG UBYTE ch; /* character to output */
BOOLEAN ctlout; /* output ^<char> for control chars? */
{
BSETUP
if (ch == tab) do /* expand tabs */
conout( ' ' );
while (GBL.column & 7);
else
{
if ( ctlout && (ch < ' ') )
{
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
temp = GBL.kbchar; /* get buffered char */
GBL.kbchar = 0; /* clear it */
return( temp ? temp : bconin() ); /* if non-zero, return it */
/* 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 return(bconout(parm & 0xff)); /* add return to make lint happy */
}
/****************************************************/
/* print line up to delimiter($) with tab expansion */
/****************************************************/
prt_line(p)
REG UBYTE *p;
{
BSETUP
while( *p != GBL.delim ) cookdout( *(p++), FALSE);
}
/**********************************************/
/* 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(p, stcol) /* backspace one character position */
REG struct conbuf *p; /* pointer to console buffer */
UWORD stcol;
{
REG WORD i;
REG WORD length;
REG UBYTE ch;
BSETUP
if (p->retlen) length = UBWORD(--(p->retlen));
/* if buffer non-empty, decrease it by 1 */
else length = 0;
i = stcol;
while (length--)
{
ch = p->cbuf[length]; /* get character from buffer */
if ( ch == tab )
{
i += 8; /* i is our column counter */
i &= ~7; /* for tab, go to multiple of 8 */
}
else if ( ch < ' ' ) i += 2;
/* control chars put out 2 printable chars */
else i += 1;
}
while (GBL.column > i)
{
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 */
if (GBL.chainp != XNULL) /* chain to program code */
{
i = UBWORD(cpy_bi(GBL.chainp++)); /* cpy in from user space */
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++ = cpy_bi(GBL.chainp++), TRUE);
i -= 1;
}
GBL.chainp = XNULL;
return;
}
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, TRUE);
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], TRUE);
}
else /* normal character */
cookdout( (p->cbuf[UBWORD((p->retlen)++)] = ch), TRUE );
}
}

View File

@@ -0,0 +1,277 @@
/****************************************************************
* *
* P-CP/M BDOS Disk Utilities Module *
* *
* This module contains the miscellaneous utilities *
* for manipulating the disk in P-CP/M. 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 *
* *
* *
* Modified for memory management on Z8000 *
* *
****************************************************************/
#include "stdio.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
#include "biosdef.h" /* Bios & mem mapperinterface */
/* 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 */
/**********************
* 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 */
XADDR 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)
UWORD secnum;
{
BSETUP
return( rdwrt((LONG)secnum, map_adr((XADDR)GBL.dirbufp, 0), 0) );
}
/****************************
* directory write routine *
****************************/
UWORD dir_wr(secnum)
REG WORD secnum;
{
REG UWORD rtn;
UBYTE dchksum();
BSETUP
rtn = rdwrt( (LONG)secnum, map_adr((XADDR)GBL.dirbufp, 0), 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 = (LONG *)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 continu 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 */
/* Sorry about this FOR loop, but the initialization terms and end test
really do depend on the input parameters, so...... */
for ( i = ( (parms & continu) ? GBL.srchpos + 1 : 0);
i <= ( (parms & pasthw) ? (dparmp->drm) : (GBL.dphp)->hiwater );
i++ )
{ /* main directory scanning loop */
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 */
}
}
return(rtn);
}
/****************************************
* Routines to manage allocation vector *
* setaloc() *
* clraloc() *
* getaloc() *
****************************************/
setaloc(bitnum)
/* Set bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
*((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7);
}
clraloc(bitnum)
/* Clear bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
if (bitnum)
*((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7));
}
UWORD getaloc()
/* Get a free block in the file system and set the bit in allocation vector */
{
REG UWORD i; /* loop counter */
REG WORD diskmax; /* # bits in alv - 1 */
REG UBYTE *p; /* ptr to byte */
BSETUP
LOCK /* need to lock the file system while messing
with the allocation vector */
diskmax = (GBL.parmp)->dsm;
/* get disk max field from dpb */
p = (GBL.dphp)->alv;
for (i = 0; i <= diskmax; i++)
{
if ( ~(*(p + (i >> 3))) & (0x80 >> (i&7)) )
{ /* found a zero in allocation vector */
setaloc(i);
UNLOCK /* can unlock file system now */
return(i); /* return block number */
}
}
return(~0); /* if no free block found, return -1 */
}

View File

@@ -0,0 +1,356 @@
;************************************************
;* *
;* P-CP/M Basic Disk Operating System *
;* Exception Handling Module *
;* *
;* Version 0.0 -- July 21, 1982 *
;* Version 0.1 -- July 25, 1982 *
;* Version 0.2 -- 821014 (Zilog) *
;* Version 0.3 -- 821222 (Zilog) *
;* *
;************************************************
__text: .sect
;****************************************************
;*
;* Externals
;*
;****************************************************
.global _sysseg
.global _tpa_lp
.global _tpa_hp
;****************************************************
;*
;* Globals and Constants
;*
;****************************************************
.global _initexc
BGETSEG .equ 18 ;Bios call to get mem seg tbl
BSETEXC .equ 22 ;Bios call to set xvec
BIOS_SC .equ 3 ;Bios system call
;****************************************************
;*
;* initexc(vecarray) -- initialize exception vector
;*
;* The BDOS maintains its OWN exception vector.
;* This routine sets up the BIOS exception
;* vectors to point to handlers in this module,
;* that vector again using the BDOS vectors.
;*
;* Only vectors 2-23 and 36-38 are handled by
;* the BDOS, leaving 0-1 and 24-35 for the BIOS
;*
;****************************************************
_initexc:
;* sp -> return addr
;* +2 table addr
ld r3,#BSETEXC ; r3 = BDOS command
ldl rr4,#2 ;rr4 = exception #
ld r6,_sysseg ;rr6 -> handler
lda r7,exchndl ; (segmented)
dec r15,#10 ;space to save regs
; on stack over SC
initloop:
ldm @r15,r3,#5
sc #BIOS_SC
ldm r3,@r15,#5
inc r5,#1 ;step exception #
inc r7,#2 ;and handler addr.
cp r5,#24 ;done 23 yet?
jr ne init1 ; no
ld r5,#36 ; yes--skip to 36
inc r7,#8 ; we have entries in
; table for 32-36
; but system uses
; them. Skip.
init1: cp r5,#48 ;done all 48?
jr ne initloop ; no--loop
inc r15,#10 ;clean stack
ld r2,2(r15) ;save vector address
ld evec_adr,r2
ld r0,#18 ; 18 long entries
subl rr4,rr4
init2: ;clear vector array
; should check current entry, and keep it if
; between old TPA and current TPA limits.
; The TPA limits are flaky because we have two TPA's,
; for split and merged spaces, not to mention
; segmented programs.
; What we are going to do is clear the lot.
; Programs that want permanent traps can use the
; Bios to set the trap vector.
ldl rr6,@r2 ; rr6 = exception addr
ldl @r2,rr4
init3:
inc r2,#4
djnz r0,init2
ret ;return
;****************************************************
;*
;* Exception Handler Routine
;*
;* An exception handler is called as a subroutine
;* in segmented mode, with all registers saved
;* on the stack.
;*
;* Returning (ret) from the handler (in segmented
;* mode) will return to the state-restorer.
;*
;****************************************************
exchndl:
calr except
excrtn0:
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
calr except
except: ; general exception handler
ldctl r0,FCW ; NONSEGMENTED
res r0,#15
ldctl FCW,r0
popl rr0,@r15 ; get return address
; from above array
sub r1,#excrtn0 ; r1 now = 4*encoded
srl r2,#2 ; exception number
; r1/4 = [0..21, 22..37] represents exceptions
; [2..23, 32..47].
;
; If r1/4 is in the range [0..9, 22..29] then the
; exception may be redirected by the BDOS.
cp r1,#36
jr le chkredir
cp r1,#88
jr lt dfltexc
cp r1,#116
jr gt dfltexc
; in range of redirected exceptions
sub r1,#48 ; subtract 4*12 to normalize [0..9,22..29]
; into [0..9,10..17]
chkredir:
ld r2,evec_adr ; index into exception
; vector array
ldl rr4,r2(r1) ; rr4 -> handler
testl rr4 ; if non-zero
jr nz usrexc ; go do it
;not redirected,
; do default handler
cp r1,#40
jr lt dfltexc
add r1,#48 ; add 4*12 sub'd above
dfltexc:
srl r1,#2 ; divide r1 by 4
; r1 = [0..21,22..37]
; meaning [2..23,32..47]
add r1,#2 ;get back real except#
cp r1,#23
jr le lowexc
add r2,#12
lowexc:
push @r15,r1 ; save exception #
; print default msg
clr r6
ld r7,#excmsg1
calr print
calr prtdollar
pop r1,@r15
calr prtbyte
clr r6
ld r7,#excmsg2
calr print
calr prtdollar
popl rr0,@r15
calr prtlong
clr r6
ld r7,#excmsg3
calr print
clr r5 ; warm boot
sc #2
ret
usrexc: ; call user exception handler
; rr4 -> handler
; user exception handler called in with FCW restored
; to that at the time of the exception, with the
; stack containing a copy of the context block.
; On top of the context block will be a GARBAGE
; return address of the appropriate mode.
; Handler must exit with XFER system call.
; stack now contains:
; return address (long) to trap_ret
; normal r0..r15
; reason, fcw, PC (long)
ld r1,38(r15) ;34+4 r1 = user FCW
bit r1,#14 ;system mode?
jr nz sysexc ; yes
; no
ldl rr2,32(r15) ;28+4 rr2 = user stack
bit r1,#15 ;segmented?
jr nz segusrx ; yes
; no -- get seg
ld r2,42(r15) ;38+4
segusrx:
ldctl r0,FCW ;go segmented
set r0,#15
ldctl FCW,r0
sub r3,#44 ;copy frame to usr
; (with junk PC)
ld r0,#22
ldir @r2,@r14,r0
pushl @r14,rr4 ;go
pushl @r14,rr0
iret
sysexc: ;system mode exc.
set r1,#15 ; go segmented
ldctl FCW,r1
jp @r4 ;go
;****************************************************
;*
;* Subroutines
;*
;****************************************************
print:
ld r5,#9 ;PRINTMSG
sc #2 ;BDOS
ret
prtdollar:
ld r5,#2 ;PRINTCHAR
ldl rr6,#24h ; dollarsign
sc #2
ret
prtlong: ; print rr0 as hex long
push @r15,r1
ex r0,r1
calr prtword
pop r1,@r15
prtword: ; print r1 as hex word
push @r15,r1
ldb rl1,rh1
calr prtbyte
pop r1,@r15
prtbyte: ; Print rl1 as hex byte
push @r15,r1
srl r1,#4
calr prtnib
pop r1,@r15
prtnib:
and r1,#15
cp r1,#10
jr lt lt10
add r1,#7
lt10:
add r1,#30h
ld r7,r1
ld r5,#2 ;PRINTBYTE
sc #2 ;BDOS
ret
;****************************************************
;*
;* data
;*
;****************************************************
__data: .sect
excmsg1:
.byte 13,10,10,"Exception $"
excmsg2:
.byte " at user address $"
excmsg3:
.byte ". Aborted.$"
;****************************************************
;*
;* bss
;*
;****************************************************
__bss: .sect
evec_adr:
.block 2
.end

View File

@@ -0,0 +1,662 @@
/****************************************************************
* *
* P-CP/M BDOS File I/O Module *
* *
* This module contains all file handling BDOS functions *
* except for read and write for P-CP/M. 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 *
* *
* *
* Modified for memory management on Z8000 *
* The main change is that search no longer calls tmp_sel *
* tmp_sel in bdosmain.c now handles drive number = '?' *
* *
****************************************************************/
#include "stdio.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "biosdef.h" /* and BIOS */
#include "pktio.h" /* Packet I/O definitions */
/* declare external fucntions */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN UWORD error(); /* disk 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) /* ARGSUSED */
/* 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 ( (GBL.dphp = (struct dph *)selpkt.infop) != NULL ) break;
} while ( ! error(3) );
GBL.dirbufp = (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) /* ARGSUSED */
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;
fp += sizeof (UWORD);
dp += sizeof (UWORD);
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 ( (fcbp->ftype[robit]) & 0x80) error(5,fcbp);
/* 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) /* ARGSUSED */
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(TRUE);
}
BOOLEAN matchit(p1, p2, i) /* ARGSUSED */
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(match(p1, p2, TRUE));
}
/* search entry point */
UWORD search(fcbp, dsparm, p) /* ARGSUSED */
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 */
/* -- now unused -- */
{
REG UWORD rtn; /* return value */
BSETUP
if (fcbp->drvcode == '?')
{
rtn = dirscan(alltrue, fcbp, dsparm);
}
else
{
if (fcbp->extent != '?') fcbp->extent = 0;
fcbp->s2 = 0;
rtn = dirscan(matchit, fcbp, dsparm);
}
cpy_out( 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) == 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 ) error(5,fcbp);
/* 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 ) error(5,fcbp);
/* 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 */
{
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
LONG random;
random = (LONG)UBWORD(fcbp->cur_rec) + extsize(fcbp);
/* compute random record field */
fcbp->ran0 = random.b2;
fcbp->ran1 = random.b1;
fcbp->ran2 = random.b0;
}
/**********************************/
/* fsize is a funtion for dirscan */
/* passed from getsize */
/**********************************/
BOOLEAN fsize(fcbp, dirp, dirindx) /* ARGSUSED */
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;
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
LONG temp;
if ( rtn = match(fcbp, dirp, FALSE) )
{
temp = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp);
/* compute file size */
fcbp->ran0 = temp.b2;
fcbp->ran1 = temp.b1;
fcbp->ran2 = temp.b0;
}
return(rtn);
}
/************************
* getsize entry point *
************************/
getsize(fcbp)
/* get file size */
REG struct fcb *fcbp; /* pointer to fcb to get file size for */
{
LONG maxrcd;
LONG temp;
REG WORD dsparm;
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
maxrcd = 0;
dsparm = 0;
temp = 0;
while ( dirscan(fsize, fcbp, dsparm) < 255 )
{ /* loop until no more matches */
temp.b2 = fcbp->ran0;
temp.b1 = fcbp->ran1;
temp.b0 = fcbp->ran2;
if (temp > maxrcd) maxrcd = temp;
dsparm = 1;
}
fcbp->ran0 = maxrcd.b2;
fcbp->ran1 = maxrcd.b1;
fcbp->ran2 = maxrcd.b0;
}
/************************
* free_sp entry point *
************************/
free_sp(dsknum)
UBYTE dsknum; /* disk number to get free space of */
{
LONG records;
REG UWORD *alvec;
REG UWORD bitmask;
REG UWORD alvword;
REG WORD i;
BSETUP
seldsk(dsknum); /* select the disk */
records = (LONG)0; /* initialize the variables */
alvec = (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;
}
/* move # records to DMA address */
cpy_out(&records, GBL.dmaadr, sizeof records);
}

View File

@@ -0,0 +1,78 @@
/****************************************************************
* *
* P-CP/M 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 *
* *
* *
* Modified for memory management on Z8000 *
* *
****************************************************************/
#include "stdio.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 = 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, (long)&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,482 @@
/****************************************************************
* *
* CP/M-8000 BDOS Program Loader *
* *
* Copyright (c) 1982 Zilog Incorporated *
* *
* This function implements BDOS call 59: Program Load. *
* The single parameter passed is a pointer to a space *
* where a partially filled LPB (Load Parameter Block) *
* can be found. pgmld must fill in the base page *
* address and the starting user stack pointer. In *
* addition, the Z8000 implementation will set a loader *
* flag if the program being loaded uses separate I/D *
* space or segmentation. *
* *
* NOTE! unlike the usual CP/M loader, the Z8000 loader *
* returns the actual starting address of the code segment *
* (starting PC) in the LPB, clobbering the program load *
* address. This is because the segment containing the *
* code may not be known until load time. *
* *
****************************************************************/
#include "stdio.h" /* Standard declarations for BDOS, BIOS */
#include "bdosdef.h" /* Type and structure declarations for BDOS */
#include "biosdef.h" /* Declarations of BIOS functions */
#include "basepage.h" /* Base page structure */
#include "x.out.h" /* structure of x.out (".Z8[KS] file") */
#define SPLIT 0x4000 /* Separate I/D flag for LPB */
#define SEG 0x2000 /* Segmented code flag for TPA */
#define NSEG 16 /* Maximum number of x.out segments */
#define SEGLEN 0x10000 /* Length of a Z8000 segment */
/* Address of basepage (near top of TPA)*/
#define BPLEN (sizeof (struct b_page))
#define DEFSTACK 0x100 /* Default stack length */
#define NREGIONS 2 /* Number of regions in the MRT */
/* return values */
#define GOOD 0 /* good return value */
#define BADHDR 1 /* bad header */
#define NOMEM 2 /* not enough memory */
#define READERR 3 /* read error */
#define MYDATA 0 /* Argument for map_adr */
#define TPAPROG 5 /* Argument for map_adr */
#define TPADATA 4 /* Argument for map_adr */
/* Get actual code segment (as opposed */
/* to segment where it can be accessed*/
/* as data) */
#define TRUE_TPAPROG (TPAPROG | 0x100)
struct lpb /* Load Parameter Block */
{
XADDR fcbaddr;/* Address of fcb of opened file */
XADDR pgldaddr;/* Low address of prog load area */
XADDR pgtop; /* High address of prog load area, +1 */
XADDR bpaddr; /* Address of basepage; return value */
XADDR stackptr;/* Stack ptr of user; return value */
short flags; /* Loader control flags; return value */
} mylpb;
struct ustack /* User's initial stack - nonsegmented */
{
short two; /* "Return address" (actually address */
/* of warm boot call in user's startup)*/
short bpoffset;/* Pointer to basepage */
};
struct sstack /* User's initial stack - segmented */
{
XADDR stwo; /* "Return address" (actually address */
/* of warm boot call in user's startup)*/
XADDR sbpadr; /* Pointer to basepage */
};
struct m_rt { /* The Memory Region Table */
int count;
struct {
XADDR tpalow;
XADDR tpalen;
} m_reg[NREGIONS];
};
#define SPREG 1 /* The MRT region for split I/D programs */
#define NSPREG 0 /* The MRT region for non-split programs */
#define SDREG 2 /* The MRT region for split I/D data */
#define NSDREG 0 /* The MRT region for non-split data */
#define READ 20 /* Read Sequential BDOS call */
#define SETDMA 26 /* Set DMA Address BDOS call */
extern UWORD bdos(); /* To do I/O into myself (note this */
/* function does not map 2nd param - */
/* see mbdos macro below) */
static XADDR textloc, /* Physical locations of pgm sections. */
dataloc,
bssloc,
stkloc;
static XADDR textsiz, /* Sizes of the various sections. */
datasiz,
bsssiz,
stksiz;
static UWORD split, /* Tells if split I/D or not */
seg; /* Tells if segmented or not */
static char *gp; /* Buffer pointer for char input */
static char *mydma; /* Local address of read buffer */
struct x_hdr x_hdr; /* Object File Header structure */
struct x_sg x_sg[NSEG]; /* Segment Header structure */
static XADDR segsiz[NSEG]; /* Segment lengths */
static XADDR seglim[NSEG]; /* Segment length limits */
static XADDR segloc[NSEG]; /* Segment base physical addresses */
static short textseg, /* Logical seg # of various segments */
dataseg,
bssseg,
stkseg;
/********************************/
/* */
/* Start of pgmld function */
/* */
/********************************/
UWORD pgmld(xlpbp) /* Load a program from LPB info */
XADDR xlpbp;
{ register int i,j; /* Temporary counters etc. */
struct m_rt *mrp; /* Pointer to a MRT structure */
char mybuf[SECLEN]; /* Local buffer for file reading*/
/* get local LPB copy */
cpy_in(xlpbp, &mylpb, (long) sizeof mylpb);
mydma = mybuf; /* Initialize addr for local DMA*/
gp = &mybuf[SECLEN]; /* Point beyond end of buffer */
mrp = (struct m_rt *) bgetseg();/* Get address of memory region */
/* table (note segment # lost)*/
if (readhdr() == EOF) /* Get x.out file header */
return (READERR); /* Read error on header */
switch (x_hdr.x_magic) /* Is this acceptable x.out file*/
{
case X_NXN_MAGIC: /* Non-seg, combined I & D */
split = FALSE;
seg = FALSE;
break;
case X_NXI_MAGIC: /* Non-seg, separate I & D */
split = SPLIT;
seg = FALSE;
break;
case X_SX_MAGIC: /* Segmented - must be combined */
split = FALSE;
seg = SEG;
break;
default:
return (BADHDR); /* Sorry, can't load it! */
}
/* Set the user space segment number, from the low address in the */
/* appropriate entry of the MRT. */
/* m_reg[SPREG] is the region used for split I/D programs in the MRT */
/* m_reg[NSPREG] is used for non-split. */
/* -1 is used for segmented */
/* NOTE -- the tpa limits passed in the LPB are ignored. This is */
/* incorrect, but saves the caller from having to look at the */
/* load module to determine the magic number. */
map_adr(seg ? -1L
: (mrp->m_reg[split ? SPREG : NSPREG].tpalow),
0xffff);
for (i = 0; i < x_hdr.x_nseg; i++) { /* For each segment... */
if( readxsg(i) == EOF) /* ...get segment hdr */
return(READERR);
seglim[i] = SEGLEN; /* ...set max length */
segsiz[i] = 0L; /* ...and current size */
}
/* Set section base addresses */
textloc = dataloc = bssloc = stkloc = 0L;
/* Zero section sizes */
textsiz = datasiz = bsssiz = 0L;
stksiz = DEFSTACK;
if (seg) { /* Locate text & data segments */
/* if segmented we know nothing */
textseg = dataseg = bssseg = stkseg = 0;
} else { /* if nonsegmented ... */
/* assign segment numbers */
textseg = 0;
dataseg = (split) ? 1 : 0;
stkseg = bssseg = dataseg;
/* assign locations */
segloc[textseg] = map_adr(0L, TPAPROG);
if (split)
segloc[dataseg] = map_adr(0L, TPADATA);
/* Assign limits */
seglim[textseg] = SEGLEN;
seglim[dataseg] = mrp->m_reg[split ? SDREG : NSDREG].tpalen
- BPLEN - stksiz;
/* Assign stack location */
stkloc = segloc[dataseg] + seglim[dataseg] + stksiz;
}
for (i = 0; i < x_hdr.x_nseg; i++) /* For each segment... */
if( (j = loadseg(i)) != GOOD) /* ...load memory. If */
return (j); /* error return, pass */
/* it back. */
setbase(setaddr(&mylpb)); /* Set addresses in LPB,*/
/* Set up base page */
cpy_out((XADDR) &mylpb, xlpbp, sizeof mylpb);
return (GOOD);
}
/* Macro to call BDOS. First parameter is passed unchanged, second */
/* is cast into an XADR, then mapped to caller data space. */
#define mbdos(func, param) (bdos((func), map_adr((XADDR) (param), MYDATA)))
/* Macro to read the next character from the input file (much faster */
/* than having to make a function call for each byte) */
#define fgetch() ((gp<mydma+SECLEN) ? (int)*gp++&0xff : fillbuff())
/* Routine to fill input buffer when fgetch macro detects it is empty */
int fillbuf() /* Returns first char in buffer */
{ /* or EOF if read fails */
/* Set up address to read into */
mbdos(SETDMA, mydma);
if (bdos(READ, mylpb.fcbaddr) != 0) /* Have BDOS do the read*/
return (EOF);
gp = mydma; /* Initialize buffer pointer */
return ((int)*gp++ & 0xff); /* Return first character */
}
/* Routine to read the file header */
int readhdr()
{
register int n, k;
register char *p;
p = (char *) &x_hdr;
for (n = 0; n < sizeof (struct x_hdr); n++) {
if( (k = fgetch()) == EOF)
return (k);
*p++ = (char) k;
}
return (GOOD);
}
/* Routine to read the header for segment i */
int readxsg(i)
int i;
{
register int n, k;
register char *p;
p = (char *) &x_sg[i];
for(n = 0; n < sizeof (struct x_sg); n++) {
if ( (k = fgetch()) == EOF)
return (READERR);
*p++ = (char) k;
}
return (GOOD);
}
/* Routine to load segment number i */
/* This assumes that the segments occur in load order in the file, and */
/* that all initialized data and, in the case of combined I/D programs, */
/* text segments, precede all bss segments. */
/* In the case of segmented programs, the stack segment must exist, */
/* and all segments are presumed to be of maximum length. */
/* Text, data, bss, and stack lengths are sum of lengths of all such */
/* segments, and so may be bigger than maximum segment length. */
int loadseg(i)
int i;
{
register UWORD l, length; /* Total, incremental length */
register int type; /* Type of segment loaded */
register short lseg; /* logical segment index */
register XADDR phystarg; /* physical target load address */
l = x_sg[i].x_sg_len; /* number of bytes to load */
type = x_sg[i].x_sg_typ; /* Type of segment */
lseg = textseg; /* try putting in text space */
if (split) { /* If separate I/D, this may */
switch (type) /* be a bad guess */
{
case X_SG_CON: /* Separate I/D: all data goes */
case X_SG_DATA: /* in data space */
case X_SG_BSS:
case X_SG_STK:
lseg = dataseg;
}
}
if (seg) { /* If segmented, compute phys. */
/* address of segment */
/* search to see if seg was used already */
/* if so, use the same logical segment index. */
/* (if not, loop ends with lseg == i) */
for (lseg = 0;
x_sg[lseg].x_sg_no != x_sg[i].x_sg_no;
lseg++) ;
segloc[lseg] = ((long)x_sg[i].x_sg_no) << 24;
}
phystarg = segloc[lseg] + segsiz[lseg]; /* physical target addr */
switch (type) /* Now load data, if necessary */
/* save physical address & size */
{
case X_SG_BSS: /* BSS gets cleared by runtime */
/* startup. */
stkloc = (phystarg & 0xffff0000L) + SEGLEN - BPLEN - stksiz;
/* ...in case no stack segment */
if (bssloc == 0L) bssloc = phystarg;
bsssiz += l;
if ((segsiz[lseg] += l) >= seglim[lseg])
return (NOMEM);
return (GOOD); /* Transfer no data */
case X_SG_STK: /* Stack segment: */
if (stkloc == 0L) { /* if segmented, we now */
/* know where to put */
seglim[lseg] -= BPLEN; /* the base page */
stkloc = segloc[lseg] + seglim[lseg];
}
stkseg = lseg;
stksiz += l; /* adjust size and */
seglim[lseg] -= l; /* memory limit */
if (segsiz[lseg] >= seglim[lseg])
return (NOMEM);
return (GOOD); /* Transfer no data */
case X_SG_COD: /* Pure text segment */
case X_SG_MXU: /* Dirty code/data (better not)*/
case X_SG_MXP: /* Clean code/data (be sep I/D)*/
if (textloc == 0L) textloc = phystarg;
textsiz += l;
break;
case X_SG_CON: /* Constant (clean) data */
case X_SG_DAT: /* Dirty data */
stkloc = (phystarg & 0xffff0000L) + SEGLEN - BPLEN - stksiz;
/* ...in case no stack or */
/* bss segments */
if (dataloc == 0L) dataloc = segloc[i];
datasiz += l;
break;
}
/* Check seg overflow */
if ((segsiz[lseg] += l) >= seglim[lseg])
return (NOMEM);
/* load data from file */
/* Following loop is optimized for load speed. It knows*/
/* about three conditions for data transfer: */
/* 1. Data in read buffer: */
/* Transfer data from read buffer to target */
/* 2. Read buffer empty and more than 1 sector of data */
/* remaining to load: */
/* Read data direct to target */
/* 3. Read buffer empty and less than 1 sector of data */
/* remaining to load: */
/* Fill read buffer, then proceed as in 1 above */
while (l) /* Until all loaded */
{ /* Data in disk buffer? */
if (gp < mydma + SECLEN)
{
length = min(l, mydma + SECLEN - gp);
cpy_out(gp, phystarg, length);
gp += length;
}
else if (l < SECLEN) /* Less than 1 sector */
{ /* remains to transfer*/
length = 0;
mbdos(SETDMA, mydma);
fillbuf();
gp = mydma;
}
else /* Read full sector */
{ /* into target space */
length = SECLEN;
bdos(SETDMA, phystarg);
bdos(READ, mylpb.fcbaddr);
}
phystarg += length;
l -= length;
}
return (GOOD);
}
/* Routine to set the addresses in the Load Parameter Block */
/* Unlike normal CP/M, the original load address is replaced on return */
/* by the actual starting address of the program (true Code-space addr) */
int setaddr(lpbp)
struct lpb *lpbp;
{
register int space;
space = (split) ? TPADATA : TPAPROG;
lpbp->pgldaddr = (seg) ? textloc : map_adr(textloc, TRUE_TPAPROG);
lpbp->bpaddr = stkloc;
lpbp->stackptr = stkloc - (seg? sizeof (struct sstack)
: sizeof (struct ustack));
lpbp->flags = split | seg;
return (space);
}
/* Routine to set up the base page. The parameter indicates whether
* the data and bss should be mapped in code space or in data space.
*/
VOID setbase(space)
int space;
{
struct b_page bp;
if (seg) {
bp.lcode = textloc;
bp.ltpa = 0L;
} else {
bp.lcode = bp.ltpa = map_adr(textloc, TRUE_TPAPROG);
}
bp.htpa = mylpb.stackptr; /* htpa is where the stack is */
bp.codelen = textsiz;
bp.ldata = dataloc;
bp.datalen = datasiz;
if (bssloc == 0L) bssloc = dataloc + datasiz;
bp.lbss = bssloc;
bp.bsslen = bsssiz;
bp.freelen = seglim[bssseg] - segsiz[bssseg];
cpy_out(&bp, map_adr((long) stkloc, space), sizeof bp);
}

View File

@@ -0,0 +1,59 @@
/********************************************************
* *
* P-CP/M header file *
* Copyright (c) 1982 by Digital Research, Inc. *
* Structure definitions for doing I/O in packets *
* *
* Modified for data in other address space *
* *
********************************************************/
/* 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 */
XADDR 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 */

View File

@@ -0,0 +1,72 @@
/*****************************************************************************
*
* 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 /* NOT using Alcyon compiler*/
/* but Zilog has similar bug*/
/*
* Standard type definitions
*/
/***************************/
#define BYTE char /* Signed byte */
#define BOOLEAN char /* 2 valued (true/false) */
#define WORD short /* Signed word (16 bits) */
#define UWORD unsigned int /* 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 */
#define XADDR long /* Extended (SEG) address */
/***************************/
#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 XNULL 0L /* Null XADDR */
#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 ? -(xIq
This directory contains the source and object files for the Z8000 CP/M Bios,
and the necessary include files. This includes the floating point emulator