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,367 @@
/****************************************************************************/
/* */
/* B D O S . H */
/* ----------- */
/* */
/* Copyright (c) 1982, Zilog Incorporated */
/* */
/* Macros defining the direct BDOS calls used by the standard CP/M */
/* utilities (ED, PIP, STAT, SET, SHOW.) Some necessary data */
/* data structures are also defined. */
/* */
/* All macros return a long value, even when the BDOS function they */
/* call does produce a return parameter. */
/* */
/* This header file can be used applications which do not require */
/* to use the C standard I/O library functions. For applications */
/* which require the library, but which wish to make use of the */
/* additional information in this file, cpm.h should be included in */
/* the source ahead of this file. The compiler flags multiple */
/* definition errors if this ordering is not observed. */
/* */
/* portab.h must always be included ahead of this file. */
/* */
/****************************************************************************/
extern long __BDOS(); /* BDOS entry point */
#define XADDR long /* 32-bit address data type */
/****************************************************************************/
/* The following BDOS calls are defined in cpm.h. Define them only if they */
/* are not defined already. */
/****************************************************************************/
#ifndef EXIT /* Find out where we stand */
/* Define if necessary */
#define EXIT 0 /* Exit to BDOS */
#define CONOUT 2 /* Direct console output */
#define LSTOUT 5 /* Direct list device output*/
#define CONIO 6 /* Direct console I/O */
#define CONBUF 10 /* Read console buffer */
#define OPEN 15 /* OPEN a disk file */
#define CLOSE 16 /* Close a disk file */
#define DELETE 19 /* Delete a disk file */
#define CREATE 22 /* Create a disk file */
#define SETDMA 26 /* Set DMA address */
#define B_READ 33 /* Read Random record */
#define B_WRITE 34 /* Write Random record */
#define FILSIZ 35 /* Compute File Size */
#define SETMSC 44 /* Set Multi-Sector Count */
#endif
/****************************************************************************/
/* The following BDOS calls are not defined in cpm.h */
/****************************************************************************/
#define CONIN 1 /* Single char I/P with echo*/
#define READER 3 /* Paper tape input */
#define PUNCH 4 /* Paper tape output */
#define GET_IOB 7 /* Get I/O byte */
#define SET_IOB 8 /* Set I/O byte */
#define PRINT 9 /* Print $-terminated line */
#define CONSTAT 11 /* Check if I/P char waiting*/
#define VERSION 12 /* Return version number */
#define RS_DISK 13 /* Reset disk system */
#define SEL_DISK 14 /* Select disk */
#define SRCH_1ST 17 /* Search 1st filename match*/
#define SRCH_NEXT 18 /* Search next match */
#define S_READ 20 /* Sequential read from file*/
#define S_WRITE 21 /* Sequential write to file */
#define RENAME 23 /* Rename a file */
#define RET_LOGIN 24 /* Return login vector */
#define RET_CDISK 25 /* Return current disk */
#define GET_ALLOC 27 /* Get allocation vector */
#define WR_PROTD 28 /* Write protect disk */
#define GET_RO 29 /* Get read-only vector */
#define SET_ATT 30 /* Set file attributes */
#define GET_DPB 31 /* Get disk parameters */
#define GSET_UCODE 32 /* Get/set user code */
#define SET_RAND 36 /* Set random record */
#define RS_DRIVE 37 /* Reset disk specified drv */
/* 38, 39 not used */
#define B_WRZF 40 /* Write random, zero fill */
/* 41 - 43 not used */
#define RET_ERRORS 45 /* Set error return mode */
#define GET_DFS 46 /* Get free disk space */
#define CHAIN 47 /* Chain to program via CCP */
#define FLUSH 48 /* Flush buffers to disk */
#define GSET_SCB 49 /* Get/set system control bk*/
#define BIOS_CALL 50 /* Direct call to BIOS */
/* 51 - 58 not used */
#define PROG_LOAD 59 /* Program load */
/* 60 unused */
#define SET_EXV 61 /* Set exception vector */
#define SET_SUP 62 /* Set supervisor state */
#define SET_LABEL 100 /* Set directory label */
#define GET_LABEL 101 /* Get directory label */
#define GET_XFCB 102 /* Get extended FCB */
#define SET_XFCB 103 /* Set extended FCB */
#define COND_LST 161 /* Conditionally attach LST:*/
/****************************************************************************/
/* The macros themselves... */
/****************************************************************************/
#define _conin() (__BDOS(CONIN, (long) 0))
#define _conout(a) (__BDOS(CONOUT, (long) (a)))
#define _reader() (__BDOS(READER, (long) 0))
#define _punch(a) (__BDOS(PUNCH, (long) (a)))
#define _lstout(a) (__BDOS(LSTOUT, (long) (a)))
#define _conio(a) (__BDOS(CONIO, (long) (a)))
#define _get_iob() (__BDOS(GET_IOB, (long) 0))
#define _set_iob(a) (__BDOS(SET_IOB, (long) (a)))
#define _print(a) (__BDOS(PRINT, (long) (a)))
#define _conbuf(a) (__BDOS(CONBUF, (long) (a)))
#define _constat() (__BDOS(CONSTAT, (long) 0))
#define _version() (__BDOS(VERSION, (long) 0))
#define _rs_disk(a) (__BDOS(RS_DISK, (long) (a)))
#define _sel_disk(a) (__BDOS(SEL_DISK, (long) (a)))
#define _open(a) (__BDOS(OPEN, (long) (a)))
#define _close(a) (__BDOS(CLOSE, (long) (a)))
#define _srch_1st(a) (__BDOS(SRCH_1ST, (long) (a)))
#define _srch_next() (__BDOS(SRCH_NEXT, (long) 0))
#define _delete(a) (__BDOS(DELETE, (long) (a)))
#define _s_read(a) (__BDOS(S_READ, (long) (a)))
#define _s_write(a) (__BDOS(S_WRITE, (long) (a)))
#define _create(a) (__BDOS(CREATE, (long) (a)))
#define _rename(a) (__BDOS(RENAME, (long) (a)))
#define _ret_login() (__BDOS(RET_LOGIN, (long) 0))
#define _ret_cdisk() (__BDOS(RET_CDISK, (long) 0))
#define _setdma(a) (__BDOS(SETDMA, (long) (a)))
#define _get_alloc() (__BDOS(GET_ALLOC, (long) 0))
#define _wr_protd() (__BDOS(WR_PROTD, (long) 0))
#define _get_ro() (__BDOS(GET_RO, (long) 0))
#define _set_att(a) (__BDOS(SET_ATT, (long) (a)))
/* _get_dpb has parameter in*/
/* some implementations */
/* of CP/M but not others */
/* This macro suitable only */
/* for former */
#define _get_dpb(a) (__BDOS(GET_DPB, (long) (a)))
/* This one handles latter */
#define _get_dpa() (__BDOS(GET_DPB, (long) 0))
#define _gset_ucode(a) (__BDOS(GSET_UCODE, (long) (a)))
#define _b_read(a) (__BDOS(B_READ, (long) (a)))
#define _b_write(a) (__BDOS(B_WRITE, (long) (a)))
#define _filsiz(a) (__BDOS(FILSIZ, (long) (a)))
#define _set_rand(a) (__BDOS(SET_RAND, (long) (a)))
#define _rs_drive(a) (__BDOS(RS_DRIVE, (long) (a)))
#define _b_wrzf(a) (__BDOS(B_WRZF, (long) (a)))
#define _setmsc(a) (__BDOS(SETMSC, (long) (a)))
#define _ret_errors(a) (__BDOS(RET_ERRORS, (long) (a)))
#define _get_dfs(a) (__BDOS(GET_DFS, (long) (a)))
#define _chain() (__BDOS(CHAIN, (long) 0))
#define _flush() (__BDOS(FLUSH, (long) 0))
#define _gset_scb(a) (__BDOS(GSET_SCB, (long) (a)))
#define _bios_call(a) (__BDOS(BIOS_CALL, (long) (a)))
#define _prog_load(a) (__BDOS(PROG_LOAD, (long) (a)))
#define _set_exv(a) (__BDOS(SET_EXV, (long) (a)))
#define _set_sup(a) (__BDOS(SET_SUP, (long) 0))
#define _get_label(a) (__BDOS(GET_LABEL, (long) (a)))
#define _set_label(a) (__BDOS(SET_LABEL, (long) (a)))
#define _get_xfcb(a) (__BDOS(GET_XFCB, (long) (a)))
#define _set_xfcb(a) (__BDOS(SET_XFCB, (long) (a)))
#define _cond_lst() (__BDOS(COND_LST, (long) 0))
/****************************************************************************/
/* BIOS calls, for use in conjunction with BDOS call 50 & struct bios_parms */
/****************************************************************************/
#define _INIT 0 /* Cold start */
#define _WARM 1 /* Warm start */
#define _CONST 2 /* Console status */
#define _CONIN 3 /* Read console character */
#define _CONOUT 4 /* Write console character */
#define _LIST 5 /* Write listing character */
#define _PUNCH 6 /* Write punch character */
#define _READER 7 /* Read tape character */
#define _HOME 8 /* Move to track 0 */
#define _SELDSK 9 /* Select disk drive */
#define _SETTRK 10 /* Set track number */
#define _SETSEC 11 /* Set sector number */
#define _SETDMA 12 /* Set DMA address */
#define _READ 13 /* Read selected sector */
#define _WRITE 14 /* Write selected sector */
#define _LISTST 15 /* Return list status */
#define _GETMRT 16 /* Get memory region table */
/* address */
#define _GETIOB 17 /* Get IOBYTE value */
#define _SETIOB 18 /* Set IOBYTE value */
#define _FLUSH 19 /* Flush buffers */
#define _SETEXC 20 /* Set exception vector */
/****************************************************************************/
/* FCB structure is defined in cpm.h. Define it here only if it is not */
/* defined already. Declare some useful values at the same time. */
/****************************************************************************/
#ifndef SECSIZ /* Not already declared? */
struct fcbtab /* File control block */
{ /* */
BYTE drive; /* Disk drive field */
BYTE fname[8]; /* File name */
BYTE ftype[3]; /* File type */
BYTE extent; /* Current extent number */
BYTE s1,s2; /* "system reserved" */
BYTE reccnt; /* Record counter */
BYTE resvd[16]; /* More "system reserved" */
LONG record; /* Note -- we overlap the */
/* current record field to */
/* make this useful. */
};
#define fcb fcbtab /* A useful synonym */
#define SECSIZ 128 /* size of CP/M sector */
#define _MAXSXFR 1 /* max # sectors xferrable */
#define _MAXSHFT 12 /* shift right BDOS rtn val */
#endif
/****************************************************************************/
/* Data structures not defined in cpm.h */
/****************************************************************************/
struct dpbs /* Disk parameter block */
{
UWORD spt; /* Sectors per track */
BYTE bls; /* Block shift factor */
BYTE bms; /* Block mask */
BYTE exm; /* Extent mark */
/* BYTE filler; *** Pad to align words ***/
UWORD mxa; /* Maximum allocation (blks)*/
UWORD dmx; /* Max directory entries */
UWORD dbl; /* Directory alloc. map */
UWORD cks; /* Directory checksum */
UWORD ofs; /* Track offset from track 0*/
};
struct bios_parm /* BIOS parameters for BDOS */
{ /* call 50 */
UWORD req; /* BIOS request code */
LONG p1; /* First parameter */
LONG p2; /* Second parameter */
};
struct scbs /* System control block */
{
BYTE resvd_1[6]; /* Reserved for system use */
BYTE u_flags[4]; /* Utility flags */
BYTE d_flags[4]; /* Display flags */
BYTE clp_flags[2]; /* Command Line Proc flags */
UWORD p_error; /* Program error return code*/
BYTE resvd_2[8]; /* Reserved for system use */
BYTE con_w; /* Console width */
BYTE con_c; /* Console column */
BYTE con_l; /* Console page length */
BYTE resvd_3[5]; /* Reserved for system use */
UWORD conin_r; /* CONIN redirection flag */
UWORD conout_r; /* CONOUT redirection flag */
UWORD auxin_r; /* AUXIN redirection flag */
UWORD auxout_r; /* AUXOUT redirection flag */
UWORD lstout_r; /* LSTOUT redirection flag */
BYTE resvd_4[2]; /* Reserved for system use */
BOOLEAN ctl_h_a; /* Backspace active */
BOOLEAN rubout_a; /* Rubout active */
BYTE resvd_5[2]; /* Reserved for system use */
UWORD c_xlate; /* Console translate func. */
UWORD con_m; /* Console mode (raw/cooked)*/
UWORD buff_a; /* 128 byte buffer available*/
BYTE o_delim; /* Output delimiter */
BOOLEAN lo_flag; /* List output flag */
BYTE resvd_6[2]; /* Reserved for system use */
UWORD d_m_a; /* Current DMA address */
BYTE disk_no; /* Current disk */
BYTE bdos_info[2]; /* BDOS variable info */
BYTE resvd_7[3]; /* Reserved for system use */
BYTE user_no; /* Current user number */
BYTE resvd_8[6]; /* Reserved for system use */
BYTE bdos_mode; /* BDOS error mode */
BYTE c_chain[4]; /* Current search chain */
BYTE tmp_drv; /* Drive for temporary files*/
BYTE resvd_9[7]; /* Reserved for system use */
BYTE date_s[5]; /* Date stamp */
BYTE error_jmp[3]; /* Error jump */
UWORD cmb_a; /* Common memory base addr */
UWORD bdos_ent; /* BDOS entry point */
};
struct scbpb /* SCB parameter block */
{
BYTE off; /* Index to data in SCB */
BYTE op; /* Operation: 0xff Set byte */
/* 0xfe Set word */
/* else Get word */
UWORD val; /* Byte/word value to be set*/
};
#define SET_BYTE 0xff
#define SET_WORD 0xfe
#define GET 0
/****************************************************************************/
/* HILO must be defined for the Z8000. Undefine it first, in case cpm.h */
/* has already defined it. The tagless structures defining byte ordering */
/* which are declared in cpm.h are not redeclared here (the use of members */
/* of tagless structures to define offsets is an obsolete feature of the C */
/* language.) */
/****************************************************************************/
#undef HILO
#define HILO

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,119 @@
;****************************************************************
;* *
;* CP/M-Z8K Interface module for the Loader BDOS *
;* For "C" version of CP/M-Z8K *
;* *
;* Copyright (c) 1982 Digital Research, Inc. *
;* *
;* Version 0.2 -- September 22, 1982 *
;* Z8000 version -- 830728 *
;* *
;****************************************************************
__text: .sect
;****************************************************
;*
;* Globals
;*
;****************************************************
.global _bios1 ; 6 BIOS entry points from BDOS
.global _bios2
.global _bios3
.global _bios4
.global _bios5
.global _swap ; byte swapper
.global _udiv ; unsigned divide routine
;****************************************************
;*
;* Externals and Constants
;*
;****************************************************
.global _bios ; The Loader BDOS calls the BIOS direct
;****************************************************
;*
;* BIOS Interface Routines
;*
;* Note - there are 5 BIOS entry points from the BDOS,
;* labelled BIOS1 - BIOS5, 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
_bios1:
; For all BIOS functions that have no parameter
; other than function number
ld r3,2(r15) ; get function number
sub r15, #10 ; adjust sp...
ldm @r15, r3, #5 ; ... and push args on stack
call _bios ; do BIOS call as a call...
add r15, #10 ; ...and readjust sp
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,216 @@
;****************************************************************
;* *
;* 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 *
;* *
;****************************************************************
; 01/10/83 Modified for use with Z8002 (DMH)
; 01/21/83 Fixed TPA caller Pseudo-segment prooblem
__text: .sect
.input "biosdefs2.z8k"
;****************************************************
;*
;* 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
.global _usrseg ; This is user pseudo-segment
.global _sysseg ; This is system pseudo_segment
;* 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 non-SEGMENTED with caller's registers
;* saved on stack, and all but rr0 intact in
;* registers.
;*
;* Calls __bdos(cmd, (word)param, (addr)param)
;*
;****************************************************
_traphnd:
; 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 (always case for Z8002)
; get (pseudo) segment number from _userseg
ldl rr2,rr6
; ld r2,_sysseg ; assume system mode
; ld r0,scfcw+co(r15)
; bit r0,#14 ; Was user system?
; jr nz,callC ; Yes.
; ld r2,_usrseg ; user pseudo segment
;
; 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 cr7+co(r15),r7
ret
;
; direct BIOS call function
;
bioscall:
ldm r3,@r7,#5 ;get parameters
sc #3 ;call BIOS
ret ;done
callBios:
;
; 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,scfcw+co(r15)
set r0,#14 ;set system
ld scfcw+co(r15),r0;in user FCW
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)
jr _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
jr _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
jr _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,173 @@
/****************************************************************
* *
* CP/M-Z8K Loader BDOS Main Routine *
* *
* This is the main routine for the loader BDOS for P-CP/M.*
* It has one entry point, _bdos, which is called from *
* the assembly language trap handler found in bdosif.z8k. *
* 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 seldsk(); /* Select disk */
EXTERN BOOLEAN openfile(); /* Open File */
EXTERN UWORD dirscan(); /* General directory scanning routine */
EXTERN UWORD seqread(); /* Sequential disk read */
/* 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 2: bconout((UBYTE)info); /* console output */
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);
break;
case 20: tmp_sel(&temp); /* read sequential */
rtnval = seqread(temp.fptr);
break;
case 26: GBL.dmaadr = infop; /* set dma address */
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 */
/****************************************************************
* *
* bdos call - replaces system call in real CP/M-Z8K *
* Function is to arrange for parameters to _bdos to be *
* in the right place. *
* *
****************************************************************/
bdos(func, longaddr)
int func;
XADDR longaddr;
{
return(_bdos(func, (int) longaddr, longaddr));
}
/*****************************************************
**
** 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;
}
}

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.3 06/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,206 @@
/****************************************************************
* *
* CP/M-Z8K Loader BDOS Disk Read 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: *
* *
* seqread() - 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 rdsec(); /* disk read/write routine */
EXTERN UWORD swap(); /* assembly language byte swapper */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN BOOLEAN openfile(); /* open file function passed to dirscan */
/**********************************************************/
/* 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]) );
}
/*********************
* disk read routine *
*********************/
UWORD do_io(block, rcrd)
UWORD block; /* block number */
UBYTE rcrd; /* record number */
{
REG LONG lsec;
REG struct dpb *dparmp;
BSETUP
dparmp = GBL.parmp; /* init dpb pointer */
lsec = ((LONG)block << (dparmp->bsh)) +
(LONG)(rcrd & (dparmp->blm));
return( rdsec(lsec, GBL.dmaadr) );
}
/*******************************************
* routine for crossing extent boundaries *
*******************************************/
WORD new_ext(fcbp)
/* If sequential I/O, open the next extent */
REG struct fcb *fcbp; /* pointer to fcb */
{
REG UBYTE mod; /* module number */
REG UBYTE ext; /* extent number */
BSETUP
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 */
fcbp->s2 = mod;
fcbp->extent = ext;
if ( dirscan(openfile, fcbp, 0) >= 255 ) /* open new extent */
return(4); /* reading unwritten 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 seqread(fcbp)
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
/* 2 = random with zero fill */
{
REG UWORD block; /* block number from fcb */
REG WORD index; /* index into disk map of fcb */
REG UBYTE *buf; /* type compatibility kludge */
REG WORD parm; /* parameter to do-io */
REG WORD bigfile; /* file system is in word mode */
BSETUP
bigfile = ((GBL.parmp)->dsm) & ~0xff;
if (fcbp->cur_rec == 128)
{ /* time to try next extent */
if ( new_ext(fcbp) )
return(1); /* if can't open new extent, error */
fcbp->cur_rec = 0; /* opened new extent, zero cur_rec */
}
if ( UBWORD(fcbp->cur_rec) >= get_rc(fcbp) )
return(1); /* this is end of file */
index = blkindx(fcbp); /* get index into fcb disk map */
block = blknum(fcbp, index, bigfile);
if ( ! block) return(1);
return( do_io(block, (fcbp->cur_rec)++));
}

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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
;********** wboot.s -- Olivetti bootstrap writer*****
;*
;* 821013 S. Savitzky (Zilog) -- adapt for nonseg.
;* 820930 S. Savitzky (Zilog) -- created
;*
;****************************************************
__text: .sect
;****************************************************
;*
;* NOTE -- THIS CODE IS HIGHLY SYSTEM-DEPENDENT
;*
;* This module contains both the bootstrap
;* writer, and the code that receives control
;* after being booted.
;*
;* The main function of the latter is to make
;* sure that the system, whose entry point is
;* called "bios", is passed a valid stack
;* and PSA pointer.
;*
;* Although this code runs segmented, it must
;* be linked with non-segmented code, so it
;* looks rather odd.
;*
;****************************************************
;* The first sector on track 1 is the PCOS file
;* descriptor block; the second is the boot file
;* header and the start of the system code.
;*
;* For now, we assume that the system starts at
;* <<11>>0000 (hex)
;*
;****************************************************
;****************************************************
;*
;* Globals
;*
;****************************************************
.global _startld
;****************************************************
;*
;* Externals
;*
;****************************************************
.global bios
;****************************************************
;*
;* Constants
;*
;****************************************************
BOOTSYS .equ 0A000000h ; system address
BOOTSTK .equ BOOTSYS+0BFFEh ; system stack top
rtc_ext .equ 02000022h ; real-time clock
; ext. call addr
BPT .equ 16 ; #blocks in a track
BPS .equ 256 ; #bytes in a sector
NBLKS .equ 9*16 ; #blocks in boot
HDRSIZE .equ 24 ; #bytes in header
FILSIZE .equ 256*(NBLKS-1) ; file data size
SYSSIZE .equ FILSIZE-HDRSIZE ; total system size
S1SIZE .equ BPS-HDRSIZE ; data in sector 1
SEG4 .equ 04000000h
SEG2 .equ 02000000h
SYSPSA .equ SEG2+100h ; system PSA
BOOTPSA .equ SEG4+100h ; PSA in PROM for boot
sscall .macro ;short segmented call
.word 05f00h
.word ?1
.endm
;****************************************************
;*
;* Entry Points and post-boot Initialization
;*
;****************************************************
;* transfer vector
; jr wboot
; jr wrboot * Commented out - this has implications for booter
jr entry
;* post-boot init.
entry: ;SEGMENTED
_startld:
DI VI,NVI
ldl rr14, #BOOTSTK ; init stack pointer
ldl rr2, #SYSPSA ; copy PROM's PSA
ldctl r4, psapseg
ldctl r5, psapoff
ld r0, #570/2
ldir @r2, @r4, r0
ldl rr2, #SYSPSA ; shift PSA pointer
ldctl psapseg, r2
ldctl psapoff, r3
ld r2,#142h ;CROCK-- turn off
ld r3,#1feh ; usart interrupts
out @r2,r3
ldar r2, $ ; go
ld r3,#bios
jp @r2

View File

@@ -0,0 +1,80 @@
;********** wboot.s -- Olivetti bootstrap writer*****
;*
;* 821013 S. Savitzky (Zilog) -- adapt for nonseg.
;* 820930 S. Savitzky (Zilog) -- created
;*
;****************************************************
; 01/12/83 Adapted for the Kontron ECB/16 Z8002 (DMH)
; 01/16/83 Added relocation code to relocate the
; Z8002 CP/M from 8000h to 0000h (DMH).
__text: .sect
;****************************************************
;*
;* NOTE -- THIS CODE IS HIGHLY SYSTEM-DEPENDENT
;*
;* This module contains the code that receives
;* control after being booted.
;*
;* The main function is to make sure that the
;* system, whose entry point is called "bios",
;* is passed a valid stack and PSA pointer.
;*
;****************************************************
;****************************************************
;*
;* Externals
;*
;****************************************************
.global bios
.global _wboot
;****************************************************
;*
;* Constants
;*
;****************************************************
SYSTEM .equ 00000000h ; system address
SYSSTK .equ 08000h-200h ; system stack top, leave room for PSA
SYSPSA .equ SYSSTK ; system PSA
;****************************************************
;*
;* Entry Points and post-boot Initialization
;*
;****************************************************
;* transfer vector
jr wboot
jr entry ; there is no write boot entry
jr entry
;* post-boot init
;* (note that this code
;* is position indepent).
entry: DI VI,NVI
ld r15, #SYSSTK ; init stack pointer
ld r3, #SYSPSA ; initialize PSA
ldctl psap, r3
ld r7,#0 ; destination of system copy
ld r5,#8000h ; source of system copy
ld r0,#4000h ; copy 16k words
ldir @r7,@r5,r0 ; Zip it!
ld r3,#bios
jp @r3 ; Actually jumping to low address
wboot: ld r3,#_wboot
jp @r3

View File

@@ -0,0 +1,62 @@
/********************************************************
* *
* 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 */
#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() bios1(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,133 @@
;************ biosdefs.z8k **************************
;*
;* Assembly language definitions for
;* P-CP/M (tm) BIOS
;*
;* 821013 S. Savitzky (Zilog) -- created.
;*
;****************************************************
;*
;* System Calls and Trap Indexes
;*
;****************************************************
XFER_SC .equ 1
BIOS_SC .equ 3
BDOS_SC .equ 2
MEM_SC .equ 1
DEBUG_SC .equ 0
;* the traps use numbers similar to those in the
;* 68K version of P-CP/M
NTRAPS .equ 48 ;total number of traps
SC0TRAP .equ 32 ;trap # of system call 0
;Z8000 traps
EPUTRAP .equ 1 ;EPU (floating pt. emulator)
SEGTRAP .equ 2 ;segmentation (68K bus err)
NMITRAP .equ 0 ;non-maskable int.
PITRAP .equ 8 ;priviledge violation
;Interrupts, etc.
TRACETR .equ 9 ; trace
;****************************************************
;*
;* C Stack frame equates
;*
;* A C stack frame consists of the PC on top,
;* followed by the arguments, leftmost argument first.
;*
;* The caller adjusts the stack on return.
;* Returned value is in r7 (int) or rr6 (long)
;*
;****************************************************
PCSIZE .equ 2 ;PC size non-segmented
INTSIZE .equ 2 ;INT data type size
LONGSIZE .equ 4 ;LONG data type size
ARG1 .equ PCSIZE ;integer arguments
ARG2 .equ ARG1+INTSIZE
ARG3 .equ ARG2+INTSIZE
ARG4 .equ ARG3+INTSIZE
ARG5 .equ ARG4+INTSIZE
;****************************************************
;*
;* Segmented Mode Operations
;*
;* NOTE: segmented indirect-register operations
;* can be done by addressing the low half
;* of the register pair.
;*
;****************************************************
SEG .MACRO ; START segmented mode
; r0 destroyed.
ldctl r0,FCW
set r0,#15
ldctl FCW,r0
.ENDM
NONSEG .MACRO ; END segmented mode
; r0 destroyed.
ldctl r0,FCW
res r0,#15
ldctl FCW,r0
.ENDM
scall .MACRO ;(segaddr) segmented CALL
.word 05F00h
.long ?1
.ENDM
sscall .MACRO ;(|segaddr|) short segmented CALL
.word 05F00h
.word ?1
.ENDM
;****************************************************
;*
;* System Call Trap Handler Stack Frame
;*
;****************************************************
cr0 .equ 0 ;WORD caller r0
cr1 .equ cr0+2 ;WORD caller r1
cr2 .equ cr1+2 ;WORD caller r2
cr3 .equ cr2+2 ;WORD caller r3
cr4 .equ cr3+2 ;WORD caller r4
cr5 .equ cr4+2 ;WORD caller r5
cr6 .equ cr5+2 ;WORD caller r6
cr7 .equ cr6+2 ;WORD caller r7
cr8 .equ cr7+2 ;WORD caller r8
cr9 .equ cr8+2 ;WORD caller r9
cr10 .equ cr9+2 ;WORD caller r10
cr11 .equ cr10+2 ;WORD caller r11
cr12 .equ cr11+2 ;WORD caller r12
cr13 .equ cr12+2 ;WORD caller r13
nr14 .equ cr13+2 ;WORD normal r14
nr15 .equ nr14+2 ;WORD normal r15
scinst .equ nr15+2 ;WORD SC instruction
scfcw .equ scinst+2 ;WORD caller FCW
scseg .equ scfcw+2 ;WORD caller PC SEG
scpc .equ scseg+2 ;WORD caller PC OFFSET
FRAMESZ .equ scpc+2

View File

@@ -0,0 +1,134 @@
;************ biosdefs2.z8k **************************
;*
;* Assembly language definitions for
;* P-CP/M (tm) BIOS
;*
;* 821013 S. Savitzky (Zilog) -- created.
;*
; 01/11/83 Modified for use with Z8002 (DMH)
;****************************************************
;*
;* System Calls and Trap Indexes
;*
;****************************************************
XFER_SC .equ 1
BIOS_SC .equ 3
BDOS_SC .equ 2
MEM_SC .equ 1
DEBUG_SC .equ 0
;* the traps use numbers similar to those in the
;* 68K version of P-CP/M
NTRAPS .equ 48 ;total number of traps
SC0TRAP .equ 32 ;trap # of system call 0
;Z8000 traps
EPUTRAP .equ 1 ;EPU (floating pt. emulator)
SEGTRAP .equ 2 ;segmentation (68K bus err)
NMITRAP .equ 0 ;non-maskable int.
PITRAP .equ 8 ;priviledge violation
;Interrupts, etc.
TRACETR .equ 9 ; trace
;****************************************************
;*
;* C Stack frame equates
;*
;* A C stack frame consists of the PC on top,
;* followed by the arguments, leftmost argument first.
;*
;* The caller adjusts the stack on return.
;* Returned value is in r7 (int) or rr6 (long)
;*
;****************************************************
co .equ 2 ;call offset, for 8002
PCSIZE .equ 2 ;PC size non-segmented
INTSIZE .equ 2 ;INT data type size
LONGSIZE .equ 4 ;LONG data type size
ARG1 .equ PCSIZE ;integer arguments
ARG2 .equ ARG1+INTSIZE
ARG3 .equ ARG2+INTSIZE
ARG4 .equ ARG3+INTSIZE
ARG5 .equ ARG4+INTSIZE
;****************************************************
;*
;* Segmented Mode Operations
;*
;* NOTE: segmented indirect-register operations
;* can be done by addressing the low half
;* of the register pair.
;*
;****************************************************
SEG .MACRO ; START segmented mode
; r0 destroyed.
ldctl r0,FCW
set r0,#15
ldctl FCW,r0
.ENDM
NONSEG .MACRO ; END segmented mode
; r0 destroyed.
ldctl r0,FCW
res r0,#15
ldctl FCW,r0
.ENDM
scall .MACRO ;(segaddr) segmented CALL
.word 05F00h
.long ?1
.ENDM
sscall .MACRO ;(|segaddr|) short segmented CALL
.word 05F00h
.word ?1
.ENDM
;****************************************************
;*
;* System Call Trap Handler Stack Frame
;*
;****************************************************
cr0 .equ 0 ;WORD caller r0
cr1 .equ cr0+2 ;WORD caller r1
cr2 .equ cr1+2 ;WORD caller r2
cr3 .equ cr2+2 ;WORD caller r3
cr4 .equ cr3+2 ;WORD caller r4
cr5 .equ cr4+2 ;WORD caller r5
cr6 .equ cr5+2 ;WORD caller r6
cr7 .equ cr6+2 ;WORD caller r7
cr8 .equ cr7+2 ;WORD caller r8
cr9 .equ cr8+2 ;WORD caller r9
cr10 .equ cr9+2 ;WORD caller r10
cr11 .equ cr10+2 ;WORD caller r11
cr12 .equ cr11+2 ;WORD caller r12
cr13 .equ cr12+2 ;WORD caller r13
cr14 .equ cr13+2 ;WORD caller r14
nr15 .equ cr14+2 ;WORD normal r15
scinst .equ nr15+2 ;WORD SC instruction
scfcw .equ scinst+2 ;WORD caller FCW
scpc .equ scfcw+2 ;WORD caller PC OFFSET
FRAMESZ .equ scpc+2

View File

@@ -0,0 +1,129 @@
;************ biosif.z8k **************************
;*
;* Assembly language interface for P-CP/M (tm) BIOS
;* ----- System-Independent -----
;*
;* 821013 S. Savitzky (Zilog) -- split into modules
;* 820913 S. Savitzky (Zilog) -- created.
;*
__text: .sect
;****************************************************
;*
;* NOTE
;* The C portion of the BIOS is non-segmented.
;*
;* This assembly-language module is assembled
;* non-segmented, and serves as the interface.
;*
;* Segmented operations are well-isolated, and
;* are either the same as their non-segmented
;* counterparts, or constructed using macros.
;* The resulting code looks a little odd.
;*
;****************************************************
.input "biosdefs.z8k"
;****************************************************
;*
;* Externals
;*
;****************************************************
.global _biosinit ;C portion init
.global _ldcpm ;Load the system into memory
.global _trapinit ;trap startup
.global _psap, _sysseg, _sysstk
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global bios ; initialization
.global _input ; input a byte
.global _output ; output a byte
;****************************************************
;*
;* Loader Bios Initialization and Entry Point
;*
;* This is where control comes after boot.
;*
;* We get here from bootstrap with:
;* segmented mode
;* valid stack pointer
;* valid PSA in RAM
;*
;****************************************************
bios:
; enter in segmented mode.
; Get system (PC) segment into r4
DI VI,NVI
calr kludge ; get PC segment on stack
kludge: popl rr4, @r14
; get PSAP into rr2.
ldctl r2, PSAPSEG
ldctl r3, PSAPOFF
; go non-segmented. save PSAP, system segment,
; system stack pointer (in system segment, please)
NONSEG
ldl _psap, rr2
ld _sysseg, r4
ld r14,_sysseg
ldl _sysstk, rr14
; set up traps, then enable interrupts
call _trapinit
EI VI,NVI
; set up C part of Bios
call _biosinit
; Turn control over to command processor
jp _ldcpm
;****************************************************
;*
;* I/O port operations
;*
;* int = input(port: int)
;* output (port, data: int)
;*
;****************************************************
_input:
ld r2,ARG1(r15)
subl rr6,rr6
inb rl7,@r2
ldb rl6,rl7
ret
_output:
ld r2,ARG1(r15)
ld r3,ARG2(r15)
outb @r2,rl3
ret
;*****************************************************
;*****************************************************

View File

@@ -0,0 +1,146 @@
;************ biosif.z8k **************************
;*
;* Assembly language interface for P-CP/M (tm) BIOS
;* ----- System-Independent -----
;*
;* 821013 S. Savitzky (Zilog) -- split into modules
;* 820913 S. Savitzky (Zilog) -- created.
;*
; 01/12/83 Adapted for a Z8002 (DMH)
__text: .sect
;****************************************************
;*
;* NOTE
;* The C portion of the BIOS is non-segmented.
;*
;* This assembly-language module is assembled
;* non-segmented, and serves as the interface.
;*
;* Segmented operations are well-isolated, and
;* are either the same as their non-segmented
;* counterparts, or constructed using macros.
;* The resulting code looks a little odd.
;*
;****************************************************
.input "biosdefs2.z8k"
;****************************************************
;*
;* Externals
;*
;****************************************************
.global _biosinit ;C portion init
.global _flush ;Flush buffers
.global ccp ;Command Processor
.global _trapinit ;trap startup
.global _psap, _sysseg, _sysstk
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global bios ; initialization
.global _wboot ; warm boot
.global _input ; input a byte
.global _output ; output a byte
;****************************************************
;*
;* Bios Initialization and Entry Point
;*
;* This is where control comes after boot.
;* Control is transferred to the CCP.
;*
;* We get here from bootstrap with:
;* valid stack pointer
;* valid PSA in RAM
;*
;****************************************************
bios:
; Get system (PC) segment into r4
DI VI,NVI
; get PSAP into r3.
ldctl r3, PSAPOFF
sub r4,r4 ; this will be _sysseg, for consistency
ld _psap, r3
ld _sysseg, r4
ld r14,_sysseg
ld _sysstk, r15
; set up system stack so that a return will warm boot
push @r15,#_wboot
; set up traps, then enable interrupts
call _trapinit
EI VI,NVI
; set up C part of Bios
call _biosinit
; Turn control over to command processor
jp ccp
;*****************************************************
;*
;* Warm Boot
;*
;* flush buffers and initialize Bios
;* then transfer to CCP
;*
;*****************************************************
_wboot:
call _flush
call _biosinit
ld r15,_sysstk
jp ccp
;****************************************************
;*
;* I/O port operations
;*
;* int = input(port: int)
;* output (port, data: int)
;*
;****************************************************
_input:
ld r2,ARG1(r15)
subl rr6,rr6
inb rl7,@r2
ldb rl6,rl7
ret
_output:
ld r2,ARG1(r15)
ld r3,ARG2(r15)
outb @r2,rl3
ret
;*****************************************************
;*****************************************************

View File

@@ -0,0 +1,104 @@
;************ biosio.z8k **************************
;*
;* I/O routines for P-CP/M (tm) BIOS
;* for Olivetti M20 (Z8001) system.
;*
;* 821013 S. Savitzky (Zilog) -- created.
;*
__text: .sect
;****************************************************
;*
;* NOTE The Olivetti PROM routines are segmented.
;* The C portion of the BIOS is non-segmented.
;*
;* This assembly-language module is assembled
;* non-segmented, and serves as the interface.
;*
;* Segmented operations are well-isolated, and
;* are either the same as their non-segmented
;* counterparts, or constructed using macros.
;*
;****************************************************
.input "biosdefs.z8k"
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global _disk_io
.global _crt_put
.global _cold_boot
;****************************************************
;*
;* Prom Subroutine Access
;*
;****************************************************
_disk_io: ;err=disk_io(drv, cmd, count, blk, addr)
dec r15,#14 ;save registers
ldm @r15,r8,#7
ldb rh7,14+ARG1+1(r15) ;get args
ldb rl7,14+ARG2+1(r15)
ld r8, 14+ARG3(r15)
ld r9, 14+ARG4(r15)
ldl rr10,14+ARG5(r15)
;rh7 = drive #
;rl7 = command
;r8 = block count
;r9 = block number
;rr10 = segmented address
SEG
scall 84000068h
NONSEG
;r8 = block count not transferred
;rh7 = #retries
;rl7 = final error code (RETURNED)
;rh6 = error retried
and r7,#0FFh ;value returned in r7
ldm r8,@r15,#7 ;restore regs
inc r15,#14
ret
_crt_put: ;crt_put(char)
dec r15,#14 ;save registers
ldm @r15,r8,#7
ld r1,14+ARG1(r15) ;get arg in r1
SEG ; SEG clobbers r0
ld r0,r1 ;rl0 = char
scall 84000080h
NONSEG
ldm r8,@r15,#7 ;restore regs
inc r15,#14
ret
_cold_boot:
SEG
scall 8400008Ch
NONSEG
ret

View File

@@ -0,0 +1,818 @@
/*
***************************************************************************
This is the Master/requestor portion of a Dual processor P-CP/M BIOS. It
should be designed such that only the low level inter-processor transfer
protocols and BIOS primitives should have to be modified to accomplish
porting to different hardware configurations. Error checking and report-
ing is necessary because I/O channel may be unplugged or unreliable.
***************************************************************************
*/
/*
*************************************************
* *
* Author: David Heintz *
* Module: Biosmasc.c *
* Creation Date: 10/20/82 *
* Language: Standard C *
* Version: 1.0 *
* Last Mod: 01/20/83 *
* *
*************************************************
*/
/*
*************************************************
* *
* STANDARD HEADERS *
* *
*************************************************
*/
#include "unstdsys.h"
#include "stdcpm.h"
#include "stdbios.h"
#include "chnequ.h"
/*
*************************************************
* *
* EXTERNAL DECLARATIONS *
* *
*************************************************
*/
/*
extern wboot();
*************************************************
* *
* BIOS Entry Point declaration *
* *
*************************************************
*/
extern LONG _bios();
/*
*************************************************
* *
* Other Globals *
* *
*************************************************
*/
extern biosinit(); /* Initialize system */
extern flush(); /* Flush buffer */
/*
*************************************************
* *
* I/O Channel Related Externals *
* *
*************************************************
*/
extern BYTE rcv_cmd();
extern BYTE rcv_byte();
extern BYTE rcv_word();
extern BYTE rcv_long();
extern BYTE rcv_data();
extern BYTE snd_cmd();
extern BYTE snd_byte();
extern BYTE snd_word();
extern BYTE snd_long();
extern BYTE snd_data();
extern chn_err();
/*
*************************************************
* *
* Machine and Processor Dependent *
* Externals *
* *
*************************************************
*/
extern *memtab;
extern LONG trapvec[];
extern mem_cpy();
extern LONG map_adr();
/*
*************************************************
* *
* LOCAL DEFINITIONS *
* *
*************************************************
*/
static char signon[] = "\n\rKontron Z8000 BIOS v. 1.0 11/23/82\n\r";
/*
*************************************************
* *
* Check Vectors *
* 512 Directory Entries Maximum *
* *
*************************************************
*/
BYTE csvtab[8][128] = {{0}};
/*
*************************************************
* *
* Allocation Vectors *
* 2048 Allocation Blocks Maximum *
* *
*************************************************
*/
BYTE alvtab[8][256] = {{0}};
/*
*************************************************
* *
* Data Parameter Blocks *
* Unitialized *
* *
*************************************************
*/
DPB dpbtab[8] = {0};
/*
*************************************************
* *
* Directory Buffer *
* *
*************************************************
*/
BYTE dirbuf[128] = {0};
/*
*************************************************
* *
* Disk Parameter Headers *
* Maximum of 8 defined *
* *
*************************************************
*/
DPH dphtab[8] =
/*
{ *xltp, dphscr[3], *dirbufp, *dpbp, *csvp, *alvp}
*/
{
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[0], csvtab[0], alvtab[0]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[1], csvtab[1], alvtab[1]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[2], csvtab[2], alvtab[2]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[3], csvtab[3], alvtab[3]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[4], csvtab[4], alvtab[4]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[5], csvtab[5], alvtab[5]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[6], csvtab[6], alvtab[6]},
{(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[7], csvtab[7], alvtab[7]},
};
/*
*************************************************
* *
* Time-Honored BIOS Variables *
* *
*************************************************
*/
static LONG dmaadr = 0; /* Caller's data transfer address */
static WORD sector = 0; /* Current sector (Unused) */
static WORD track = 0; /* Current track (Unused) */
static BYTE disk = 0; /* Current drive number (Unused) */
static BYTE IOBYTE = 0; /* Logical to physical mapping (Unused) */
static BYTE retry = 0xff; /* I/O channel retry boolean */
/*
*************************************************
* *
* Sector Buffer *
* *
*************************************************
*/
static BYTE secbuf[seclen] = {0};
/*
*************************************************
* *
* MISCELLANEOUS FUNCTIONS *
* *
*************************************************
*/
/*
/--------------------------------
/ |
/ Print a Message |
/ |
/--------------------------------
/ Inputs: Pointer to message
/ terminated by '\0'
/ Outputs: None
/ Actions: Send message to slave
/ console output.
/
*/
prtmsg(pbyte)
BYTE *pbyte;
{
char c;
while(c = *(pbyte++))
_bios((WORD)coreq, (LONG)c, 0L);
}
/*
/--------------------------------
/ |
/ Illegal Command |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Currently unused
/
*/
ill_cmd()
{
}
/*
/--------------------------------
/ |
/ biosinit(); |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Initialize hardware
/
*/
biosinit()
{
prtmsg(signon);
_bios((WORD)inreq, 0L, 0L); /* Make BIOS request */
}
/*
/--------------------------------
/ |
/ Flush Disk Buffer |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Flush Disk Buffer on Slave
/
*/
flush()
{
_bios((WORD)fbreq, 0L, 0L); /* Ignore return code? */
}
/*
/--------------------------------
/ |
/ snd_rcv(): |
/ send a command and |
/ receive a parameter |
/ |
/--------------------------------
/ Inputs: BIOS parameters d0, d1, d2
/ Outputs: LONG return parameter
/ Actions: Send command through fifo and
/ receive return parameter
/
*/
LONG snd_rcv(d0, d1, d2)
WORD d0;
LONG d1, d2;
{
BYTE code;
LONG temp;
do
{
code = snd_cmd(d0, d1, d2);
if (code == chsuc)
code = rcv_long(&temp);
if (code != chsuc)
{
chn_err(d0, code);
temp = cherr;
}
}
while (retry && (code != chsuc));
return(temp);
}
/*
*************************************************
* *
* P-CP/M BIOS ENTRY POINT *
* *
*************************************************
*/
LONG _bios(d0, d1, d2)
WORD d0;
LONG d1, d2;
{
char zzz = {"kludge "};
switch(d0)
{
/*
/--------------------------------
/ |
/ Function 4: |
/ Console Output |
/ |
/--------------------------------
/ Inputs: (BYTE) d1 contains character
/ to output to slave console
/ Outputs: None
/ Actions: Output character from master
/ to slave console I/O.
*/
case coreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 5: |
/ List Output |
/ |
/--------------------------------
/ Inputs: (BYTE) d1 contains character
/ to output to slave list device.
/ Outpus: None
/ Actions: Output character from master
/ to slave list I/O.
*/
case loreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 6: |
/ Auxilliary Output |
/ |
/--------------------------------
/ Inputs: (BYTE) d1 contains character
/ to output to slave aux. device.
/ Outputs: None
/ Actions: Output character from master
/ to slave auxilliary (punch) I/O.
*/
case aoreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 8: |
/ Home disk |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Perform slave home disk function.
*/
case hdreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 10: |
/ Set Track |
/ |
/--------------------------------
/ Inputs: (WORD) d1 contains track number.
/ Outputs: None
/ Actions: Set track number from master on slave.
*/
case streq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 11: |
/ Set Sector |
/ |
/--------------------------------
/ Inputs: (WORD) d1 contains sector number
/ Outputs: None
/ Actions: Set sector number from master on slave.
*/
case ssreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 20: |
/ Set I/O byte |
/ |
/--------------------------------
/ Inputs: BYTE d1 contains IOBYTE value
/ Outputs: None
/ Actions: Send contents of slave
/ location IOBYTE to master.
*/
case sireq: /* Fall through to next case */
/* All degenerate cases of BIOS functions */
/* end up falling through to here. Request */
/* is forwarded to the slave BIOS and no */
/* parameters are returned to the master. */
{
BYTE code;
code = snd_cmd(d0, d1, d2);
if (code != chsuc)
chn_err(d0, code);
}
break; /* Request completed. */
/*
/--------------------------------
/ |
/ Function 2: |
/ Console Status |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: returns console status.
/ Actions: receive 1-byte slave con-
/ sole status.
*/
case csreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 7: |
/ Auxilliary Input |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Return character from aux device
/ Actions: Input a character from slave
/ auxilliary (reader) I/O to master.
*/
case aireq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 15: |
/ List Status |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Return status of slave list device.
/ Actions: Send 1-byte slave list
/ status to master.
*/
case lsreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 16: |
/ Translate Sector |
/ |
/--------------------------------
/ Inputs: (LONG) d1 is sector translation table address
/ (WORD) d2 is sector number to be translated
/ Outputs: Return translated sector.
/ Actions: Perform slave BIOS sector
/ translation call
*/
case tsreq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 19: |
/ Get I/O byte |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Returns IOBYTE value from slave.
/ Actions: Receive byte from master and
/ store in slave location IOBYTE.
*/
case gireq: /* Fall through to next case */
/*
/--------------------------------
/ |
/ Function 21: |
/ Flush disk buffer |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Send request to slave
/
*/
case fbreq: /* Fall through to next case */
/* All cases which return status or data */
/* end up falling through to here. Request */
/* passed on to the slave BIOS and a long */
/* parameter is returned to the master. */
return(snd_rcv(d0, d1, d2));
/*
/--------------------------------
/ |
/ Function 0: |
/ System Init |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Initialize Master.
/ Just print message, so far.
*/
case inreq:
break;
/*
/--------------------------------
/ |
/ Function 1: |
/ Warm Boot |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Warm boot master.
*/
case wbreq:
wboot();
break;
/*
/--------------------------------
/ |
/ Function 3: |
/ Console Input |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: returns console character.
/ Actions: Input character from
/ slave console to master.
*/
case cireq:
while(!_bios(csreq, 0L, 0L));
return(snd_rcv(d0, d1, d2));
/*
/--------------------------------
/ |
/ Function 9: |
/ Select Disk |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Pointer to DPH for selected drive.
/ Null if illegal drive.
/ Actions: Select drive number from master on slave.
/ Return condition code from slave to master.
/ Pass selected drive's DPB from slave to master,
/ if drive selected.
*/
case sdreq:
{
BYTE code;
LONG temp;
DPH *dphptr;
DPB *dpbptr;
do
{
code = snd_cmd(d0, d1, d2);
if (code == chsuc)
code = rcv_long(&temp);
if (code == chsuc)
if ((DPH *)temp != NULL)
{
dphptr = &dphtab[d1];
dpbptr = dphptr -> dpbp;
if (!((BYTE)d2 & 0x1))
{
code = rcv_long(&temp);
if (code == chsuc)
(dphptr -> xltp) = (BYTE *)temp;
if (code == chsuc)
code = rcv_word(&(dpbptr -> spt));
if (code == chsuc)
code = rcv_byte(&(dpbptr -> bsh));
if (code == chsuc)
code = rcv_byte(&(dpbptr -> blm));
if (code == chsuc)
code = rcv_byte(&(dpbptr -> exm));
if (code == chsuc)
code = rcv_word(&(dpbptr -> dsm));
if (code == chsuc)
code = rcv_word(&(dpbptr -> drm));
if (code == chsuc)
code = rcv_byte(&(dpbptr -> al0));
if (code == chsuc)
code = rcv_byte(&(dpbptr -> al1));
if (code == chsuc)
code = rcv_word(&(dpbptr -> cks));
if (code == chsuc)
code = rcv_word(&(dpbptr -> off));
}
temp = (LONG)dphptr;
}
else temp = (LONG)NULL;
if (code != chsuc)
{
chn_err(sdreq, code);
temp = (LONG)cherr;
}
}
while (retry && (code != chsuc));
return(temp);
}
/*
/--------------------------------
/ |
/ Function 13: |
/ Read Sector |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Read completion status
/ Actions: Receive a 128 byte sector specified by
/ current drive, sector, track from slave
/ and place it at the current DMA add-
/ ress.
*/
case rsreq:
{
BYTE stat, code;
LONG temp;
do
{
code = snd_cmd(d0, d1, d2);
if (code == chsuc)
code = rcv_byte(&stat);
if ((stat == rssuc) && (code == chsuc))
code = rcv_data(&secbuf[0], seclen);
if (code == chsuc)
temp = (LONG)stat;
else
{
chn_err(d0, code);
temp = cherr;
}
}
while (retry && (code != chsuc));
if (temp == rssuc)
mem_cpy(map_adr((LONG)secbuf, 0),(LONG)dmaadr,(LONG)seclen);
return(temp);
}
/*
/--------------------------------
/ |
/ Function 14: |
/ Write Sector |
/ |
/--------------------------------
/ Inputs: Write type.
/ Outputs: Write sector completion status.
/ Actions: Send a 128 byte sector from current DMA
/ address to slave.
/ Receive a 1-byte completion code, in-
/ dicating if write successful or not.
*/
case wsreq:
{
BYTE stat, code;
LONG temp;
do
{
mem_cpy((LONG)dmaadr,map_adr((LONG)secbuf,0),(LONG)seclen);
code = snd_cmd(d0, d1, d2);
if (code == chsuc)
code = snd_data(&secbuf[0], seclen);
if (code == chsuc)
code = rcv_byte(&stat);
if (code == chsuc)
temp = (LONG)stat;
else
{
chn_err(d0, code);
temp = cherr;
}
}
while (retry && (code != chsuc));
return(temp);
}
/*
/--------------------------------
/ |
/ Function 12: |
/ Set DMA Address |
/ |
/--------------------------------
/ Inputs: (LONG) d1 contains DMA address.
/ Outputs: None
/ Actions: Set DMA address from master.
*/
case sareq:
dmaadr = d1;
break;
/*
/--------------------------------
/ |
/ Function 17: |
/ Get Memory Table |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: Return pointer to memory region table
/ Actions: None
*/
case gmreq:
return((long)&memtab);
/*
/--------------------------------
/ |
/ Function 22: |
/ Set Exception Vector |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Currently unused
/
*/
case svreq:
{
LONG oldval;
oldval = trapvec[(int)d1];
trapvec[(int)d1] = d2;
return(oldval);
}
/*
/--------------------------------
/ |
/ Illegal Request |
/ |
/--------------------------------
/ Inputs: None
/ Outputs: None
/ Actions: Currently unused
/
*/
default:
ill_cmd(); /* Illegal command */
break;
} /* End of Switch */
} /* End of BIOS */

View File

@@ -0,0 +1,234 @@
;************ biosmem.z8k **************************
;*
;* Memory Management for P-CP/M (tm) BIOS
;* for Olivetti M20 (Z8001) system.
;*
;* 821013 S. Savitzky (Zilog) -- split modules
;* 820913 S. Savitzky (Zilog) -- created.
;*
__text: .sect
;****************************************************
;*
;* This module copies data from one memory space
;* to another. The machine-dependent parts of
;* the mapping are well isolated.
;*
;* Segmented operations are well-isolated, and
;* are either the same as their non-segmented
;* counterparts, or constructed using macros.
;*
;****************************************************
.input "biosdefs.z8k"
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global _sysseg, _usrseg, _sysstk, _psap
.global memsc
;****************************************************
;*
;* Externals
;*
;****************************************************
.global xfersc
;****************************************************
;*
;* System/User Memory Access
;*
;* _mem_cpy( source, dest, length)
;* long source, dest, length;
;* _map_adr( addr, space) -> paddr
;* long addr; int space;
;*
;* _map_adr( addr, -1) -> addr
;* sets user seg# from addr
;*
;* _map_adr( addr, -2)
;* control transfer to context at addr.
;*
;* system call: mem_cpy
;* rr6: source
;* rr4: dest
;* rr2: length (0 < length <= 64K)
;* returns
;* registers unchanged
;*
;* system call: map_adr
;* rr6: logical addr
;* r5: space code
;* r4: ignored
;* rr2: 0
;* returns
;* rr6: physical addr
;*
;* space codes:
;* 0: caller data
;* 1: caller program
;* 2: system data
;* 3: system program
;* 4: TPA data
;* 5: TPA program
;*
;* x+256 x=1, 3, 5 : segmented I-space addr.
;* instead of data access
;*
;* FFFF: set user segment
;*
;****************************************************
memsc: ;memory manager system call
; CALLED FROM SC
; IN SEGMENTED MODE
; rr6: source
; rr4: dest / space
; rr2: length / 0
testl rr2
jr z mem_map
mem_copy: ; copy data.
; rr6: source
; rr4: dest
; rr2: length
ldirb @r4,@r6,r3
ldl rr6,rr4 ; rr6 = dest + length
ret
mem_map: ; map address
; rr6: source
; r4: caller's seg.
; r5: space
; r2: caller's FCW
NONSEG
cp r5,#-2 ; space=-2: xfer
jp eq xfersc
ld r4,scseg+4(r15)
ld r2,scfcw+4(r15)
calr map_1
ldl cr6+4(r15),rr6 ; return rr6
SEG
ret
map_1: ; dispatch
cp r5,#0FFFFh
jr eq set_usr ; space=-1: user seg
cpb rl5,#0
jr eq call_data
cpb rl5,#1
jr eq call_prog
cpb rl5,#2
jr eq sys_data
cpb rl5,#3
jr eq sys_prog
cpb rl5,#4
jr eq usr_data
cpb rl5,#5
jr eq usr_prog
ret ;default: no mapping
set_usr: ;-1: set user seg.
ld _usrseg,r6
ret
;*
;*** THE FOLLOWING CODE IS SYSTEM-DEPENDENT ***
;*
;* rr6= logical address
;* r4 = caller's PC segment
;* r2 = caller's FCW
;* returns
;* rr6= mapped address
;*
;* Most of the system dependencies are in map_prog,
;* which maps a program segment into a data segment
;* for access as data.
;*
call_data:
bit r2,#15 ; segmented caller?
ret nz ; yes-- use passed seg
ld r6,r4 ; no -- use pc segment
ret ; already mapped
call_prog:
bit r2,#15 ; segmented caller?
jr nz map_prog ; yes-- use passed seg
ld r6,r4 ; no -- use pc segment
jr map_prog ; map prog as data
sys_data:
ld r6, _sysseg
ret
sys_prog:
ld r6, _sysseg
ret ; assume sys does not
; separate code, data
usr_data:
ld r0, #-1
cp r0, _usrseg
ret eq
ld r6, _usrseg
ret
usr_prog:
ld r0, #-1
cp r0, _usrseg
jr eq map_prog
ld r6, _usrseg
jr map_prog
map_prog: ;map program addr into data
; rr6 = address
testb rh5 ; data access?
ret nz ; no: done
and r6,#7F00h ; extract seg bits
; olivetti: segment 8 is the only one with
; separate I and D spaces, and
; the program space is accessed
; as segment 10's data.
cpb rh6,#8
ret ne
ldb rh6,#10
ret
;****************************************************
;*
;* Data
;*
;****************************************************
__bss: .sect
_sysseg: .block 2 ;system segment
_usrseg: .block 2 ;user segment
_sysstk: .block 4 ;system stack pointer
_psap: .block 4 ;program status area ptr
;****************************************************
;****************************************************

View File

@@ -0,0 +1,303 @@
;************ biosmem2.z8k **************************
;*
;* Memory Management for P-CP/M (tm) BIOS
;* for Olivetti M20 (Z8001) system.
;*
;* 821013 S. Savitzky (Zilog) -- split modules
;* 820913 S. Savitzky (Zilog) -- created.
;*
; 01/12/83 Adapted for Z8002 (DMH, FMZ)
__text: .sect
;****************************************************
;*
;* This module copies data from one memory space
;* to another. The machine-dependent parts of
;* the mapping are well isolated.
;*
;* Segmented operations are well-isolated, and
;* are either the same as their non-segmented
;* counterparts, or constructed using macros.
;*
;****************************************************
.input "biosdefs2.z8k"
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global _sysseg, _usrseg, _sysstk, _psap
.global _mem_mov, _map_wdw
.global memsc
.global _blkmov
;****************************************************
;*
;* Externals
;*
;****************************************************
.global xfersc
.global _mem_bcp
;****************************************************
;*
;* System/User Memory Access
;*
;* _mem_cpy( source, dest, length)
;* long source, dest, length;
;* _map_adr( addr, space) -> paddr
;* long addr; int space;
;*
;* _map_adr( addr, -1) -> addr
;* sets user seg# from addr
;*
;* _map_adr( addr, -2)
;* control transfer to context at addr.
;*
;* system call: mem_cpy
;* rr6: source
;* rr4: dest
;* rr2: length (0 < length <= 64K)
;* returns
;* registers unchanged
;*
;* system call: map_adr
;* rr6: logical addr
;* r5: space code
;* r4: ignored
;* rr2: 0
;* returns
;* rr6: physical addr
;*
;* space codes:
;* 0: caller data
;* 1: caller program
;* 2: system data
;* 3: system program
;* 4: TPA data
;* 5: TPA program
;*
;* The following does not apply in Z8002 case
;*
;* x+256 x=1, 3, 5 : segmented I-space addr.
;* instead of data access
;*
;* FFFF: set user segment
;*
;****************************************************
memsc: ;memory manager system call
; CALLED FROM SC
; IN SEGMENTED MODE
; rr6: source
; rr4: dest / space
; rr2: length / 0
testl rr2
jr z mem_map
mem_copy: ; copy data.
; rr6: source
; rr4: dest
; rr2: length
push @r15,r3 ; push length as a short!
pushl @r15,rr4 ; push dest
pushl @r15, rr6 ; push source
call _mem_bcp ; call C copy routine
ldl rr6,4(r15) ; get dest into rr6
add r7,8(r15) ; return dest plus length
inc r15,#10 ; restore stack
ret
mem_map: ; map address
; rr6: source
; r4: caller's seg.
; r5: space
; r2: caller's FCW
cp r5,#-2 ; space=-2: xfer
jp eq xfersc
;* ld r4,scseg+co(r15) Not done in Z8002 implementation
ld r2,scfcw+co(r15)
calr map_1
ldl cr6+co(r15),rr6 ; return rr6
ret
map_1: ; dispatch
cp r5,#0FFFFh
jr eq set_usr ; space=-1: user seg
cpb rl5,#0
jr eq call_data
cpb rl5,#1
jr eq call_prog
cpb rl5,#2
jr eq sys_data
cpb rl5,#3
jr eq sys_prog
cpb rl5,#4
jr eq usr_data
cpb rl5,#5
jr eq usr_prog
ret ;default: no mapping
set_usr: ;-1: set user seg.
ld _usrseg,r6
ret
;*
;*** THE FOLLOWING CODE IS SYSTEM-DEPENDENT ***
;*
;* rr6= logical address
;* r4 = caller's PC segment - but NOT in the Z8002 implementation!
;* r2 = caller's FCW
;* returns
;* rr6= mapped address
;*
;* This code is much simpler than the corresponding
;* Z8001 code. If the caller's FCW indicates that he
;* was in Normal mode, then _usrseg is returned.
;* Otherwise, pseudo-segment 0 is returned.
;*
call_data:
bit r2,#14 ; System caller?
jr nz sys_data ; yes-- use system seg
ld r6,_usrseg ; no -- use pc segment
ret
call_prog:
bit r2,#14 ; System caller?
jr nz sys_prog ; yes-- use system seg
ld r6,_usrseg ; no 00 use pc segment
jr map_prog ; map prog as data
sys_data:
sys_prog:
ld r6, _sysseg
ret ; assume sys does not
; separate code, data
usr_data:
ld r6, _usrseg
ret
usr_prog:
ld r6, _usrseg
jr map_prog
map_prog: ; map program addr into data
; rr6 = address
and r6,#7F00h ; extract seg bits
; kontron: pseudo-segment 2 is the only one with
; separate I and D spaces, and
; the program space is accessed
; as pseudo-segment 1, data space as pseudo-segment 2
cpb rh6,#2
ret ne
ldb rh6,#1
ret
;*
;* The following routine copies a block of data from one part
;* of the system address space to another. In practice, part
;* of the address space may be windowed, but that is transparent
;* here.
;*
;* The interface is:
;* blkmov(source,dest,length)
;* short source,dest,length;
;*
_blkmov:
ld r5,ARG1(r15) ; r5: source
ld r4,ARG2(r15) ; r4: dest
ld r2,ARG3(r15) ; r2: length (just a word!)
ld r7,r2 ; return value = bytes copied
ldirb @r4,@r5,r2 ; copy!
ret
;****************************************************
;* mem_mov -- C callable block move routine
;* input stack:
;* ret. addr (word)
;* source (word)
;* destination (word)
;* length, bytes (word)
_mem_mov:
ld r5,2(r15) ; pull off source
ld r7,4(r15) ; pull off destination
ld r0,6(r15) ; pull off length
ldirb @r7,@r5,r0 ; block move
ret
;****************************************************
;* map_wdw -- C callable map window routine,
; system dependent.
;* input stack:
;* ret. addr (word)
;* window code (word)
;* 2 means physical block 2
;* 3 means physical block 3
;* x means physical block 1
;*
;* Note: the manual is unclear, but implies that
;* history must be kept concerning the window
;* mapping, if the window was last block 3.
;* That is why I map block one before others.
;* See ECB/C16 Hardware description for details.
_map_wdw:
ld r0,2(r15) ; pull off window code
out 0c000h,r0 ; map physical block 1
cp r0,#2 ; map physical block 2?
jr nz,map_wdw_3 ; No, go for physical block 3.
out 8001h,r0 ; Funny port address, huh?
ret
map_wdw_3:
cp r0,#3 ; map pysical block 3?
ret nz ; no, already mapped to 1.
out 0c001h,r0 ; yes.
ret
;****************************************************
;*
;* Data
;*
;****************************************************
__bss: .sect
_sysseg: .block 2 ;system segment
_usrseg: .block 2 ;user segment
_sysstk: .block 2 ;system stack pointer
_psap: .block 2 ;program status area ptr
;****************************************************
;****************************************************

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,370 @@
;************ biostrap.z8k **************************
;*
;* Trap handlers for P-CP/M (tm) BIOS
;*
;* 821013 S. Savitzky (Zilog) -- created
;* 821123 D. Dunlop (Zilog) -- added Olivetti M20-
;* specific code to invalidate track buffer
;* contents when disk drive motor stops
;* (fixes directory-overwrite on disk change)
;* 830305 D. Sallume (Zilog) -- added FPE trap
;* code.
;*
__text: .sect
;****************************************************
;*
;* NOTE
;* Trap and interrupt handlers are started up
;* in segmented mode.
;*
;****************************************************
.input "biosdefs.z8k"
;****************************************************
;*
;* Externals
;*
;****************************************************
.global _bios ;C portion of BIOS
.global memsc ;memory-management SC
.global _tbvalid ;disk track buff valid
.global _tbdirty ;disk track buff is dirty
.global _sysseg, _usrseg, _sysstk, _psap
;****************************************************
;*
;* M-20 ROM scratchpad RAM addresses
;*
;****************************************************
rtc_ext: .equ 82000022h ;Place to put address
; of list of functions
; for each clock tick
motor_on: .equ 82000020h ;Disk motor timeout
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global _trapinit
.global _trapvec
.global _trap
.global xfersc
;****************************************************
;*
;* Trap vector table
;*
;* entries 0..31 are misc. system traps
;* entries 32..47 are system calls 0..15
;*
;****************************************************
__bss: .sect
_trapvec:
.block NTRAPS*4
;****************************************************
;*
;* System Call and General Trap Handler And Dispatch
;*
;* It is assumed that the system runs
;* non-segmented on a segmented CPU.
;*
;* _trap is jumped to segmented, with the
;* following information on the stack:
;*
;* trap type: WORD
;* reason: WORD
;* fcw: WORD
;* pc: LONG
;*
;* The trap handler is called as a subroutine,
;* with all registers saved on the stack,
;* IN SEGMENTED MODE. This allows the trap
;* handler to be in another segment (with some
;* care). This is useful mainly to the debugger.
;*
;* All registers except rr0 are also passed
;* intact to the handler.
;*
;****************************************************
__text: .sect
sc_trap: ;system call trap server
push @r14,@r14
_trap:
sub r15,#30 ; push caller state
ldm @r14,r0,#14
NONSEG ; go nonsegmented
ldctl r1,NSP
ld nr14(r15),r14
ex r1,nr15(r15)
; trap# now in r1
cpb rh1,#7Fh ; system call?
jr ne trap_disp ; no
; yes: map it
clrb rh1
add r1,#SC0TRAP
;=== need range check ===
trap_disp: ; dispatch
sll r1,#2
ldl rr0,_trapvec(r1)
testl rr0
jr z _trap_ret ; zero -- no action
; else call seg @rr0
pushl @r15,rr0 ; (done via kludge)
SEG
popl rr0,@r14
calr trap_1
jr _trap_ret
trap_1: ; jp @rr0
pushl @r14,rr0
ret
_trap_ret: ;return from trap or interrupt
NONSEG
ld r1,nr15(r15) ; pop state
ld r14,nr14(r15)
ldctl NSP,r1
SEG ; go segmented for the iret.
ldm r0,@r14,#14
add r15,#32
iret ; return from interrupt
;****************************************************
;*
;* Assorted Trap Handlers
;*
;****************************************************
epu_trap:
push @r14,#EPUTRAP
jr _trap
pi_trap:
push @r14,#PITRAP
jr _trap
seg_trap:
push @r14,#SEGTRAP
jr _trap
nmi_trap:
push @r14,#NMITRAP
jr _trap
;****************************************************
;*
;* Bios system call handler
;*
;****************************************************
;biossc: ;call bios
; NONSEG
; ; r3 = operation code
; ; rr4= P1
; ; rr6= P2
;
; ld r0,scfcw+4(r15) ; if caller nonseg, normal
; and r0,#0C000h
; jr nz seg_ok
;
; ld r4,scseg+4(r15) ; then add seg to P1, P2
; ld r6,r4
;seg_ok:
; ; set up C stack frame
;;===
; pushl @r15,rr6
; pushl @r15,rr4
; push @r15,r3
;
; ; call C program
; call _bios
;
; ; clean stack & return
; add r15,#10
; ldl cr6+4(r15),rr6 ; with long in rr6
;
; SEG
; ret
;
;****************************************************
;*
;* Context Switch System Call
;*
;* xfer(context)
;* long context;
;*
;* context is the physical (long) address of:
;* r0
;* ...
;* r13
;* r14 (normal r14)
;* r15 (normal r15)
;* ignored word
;* FCW (had better specify normal mode)
;* PC segment
;* PC offset
;*
;* The system stack pointer is not affected.
;*
;* Control never returns to the caller.
;*
;****************************************************
xfersc: ;enter here from system call
SEG
; build frame on system stack
; when called from system call, the frame replaces
; the caller's context, which will never be resumed.
inc r15,#4 ;discard return addr
ldl rr4,rr14 ;move context
ld r2,#FRAMESZ/2
ldir @r4,@r6,r2
jr _trap_ret ;restore context
;****************************************************
;*
;* _motor_c -- check if disk motor still running.
;* Entered each clock tick. Invalidates
;* track buffer when motor stops
;* (Note: runs segmented)
;*
;****************************************************
_motor_c:
ldl rr4,#motor_on ;Motor running?
test @r4
ret nz ;Yes: do nothing
ldar r4,$
ld r5,#_tbdirty ; Is track buff dirty?
test @r4 ; Yes...
ret nz ; ...return without invalidating
ld r5,#_tbvalid
clr @r4 ;No: mark track buffer
ret ; invalid
; Table of functions run each real time clock tick
_ticktab:
.long -1 ;Will contain _motor_c
.word 0ffffh ;Terminator
;****************************************************
;*
;* _trapinit -- initialize trap system
;*
;****************************************************
;*
;* PSA (Program Status Area) structure
;*
ps .equ 8 ; size of a program status entry
; --- segmented ---
psa_epu .equ 1*ps ; EPU trap offset
psa_prv .equ 2*ps ; priviledged instruction trap
psa_sc .equ 3*ps ; system call trap
psa_seg .equ 4*ps ; segmentation trap
psa_nmi .equ 5*ps ; non-maskable interrupt
psa_nvi .equ 6*ps ; non-vectored interrupt
psa_vi .equ 7*ps ; vectored interrupt
psa_vec .equ psa_vi+(ps/2) ; vectors
_trapinit:
; initialize trap table
lda r2,_trapvec
ld r0,#NTRAPS
subl rr4,rr4
clrtraps:
ldl @r2,rr4
inc r2,#4
djnz r0,clrtraps
ld r2,_sysseg
; lda r3,biossc
; ldl _trapvec+(BIOS_SC+SC0TRAP)*4,rr2
lda r3,memsc
ldl _trapvec+(MEM_SC+SC0TRAP)*4,rr2
; lda r3,fp_epu
; ldl _trapvec+EPUTRAP*4,rr2
; initialize some PSA entries.
; rr0 PSA entry: FCW (ints ENABLED)
; rr2 PSA entry: PC
; rr4 -> PSA slot
ldl rr4,_psap
SEG
ldl rr0,#0000D800h
add r5,#ps ; EPU trap
ldar r2,epu_trap
ldm @r4,r0,#4
add r5,#ps ; Priviledged Inst
ldar r2,pi_trap
ldm @r4,r0,#4
add r5,#ps ; System Call
ldar r2,sc_trap
ldm @r4,r0,#4
add r5,#ps ; segmentation
ldar r2,seg_trap
ldm @r4,r0,#4
add r5,#ps ; Non-Maskable Int.
ldar r2,nmi_trap
ldm @r4,r0,#4
; Set up Real-Time Clock external call loc
ldar r2,_motor_c
ldar r4,_ticktab
ldl @r4,rr2
ldl rr2,#rtc_ext
ldl @r2,rr4
NONSEG
ret
;****************************************************
;****************************************************

View File

@@ -0,0 +1,294 @@
;************ biostrap.z8k **************************
;*
;* Trap handlers for P-CP/M (tm) BIOS
;*
;* 821013 S. Savitzky (Zilog) -- created
;* 821123 D. Dunlop (Zilog) -- added Olivetti M20-
;* specific code to invalidate track buffer
;* contents when disk drive motor stops
;* (fixes directory-overwrite on disk change)
;*
; 01/12/83 Adapted for Z8002 (DMH)
__text: .sect
;****************************************************
;*
;* NOTE
;* Trap and interrupt handlers are started up
;* in segmented mode on the Z8001.
;*
;****************************************************
.input "biosdefs2.z8k"
;****************************************************
;*
;* Externals
;*
;****************************************************
.global __bios ;C portion of BIOS
.global memsc ;memory-management SC
.global _sysseg, _usrseg, _sysstk, _psap
;****************************************************
;*
;* Global declarations
;*
;****************************************************
.global _trapinit
.global _trapvec
.global _trap
.global xfersc
;****************************************************
;*
;* Trap vector table
;*
;* entries 0..31 are misc. system traps
;* entries 32..47 are system calls 0..15
;*
;****************************************************
__bss: .sect
_trapvec:
.block NTRAPS*4 ; leave trap space same as for Z8001,
; for compatibility
;****************************************************
;*
;* System Call and General Trap Handler And Dispatch
;*
;* It is assumed that the system runs
;* non-segmented on a segmented CPU.
;*
;* _trap is jumped to with the
;* following information on the stack:
;*
;* trap type: WORD
;* reason: WORD
;* fcw: WORD
;* pc: WORD
;*
;* The trap handler is called as a subroutine,
;* with all registers saved on the stack. This
;* allows the trap handler to be in another
;* segment (with some care). This is useful
;* mainly to the debugger.
;*
;* All registers except rr0 are also passed
;* intact to the handler.
;*
;****************************************************
__text: .sect
sc_trap: ; system call trap server
push @r15,@r15 ; duplicate type as reason
_trap: ; general trap server
sub r15,#FRAMESZ-8 ; push caller state
ldm @r15,r0,#15
ldctl r1,NSP
ex r1,nr15(r15)
; trap# now in r1
cpb rh1,#7Fh ; system call?
jr ne trap_disp ; no
; yes: map it
clrb rh1
add r1,#SC0TRAP
;=== need range check ===
trap_disp: ; dispatch
sll r1,#2
ldl rr0,_trapvec(r1)
testl rr0
jr z _trap_ret ; zero -- no action
call @r1 ; go execute the trap
_trap_ret: ;return from trap or interrupt
ld r1,nr15(r15) ; pop state
ldctl NSP,r1
ldm r0,@r15,#15
add r15,#FRAMESZ-6 ; re-adjust stack
iret ; return from interrupt
;****************************************************
;*
;* Assorted Trap Handlers
;*
;****************************************************
epu_trap:
push @r15,#EPUTRAP
jr _trap
pi_trap:
push @r15,#PITRAP
jr _trap
seg_trap:
push @r15,#SEGTRAP
jr _trap
nmi_trap:
push @r15,#NMITRAP
jr _trap
;****************************************************
;*
;* Bios system call handler
;*
;****************************************************
biossc: ; call bios
; r3 = operation code
; rr4= P1
; rr6= P2
; set up C stack frame
;===
pushl @r15,rr6
pushl @r15,rr4
push @r15,r3
; call C program
call __bios
; clean stack & return
add r15,#10
ldl cr6+co(r15),rr6 ; with long in rr6
ret
;****************************************************
;*
;* Context Switch System Call
;*
;* xfer(context)
;* long context;
;*
;* context is the physical (long) address of:
;* r0
;* ...
;* r13
;* r14 (normal r14)
;* r15 (normal r15)
;* ignored word (trap reason)
;* FCW (had better specify normal mode)
;* PC offset
;*
;* The system stack pointer is not affected.
;*
;* Control never returns to the caller.
;*
;****************************************************
xfersc: ;enter here from system call
; build frame on system stack
; when called from system call, the frame replaces
; the caller's context, which will never be resumed.
inc r15,#co ; discard return addr
ld r5,r15 ; move context
ld r2,#FRAMESZ/2
ldir @r5,@r7,r2
dec r5,#2 ;point back to PC
ldi @r5,@r7,r2 ;transfer PC
jr _trap_ret ;restore context
;****************************************************
;*
;* _trapinit -- initialize trap system
;*
;****************************************************
;*
;* PSA (Program Status Area) structure
;*
ps .equ 4 ; size of a program status entry
; --- non-segmented ---
psa_epu .equ 1*ps ; EPU trap offset
psa_prv .equ 2*ps ; priviledged instruction trap
psa_sc .equ 3*ps ; system call trap
psa_seg .equ 4*ps ; segmentation trap
psa_nmi .equ 5*ps ; non-maskable interrupt
psa_nvi .equ 6*ps ; non-vectored interrupt
psa_vi .equ 7*ps ; vectored interrupt
psa_vec .equ psa_vi+(ps/2) ; vectors
_trapinit:
; initialize trap table
lda r2,_trapvec
ld r0,#NTRAPS
subl rr4,rr4
clrtraps:
ldl @r2,rr4
inc r2,#4
djnz r0,clrtraps
ld r2,_sysseg
lda r3,biossc
ldl _trapvec+(BIOS_SC+SC0TRAP)*4,rr2
lda r3,memsc
ldl _trapvec+(MEM_SC+SC0TRAP)*4,rr2
; initialize some PSA entries.
; r0 PSA entry: FCW (ints ENABLED)
; r1 PSA entry: PC
; r5 -> PSA slot
ld r5,_psap
ld r0,#0D800h
add r5,#ps ; skip reserved to EPU trap
ld r1,#epu_trap
ldm @r5,r0,#2
add r5,#ps ; Priviledged Inst
ld r1,#pi_trap
ldm @r5,r0,#2
add r5,#ps ; System Call
ld r1,#sc_trap
ldm @r5,r0,#2
add r5,#ps ; segmentation
ld r1,#seg_trap
ldm @r5,r0,#2
add r5,#ps ; Non-Maskable Int.
ld r1,#nmi_trap
ldm @r5,r0,#2
ret
;****************************************************
;****************************************************

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,158 @@
/*--------------------------------------------------------------*\
| ccp_def.c DEFINES v1.0 |
| ======= |
| |
| P-CP/M: 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: 12/20/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
/*-------------------------------------------*\
| 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 char
#define REG register
#define WORD short
#define UWORD unsigned int
#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 26
#define NO_OF_DRIVES 16
#define NUMDELS 16
#define FCB_LEN 36
#define DMA_LEN 128
#define FILES_PER_LINE 4 /* Zilog */
#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_I/O 6
#define GET_I/O_BYTE 7
#define SET_I/O_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_READ/O_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,98 @@
;******* ccpif.z8k -- CCP interface *****************
;*
;* 821015 S. Savitzky (Zilog) derived from 68K version
;*
;****************************************************
__text: .sect
;****************************************************
;*
;* EXTERNALS
;*
;****************************************************
.global _bdosinit
.global _main
;****************************************************
;*
;* GLOBALS
;*
;****************************************************
.global ccp ; main entry point
.global _autost
.global _usercmd
.global _submit
.global _morecmds
;****************************************************
;*
;* JUMP VECTOR
;*
;****************************************************
ccp: jr ccpstart ; start ccp with possible
; initial command
jp ccpclear ; clear autostart flag
;****************************************************
;*
;* DATA
;*
;****************************************************
__data: .sect
copy: .byte " COPYRIGHT (C) 1982, Digital Research "
_autost: ; autostart command flag
.byte 0
sysinit: ; set if system initialized
.byte 0
_submit:
.byte 0
_morecmds:
.byte 0
__bss: .sect
_usercmd: ; user command buffer
.block 130
stackp: ; saved stack pointer
.block 2
;****************************************************
;*
;* PROGRAM INTERFACE
;*
;* ccpclear -- clear autostart flag
;* ccpstart -- normal entry from boot
;* jumped to with valid stack ptr.
;* ccploop -- main loop (internal)
;*
;****************************************************
__text: .sect
ccpclear:
clrb _autost ; clear the autostart flag
ccpstart:
ld stackp,r15 ; save stack pointer
tsetb sysinit ; system initialized?
jr mi ccploop ; yes
; no: init flag now set
call _bdosinit ; init bdos
ccploop:
ld r15,stackp ; reset stack pointer
call _main ; call the CCP
jr ccploop ; loop forever

View File

@@ -0,0 +1,344 @@
/* Transfer data through an I/O channel -- in this */
/* particular case the quasi fifo on the Zilog Z8000 */
/* Zoom board. This module should be replacable by */
/* others which utitilize a different I/O channel */
/* (i.e. RS-232), and different protocols. */
/*
*************************************************
* *
* Author: David Heintz *
* Module: Channelc.c *
* Creation Date: 10/26/82 *
* Language: Standard C *
* Version: 0.0 *
* Last Mod: 01/17/83 P.S.W. *
* *
*************************************************
*/
/*
*************************************************
* *
* STANDARD HEADERS *
* *
*************************************************
*/
#include "unstdsys.h"
#include "fioequ.h"
#include "chnequ.h"
/*
*************************************************
* *
* EXTERNAL DECLARATIONS *
* *
*************************************************
*/
/*
*************************************************
* *
* I/O Channel Related Externals *
* and Globals *
* *
*************************************************
*/
/* Routines defined other modules */
extern BYTE input();
extern output();
extern BYTE gb_word();
extern BYTE gb_long();
extern pb_word();
extern pb_long();
/* Varibles defined in other modules */
extern WORD bytlen;
extern WORD wrdlen;
extern WORD lnglen;
/* External port addresses */
extern WORD fiocr1;
extern WORD fioir0;
extern WORD fiomsi;
extern WORD fiomso;
/* Routines defined within this module */
extern BYTE snd_pkt();
extern BYTE rcv_pkt();
extern BYTE snd_sys();
extern chn_err();
/* Static definitions for use within module */
/*
*****************************************
* *
* snd_sys(): *
* Transmit a load buffer *
* over I/O channel *
* *
*****************************************
/
/ Inputs: buffer type, segment, offset, data address, length
/ Outputs: I/O channel status (byte)
/ Assumptions: Data length is always less than FIO size
*/
BYTE snd_sys(buftyp, basseg, basoff, buffer, ldlen)
BYTE buftyp, basseg, *buffer;
WORD basoff, ldlen;
{
BYTE code, fio_put(), fio_gack();
int i;
if (code == chsuc)
{
fio_put(buftyp);
fio_put(basseg);
for (i=(wrdlen-1); i>=0; i--)
fio_put(gb_word(&basoff, i)); /* Send high-order byte first */
for (i=(wrdlen-1); i>=0; i--)
fio_put(gb_word(&ldlen, i)); /* Send high-order byte first */
for (i=0; i<ldlen; i++) /* Send data */
fio_put(buffer[i]);
code = fio_gack(fioack); /* Try for an ack */
}
return(code);
}
/*
****************************************.
* *
* snd_pkt(): *
* Transmit a data packet *
* over I/O channel *
* *
********************"*******************

/
/ Inputs: data type, address, and length
/ Outputs: I/O channel status (byte)
*/
BYTE snd_pkt(pkttyp, pbyte, pktlen)
BYTE pkttyp, *pbyte;
WORD pktlen;
{
BYTE code, fio_put(), fio_gack();
WORD i;
code = chsuc;
if ((code = fio_put(pkttyp)) == chsuc)
{
for (i=1; i <= pktlen; i++)
if ((code = fio_put(*(pbyte++))) != chsuc)
return(code);
code = fio_gack(acktyp);
}
return(code);
}
/*
*****************************************
* *
* rcv_pkt(): *
* Receive a data packet *
* over I/O channel *
* *
*****************************************
/
/ Inputs: data type, address, and length
/ Outputs: I/O channel status (byte)
*/
BYTE rcv_pkt(pkttyp, pbyte, pktlen)
BYTE pkttyp, *pbyte;
WORD pktlen;
{
BYTE code, fio_cat(), fio_get(), fio_pack();
WORD i;
code = chsuc;
if ((code = fio_cat(pkttyp)) == chsuc)
{
for (i=1; i <= pktlen; i++)
if ((code = fio_get(pbyte++)) != chsuc)
return(code);
code = fio_pack(acktyp);
}
else fio_pack(ncktyp);
return(code);
}
/*
*****************************************
* *
* fio_gack(): *
* Wait for a certain byte *
* from the fio. *
* *
*****************************************
/
/ Inputs: Byte to wait for
/ Outputs: Status indicating success/failure
*/
BYTE fio_gack(gbyte)
BYTE gbyte;
{
BYTE code, ack, fio_get();
WORD count;
count = chto2;
while (count--)
{
code = fio_get(&ack);
if ((code == chsuc) && (ack == gbyte))
return(code);
}
return(chena);
}
/*
*****************************************
* *
* fio_pack(): *
* Send either positive or *
* negative acknowledgement. *
* *
*****************************************
/
/ Inputs: chack, or chnck
/ Outputs: Status indicating success/failure
*/
BYTE fio_pack(ack)
BYTE ack;
{
BYTE fio_put();
return(fio_put(ack));
}
/*
*****************************************
* *
* fio_cat(): *
* Conditionally attach to *
* the fifo. *
* *
*****************************************
/
/ Inputs: Byte to wait for
/ Outputs: Status indicating success/failure
*/
BYTE fio_cat(tbyte)
BYTE tbyte;
{
BYTE code, ack, fio_get();
WORD count;
count = chto2;
while (count--)
{
code = fio_get(&ack);
if ((code == chsuc) && (ack == tbyte))
return(code);
}
return(cheut);
}
/*
*****************************************
* *
* fio_get(): *
* Get a byte from *
* the I/O channel. *
* *
*****************************************
/
/ Inputs: Address where byte is to be returned
/ Outputs: Status indicating success/failure
*/
BYTE fio_get(rbyte)
BYTE *rbyte;
{
WORD count;
count = chto1;
while (count--)
{
if ((input(fioir0) & fiordy) == fiordy)
{
*rbyte = input(fiomsi);
return(chsuc);
}
}
return(cheto);
}
/*
*****************************************
* *
* fio_put(): *
* Put a byte into *
* the I/O channel. *
* *
*****************************************
/
/ Inputs: Byte to be written to I/O channel
/ Outputs: Status indicating success/failure
*/
BYTE fio_put(sbyte)
BYTE sbyte;
{
WORD count;
count = chto1;
while (count--)
{
if ((input(fiocr1) & fiobsy) != fiobsy)
{
output(fiomso, sbyte);
return(chsuc);
}
}
return(cheto);
}
/*
*****************************************
* *
* chn_err(): *
* Global I/O channel error *
* handling routine *
* *
*****************************************
/
/ Inputs: Error code
/ Outputs: None
*/
chn_err(d0,ebyte)
int d0;
BYTE ebyte;
{
/* Dummy out for now */
}
/* End of Module */

View File

@@ -0,0 +1,18 @@
/* I/O channel definitions (put in header) */
/* Hopefully hardware independent? */
#define byttyp 0x00
#define wrdtyp 0x01
#define lngtyp 0x02
#define dattyp 0x03
#define cmdtyp 0x04
#define acktyp 0x05
#define ncktyp 0x06
#define chsuc 0x00
#define cheto 0x01
#define chena 0x02
#define cheut 0x03
#define cherr 0xff
#define chto1 0x7fff /* In the 5--15 second range, I think */
#define chto2 0x7fff

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,8 @@
/*
Copyright (C) 1981
Digital Research
P.O. Box 579
Pacific Grove, CA 93950
*/

View File

@@ -0,0 +1,155 @@
/****************************************************************************/
/* */
/* C P M . H */
/* --------- */
/* Copyright 1982 by Digital Research Inc. All rights reserved. */
/* */
/* This file contains CP/M specific definitions for the CP/M */
/* C Run Time Library. */
/* This file is intended only for inclusion with those functions */
/* dealing directly with the BDOS, as well as any function which */
/* has hardware dependent code (byte storage order, for instance). */
/* */
/* <portab.h> must be included BEFORE this file. */
/* */
/****************************************************************************/
/*
* CP/M FCB definition
*/
struct fcbtab /****************************/
{ /* */
BYTE drive; /* Disk drive field */
BYTE fname[8]; /* File name */
BYTE ftype[3]; /* File type */
BYTE extent; /* Current extent number */
BYTE s1,s2; /* "system reserved" */
BYTE reccnt; /* Record counter */
BYTE resvd[16]; /* More "system reserved" */
LONG record; /* Note -- we overlap the */
/* current record field to */
/* make this useful. */
}; /****************************/
#define SECSIZ 128 /* size of CP/M sector */
#define _MAXSXFR 1 /* max # sectors xferrable */
#define _MAXSHFT 12 /* shift right BDOS rtn val */
/* to obtain nsecs on err */
/****************************/
/****************************************************************************/
/* */
/* Channel Control Block (CCB) */
/* */
/* One CCB is allocated (statically) for each of the 16 possible open */
/* files under C (including STDIN, STDOUT, STDERR). Permanent data */
/* regarding the channel is kept here. */
/* */
/* */
/****************************************************************************/
struct ccb /************************************/
{ /* */
BYTE flags; /* Flags byte */
BYTE chan; /* Channel number being used */
LONG offset; /* File offset word (bytes) */
LONG sector; /* Sector currently in buffer */
LONG hiwater; /* High water mark */
struct fcbtab fcb; /* File FCB (may have TTY info)*/
BYTE buffer[SECSIZ]; /* Read/write buffer */
}; /************************************/
#define MAXCCBS 16 /* Maximum # CC Blocks */
extern struct ccb _fds[MAXCCBS]; /* Declare storage */
#define FD struct ccb /* FD Type definition */
/************************************/
/* Flags word bit definitions */
/************************************/
#define OPENED 0x01 /* Channel is OPEN */
#define ISTTY 0x02 /* Channel open to TTT */
#define ISLPT 0x04 /* Channel open to LPT */
#define ISREAD 0x08 /* Channel open readonly */
#define ISASCII 0x10 /* ASCII file attached */
#define ATEOF 0x20 /* End of file encountered */
#define DIRTY 0x40 /* Buffer needs writing */
#define ISSPTTY 0x80 /* Special tty info */
/************************************/
#define READ 0 /* Read mode parameter for open */
#define WRITE 1 /* Write mode */
/* CCB manipulation macros *************************************/
#define _getccb(i) (&_fds[i]) /* Get CCB addr */
/* Error handling *************************************/
EXTERN WORD errno; /* error place for assigning */
EXTERN WORD __cpmrv; /* the last BDOS return value */
EXTERN WORD _errcpm; /* place to save __cpmrv */
#define RETERR(val,err) {errno=(err);_errcpm=__cpmrv;return(val);}
/************************************/
/****************************************************************************/
/* */
/* B D O S F u n c t i o n D e f i n i t i o n s */
/* ------------------------------------------------- */
/* */
/* Following are BDOS function definitions used by the C runtime */
/* library. */
/* */
/****************************************************************************/
/****************************/
#define EXIT 0 /* Exit to BDOS */
#define CONOUT 2 /* Direct console output */
#define LSTOUT 5 /* Direct list device output*/
#define CONIO 6 /* Direct console I/O */
#define CONBUF 10 /* Read console buffer */
#define OPEN 15 /* OPEN a disk file */
#define CLOSE 16 /* Close a disk file */
#define DELETE 19 /* Delete a disk file */
#define CREATE 22 /* Create a disk file */
#define SETDMA 26 /* Set DMA address */
#define B_READ 33 /* Read Random record */
#define B_WRITE 34 /* Write Random record */
#define FILSIZ 35 /* Compute File Size */
#define SETMSC 44 /* Set Multi-Sector Count */
/****************************/
/****************************************************************************/
/* Other CP/M definitions */
/****************************************************************************/
#define TERM "CON:" /* Console file name */
#define LIST "LST:" /* List device file name */
#define EOFCHAR 0x1a /* End of file character-^Z */
/****************************/
/****************************************************************************/
/* Hardware dependencies */
/****************************************************************************/
#define HILO /* used when bytes stored */
/* Hi,Lo */
/****************************/
#ifdef HILO /* Hi/Lo storage used in */
struct { /* 68K */
BYTE lbhihi; /* Use this for accessing */
BYTE lbhilo; /* ordered bytes in 32 bit*/
BYTE lblohi; /* LONG qtys. */
BYTE lblolo; /* */
}; /* */
struct { /* Use this for accessing */
WORD lwhi; /* ordered words in 32 bit*/
WORD lwlo; /* LONG qtys. */
}; /* */
#else /****************************/
struct { /* Lo/Hi storage use on */
BYTE lblolo; /* PDP-11, VAX, 8086,... */
BYTE lblohi; /* */
BYTE lbhilo; /* */
BYTE lbhihi; /* */
}; /* */
struct { /* */
WORD lwlo; /* */
WORD lwhi; /* */
}; /* */
#endif /****************************/
/*************************** end of cpm.h ***********************************/

View File

@@ -0,0 +1,39 @@
/**************************************************************************
* CTYPE.H - macros to classify ASCII-coded integers by table lookup.
*
*
* Note: Integer args are undefined for all int values > 127,
* except for macro 'isascii()'.
* Assumes:
* User will link with standard library functions.
* Compiler can handle declarator initializers and
* '#defines' with parameters.
***************************************************************************/
/* Define bit patterns for character classes */
#define __c 01
#define __p 02
#define __d 04
#define __u 010
#define __l 020
#define __s 040
#define __cs 041
#define __ps 042
#ifndef CTYPE
extern char __atab[];
#endif
#define isascii(ch) ((ch) < 0200)
#define isalpha(ch) (__atab[ch] & (__u | __l))
#define isupper(ch) (__atab[ch] & __u)
#define islower(ch) (__atab[ch] & __l)
#define isdigit(ch) (__atab[ch] & __d)
#define isalnum(ch) (__atab[ch] & (__u | __l | __d))
#define isspace(ch) (__atab[ch] & __s)
#define ispunct(ch) (__atab[ch] & __p)
#define isprint(ch) (__atab[ch] & (__u | __l | __d | __p))
#define iscntrl(ch) (__atab[ch] & __c)
#define tolower(ch) (isupper(ch) ? (ch)-'A'+'a' : (ch) )
#define toupper(ch) (islower(ch) ? (ch)-'a'+'A' : (ch) )
#define toascii(ch) ((ch) & 0177)

View File

@@ -0,0 +1,108 @@
/****************************************************************
* *
* CP/M-Z8K Loader 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 *
* dir_rd() - read 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 */
/****************
* read routine *
****************/
UWORD rdsec(secnum, dma)
/* General disk sector read 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 */
{
struct iopb rwpkt;
BSETUP
rwpkt.devnum = GBL.curdsk; /* disk to read/write */
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 */
return ( do_phio(&rwpkt) );
}
/***************************
* directory read routine *
***************************/
UWORD dir_rd(secnum)
UWORD secnum;
{
BSETUP
return( rdsec((LONG)secnum, map_adr((XADDR)GBL.dirbufp, 0) ) );
}
/************************
* dirscan entry point *
************************/
UWORD dirscan(funcp, fcbp)
BOOLEAN (*funcp)(); /* funcp is a pointer to a Boolean function */
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
{
REG UWORD i; /* loop counter */
REG struct dpb *dparmp; /* pointer to disk parm block */
REG UWORD dirsec; /* sector number we're working on */
BSETUP
dparmp = GBL.parmp; /* init ptr to dpb */
for ( i = 0; i <= dparmp->drm; i++ )
{ /* main directory scanning loop */
if ( ! (i & 3) )
{ /* inside loop happens when we need to
read another directory sector */
dirsec = i >> 2;
if( dir_rd(dirsec)) /* read the directory sector */
return(-1);
}
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 */
return(i & 3); /* return directory code */
}
return(255);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
/*
* errno.h - error codes
*/
#define EPERM 1
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define EIO 5
#define ENXIO 6
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define ECHILD 10
#define EAGAIN 11
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
/* math software */
#define EDOM 33
#define ERANGE 34
/* hereafter is available to CP/M specials */
#define ENODSPC 35
/****** end of errno.h ******/

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,352 @@
;************************************************
;* *
;* 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) *
;* *
;************************************************
; 01/11/83 Adapted for Z8002 (DMH)
.input "biosdefs2.z8k"
__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
;****************************************************
;*
;* 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 = BIOS command
ldl rr4,#2 ;rr4 = exception #
ld r6,_sysseg ;rr6 -> handler
lda r7,exchndl ;exception handler offset
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
;* 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
pop r1,@r15 ; get return address
; from above array
sub r1,#excrtn0 ; r1 now = 2 * encoded
sll r1,#2 ; r1 now = 4 * encoded
; 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
pop r1,@r15
sub r0,r0
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 to trap_ret
; normal r0..r15
; reason, fcw, PC
ldl usr_vec,rr4 ; save user exception vector
ld r7,r15 ; map current stack pointer
sub r6,r6 ; dummy segment
ld r5,#2 ; system space code
subl rr2,rr2 ; for map_adr call
sc #MEM_SC ; do map_adr call
ldl rr2,rr6 ; save map_addr results
ld r1,scfcw+co(r15) ; get user fcw
ld r5,#2 ; anticipate system space code
bit r1,#14 ; system mode?
jr nz,sysexc ; yes.
ld r5,#4 ; Normal space code
sysexc: ld r7,nr15+co(r15) ; user stack
sub r7,#FRAMESZ+co ; allocate stack frame on user's stack
sub r6,r6 ; dummy segment, dest. in rr6
pushl @r15,rr2 ; save source on stack
subl rr2,rr2 ; for map_adr call
sc #MEM_SC ; do map_adr call
popl rr4,@r15 ; retrieve source
ldl rr2,#FRAMESZ+co ; length
sc #MEM_SC ; transfer stack frame to user stack
ldl rr4,usr_vec ; restore user exception vector
ld r0,scfcw+co(r15) ; get back user's fcw
push @r15,r5 ; push on user's exception vector.
pushl @r15,rr0 ; push identifier and user's fcw
iret ; 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
;*
;****************************************************
__con: .sect
excmsg1:
.byte 13,10,10,"Exception $"
excmsg2:
.byte " at user address $"
excmsg3:
.byte ". Aborted.$"
;****************************************************
;*
;* bss
;*
;****************************************************
__bss: .sect
evec_adr:
.block 2
usr_vec:
.block 4
.end

View File

@@ -0,0 +1,134 @@
/****************************************************************
* *
* CP/M-Z8k Loader BDOS File I/O Module *
* *
* This module contains all file handling BDOS functions *
* except for read and write for CP/M-Z8K. Included are: *
* *
* seldsk() - select disk *
* openfile() - open file *
* 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 do_phio(); /* packet disk i/o handler */
EXTERN UWORD swap(); /* assembly language byte swapper */
/************************
* seldsk entry point *
************************/
seldsk(dsknum)
REG UBYTE dsknum; /* disk number to select */
{
struct iopb selpkt;
REG WORD i;
UWORD j;
BSETUP
if (UBWORD(dsknum) > 15) return(-1);
selpkt.devnum = dsknum;
selpkt.iofcn = sel_info;
selpkt.ioflags = 0;
do_phio(&selpkt); /* actually do the disk select */
if( (GBL.dphp = selpkt.infop) == NULL)
return(-1);
GBL.dirbufp = (GBL.dphp)->dbufp;
/* set up GBL copies of dir_buf and dpb ptrs */
GBL.parmp = (GBL.dphp)->dpbp;
return(0);
}
/*******************************
* 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) */
}
return(rtn);
}

View File

@@ -0,0 +1,15 @@
getfile -D basepage.h
getfile -D bdos.h
getfile -D copyrt.lit
getfile -D cpm.h
getfile -D ctype.h
getfile -D ed.c
getfile -D errno.h
getfile -D makefile
getfile -D pip.c
getfile -D portab.h
getfile -D setjmp.h
getfile -D sgtty.h
getfile -D stat.c
getfile -D stdio.h
getfile -D x.out.h

View File

@@ -0,0 +1,18 @@
/* Zoom board fifo definitions */
#define fiobsy 0x20
#define fiordy 0x20
#define fiotst 0xaa
#define fioini 0xfe
#define fiofre 0xfd
#define fioack 0x03
#define fiobeg 0x00
#define fiolen 0x0400 /* No. of bytes in fio */
#define nrmbuf 0x02 /* Not last buffer */
#define lstbuf 0x01 /* Last buffer */
/* System Location */
#define sysseg 0x00 /* System segment */
#define sysoff 0x0000 /* System offset */
#define sysent 0x1002 /* System entry point */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
;*************************************************
;** Change history --
;** 30mar81: Broken off from general interface.
;** 30mar81: Set up for Zilog ZLAB 8000
;** 09may81: Tell cpu when state is free.
;** 19jan82: Allow segmented users.
;** 21jan82: Took out references to freecpu and needcpu
;** 15feb82: Dummy out need/free cpu.
;** 13may82: Comment out references to setfp and resfp
;*************************************************
.title "sysdep MODULE"
.input "biosdefs2.z8k"
;*************************************************
;** SAVED CPU STATE --
;** is specified by the following "constants."
;** Offset stapcsg must point to the word preceding
;** the saved PC offset, EVEN FOR NONSEGMENTED
;** OPERATION.
;*************************************************
__data .sect
.GLOBAL stareg,staevnt,stafcw,stapcsg
stareg .WORD 4 ;offset of r0
staevnt .WORD 36 ;saved 1st word
stafcw .WORD 38 ;saved fcw
stapcsg .WORD 40 ;seg word of PC
;*************************************************
;** ADDRESSES --
;** as input parameters to the routines below are
;** delivered in register pairs (i.e. as though
;** segmented). The high-order word of such an
;** address is undefined when the process running
;** in that address space runs in nonsegmented
;** mode.
;*************************************************
.eject
;*************************************************
;** GET NEXT INSTRUCTION WORD --
;** Input:
;** rr6 = saved PC -- seg # must be fixed for
;** nonseg users
;** Output:
;** r3 = next instruction word
;*************************************************
__data .sect
gttxt: .WORD 0
__text .sect
.GLOBAL gettext
gettext: ; PROCEDURE ENTRY
; ld r5,#2 ; it is system data
; ldl rr2,#0 ; required parameter
; sc #MEM_SC ; MAP source
pushl @r15,rr6
ld r7,#gttxt ; address of temp
ld r5,#0 ; it is caller Instruction
ldl rr2,#0 ; required parameter
sc #MEM_SC ; MAP destination
ldl rr4,rr6
popl rr6,@r15 ; restore source
ldl rr2,#2 ; byte count to move
sc #MEM_SC ; DO TRANSFER
ld r3,gttxt ; load return values
ldb rl2,#0
ret
.eject
;*************************************************
;** GET MEMORY BYTES --
;** Segmented emulator input --
;** rr6 - src address (trapee space)
;** rr4 - dst address (emulator space)
;** r3 - byte count
;*************************************************
.GLOBAL getmem
getmem:
push @r15,r3
pushl @r15,rr4 ; save dest - MEM_SC steps on rr4
ld r5,#4 ; it is TPA data
ldl rr2,#0 ; required parameter
sc #MEM_SC ; MAP source
popl rr4,@r15 ; restore dest
pushl @r15,rr6 ; save source
ldl rr6,rr4 ; position dest
ld r5,#0 ; it is caller data
ldl rr2,#0 ; required parameter
sc #MEM_SC ; MAP destination
ldl rr4,rr6
popl rr6,@r15 ; restore source
pop r3,@r15 ; restore byte count
ld r2,#0 ; requrired parameter
sc #MEM_SC ; DO TRANSFER
ret
.eject
;*************************************************
;** PUT MEMORY BYTES --
;** Emulator input --
;** rr6 - src address (emulator space)
;** rr4 - dst address (trapee space)
;** r3 - byte count
;*************************************************
.GLOBAL putmem
putmem: ; PROCEDURE ENTRY
push @r15,r3
pushl @r15,rr4 ; save dest - MEM_SC steps on rr4
ld r5,#0 ; it is caller data
ldl rr2,#0 ; required parameter
sc #MEM_SC ; MAP source
popl rr4,@r15
pushl @r15,rr6 ; save source
ldl rr6,rr4 ; position destination
ld r5,#4 ; it is TPA data
ldl rr2,#0 ; required parameter
sc #MEM_SC ; MAP destination
ldl rr4,rr6 ; put mapped dest in rr4
popl rr6,@r15 ; restore source
pop r3,@r15 ; restore byte count
ld r2,#0 ; required parameter
sc #MEM_SC ; DO TRANSFER
ret

View File

@@ -0,0 +1,212 @@
/************************************************************************
* *
* CP/M-8000 CCP Program Loader (__LOAD) *
* *
* Copyright (c) 1982 Zilog Incorporated *
* *
* This function arranges for the BDOS program loader to be *
* invoked in a suitable environment. Suitable means that it *
* fills in whatever is expected in the LPB, gets the rest back *
* from the BDOS, and then completes the basepage and resets the *
* dma buffer. *
* *
* The loading of segmented programs is not currently supported *
* *
************************************************************************/
#include "stdio.h" /* Standard declarations for BDOS, BIOS */
#include "bdosdef.h" /* BDOS type and structure declarations */
#include "biosdef.h" /* Declarations of BIOS functions */
#include "basepage.h" /* Base page structure */
#define SEP_ID 0x4000 /* Separate I/D flag */
#define SEG 0x2000 /* Segmented load module */
#define NREGIONS 2 /* Number of MRT regions */
/* Return values: indexes into msgs (included here for documentation */
/* purposes - only GOOD is used in this module */
#define GOOD 0 /* good return value */
#define BADHDR 1 /* bad header */
#define NOMEM 2 /* not enough memory */
#define READERR 3 /* read error */
#define WARMBOOT 0 /* Warm reboot BDOS call */
#define PRNTSTR 9 /* Print String BDOS call */
#define SETDMA 26 /* Set DMA Address BDOS call */
#define PGLOAD 59 /* Program Load BDOS call */
#define MYDATA 0 /* Argument for map_adr */
#define TPADATA 4 /* Argument for map_adr */
#define TPAPROG 5 /* Argument for map_adr */
/* Get actual code segment (as opposed */
/* to segment where it can be accessed*/
/* as data) */
#define TRUE_TPAPROG (TPAPROG | 0x100)
#define BGETMRT 18 /* Number of the BIOS call */
extern char cmdfcb[]; /* the FCB for everything */
extern char *tail; /* where the command tail is */
extern UWORD bdos(); /* To do I/O into myself */
extern XADDR bios(); /* To get MRT pointer */
extern VOID fill_fcb(); /* Parse filename into fcb */
extern VOID xfer(); /* Transfer control to user program */
struct lpb {
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 */
} LPB;
struct m_rt { /* The Memory Region Table */
int entries;
struct {
XADDR m_low;
XADDR m_len;
} m_reg[NREGIONS];
};
struct ustack /* User's initial stack (nonsegmented) */
{
short two; /* "Return address" (actually a call to */
/* BDOS warm boot in runtime startup) */
short bpgaddr;/* Input parameter: pointer to basepage */
} stack =
{
0x0002 /* bpgaddr initialized at runtime */
};
struct sstack /* User's initial stack (segmented) */
{
XADDR stwo; /* "Return address" (actually a call to */
/* BDOS warm boot in runtime startup) */
XADDR sbpgadr;/* Input parameter: pointer to basepage */
} sstack;
/* Error messages for bad loads */
static char *msgs[] =
{
"",
"File is not executable$",
"Insufficient memory$",
"Read error on program load$",
"Program Load Error$"
};
struct context /* Startup context for user's program */
{
short regs[16];
short ignore;
short FCW;
XADDR PC;
} context =
{ /* Regs 0-14 cleared, 15 set up below */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
0, /* Ignore: value is zero */
0x1800 /* FCW: nonsegmented normal, VI, NVI set*/
}; /* PC initialized below */
/********************************/
/* */
/* _ _ L O A D */
/* */
/********************************/
VOID /* Load a program from */
__LOAD() /* info in cmdfcb */
{
register short k;
struct m_rt *mpr;
register XADDR physaddr;
BYTE tlen; /* length of cmd tail */
register char *tp;
mpr = (struct m_rt *) bios(BGETMRT);
/* Set up the Load Parameter Block */
/* Strictly speaking we should look at magic number to find out */
/* which segment(s) the program needs. */
LPB.pgldaddr = mpr->m_reg[0].m_low;
LPB.pgtop = mpr->m_reg[0].m_len;
LPB.fcbaddr = map_adr((XADDR) cmdfcb, MYDATA);
/* Try loading the program. Print message and reboot if load fails */
if ((k = bdos(PGLOAD, map_adr((XADDR) &LPB, MYDATA))) != GOOD)
{
bdos(PRNTSTR, map_adr((XADDR) msgs[min(4, k)], MYDATA));
bdos(WARMBOOT, 0L);
}
/* Move command tail to basepage buffer; reset DMA address to that buffer. */
/* Due to difficulty of adding structure member offset to something */
/* which is not a structure pointer, we use a kludge to get physical */
/* DMA buffer address: buffer is at last thing on basepage and has a */
/* length of one sector. */
/* Compute length of tail, since CCP does not supply it */
for (tlen=0, tp=tail; *tp++ != NULL; tlen++) ;
/* Next expression written in strange way to overcome compiler bug */
physaddr = LPB.bpaddr - (SECLEN - sizeof (struct b_page));
bdos(SETDMA, physaddr);
cpy_out(&tlen, physaddr, 1L); /* tail length */
cpy_out(tail, physaddr+1, (long) SECLEN-1); /* and cmd tail */
/* Fill base page fcb's */
fill_fcb(1, cmdfcb);
physaddr -= sizeof (struct fcb); /* Another kludge */
cpy_out(cmdfcb, physaddr, sizeof (struct fcb));
fill_fcb(2, cmdfcb);
physaddr -= sizeof (struct fcb); /* Yet a third kludge */
cpy_out(cmdfcb, physaddr, sizeof(struct fcb));
/* Now build a user stack which looks like:
* ----------------- ^ ^
* word/long | Base page addr| ^ High address ^
* ----------------- ^ ^
* word/long | 2 | <-- Stack pointer points here
* -----------------
*/
if (LPB.flags & SEG) { /* Segmented */
sstack.sbpgadr = LPB.bpaddr;
sstack.stwo = LPB.pgldaddr + 2;
cpy_out(&sstack, LPB.bpaddr - sizeof sstack, sizeof sstack);
} else { /* Nonsegmented */
stack.bpgaddr = (short) LPB.bpaddr;
cpy_out(&stack, LPB.bpaddr - sizeof stack, sizeof stack);
}
/* Finally, ready to transfer control. Must complete context first. */
if (LPB.flags & SEG) { /* Segmented */
context.regs[14] = (short)(LPB.stackptr >> 16);
context.regs[15] = (short)LPB.stackptr;
context.PC = LPB.pgldaddr;
context.FCW= 0x9800;
} else { /* Nonsegmented!*/
context.regs[15] = (short) LPB.stackptr;
context.PC = map_adr(LPB.pgldaddr, TRUE_TPAPROG);
context.FCW= 0x1800;
}
xfer(map_adr((XADDR) &context, MYDATA)); /* Go for it! */
}

View File

@@ -0,0 +1,67 @@
/****************************************************************
* *
* 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:
iop->infop = bseldsk(last_dsk, iop->ioflags);
break;
case read:
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);
return(bread());
}
UNLOCK
return(0);
}

View File

@@ -0,0 +1,228 @@
/* This module is a collection of all the Z8000 */
/* dependent C code for the P-CP/M dual processor */
/* BIOS. */
/*
*************************************************
* *
* Author: David Heintz *
* Module: Kon8kc.c *
* Creation Date: 10/26/82 *
* Language: Standard C *
* Version: 1.0 *
* Last Mod: 12/16/83 *
* *
*************************************************
*/
/* 01/16/83 Adapted for Kontron Z8002 board (DMH) */
/*
*************************************************
* *
* STANDARD HEADERS *
* *
*************************************************
*/
#include "unstdsys.h"
#include "fioequ.h"
#include "chnequ.h"
/*
*************************************************
* *
* EXTERNAL DECLARATIONS *
* *
*************************************************
*/
extern BYTE gb_word();
extern BYTE gb_long();
extern pb_word();
extern pb_long();
extern WORD bytlen;
extern WORD wrdlen;
extern WORD lnglen;
/*
*************************************************
* *
* Byte Ordering Arrays For *
* Word and Long *
* *
*************************************************
*/
static BYTE wrdtab[2] = {1, 0};
static WORD lngtab[4] = {3, 2, 1, 0};
/*
*************************************************
* *
* Machine dependent entities *
* *
*************************************************
*/
WORD bytlen = 1;
WORD wrdlen = 2;
WORD lnglen = 4;
/*
*************************************************
* *
* Port Addresses for Zoom Board *
* *
*************************************************
*/
WORD fiodat = 0x0001; /* Values for Z8002 side */
WORD fioctl = 0x0003; /* only. */
/* Port Addresses for the Zilog 8038 fifo */
WORD fioreg = 0x0051;
WORD fiocr1 = 0x0003;
WORD fioir0 = 0x0005;
WORD fiomso = 0x0017;
WORD fiomsi = 0x0019;
/*
*************************************************
* *
* Memory Region Table *
* *
*************************************************
*/
/* The following table describes two memory regions: */
/* Region 1 Type: Merged instruction and data space */
/* Length: 64k combined space. */
/* Base: Pseudo-segement <<1>> */
/* */
/* Region 2 Type: Split instruction and data space */
/* Length: 64k instruction space, 32, data space */
/* Base: Pseudo-segment <<2>> */
/* */
/* Notes This table is machine dependent */
/* but not processor dependent. */
/* Table does not include system segment. */
/* Table should probably be removed to module of */
/* machine dependent code and data. */
/* ********* This is the real memory region table ******** */
struct mrt {
int count;
struct {long tpalow;
long tpalen;
} regions[2];
} memtab = {2,
{{0x01000000L, 0x10000L},
{0x02000000L, 0x10000L}
}
};
/*
*****************************************
* *
* gb_word(): *
* Retrieve a specified *
* byte from a word *
* *
*****************************************
/
/ Inputs: Address of word
/ Byte number
/ Outputs: Byte corresponding to
/ byte number in word
*/
BYTE gb_word(pbyte, i)
BYTE *pbyte;
WORD i;
{
return(pbyte[wrdtab[i]]);
}
/*
*****************************************
* *
* gb_long(): *
* Retrieve a specified *
* byte from a long *
* *
*****************************************
/
/
/ Inputs: Address of long
/ Byte number
/ Outputs: Byte corresponding to
/ byte number in long
*/
BYTE gb_long(pbyte, i)
BYTE *pbyte;
WORD i;
{
return(pbyte[lngtab[i]]);
}
/*
*****************************************
* *
* pb_word(): *
* Place a specified *
* byte into a word *
* *
*****************************************
/
/
/ Inputs: Byte to be place
/ Address of word
/ Byte number
/ Outputs: None
*/
pb_word(sbyte, pbyte, i)
BYTE sbyte, *pbyte;
WORD i;
{
pbyte[wrdtab[i]] = sbyte;
}
/*
*****************************************
* *
* pb_long(): *
* Place a specified *
* byte into a long *
* *
*****************************************
/
/
/ Inputs: Byte to be place
/ Address of long
/ Byte number
/ Outputs: None
*/
pb_long(sbyte, pbyte, i)
BYTE sbyte, *pbyte;
WORD i;
{
pbyte[lngtab[i]] = sbyte;
}
/* End of Module */

View File

@@ -0,0 +1,75 @@
# Makefile for Portable CP/M Peripheral Interchange Program, PIP.
#
# Change the variables INCLUDE, BIN, UBIN, CC, LD, LIB as necessary for a
# particular environment.
#
# Usage:
# make makes executable file PIP for CP/M target
# make pipn makes non-split version of above
# make pip.o compiles pip.c
# make pip.cpm makes file pip.cpm for loading with mkfile
# make list sends formatted listing of ALL source
# files to print spooler
#
# Author: D Dunlop, Zilog Inc. 11/19/82
INCLUDE = /u/Tests/include
BIN = /bin
UBIN = /usr/bin
CC = $(BIN)/zcc -M1 -c
LD = $(UBIN)/ld8k -i -w
ULIB = /usr/lib
LIB = /lib
PSOURCE = makefile pip.c portab.h bdos.h\
basepage.h setjmp.h
ESOURCE = makefile ed.c portab.h bdos.h\
basepage.h setjmp.h
SSOURCE = makefile stat.c portab.h bdos.h\
basepage.h setjmp.h
SOURCE = makefile ed.c pip.c stat.c portab.h bdos.h\
basepage.h setjmp.h
POBJS = pip.o $(ULIB)/libcpm.a $(ULIB)/startup.o
EOBJS = ed.o $(ULIB)/libcpm.a $(ULIB)/startup.o
SOBJS = stat.o $(ULIB)/libcpm.a $(ULIB)/startup.o
pip: $(POBJS)
$(LD) -o pip $(ULIB)/startup.o pip.o -lcpm
pip.o: $(PSOURCE)
$(CC) pip.c
pip.cpm: pip
$(UBIN)/imager pip
plist:
pr $(PSOURCE) | lpr&
elist:
pr $(ESOURCE) | lpr&
slist:
pr $(SSOURCE) | lpr&
list:
pr $(SOURCE) | lpr&
pipn: $(POBJS)
/bin/ld8k -w -o pipn $(ULIB)/startup.o pip.o -lcpm
ed: $(EOBJS)
$(LD) -o ed $(ULIB)/startup.o ed.o -lcpm
ed.o: $(ESOURCE)
$(CC) ed.c
ed.cpm: ed
$(UBIN)/imager ed
stat: $(SOBJS)
$(LD) -o stat $(ULIB)/startup.o stat.o -lcpm
stat.o: $(SSOURCE)
$(CC) stat.c
stat.cpm: stat
$(UBIN)/imager stat

View File

@@ -0,0 +1,99 @@
/*=======================================================================*/
/*+---------------------------------------------------------------------+*/
/*| |*/
/*| P-CP/M(tm) Block Move for the KONTRON BOARD (Z8002) |*/
/*| |*/
/*| Copyright 1982, Zilog Incorporated. |*/
/*| |*/
/*+---------------------------------------------------------------------+*/
/*=======================================================================*/
char copyright[] = "Copyright 1982, Zilog Incorporated";
/* HISTORY
**
** 830111 F. Zlotnick (Zilog)
** 830121 D. Heintz (Me) Fixed bug in s/d window computation
*/
mem_bcp( sseg, source, dseg, dest, length)/* sseg and dseg are pseudo-segment */
unsigned short sseg, source, dseg, dest;/* numbers from mem_copy. */
unsigned short length; /* source and dest are offsets in */
/* the pseudo-segments. length is */
/* the number of bytes to be copied*/
{
register unsigned length1, length2;
register unsigned middle;
short swindow, dwindow;
unsigned short blength;
static char locbuf[256]; /* intermediate buffer */
/* deal recursively with the possibility of crossing the half-segment line */
middle = 0x8000;
if(source < middle && source + length > middle) {
length1 = middle - source; /* first half */
length2 = length - length1; /* second half */
mem_bcp(sseg,source,dseg,dest,length1); /* recurse */
mem_bcp(sseg,middle,dseg,dest+length1,length2);/* recurse */
return;
}
if(dest < middle && dest + length > middle) {
length1 = middle - dest; /* first half */
length2 = length - length1; /* second half */
mem_bcp(sseg,source,dseg,dest,length1); /* recurse */
mem_bcp(sseg,source+length1,dseg,middle,length2);/* recurse */
return;
}
/*
* This part is non-recursive. If you get this far, you're guaranteed
* not to cross a mid-segment boundary on either the source or dest
* blocks.
*/
swindow = ((sseg >> 8) << 1) | ( (source >= middle) ? 1 : 0);
dwindow = ((dseg >> 8) << 1) | ( (dest >= middle) ? 1 : 0);
if ( swindow == dwindow ) { /* Both in same window */
map_wdw(swindow);
if(swindow != 0) { /* If really mapped, then */
source |= 0x8000; /* must be in upper half */
dest |= 0x8000; /* of system address space */
}
blkmov(source,dest,length);
}
else if(swindow != 0 && dwindow != 0) {
source |= 0x8000;
dest |= 0x8000;
while(length > 0) {
blength = (length > 256)? 256: length ;
map_wdw(swindow);
blkmov(source,locbuf,blength); /* Assumes pointers*/
map_wdw(dwindow); /* are short! */
blkmov(locbuf,dest,blength); /* Ditto */
source += blength;
dest += blength;
length -= blength;
}
}
else {
if ( swindow == 0 ) { /* System lower half: no window */
map_wdw(dwindow); /* Put dest block in upper */
dest |= 0x8000; /* half of system space */
}
else if ( dwindow == 0 ) {
map_wdw(swindow); /* Put source block in upper */
source |= 0x8000; /* half of system space */
}
while ( length > 0 ) {
blength = (length > 256)? 256: length ;
blkmov(source,dest,blength);
source += blength;
dest += blength;
length -= blength;
}
}
}

View File

@@ -0,0 +1,368 @@
/* This module performs packet normalization and */
/* preparation to/from I/O channel. Context dependent */
/* data are put in a normal form before transmission */
/* over the I/O channel. Conversly, received messages */
/* are 'de-normalized' into machine dependent quanti- */
/* ties before being returned to the caller. This */
/* portion of code should be machine independent, */
/* since values such as word-length and long-length */
/* are declared as externals. */
/*
*************************************************
* *
* Author: David Heintz *
* Module: Normalc.c *
* Creation Date: 10/26/82 *
* Language: Standard C *
* Version: 0.0 *
* Last Mod: 01/16/83 *
* *
*************************************************
*/
/*
*************************************************
* *
* STANDARD HEADERS *
* *
*************************************************
*/
#include "unstdsys.h"
#include "fioequ.h"
#include "chnequ.h"
/*
*************************************************
* *
* EXTERNAL DECLARATIONS *
* *
*************************************************
*/
/*
*************************************************
* *
* I/O Channel Related Externals *
* and Globals *
* *
*************************************************
*/
/* Routines defined within this module */
extern BYTE rcv_cmd();
extern BYTE rcv_byte();
extern BYTE rcv_word();
extern BYTE rcv_long();
extern BYTE rcv_data();
extern BYTE snd_cmd();
extern BYTE snd_byte();
extern BYTE snd_word();
extern BYTE snd_long();
extern BYTE snd_data();
extern chn_err();
/* Routines defined outside of this module */
extern BYTE snd_pkt();
extern BYTE rcv_pkt();
extern BYTE gb_word();
extern BYTE gb_long();
extern pb_word();
extern pb_long();
/* Machine dependent externals */
extern WORD bytlen;
extern WORD wrdlen;
extern WORD lnglen;
/*
*************************************************
* *
* I/O Channel Data Normalization *
* Routines *
* *
*************************************************
*/
/*
*****************************************
* *
* snd_byte(): *
* Normalize and transmit *
* a byte over I/O channel *
* *
*****************************************
/
/ Inputs: byte to be transmitted
/ Outputs: I/O channel status (byte)
*/
BYTE snd_byte(sbyte)
BYTE sbyte;
{
return(snd_pkt(byttyp, (BYTE *)&sbyte, bytlen));
}
/*
*****************************************
* *
* snd_word(): *
* Normalize and transmit *
* a word over I/O channel *
* *
*****************************************
/
/ Inputs: word to be transmitted
/ Outputs: I/O channel status (byte)
*/
BYTE snd_word(sword)
WORD sword;
{
WORD i, nword;
BYTE *pbyte;
pbyte = (BYTE *)&nword;
for (i = 0; i < wrdlen; i++)
*(pbyte++) = gb_word(&sword, i);
return(snd_pkt(wrdtyp, (BYTE *)&nword, wrdlen));
}
/*
*****************************************
* *
* snd_long(): *
* Normalize and transmit *
* a long over I/O channel *
* *
*****************************************
/
/ Inputs: long to be transmitted
/ Outputs: I/O channel status (byte)
*/
BYTE snd_long(slong)
LONG slong;
{
LONG nlong;
WORD i;
BYTE *pbyte;
pbyte = (BYTE *)&nlong;
for (i = 0; i < lnglen; i++)
*(pbyte++) = gb_long(&slong, i);
return(snd_pkt(lngtyp, (BYTE *)&nlong, lnglen));
}
/*
*****************************************
* *
* snd_data(): *
* Normalize and transmit *
* data over I/O channel *
* *
*****************************************
/
/ Inputs: pointer to data to be transmitted
/ Outputs: I/O channel status (byte)
*/
BYTE snd_data(pbyte, datlen)
BYTE *pbyte;
WORD datlen;
{
return(snd_pkt(dattyp, pbyte, datlen));
}
/*
*****************************************
* *
* snd_cmd(): *
* Normalize and transmit *
* a command over I/O channel *
* *
*****************************************
/
/ Inputs: command to be transmitted
/ Outputs: I/O channel status (byte)
*/
BYTE snd_cmd(sd0, sd1, sd2)
WORD sd0;
LONG sd1, sd2;
{
struct {
WORD request;
LONG param1;
LONG param2;
} cmd;
LONG nlong;
WORD i;
BYTE *pbyte;
pbyte = (BYTE *)&cmd;
for (i = 0; i < wrdlen; i++)
*(pbyte++) = gb_word(&sd0, i);
for (i = 0; i < lnglen; i++)
*(pbyte++) = gb_long(&sd1, i);
for (i = 0; i < lnglen; i++)
*(pbyte++) = gb_long(&sd2, i);
return(snd_pkt(cmdtyp, (BYTE *)&cmd, sizeof(cmd)));
}
/*
*****************************************
* *
* rcv_byte(): *
* Receive and normalize *
* a byte over I/O channel *
* *
*****************************************
/ Inputs: Address of where to put received byte
/ Outputs: I/O channel status (BYTE)
/ Actions: Place received byte at pbyte
*/
BYTE rcv_byte(pbyte)
BYTE *pbyte;
{
return(rcv_pkt(byttyp, pbyte, bytlen));
}
/*
*****************************************
* *
* rcv_word(): *
* Receive and normalize *
* a word over I/O channel *
* *
*****************************************
/ Inputs: Address of where to put received word
/ Outputs: I/O channel status (BYTE)
/ Actions: Place received word at pword
*/
BYTE rcv_word(pword)
BYTE *pword;
{
BYTE code, *pbyte;
WORD i, rword;
pbyte = (BYTE *)&rword;
code = rcv_pkt(wrdtyp, (BYTE *)&rword, wrdlen);
if (code == chsuc)
for (i = 0; i < wrdlen; i++)
pb_word(*(pbyte++), pword, i);
return(code);
}
/*
*****************************************
* *
* rcv_long(): *
* Receive and normalize *
* a long over I/O channel *
* *
*****************************************
/ Inputs: Address of where to put received long
/ Outputs: I/O channel status (BYTE)
/ Actions: Place received long at plong
*/
BYTE rcv_long(plong)
BYTE *plong;
{
BYTE code, *pbyte;
WORD i;
LONG rlong;
pbyte = (BYTE *)&rlong;
code = rcv_pkt(lngtyp, (BYTE *)&rlong, lnglen);
if (code == chsuc)
for (i = 0; i < lnglen; i++)
pb_long(*(pbyte++), plong, i);
return(code);
}
/*
*****************************************
* *
* rcv_data(): *
* Receive and normalize *
* data over I/O channel *
* *
*****************************************
/ Inputs: Address of where to put received data
/ Outputs: I/O channel status (BYTE)
/ Actions: Place received data at pbyte
*/
BYTE rcv_data(pbyte, datlen)
BYTE *pbyte;
{
return(rcv_pkt(dattyp, pbyte, datlen));
}
/*
*****************************************
* *
* rcv_cmd(): *
* Receive and Normalize *
* a command over I/O channel *
* *
*****************************************
/
/ Inputs: addresses of command parameters
/ Outputs: I/O channel status (byte)
*/
BYTE rcv_cmd(sd0, sd1, sd2)
WORD *sd0;
LONG *sd1, *sd2;
{
struct {
WORD request;
LONG param1;
LONG param2;
} cmd;
LONG nlong;
WORD i;
BYTE code, *pbyte;
code = rcv_pkt(cmdtyp, (BYTE *)&cmd, sizeof(cmd));
if (code == chsuc)
{
pbyte = (BYTE *)&cmd;
for (i = 0; i < wrdlen; i++)
pb_word(*(pbyte++), sd0, i);
for (i = 0; i < lnglen; i++)
pb_long(*(pbyte++), sd1, i);
for (i = 0; i < lnglen; i++)
pb_long(*(pbyte++), sd2, i);
}
return(code);
}
/* End of Module */

View File

@@ -0,0 +1,432 @@
/****************************************************************
* *
* CP/M-8000 BDOS Program Loader *
* *
* Copyright (c) 1982 Zilog Incorporated *
* *
* This module contains routines for loading the file *
* naked "CPM.SYS" into memory, at the address specified *
* by the first entry in the MRT. If we are properly *
* linked with the Bootstrap BIOS, this is a loader- *
* specific MRT which actually contains the address of *
* system space. *
* *
****************************************************************/
#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 SEP_ID 0x4000 /* Separate I/D flag */
#define PRNTSTR 9 /* Print String BDOS call */
#define SETDMA 26 /* Set DMA Address BDOS call */
#define BGETMRT 18 /* Number of the BIOS call */
#define open(fcbp) _bdos(15, 0, map_adr( (XADDR)fcbp, MYDATA) )
/* BDOS open call */
extern UWORD bdos(); /* To do I/O into myself */
extern XADDR bios(); /* To get MRT pointer */
extern VOID xfer(); /* Transfer control to user program */
#define NPSEG 1 /* Number of physical segs available */
/* for CP/M kernel */
#define NSEG 16 /* Maximum number of x.out segments */
#define SEGLEN 0x10000 /* Length of a Z8000 segment */
#define BPLEN (sizeof (struct b_page))
#define DEFSTACK 0x100 /* Default stack length */
#define NREGIONS 1 /* Number of regions in the Loader 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 SYSPROG 3 /* Argument for map_adr */
#define SYSDATA 2 /* Argument for map_adr */
/* Get actual code segment (as opposed */
/* to segment where it can be accessed*/
/* as data) */
#define TRUE_SYSPROG (SYSPROG | 0x100)
struct m_rt { /* The Memory Region Table */
int entries;
struct {
XADDR m_low;
XADDR m_len;
} m_reg[NREGIONS];
};
struct context /* Startup context for user's program */
{
short regs[14];
XADDR segstkptr;
short ignore;
short FCW;
XADDR PC;
};
extern struct context context; /* defined in bios.c */
/* Define the data structures used in ldcpm */
struct fcb cpmfcb =
{ (BYTE)0, /* drive code */
'C','P','M',' ',' ',' ',' ',' ','S','Y','S', /* file name */
0,0,0,0,0,0,0,0,0,0, /* the rest of the fcb */
0,0,0,0,0,0,0,0,0,0,0
};
#define NSPREG 0 /* The MRT region for non-split programs */
#define READ 20 /* Read Sequential BDOS call */
extern UWORD bdos(); /* To do I/O into myself (note this */
/* function does not map 2nd param - */
/* see mbdos macro below) */
XADDR textloc, /* Physical locations of pgm sections. */
dataloc,
bssloc,
stkloc;
XADDR textsiz, /* Sizes of the various sections. */
datasiz,
bsssiz,
stksiz;
UWORD split, /* Tells if split I/D or not */
seg; /* Tells if segmented or not */
char *gp; /* Buffer pointer for char input */
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 */
XADDR segsiz[NPSEG]; /* Segment lengths */
XADDR seglim[NPSEG]; /* Segment length limits */
XADDR segloc[NPSEG]; /* Segment base physical addresses */
short textseg, /* Logical seg # of various segments */
dataseg,
bssseg,
stkseg;
/**************************/
/* Utility Routines */
/**************************/
pstring(p)
/* print string */
REG BYTE *p;
{
while (*p) bconout(*p++);
}
badload(errtype)
/* Load failed. Print message and try again */
REG WORD errtype;
{
REG WORD i;
switch (errtype)
{
case 0: pstring("\r\nBoot error.");
startld();
case 1: pstring("\n\rOpen or Read error on ");
break;
case 2: pstring("\n\rBad file format on ");
}
pstring("CPM.SYS");
startld();
}
/***************************
* ldcpm main routine *
***************************/
/********************************/
/* */
/* l d c p m */
/* */
/********************************/
VOID /* Load a program from */
ldcpm() /* info in cpmfcb */
{
register unsigned k;
register XADDR physaddr;
register char *tp;
if (seldsk(0)) badload(0);
k = open(&cpmfcb);
if( k >= 255 ) badload(1);
k = load(); /* load the CP/M system */
if(k != GOOD) badload(2);
pstring("\r\n\nCP/M-Z8K(tm) Version 1.3 ");
pstring("\n\rCopyright (c) 1983 Zilog Inc, Digital Research, Inc.\r\n\n");
/* Finally, ready to transfer control. Must complete context first. */
xfer(map_adr((XADDR) &context, MYDATA)); /* Go for it! */
}
/********************************/
/* */
/* Start of load function */
/* */
/********************************/
load() /* Load a program from FCB info */
{ register int i,j; /* Temporary counters etc. */
struct m_rt *mrp; /* Pointer to a MRT structure */
char mybuf[SECLEN]; /* Local buffer for file reading*/
mydma = mybuf; /* Initialize addr for local DMA*/
gp = &mybuf[SECLEN]; /* Point beyond end of buffer */
mrp = (struct m_rt *) bios(BGETMRT);/* Get address of memory region */
/* table (note segment # lost)*/
if (readhdr() == EOF) /* Get x.out file header */
return (READERR); /* Read error on header */
if (x_hdr.x_magic == X_NXN_MAGIC) /* Is this acceptable x.out file*/
{ /* CP/M kernel must be nonseg nonsplit*/
split = FALSE;
seg = FALSE;
}
else
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. */
/* NOTE -- the tpa limits passed in the MRT are really system space */
/* limits. It is assumed that the system is non-split. */
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;
stkseg = bssseg = dataseg= textseg = 0;
/* assign locations */
segloc[textseg] = mrp->m_reg[NSPREG].m_low;
/* Assign limits */
seglim[textseg] = mrp->m_reg[NSPREG].m_len - 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. */
return (GOOD);
}
/* Macro to call BDOS. First parameter is passed unchanged, second */
/* is cast into an XADDR, 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 (mbdos(READ, &cpmfcb) != 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 */
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);
mbdos(READ, &cpmfcb);
}
phystarg += length;
l -= length;
}
return (GOOD);
}

File diff suppressed because it is too large Load Diff

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,52 @@
/*****************************************************************************
*
* C P / M C R U N T I M E L I B 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.
*
*****************************************************************************/
#
/* #un!define ALCYON 1 */ /* using Alcyon compiler */
/* ALCYON undefined 9/3/82 by FZ */
/*
* 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 */
/***************************/
#ifdef ALCYON
#define UBYTE char
#else
#define UBYTE unsigned char /* Unsigned byte */
#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 0 /* Null pointer value */
#define EOF (-1) /* EOF Value */
#define TRUE (1) /* Function TRUE value */
#define FALSE (0) /* Function FALSE value */
/*************************** end of portab.h ********************************/

View File

@@ -0,0 +1,216 @@
/*=======================================================================*/
/*+---------------------------------------------------------------------+*/
/*| |*/
/*| P-CP/M(tm) Bootstrap Writer for the OLIVETTI M20 (Z8000) |*/
/*| |*/
/*| Copyright 1982, Zilog Incorporated. |*/
/*| |*/
/*+---------------------------------------------------------------------+*/
/*=======================================================================*/
char copyright[] = "Copyright 1982, Zilog Incorporated";
/* HISTORY
**
** 830801 F. Zlotnick (Zilog) -- written
**
*/
#include "portab.h"
#include "cpm.h"
#include "bdos.h"
#include "stdio.h"
#include "xout.h"
#define CDATA 0 /* Parameter for map_adr() */
#define DIRSEC 1 /* Parameter for BIOS Write call */
#define SETTRK 10 /* BIOS Function 10 = Set Track */
#define SETSEC 11 /* BIOS Function 11 = Set Sector */
#define BSETDMA 12 /* BIOS Function 12 = Set DMA Addr */
#define WSECTOR 14 /* BIOS Function 14 = Write Sector */
XADDR physdir; /* Segmented address of dirbuf */
struct dpbs idpb; /* Disk Parameter Block */
struct bios_parm ibp; /* BIOS param block for BDOS call 50*/
XADDR physibp; /* physical address of ibp structure*/
extern long map_adr(); /* Function to return physical addr */
#define BPLS 128 /* Bytes per logical sector */
#define BPS 256 /* Bytes per sector */
#define BPS0 128 /* Bytes per sector, trk 0 */
#define SPT 16 /* sectors per track */
#define LSPT 32 /* Logical sectors per track */
#define SYSTRKS 2 /* Number of boot tracks */
#define SYSSIZE SPT*BPS*SYSTRKS /* Max size of bootstrap */
#define STARTRK 1 /* Track number to start on */
FILE *fin;
char syscode[SYSSIZE]; /* Hold the entire bootstrap here! */
char *system = "CPMLDR.SYS"; /* Name of the prog to boot */
#ifdef OLIVETTI
extern char T0S0[]; /* Track 0 Sector 0 */
extern char T1S0[]; /* Track 1 Sector 0 */
extern char T1S1[]; /* Track 1 Sector 1 */
#define HDRSIZE 24 /* # bytes in track 1 sect 1 header */
#endif
struct x_hdr xh;
struct x_sg xs;
int dsknum; /* Drive number 0-15 = A-P */
main(argc,argv)
int argc;
char *argv[];
{
register int i, j, c;
register char *p;
long fsize;
int curdsk; /* Good to remember, & reset*/
if(argc != 3) usage();
system = *++argv;
if( (dsknum = **++argv - 'a') < 0 || dsknum > 15) {
printf("putboot: Illegal drive code %c\n", *argv[0]);
exit(1);
}
curdsk = _ret_cdisk();
_get_dpb(map_adr((long) &idpb, CDATA)); /* Physaddr of idpb */
if( (fin = fopenb(system, "r")) == NULL) {
printf("putboot: Can't open bootstrap file %s\n", system);
exit(1);
}
fsize = 0L;
/* read file header */
p = (char *) &xh;
for (i = 0; i < sizeof(xh); i++)
*p++ = (char) getc(fin);
/* read and count segment headers to get file size */
for (i = 0; i < xh.x_nseg; i++) {
p = (char *) &xs;
for( j = 0; j < sizeof(xs); j++)
*p++ = (char) getc(fin);
if( xs.x_sg_typ != X_SG_BSS && xs.x_sg_typ != X_SG_STK)
fsize += xs.x_sg_len;
}
if (fsize > SYSSIZE) {
printf("Bootstrap too big\n");
exit(1);
}
else
printf("Bootstrap file is %ld bytes\n", fsize);
p = syscode;
#ifdef OLIVETTI
for( i = 0; i < BPS; i++) *p++ = T1S0[i];
for( i = 0; i < HDRSIZE; i++) *p++ = T1S1[i];
#endif
while(fsize--) {
if( (c = getc(fin)) == EOF) {
printf("Unexpected EOF in %s, %ld left\n",system,fsize);
exit(1);
}
*p++ = c;
}
/*
** At this point, the entire bootstrap program code and data has been loaded
** into the array named "syscode", preceded by a bunch of PCOS garbage
** which the Olivetti boot PROM expects to find there. Now we use direct
** BIOS calls to write the syscode array out to the proper area on disk.
** For the Olivetti, this is tracks 1 and 2, since track 0 is special.
*/
putboot(syscode);
printf("Bootstrap has been written.\n");
_sel_disk(curdsk); /* reselect original disk*/
}
putboot(code)
char *code;
{
register int i; /* Handy index */
register int nlsecs; /* # logical sectors in boot*/
register char *p; /* ptr to next part of code */
int track; /* Current track */
int sector; /* Current sector */
physibp = map_adr( (long) &ibp, CDATA );
nlsecs = SYSTRKS * LSPT; /* size / log secs per trk */
/* Pause for the user to insert disk */
/* pause(drvname); */
#ifdef OLIVETTI
/* Olivetti Track 0 Sector 0 is special */
_sel_disk(dsknum); /* select as current disk */
putblk(0, 0, T0S0);
#endif
p = code;
for(i = 0; i < nlsecs; i++) {
track = STARTRK + i/LSPT;
sector = i%LSPT;
putblk(track, sector, p);
p += BPLS;
}
}
/*
* Function to select a given track for writing on, on the current disk.
* Makes use of the BDOS direct BIOS call to issue Bios function 10.
*/
settrk(n)
int n;
{
ibp.req = SETTRK; /* BIOS request number 10 */
ibp.p1 = (long) n; /* parameter = track # */
_bios_call( physibp ); /* Pass seg ibp address */
}
/*
* Function to put block i of the boot track.
*/
putblk(trk, sec, addr)
int trk, sec;
char *addr;
{
register int n;
_sel_disk(dsknum); /* select as current disk */
settrk(trk);
n = sec + 1; /* sector number */
ibp.req = SETSEC; /* BIOS request number 11 */
ibp.p1 = (long) n; /* parameter = sector # */
_bios_call( physibp ); /* Pass seg ibp address */
/* Sector is now set; now set dma address. */
ibp.req = BSETDMA; /* BIOS Request number 12 */
ibp.p1 = map_adr( (long) addr, CDATA);
/* param = seg address of I/O buffer */
_bios_call( physibp ); /* Call BIOS */
/* Now can do a write */
ibp.req = WSECTOR; /* BIOS Request number 14 */
ibp.p1 = DIRSEC; /* Complete write immediately */
_bios_call( physibp ); /* Do it! */
}
/*
* If the user invoked us with the wrong number of args...
*/
usage()
{
printf("Usage: putboot <filename> <drivecode>\n");
exit(1);
}

View File

@@ -0,0 +1,17 @@
/****************************************************************************/
/* */
/* s e t j m p . h */
/* --------------- */
/* */
/* Copyright 1982 by Zilog Inc. All rights reserved */
/* */
/* Definitions for setjmp and longjmp non-local goto library functions.*/
/* jmp_buf is large enough to hold copies of the eight "safe" */
/* registers and a segmented return address. Thus the last word is */
/* not used in non-segmented environments */
/* */
/****************************************************************************/
typedef int jmp_buf[10];
extern int setjmp(), longjmp();

View File

@@ -0,0 +1,14 @@
/* sgtty.h - tty control information */
/* Note reduced contents for CP/M implementation... */
struct sgttyb{
char sg_ispeed; /* ignored */
char sg_ospeed; /* ignored */
char sg_erase; /* ignored */
char sg_kill; /* ignored */
int sg_flags;
};
#define RAW 0000040
#define CRMOD 0000020
#define ECHO 0000010
#define LCASE 0000004
#define CBREAK 0000002

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/*
/--------------------------------
/ BIOS Request Codes |
/--------------------------------
*/
#define inreq 0 /* Initialize */
#define wbreq 1 /* Warm boot */
#define csreq 2 /* Console status */
#define cireq 3 /* Console input */
#define coreq 4 /* Console output */
#define loreq 5 /* List output */
#define aoreq 6 /* Auxilliary output */
#define aireq 7 /* Auxilliary input */
#define hdreq 8 /* Home disk head */
#define sdreq 9 /* Select disk */
#define streq 10 /* Set track */
#define ssreq 11 /* Set sector */
#define sareq 12 /* Set DMA address */
#define rsreq 13 /* Read a sector */
#define wsreq 14 /* Write a sector */
#define lsreq 15 /* List status */
#define tsreq 16 /* Translate Sector */
#define sbreq 17 /* Set DMA base */
#define gmreq 18 /* Get memory table */
#define gireq 19 /* Get IOBYTE */
#define sireq 20 /* Set IOBYTE */
#define fbreq 21 /* Flush disk buffers */
#define svreq 22 /* Set Exception Vector */
/*
/--------------------------------
/ BIOS Status Codes |
/--------------------------------
*/
#define csaye 0xff /* Console character available */
#define csnay 0x00 /* Console character not available */
#define sdsuc 0x00 /* Select disk successful */
#define sderr 0x01 /* Select disk error */
#define sdfrs 0x00 /* First select call since warm boot */
#define rssuc 0x00 /* Read sector successful */
#define rserr 0x01 /* Read sector error, non-recoverable */
#define wssuc 0x00 /* Write sector successful */
#define wserr 0x01 /* Write sector error, non-recoverable */
#define lsaye 0xff /* List device ready */
#define lsnay 0x00 /* List device not ready */
/*
/--------------------------------
/ BIOS Sector Length |
/--------------------------------
*/
#define seclen 0x80 /* Length of CP/M sector (128 bytes) */

View File

@@ -0,0 +1,128 @@
/* CP/M INTERFACE HEADER FILE
*/
/* Modified to include additional CP/M function defi-
nitions and DPB structure definition 07/20/82 (DMH)
*/
/* Modified to include BIOS header 10/13/82 (DMH)
*/
/* Modified to include size of DPB 10/15/82 (DMH)
*/
#define FCB struct fcb
#define FCBLEN sizeof(FCB)
struct fcb {
TEXT et; /* assumed zero */
TEXT fn[8]; /* blank padded */
TEXT ft[3]; /* ditto */
TINY ex; /* start with zero */
TEXT pad[2]; /* assumed zero by CP/M */
TINY rcount; /* [0, 128] */
TINY dmap[16]; /* eight records per 1024 byte cluster */
TINY nr; /* next record to read/write */
TINY bleft;
TEXT *bnext;
LONG lseek;
COUNT bufseg;
TEXT buf[128];
};
/* CP/M Disk Parameter Block
*/
#define DPB struct dpb
#define DPBLEN sizeof(DPB)
struct dpb {
WORD spt; /* Sectors per track */
BYTE bsh; /* Block shift factor */
BYTE blm; /* Block mask */
BYTE exm; /* Extent mask */
WORD dsm; /* Drive capacity */
WORD drm; /* Directory capacity */
BYTE al0; /* Directory allocation 0 */
BYTE al1; /* Directory allocation 1 */
WORD cks; /* Check vector size */
WORD off; /* Track offset */
};
/* CP/M Disk Parameter Header
*/
#define DPH struct dph
#define DPHLEN sizeof(DPH)
struct dph {
BYTE *xltp; /* Translation vector address */
WORD dphscr[3]; /* CP/M scratch pad area */
BYTE *dirbufp; /* CP/M directory buffer */
DPB *dpbp; /* DPB address */
BYTE *csvp; /* Check vector address */
BYTE *alvp; /* Allocation vector address */
};
/* the Whitesmiths control block
*/
#define WCB struct wcb
struct wcb {
TINY flags, dev;
FCB *pf;
};
/* flag values:
*/
#define WOPEN 1
#define WDIRT 2
#define WSTD 4
#define WCR 010
#define WXDIRT 020
#define WXOPEN 040
/* device values:
*/
#define LST -4
#define PUN -3
#define RDR -2
#define CON -1
/* intermodule communication
*/
#define CTRLZ 032
#define EOF 1
#define FAIL -1
#define MCREATE 0
#define MOPEN 1
#define MREMOVE 2
#define MWRITE 4
#define SYSBUF 0x80
/* CP/M innards
*/
#define CRDCON 1
#define CWRCON 2
#define CRDRDR 3
#define CWRPUN 4
#define CWRLST 5
#define CGIOST 7
#define CSIOST 8
#define CPRBUF 9
#define CRDBUF 10
#define CICRDY 11
#define CLFTHD 12
#define CINIT 13
#define CSDRNO 14
#define COPEN 15
#define CCLOSE 16
#define CSRCH 17
#define CSRCHN 18
#define CDEL 19
#define CREAD 20
#define CWRITE 21
#define CMAKE 22
#define CRENAME 23
#define CILOGIN 24
#define CGDRNO 25
#define CSETAD 26
#define CIALLOC 27
#define CIPARMS 31

View File

@@ -0,0 +1,74 @@
/*****************************************************************************
*
* 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 the standard include file for the CP/M C Run Time Library.
*
*****************************************************************************/
/* */
#ifndef BYTE /* If it looks like portab.h not */
#include <portab.h> /* included already, include it */
#endif /* */
/* */
/****************************************************************************
* Stream I/O File Definitions
*****************************************************************************/
#define BUFSIZ 512 /* Standard (ascii) buf size */
#define MAXFILES 16 /* Max # open files ( < 32 ) */
struct _iobuf { /* */
WORD _fd; /* file descriptor for low level io */
WORD _flag; /* stream info flags */
BYTE *_base; /* base of buffer */
BYTE *_ptr; /* current r/w pointer */
WORD _cnt; /* # chars to be read/have been wrt */
}; /* */
#ifndef FILE /* conditionally include: */
extern struct _iobuf _iob[MAXFILES]; /* an array of this info */
#define FILE struct _iobuf /* stream definition */
#endif /************************************/
/* flag byte definition */
#define _IOREAD 0x01 /* readable file */
#define _IOWRT 0x02 /* writeable file */
#define _IOABUF 0x04 /* alloc'd buffer */
#define _IONBUF 0x08 /* no buffer */
#define _IOERR 0x10 /* error has occurred */
#define _IOEOF 0x20 /* EOF has occurred */
#define _IOLBUF 0x40 /* handle as line buffer */
#define _IOSTRI 0x80 /* this stream is really a string */
#define _IOASCI 0x100 /* this was opened as an ascii file */
/************************************/
#define stdin (&_iob[0]) /* standard input stream */
#define stdout (&_iob[1]) /* " output " */
#define stderr (&_iob[2]) /* " error " */
/************************************/
#define clearerr(p) ((p)->_flag & ~_IOERR) /* clear error flag */
#define feof(p) ((p)->_flag & _IOEOF) /* EOF encountered on stream */
#define ferror(p) ((p)->_flag & _IOERR) /* error encountered on stream */
#define fileno(p) ((p)->_fd) /* get stream's file descriptor */
#define getchar() getc(stdin) /* get char from stdin */
#define putchar(c) putc(c,stdout) /* put char to stdout */
#define putc fputc
#define getc fgetc
FILE *fopen(), *fopena(), *fopenb(), *fdopen();
FILE *freopen(), *freopa(), *freopb();
LONG ftell(), getl();
BYTE *fgets(), *gets();
/****************************************************************************/
/* */
/* 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,144 @@
;************ syscall.z8s **************************
;*
;* System Call interface for P-CP/M (tm) BIOS
;*
;* 820927 S. Savitzky (Zilog) -- created.
;*
__text: .sect
;****************************************************
;*
;* NOTE
;* The following system call interface routines
;* are designed to be called from non-segmented
;* C programs.
;*
;* Addresses are passed as LONGs.
;*
;****************************************************
.input "biosdefs.z8k"
.global _xfer
.global _mem_cpy
.global _map_adr
.global _bios
.global _bdos
;****************************************************
;*
;* Context Switch Routine
;*
;* xfer(context)
;* long context;
;*
;* context is the physical (long) address of:
;* r0
;* ...
;* r13
;* r14 (normal r14)
;* r15 (normal r15)
;* ignored word
;* FCW (had better specify normal mode)
;* PC segment
;* PC offset
;*
;* The system stack pointer is not affected.
;*
;* Control never returns to the caller.
;*
;****************************************************
_xfer:
ldl rr6,ARG1(r15)
ldl rr4,#-2
subl rr2,rr2
sc #XFER_SC
ret
;****************************************************
;*
;* System/User Memory Access
;*
;* _mem_cpy( source, dest, length)
;* long source, dest, length;
;* _map_adr( addr, space) -> paddr
;* long addr; int space;
;*
;* _map_adr( addr, -1)
;* sets user segment # from addr.
;*
;* _map_adr( addr, -2)
;* transfer to context block at addr
;*
;* system call: mem_cpy
;* rr6: source
;* rr4: dest
;* rr2: length (0 < length <= 64K)
;* returns
;* registers unchanged
;*
;* system call: map_adr
;* rr6: logical addr
;* r5: space code
;* r4: ignored
;* rr2: 0
;* returns
;* rr6: physical addr
;*
;* space codes:
;* 0: caller data
;* 1: caller program
;* 2: system data
;* 3: system program
;* 4: TPA data
;* 5: TPA program
;*
;* x+256 return segmented instruction address,
;* not data access address
;*
;* FFFF set user-space segment from address
;*
;****************************************************
_mem_cpy: ;copy memory C subroutine
;===
ldl rr6,ARG1(r15)
ldl rr4,ARG3(r15)
ldl rr2,ARG5(r15)
sc #MEM_SC
ret
_map_adr: ;map address C subroutine
;===
ldl rr6,ARG1(r15)
ld r5, ARG3(r15)
subl rr2,rr2 ; 0 length says map
sc #MEM_SC
ret
;****************************************************
;*
;* long _bdos(code, p1)
;* int code;
;* long p1, p2;
;*
;* BIOS, BDOS access. Not used in the bootstrap!
;*
;****************************************************
;_bdos:
; ld r5,ARG1(r15)
; ldl rr6,ARG2(r15)
; sc #BDOS_SC
; ret

View File

@@ -0,0 +1,157 @@
;************ syscall2.z8k **************************
;*
;* System Call interface for P-CP/M (tm) BIOS
;*
;* 820927 S. Savitzky (Zilog) -- created.
;*
;* 01/17/83 Adapted for Z8002 (DMH)
__text: .sect
;****************************************************
;*
;* NOTE
;* The following system call interface routines
;* are designed to be called from non-segmented
;* C programs.
;*
;* Addresses are passed as LONGs.
;*
;****************************************************
.input "biosdefs2.z8k"
.global _xfer
.global _mem_cpy
.global _map_adr
.global _bios
.global _bdos
;****************************************************
;*
;* Context Switch Routine
;*
;* xfer(context)
;* long context;
;*
;* context is the physical (long) address of:
;* r0
;* ...
;* r13
;* r14 (normal r14)
;* r15 (normal r15)
;* ignored word
;* FCW (had better specify normal mode)
;* PC segment
;* PC offset
;*
;* The system stack pointer is not affected.
;*
;* Control never returns to the caller.
;*
;****************************************************
_xfer:
ldl rr6,ARG1(r15)
ldl rr4,#-2
subl rr2,rr2
sc #XFER_SC
ret
;****************************************************
;*
;* System/User Memory Access
;*
;* _mem_cpy( source, dest, length)
;* long source, dest, length;
;* _map_adr( addr, space) -> paddr
;* long addr; int space;
;*
;* _map_adr( addr, -1)
;* sets user segment # from addr.
;*
;* _map_adr( addr, -2)
;* transfer to context block at addr
;*
;* system call: mem_cpy
;* rr6: source
;* rr4: dest
;* rr2: length (0 < length <= 64K)
;* returns
;* registers unchanged
;*
;* system call: map_adr
;* rr6: logical addr
;* r5: space code
;* r4: ignored
;* rr2: 0
;* returns
;* rr6: physical addr
;*
;* space codes:
;* 0: caller data
;* 1: caller program
;* 2: system data
;* 3: system program
;* 4: TPA data
;* 5: TPA program
;*
;* x+256 return segmented instruction address,
;* not data access address
;*
;* FFFF set user-space segment from address
;*
;****************************************************
_mem_cpy: ;copy memory C subroutine
;===
ldl rr6,ARG1(r15)
ldl rr4,ARG3(r15)
ldl rr2,ARG5(r15)
sc #MEM_SC
ret
_map_adr: ;map address C subroutine
;===
ldl rr6,ARG1(r15)
ld r5, ARG3(r15)
subl rr2,rr2 ; 0 length says map
sc #MEM_SC
ret
;****************************************************
;*
;* long _bios(code, p1, p2)
;* long _bdos(code, p1)
;* int code;
;* long p1, p2;
;*
;* BIOS, BDOS access
;*
;****************************************************
_bios:
ld r3,ARG1(r15)
ldl rr4,ARG2(r15)
ldl rr6,ARG4(r15)
sc #BIOS_SC
ret
_bdos:
ld r5,ARG1(r15)
ldl rr6,ARG2(r15)
sc #BDOS_SC
ret

View File

@@ -0,0 +1,9 @@
main()
{ float x,y,z;
x = 1.0;
y = 2.0;
z = x * y;
printf ("%0lx\n", *((int *)&z));
}

View File

@@ -0,0 +1,186 @@
;****************************************************
;*
;* Globals
;*
;****************************************************
.global _T0S0, _T1S0, _T1S1
;****************************************************
;*
;* Constants
;*
;****************************************************
SYSTEM .equ 0A000000h ; system address
SYSSTK .equ SYSTEM+0BFFEh ; system stack top
rtc_ext .equ 02000022h ; real-time clock
; ext. call addr
BPT .equ 16 ; #blocks in a track
BPS .equ 256 ; #bytes in a sector
NBLKS .equ 2*16 ; #blocks in boot
HDRSIZE .equ 24 ; #bytes in header
FILSIZE .equ 256*(NBLKS-1) ; file data size
SYSSIZE .equ FILSIZE-HDRSIZE ; total system size
S1SIZE .equ BPS-HDRSIZE ; data in sector 1
SEG4 .equ 04000000h
SEG2 .equ 02000000h
SYSPSA .equ SEG2+100h ; system PSA
BOOTPSA .equ SEG4+100h ; PSA in PROM for boot
;****************************************************
;*
;* Track 0 Sector 0
;*
;* This sector contains the pointer to the
;* bootstrap file's FDB.
;*
;****************************************************
__data: .sect
_T0S0:
.byte 0 ; major version
.byte 0 ; minor version
.word 40 ; #tracks/surface ?? 35 ??
.byte 2 ; #surfaces
.byte 16 ; #sectors/track
.word 256 ; #bytes/sector
.word 40 ; ??? track # of control blk
.word 38h ; ??? vdb size
.word 136 ; ??? block bitmap size
.byte 30 ; ??? directory bitmap size
.byte 0 ; ??? track count direction ???
.byte 0 ; number of uses (if 0, no boot)
.byte 0 ; copy protection (OFF)
.byte 0 ; boot block read protect (OFF)
.byte 0 ; boot block write protect (OFF)
.word 0 ; soft error count
.word 0 ; hard error count
.word 0 ; lowest useable track side 0 ?1?
.word 39 ; highest
.word 0 ; side 1
.word 39 ;
.word 0 ; side 2
.word 0 ;
.word 0 ; side 3
.word 0 ;
.long BPT ; BOOT FILE FDB BLOCK NUMBER
.byte "PCOS" ; system name??
.long 2 ; ??? directory start addr
.long 0 ; ??? drive data ???
.long 0
.long 0
.long 0
.long 0
.word 1 ; disk valid (VALID)
.byte 0 ; drive number required ???
.byte 0 ; disk open
.byte 0 ; format major version #
.byte 0 ; minor
.byte 2 ; disk type = 320Kb
.byte 0 ; 27 bytes of nothing
.byte 0 ; 26
.byte 0 ; 25
.byte 0 ; 24
.byte 0 ; 23
.byte 0 ; 22
.byte 0 ; 21
.byte 0 ; 20
.byte 0 ; 19
.byte 0 ; 18
.byte 0 ; 17
.byte 0 ; 16
.byte 0 ; 15
.byte 0 ; 14
.byte 0 ; 13
.byte 0 ; 12
.byte 0 ; 11
.byte 0 ; 10
.byte 0 ; 9
.byte 0 ; 8
.byte 0 ; 7
.byte 0 ; 6
.byte 0 ; 5
.byte 0 ; 4
.byte 0 ; 3
.byte 0 ; 2
.byte 0 ; 1
.block 22 ; forgotten, aparently
;****************************************************
;*
;* Track 1 Sector 0
;*
;* This sector is the FDB for the bootstrap
;* file. It has a single extent.
;*
;****************************************************
_T1S0:
.long FILSIZE ; file length in bytes
.word 1 ; #extents
.byte 0 ; 14 password (14 bytes)
.byte 0 ; 13
.byte 0 ; 12
.byte 0 ; 11
.byte 0 ; 10
.byte 0 ; 9
.byte 0 ; 8
.byte 0 ; 7
.byte 0 ; 6
.byte 0 ; 5
.byte 0 ; 4
.byte 0 ; 3
.byte 0 ; 2
.byte 0 ; 1
.word 0 ; ??? verify location ???
.byte 0 ; write protect
.byte 0 ; future
.long BPT+1 ; STARTING BLOCK OF EXTENT
.word NBLKS-1 ; NUMBER OF BLOCKS IN EXTENT
.block 222 ; other extents
.long 0 ; next fdb
;****************************************************
;*
;* Track 1 Sector 1
;*
;* This sector is the header for the bootstrap
;* file, followed by the first S1SIZE bytes of
;* data, which are copied in.
;*
;****************************************************
_T1S1:
.word 0101h ; magic number
.byte "PCPM" ; identifier
.byte "x01."
.byte "01"
.long SYSTEM ; starting addr.
.word 1 ; #code blocks
.long SYSTEM ; load address
.word SYSSIZE/2 ; #words
s1data .block S1SIZE ; data area

View File

@@ -0,0 +1,71 @@
/* 07/20/82 Added new types WORD and BYTE (DMH) */
/* 10/15/82 Added some new defines (DMH) */
/* 11/13/82 This is the version for Unidot comp- */
/* iler which doesn't support unsigned. */
/* the pseudo storage classes */
#define AFAST register
#define FAST register
#define GLOBAL extern
#define IMPORT extern
#define INTERN static
#define LOCAL static
/* the pseudo types */
typedef char TEXT, TINY;
typedef double DOUBLE;
typedef int ARGINT, BOOL, VOID;
typedef long LONG;
typedef short BITS, COUNT, FILE;
typedef /* unsigned */ BYTES, WORD;
typedef /* unsigned */ char BYTE, UTINY;
typedef /* unsigned */ long ULONG;
typedef /* unsigned */ short UCOUNT;
/* system parameters */
#define STDIN 0
#define STDOUT 1
#define STDERR 2
#define YES 1
#define NO 0
#define TRUE 1
#define FALSE 0
#define NULL 0
#define FOREVER for (;;)
#define BUFSIZE 512
#define BWRITE -1
#define READ 0
#define WRITE 1
#define UPDATE 2
#define EOF -1
#define BYTMASK 0377
/* macros */
#define abs(x) ((x) < 0 ? -(x) : (x))
#define gtc(pf) (0 < (pf)->_nleft ? (--(pf)->_nleft, *(pf)->_pnext++ & BYTMASK) \
: getc(pf))
#define isalpha(c) (islower(c) || isupper(c))
#define isdigit(c) ('0' <= (c) && (c) <= '9')
#define islower(c) ('a' <= (c) && (c) <= 'z')
#define isupper(c) ('A' <= (c) && (c) <= 'Z')
#define iswhite(c) ((c) <= ' ' || 0177 <= (c)) /* ASCII ONLY */
#define max(x, y) (((x) < (y)) ? (y) : (x))
#define min(x, y) (((x) < (y)) ? (x) : (y))
#define ptc(pf, c) if ((pf)->_nleft < 512) (pf)->_buf[(pf)->_nleft++] = (c); \
else putc(pf, (c))
#define tolower(c) (isupper(c) ? ((c) + ('a' - 'A')) : (c))
#define toupper(c) (islower(c) ? ((c) - ('a' - 'A')) : (c))
/* the file IO structure */
typedef struct fio
{
FILE _fd;
COUNT _nleft;
COUNT _fmode;
TEXT *_pnext;
TEXT _buf[BUFSIZE];
} FIO;

View File

@@ -0,0 +1,61 @@
struct x_hdr {
short x_magic; /* magic number */
short x_nseg; /* number of segments in file */
long x_init; /* length of initialized part of file */
long x_reloc; /* length of relocation part of file */
long x_symb; /* length of symbol table part of file */
};
struct x_sg {
char x_sg_no; /* assigned number of segment */
char x_sg_typ; /* type of segment */
unsigned x_sg_len; /* length of segment */
} x_sg[]; /* array of size x_nseg */
#define X_SU_MAGIC 0xEE00 /* segmented, non executable */
#define X_SX_MAGIC 0xEE01 /* segmented, executable */
#define X_NU_MAGIC 0xEE02 /* non-segmented, non executable */
#define X_NXN_MAGIC 0xEE03 /* non-segmented, executable, non-shared */
#define X_NXS_MAGIC 0xEE07 /* non-segmented, executable, shared */
#define X_NXI_MAGIC 0xEE0B /* non-segmented, executable, split ID */
#define X_SG_BSS 1 /* non-initialized data segment */
#define X_SG_STK 2 /* stack segment, no data in file */
#define X_SG_COD 3 /* code segment */
#define X_SG_CON 4 /* constant pool */
#define X_SG_DAT 5 /* initialized data */
#define X_SG_MXU 6 /* mixed code and data, not protectable */
#define X_SG_MXP 7 /* mixed code and data, protectable */
struct x_rel { /* relocation item */
char x_rl_sgn; /* segment containing item to be relocated */
char x_rl_flg; /* relocation type (see below) */
unsigned x_rl_loc; /* location of item to be relocated */
unsigned x_rl_bas; /* number of (external) element in symbol table
or (internal) segment by which to relocate */
};
#define X_RL_OFF 1 /* adjust a 16 bit offset value only */
#define X_RL_SSG 2 /* adjust a short form segment plus offset */
#define X_RL_LSG 3 /* adjust a long form (32 bit) seg plus off */
#define X_RL_XOF 5 /* adjust a 16 bit offset by an external */
#define X_RL_XSSG 6 /* adjust a short seg ref by an external */
#define X_RL_XLSG 7 /* adjust a long seg ref by an external */
#define XNAMELN 8 /* length of a symbol */
struct x_sym {
char x_sy_sg; /* the segment number */
char x_sy_fl; /* the type of entry */
unsigned x_sy_val; /* the value of this entry */
char x_sy_name[XNAMELN]; /* the symbol name, padded with 0's */
};
#define X_SY_LOC 1 /* local symbol (for debug only) */
#define X_SY_UNX 2 /* undefined external entry */
#define X_SY_GLB 3 /* global definition */
#define X_SY_SEG 4 /* segment name */

View File

@@ -0,0 +1,272 @@
/* This module is a collection of all the Z8000 */
/* dependent C code for the P-CP/M dual processor */
/* BIOS. */
/*
*************************************************
* *
* Author: David Heintz *
* Module: Zoom8kc.c *
* Creation Date: 10/26/82 *
* Language: Standard C *
* Version: 1.0 *
* Last Mod: 11/26/82 *
* *
*************************************************
*/
/*
*************************************************
* *
* STANDARD HEADERS *
* *
*************************************************
*/
#include "unstdsys.h"
#include "zooequ.h"
#include "chnequ.h"
/*
*************************************************
* *
* EXTERNAL DECLARATIONS *
* *
*************************************************
*/
extern BYTE gb_word();
extern BYTE gb_long();
extern pb_word();
extern pb_long();
extern WORD bytlen;
extern WORD wrdlen;
extern WORD lnglen;
/*
*************************************************
* *
* Byte Ordering Arrays For *
* Word and Long *
* *
*************************************************
*/
static BYTE wrdtab[2] = {1, 0};
static WORD lngtab[4] = {3, 2, 1, 0};
/*
*************************************************
* *
* Machine dependent entities *
* *
*************************************************
*/
WORD bytlen = 1;
WORD wrdlen = 2;
WORD lnglen = 4;
/*
*************************************************
* *
* Port Addresses for Zoom Board *
* *
*************************************************
*/
WORD fiodat = 0x0001; /* Values for Zoom side */
WORD fioctl = 0x0003; /* only. */
/*
*************************************************
* *
* Memory Region Table *
* *
*************************************************
*/
/* The following table describes two memory regions: */
/* Region 1 Type: Separated instruction and data space */
/* Length: 64k I space, 64k D space, 128k total. */
/* Base: <<42>> */
/* */
/* Region 2 Type: Merged instruction and data space */
/* Length: 64k combined space. */
/* Base: <<1>> */
/* */
/* Notes This table is machine dependent (ZOOM board), */
/* but not processor dependent. */
/* Table does not include system segment. */
/* Table should probably be removed to module of */
/* machine dependent code and data. */
/* ********* This is the real memory region table ******** */
/*
struct mrt {
int count;
struct {long tpalow;
long tpalen;
} regions[2];
} memtab = {2,
{{0x42000000L, 0x1ffffL},
{0x01000000L, 0x0ffffL}
}
};
*/
/* ******** This is a kludge table for use with ****** */
/* ******** flaky zoom board hardware. ****** */
struct mrt {
int count;
struct {long tpalow;
long tpalen;
} regions[2];
} memtab = {2,
{{0x42000000L, 0x1ffffL},
{0x02000000L, 0x0ffffL}
}
};
/*
*****************************************
* *
* gb_word(): *
* Retrieve a specified *
* byte from a word *
* *
*****************************************
/
/ Inputs: Address of word
/ Byte number
/ Outputs: Byte corresponding to
/ byte number in word
*/
BYTE gb_word(pbyte, i)
BYTE *pbyte;
WORD i;
{
return(pbyte[wrdtab[i]]);
}
/*
*****************************************
* *
* gb_long(): *
* Retrieve a specified *
* byte from a long *
* *
*****************************************
/
/
/ Inputs: Address of long
/ Byte number
/ Outputs: Byte corresponding to
/ byte number in long
*/
BYTE gb_long(pbyte, i)
BYTE *pbyte;
WORD i;
{
return(pbyte[lngtab[i]]);
}
/*
*****************************************
* *
* pb_word(): *
* Place a specified *
* byte into a word *
* *
*****************************************
/
/
/ Inputs: Byte to be place
/ Address of word
/ Byte number
/ Outputs: None
*/
pb_word(sbyte, pbyte, i)
BYTE sbyte, *pbyte;
WORD i;
{
pbyte[wrdtab[i]] = sbyte;
}
/*
*****************************************
* *
* pb_long(): *
* Place a specified *
* byte into a long *
* *
*****************************************
/
/
/ Inputs: Byte to be place
/ Address of long
/ Byte number
/ Outputs: None
*/
pb_long(sbyte, pbyte, i)
BYTE sbyte, *pbyte;
WORD i;
{
pbyte[lngtab[i]] = sbyte;
}
/* End of Modul;
A!2,/****************************************************************************/
/* */
/* 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 */
};