mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 08:54:17 +00:00
Upload
Digital Research
This commit is contained in:
@@ -0,0 +1 @@
|
||||
$ as68 -p -L 'p1'.s >'p1'.lis
|
||||
152
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosdef.h
Normal file
152
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosdef.h
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* CP/M-68K 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
|
||||
FALSE to create based structure for re-entrant model */
|
||||
#if snglthrd
|
||||
#define GBL gbls
|
||||
/* In single thread case, GBL just names
|
||||
the structure */
|
||||
#define BSETUP EXTERN struct stvars gbls;
|
||||
/* and BSETUP defines the extern structure */
|
||||
#endif
|
||||
|
||||
#if ! snglthrd
|
||||
#define GBL (*statep)
|
||||
/* If multi-task, state vars are based */
|
||||
#define BSETUP REG struct stvars *statep; \
|
||||
statep = &gbls;
|
||||
/* set up pointer to state variables */
|
||||
/* This is intended as an example to show the intent */
|
||||
#endif
|
||||
|
||||
|
||||
/* Note that there are a few critical regions in the file system that must
|
||||
execute without interruption. They pertain mostly to the manipulation of
|
||||
the allocation vector. This isn't a problem in a single-thread model, but
|
||||
must be provided for in a multi-tasking file system. Consequently, the
|
||||
primitives LOCK and UNLOCK are defined and used where necessary in the
|
||||
file system. For the single thread model, they are null routines */
|
||||
|
||||
#define LOCK /**/
|
||||
#define UNLOCK /**/
|
||||
/* Be sure LOCK and UNLOCK are implemented to allow recursive calls to LOCK.
|
||||
That is, if a process that calls LOCK already owns the lock, let it proceed,
|
||||
but remember that only the outer-most call to UNLOCK really releases the
|
||||
file system. */
|
||||
|
||||
|
||||
#define VERSION 0x2022 /* Version number for CP/M-68K */
|
||||
#define robit 0 /* read-only bit in file type field of fcb */
|
||||
#define SECLEN 128 /* length of a CP/M sector */
|
||||
|
||||
|
||||
/* File Control Block definition */
|
||||
struct fcb
|
||||
{
|
||||
UBYTE drvcode; /* 0 = default drive, 1..16 are drives A..P */
|
||||
UBYTE fname[8]; /* File name (ASCII) */
|
||||
UBYTE ftype[3]; /* File type (ASCII) */
|
||||
UBYTE extent; /* Extent number (bits 0..4 used) */
|
||||
UBYTE s1; /* Reserved */
|
||||
UBYTE s2; /* Module field (bits 0..5), write flag (7) */
|
||||
UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
|
||||
union
|
||||
{
|
||||
UBYTE small[16]; /* 16 block numbers of 1 byte */
|
||||
WORD big[8]; /* or 8 block numbers of 1 word */
|
||||
} dskmap;
|
||||
UBYTE cur_rec; /* current record field */
|
||||
UBYTE ran0; /* random record field (3 bytes) */
|
||||
UBYTE ran1;
|
||||
UBYTE ran2;
|
||||
};
|
||||
|
||||
|
||||
/* Declaration of directory entry */
|
||||
struct dirent
|
||||
{
|
||||
UBYTE entry; /* 0 - 15 for user numbers, E5 for empty */
|
||||
/* the rest are reserved */
|
||||
UBYTE fname[8]; /* File name (ASCII) */
|
||||
UBYTE ftype[3]; /* File type (ASCII) */
|
||||
UBYTE extent; /* Extent number (bits 0..4 used) */
|
||||
UBYTE s1; /* Reserved */
|
||||
UBYTE s2; /* Module field (bits 0..5), write flag (7) */
|
||||
UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
|
||||
union
|
||||
{
|
||||
UBYTE small[16]; /* 16 block numbers of 1 byte */
|
||||
WORD big[8]; /* or 8 block numbers of 1 word */
|
||||
} dskmap;
|
||||
};
|
||||
|
||||
|
||||
/* Declaration of disk parameter tables */
|
||||
struct dpb /* disk parameter table */
|
||||
{
|
||||
UWORD spt; /* sectors per track */
|
||||
UBYTE bsh; /* block shift factor */
|
||||
UBYTE blm; /* block mask */
|
||||
UBYTE exm; /* extent mask */
|
||||
UBYTE dpbdum; /* dummy byte for fill */
|
||||
UWORD dsm; /* max disk size in blocks */
|
||||
UWORD drm; /* max directory entries */
|
||||
UWORD dir_al; /* initial allocation for dir */
|
||||
UWORD cks; /* number dir sectors to checksum */
|
||||
UWORD trk_off; /* track offset */
|
||||
};
|
||||
|
||||
struct dph /* disk parameter header */
|
||||
{
|
||||
UBYTE *xlt; /* pointer to sector translate table */
|
||||
UWORD hiwater; /* high water mark for this disk */
|
||||
UWORD dum1; /* dummy (unused) */
|
||||
UWORD dum2;
|
||||
UBYTE *dbufp; /* pointer to 128 byte directory buffer */
|
||||
struct dpb *dpbp; /* pointer to disk parameter block */
|
||||
UBYTE *csv; /* pointer to check vector */
|
||||
UBYTE *alv; /* pointer to allocation vector */
|
||||
};
|
||||
|
||||
|
||||
/* Declaration of structure containing "global" state variables */
|
||||
struct stvars
|
||||
{
|
||||
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 */
|
||||
UBYTE *dmaadr; /* Disk dma address */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
*****************************************************************
|
||||
* *
|
||||
* CP/M-68K Interface Module for the Loader BDOS *
|
||||
* For "C" version of CP/M-68K *
|
||||
* *
|
||||
* Copyright (c) 1982 Digital Research, Inc. *
|
||||
* *
|
||||
* Version 0.1 -- September 22, 1982 *
|
||||
* *
|
||||
*****************************************************************
|
||||
|
||||
* Declare Public Routines
|
||||
|
||||
.globl _bios1 * 5 BIOS entry points from BDOS
|
||||
.globl _bios2
|
||||
.globl _bios3
|
||||
.globl _bios4
|
||||
.globl _bios5
|
||||
.globl _swap * byte swapper
|
||||
.globl _udiv * unsigned divide routine
|
||||
|
||||
* External Routine
|
||||
|
||||
.globl _bios
|
||||
|
||||
*
|
||||
* 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
|
||||
* Has function number and 2 parameters, a word followed by a long word
|
||||
move.l 8(sp),d2 * get 2nd parameter (long word)
|
||||
bra _bios2 * join common routine
|
||||
|
||||
_bios4:
|
||||
* For BIOS function seldsk
|
||||
* Has function number followed by 2 word parameters
|
||||
move.w 8(sp),d2 * get 2nd parameter (word)
|
||||
bra _bios2 * join common routine
|
||||
|
||||
_bios3:
|
||||
* For BIOS function set dma
|
||||
* Has function number followed by 1 long parameter
|
||||
move.l 6(sp),d1 * get long word parameter
|
||||
bra _bios1 * join common routine
|
||||
|
||||
_bios2:
|
||||
* For all BIOS functions with a word parameter
|
||||
* Word parameter follows function number
|
||||
move.w 6(sp),d1 * get 1st parameter (word)
|
||||
|
||||
_bios1:
|
||||
* For all BIOS functions that have no parameter other than function number
|
||||
move.w 4(sp),d0 * get function number
|
||||
movem.l d3-d7/a3-a6,-(sp)
|
||||
jsr _bios * do BIOS call
|
||||
movem.l (sp)+,d3-d7/a3-a6
|
||||
* * returns value in d0
|
||||
rts
|
||||
|
||||
*
|
||||
* Utility Subroutines
|
||||
*
|
||||
|
||||
_swap:
|
||||
* Swap bytes of a word, return swapped value in d0
|
||||
move.b 5(sp),d0
|
||||
lsl #8,d0
|
||||
move.b 4(sp),d0
|
||||
rts
|
||||
|
||||
_udiv:
|
||||
* Unsigned divide.
|
||||
* Inputs: Long dividend, unsigned word divisor, address of return structure
|
||||
* Return: In structure passed, unsigned word quotient, unsigned word remainder
|
||||
move.l a0, -(sp) * save a0
|
||||
move.l 14(sp), a0 * get address of return structure
|
||||
move.l 8(sp), d0 * get dividend
|
||||
divu 12(sp), d0 * do the divide
|
||||
move.w d0, (a0)+ * store quotient
|
||||
swap d0
|
||||
move.w d0, (a0) * store remainder
|
||||
move.l (sp)+, a0 * restore a0
|
||||
rts
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K Loader BDOS Main Routine *
|
||||
* *
|
||||
* This is the main routine for the Loader BDOS for *
|
||||
* CP/M-68K. It has one entry point, _bdos. *
|
||||
* the assembly language trap handler found in bdosif.s. *
|
||||
* There are two parameters: a function number (integer) *
|
||||
* and an information parameter, potentially a long word *
|
||||
* The BDOS can potentially return a pointer, long word, *
|
||||
* or word *
|
||||
* *
|
||||
* Configured for Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "stdio.h" /* Standard I/O declarations */
|
||||
|
||||
#include "bdosdef.h" /* Type and structure declarations for BDOS */
|
||||
|
||||
#include "biosdef.h" /* Declarations of BIOS functions */
|
||||
|
||||
/* Serial Number and Copyright Notice */
|
||||
|
||||
char *copyrt="CP/M-68K(tm), Version 1.1, Copyright (c) 1983, Digital Research";
|
||||
char *serial = "XXXX-0000-654321";
|
||||
|
||||
|
||||
/* Declare EXTERN functions */
|
||||
|
||||
EXTERN WORD seldisk(); /* 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;
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* _bdos MAIN ROUTINE *
|
||||
* *
|
||||
* Called with _bdos(func, info, infop) *
|
||||
* *
|
||||
* Where: *
|
||||
* func is the BDOS function number (d0.w) *
|
||||
* info is the word parameter (d1.w) *
|
||||
* infop is the pointer parameter (d1.l) *
|
||||
* note that info is the word form of infop*
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
|
||||
UWORD _bdos(func,info,infop)
|
||||
REG WORD func; /* BDOS function number */
|
||||
REG UWORD info; /* d1.w word parameter */
|
||||
REG UBYTE *infop; /* d1.l pointer parameter */
|
||||
{
|
||||
|
||||
switch (func) /* switch on function number */
|
||||
{
|
||||
|
||||
case 2: bconout((UBYTE)info); /* console output */
|
||||
break;
|
||||
|
||||
case 14: return(seldisk(info)); /* select disk */
|
||||
|
||||
case 15: infop->drvcode = 0; /* open file */
|
||||
infop->extent = 0;
|
||||
infop->s2 = 0;
|
||||
return(dirscan(openfile, infop));
|
||||
|
||||
case 20: infop->drvcode = 0; /* read sequential */
|
||||
return(seqread(infop));
|
||||
|
||||
case 26: GBL.dmaadr = infop; /* set dma address */
|
||||
break;
|
||||
|
||||
default: return(0xffff); /* bad function number */
|
||||
/* break; */
|
||||
|
||||
}; /* end of switch statement */
|
||||
|
||||
return(0); /* return the BDOS return value */
|
||||
} /* end _bdos */
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
.globl _bios1
|
||||
.globl _bios2
|
||||
.globl _bios3
|
||||
.globl _bios4
|
||||
.globl _bios5
|
||||
.globl _copyrt
|
||||
.data
|
||||
_copyrt:
|
||||
.dc.l L1
|
||||
.globl _serial
|
||||
.data
|
||||
_serial:
|
||||
.dc.l L2
|
||||
.globl _seldisk
|
||||
.globl _openfile
|
||||
.globl _dirscan
|
||||
.globl _seqread
|
||||
.globl _gbls
|
||||
.comm _gbls,16
|
||||
.globl __bdos
|
||||
.text
|
||||
__bdos:
|
||||
~~_bdos:
|
||||
~infop=R13
|
||||
~info=R6
|
||||
~func=R7
|
||||
link R14,#0
|
||||
movem.l R5-R7/R13-R13,-(sp)
|
||||
move 8(R14),R7
|
||||
move 10(R14),R6
|
||||
move.l 12(R14),R13
|
||||
move R7,R0
|
||||
bra L5
|
||||
L6:
|
||||
move.b R6,R0
|
||||
ext.w R0
|
||||
move R0,(sp)
|
||||
move #4,-(sp)
|
||||
jsr _bios2
|
||||
add #2,sp
|
||||
bra L4
|
||||
L7:
|
||||
move R6,(sp)
|
||||
jsr _seldisk
|
||||
bra L3
|
||||
L8:
|
||||
clr.b (R13)
|
||||
clr.b 12(R13)
|
||||
clr.b 14(R13)
|
||||
move.l R13,(sp)
|
||||
move.l #_openfile,-(sp)
|
||||
jsr _dirscan
|
||||
add #4,sp
|
||||
bra L3
|
||||
L9:
|
||||
clr.b (R13)
|
||||
move.l R13,(sp)
|
||||
jsr _seqread
|
||||
bra L3
|
||||
L10:
|
||||
move.l R13,12+_gbls
|
||||
bra L4
|
||||
L11:
|
||||
move #65535,R0
|
||||
bra L3
|
||||
bra L4
|
||||
L5:ext.l R0
|
||||
move.l #L12,R8
|
||||
move #5,R1
|
||||
L13:cmp.l (R8)+,R0
|
||||
dbeq R1,L13
|
||||
move.l 20(R8),R8
|
||||
jmp (R8)
|
||||
.data
|
||||
L12:.dc.l 2
|
||||
.dc.l 14
|
||||
.dc.l 15
|
||||
.dc.l 20
|
||||
.dc.l 26
|
||||
.dc.l 0
|
||||
.dc.l L6
|
||||
.dc.l L7
|
||||
.dc.l L8
|
||||
.dc.l L9
|
||||
.dc.l L10
|
||||
.dc.l L11
|
||||
.text
|
||||
L4:
|
||||
clr R0
|
||||
bra L3
|
||||
L3:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.data
|
||||
L1:.dc.b 67,80,47,77,45,54,56,75,40,116,109,41,44,32,86,101,114,115,105,111,110,32,49,46,49,44,32,67,111,112,121,114,105,103,104,116,32,40,99,41,32,49,57,56,51,44,32,68,105,103,105,116,97,108,32,82,101,115,101,97,114,99,104,0
|
||||
L2:.dc.b 88,88,88,88,45,48,48,48,48,45,54,53,52,51,50,49,0
|
||||
208
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosread.c
Normal file
208
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosread.c
Normal file
@@ -0,0 +1,208 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K BDOS Disk Read/Write Module *
|
||||
* *
|
||||
* This module contains functions to perform sequential *
|
||||
* or random access read or write to the disk for CP/M-68K *
|
||||
* *
|
||||
* It includes the following external functions: *
|
||||
* *
|
||||
* seqread() - sequential disk read *
|
||||
* *
|
||||
* *
|
||||
* Compiled with Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "stdio.h" /* Standard I/O declarations */
|
||||
|
||||
#include "bdosdef.h" /* Type and structure declarations for BDOS */
|
||||
|
||||
|
||||
/* External function definitions */
|
||||
EXTERN UWORD rdsec(); /* disk read routine */
|
||||
EXTERN WORD 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 */
|
||||
{
|
||||
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) >= 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 */
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
* seqread entry point *
|
||||
************************/
|
||||
|
||||
UWORD seqread(fcbp)
|
||||
|
||||
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
|
||||
|
||||
{
|
||||
REG UWORD block; /* block number from fcb */
|
||||
REG WORD index; /* index into disk map of fcb */
|
||||
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) /* no data allocated at that position */
|
||||
return(1); /* reading unwritten data */
|
||||
return( do_io(block, (fcbp->cur_rec)++) );
|
||||
}
|
||||
|
||||
311
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosread.s
Normal file
311
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/bdosread.s
Normal file
@@ -0,0 +1,311 @@
|
||||
.globl _rdsec
|
||||
.globl _swap
|
||||
.globl _dirscan
|
||||
.globl _openfile
|
||||
.globl _blkindx
|
||||
.text
|
||||
_blkindx:
|
||||
~~blkindx:
|
||||
~i=R7
|
||||
~blkshf=R6
|
||||
~dparmp=R12
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R5-R7/R12-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l 8+_gbls,R12
|
||||
move.b 2(R12),R6
|
||||
ext.w R6
|
||||
move.b 12(R13),R0
|
||||
ext.w R0
|
||||
move.b 4(R12),R1
|
||||
ext.w R1
|
||||
and R1,R0
|
||||
move #7,R1
|
||||
sub R6,R1
|
||||
asl R1,R0
|
||||
move R0,R7
|
||||
move R7,R0
|
||||
move.b 32(R13),R1
|
||||
ext.w R1
|
||||
and #255,R1
|
||||
move R6,R2
|
||||
asr R2,R1
|
||||
add R1,R0
|
||||
bra L1
|
||||
L1:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R12-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _blknum
|
||||
.text
|
||||
_blknum:
|
||||
~~blknum:
|
||||
~index=R7
|
||||
~wrdfcb=14
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R6-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move 12(R14),R7
|
||||
tst 14(R14)
|
||||
beq L3
|
||||
move R7,R8
|
||||
add.l R8,R8
|
||||
move 16(R13,R8.l),(sp)
|
||||
jsr _swap
|
||||
bra L2
|
||||
bra L4
|
||||
L3:
|
||||
move.b 16(R13,R7),R0
|
||||
ext.w R0
|
||||
and #255,R0
|
||||
bra L2
|
||||
L4:L2:tst.l (sp)+
|
||||
movem.l (sp)+,R7-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _do_io
|
||||
.text
|
||||
_do_io:
|
||||
~~do_io:
|
||||
~block=8
|
||||
~dparmp=R13
|
||||
~lsec=-4
|
||||
~rcrd=11
|
||||
link R14,#-4
|
||||
movem.l R7-R7/R13-R13,-(sp)
|
||||
move.l 8+_gbls,R13
|
||||
clr.l R0
|
||||
move 8(R14),R0
|
||||
move.b 2(R13),R1
|
||||
ext.w R1
|
||||
ext.l R1
|
||||
asl.l R1,R0
|
||||
move.b 3(R13),R1
|
||||
ext.w R1
|
||||
move.b 11(R14),R2
|
||||
ext.w R2
|
||||
and R2,R1
|
||||
ext.l R1
|
||||
add.l R1,R0
|
||||
move.l R0,-4(R14)
|
||||
move.l 12+_gbls,(sp)
|
||||
move.l -4(R14),-(sp)
|
||||
jsr _rdsec
|
||||
add #4,sp
|
||||
bra L5
|
||||
L5:tst.l (sp)+
|
||||
movem.l (sp)+,R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _new_ext
|
||||
.text
|
||||
_new_ext:
|
||||
~~new_ext:
|
||||
~mod=R7
|
||||
~ext=R6
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R5-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.b 14(R13),R7
|
||||
and.b #63,R7
|
||||
move.b 12(R13),R6
|
||||
add.b #1,R6
|
||||
cmp.b #32,R6
|
||||
blt L7
|
||||
clr.b R6
|
||||
add.b #1,R7
|
||||
L7:
|
||||
cmp.b #64,R7
|
||||
blt L8
|
||||
move #6,R0
|
||||
bra L6
|
||||
L8:
|
||||
move.b R7,R0
|
||||
ext.w R0
|
||||
move.b 14(R13),R1
|
||||
ext.w R1
|
||||
and #63,R1
|
||||
cmp R1,R0
|
||||
bne L9
|
||||
move.b R6,R0
|
||||
ext.w R0
|
||||
move.b 12(R13),R1
|
||||
ext.w R1
|
||||
eor R1,R0
|
||||
move.l 8+_gbls,R9
|
||||
move.b 4(R9),R1
|
||||
ext.w R1
|
||||
not.b R1
|
||||
and R1,R0
|
||||
and #31,R0
|
||||
bne L10
|
||||
move.b R6,12(R13)
|
||||
clr R0
|
||||
bra L6
|
||||
L10:L9:
|
||||
move.b R7,14(R13)
|
||||
move.b R6,12(R13)
|
||||
move.l R13,(sp)
|
||||
move.l #_openfile,-(sp)
|
||||
jsr _dirscan
|
||||
add #4,sp
|
||||
cmp #255,R0
|
||||
blo L11
|
||||
move #4,R0
|
||||
bra L6
|
||||
L11:
|
||||
clr R0
|
||||
bra L6
|
||||
L6:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _calcext
|
||||
.text
|
||||
_calcext:
|
||||
~~calcext:
|
||||
~i=R7
|
||||
~p=R12
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R6-R7/R12-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move #15,R7
|
||||
lea 32(R13),R12
|
||||
L15:
|
||||
tst.b -(R12)
|
||||
bne L13
|
||||
sub #1,R7
|
||||
L14:
|
||||
tst R7
|
||||
bne L15
|
||||
L13:
|
||||
move.l 8+_gbls,R8
|
||||
cmp #255,6(R8)
|
||||
bls L16
|
||||
lsr R7
|
||||
L16:
|
||||
clr.l R0
|
||||
move #7,R0
|
||||
move.l 8+_gbls,R9
|
||||
move.b 2(R9),R1
|
||||
ext.w R1
|
||||
sub R1,R0
|
||||
lsr R0,R7
|
||||
move R7,R0
|
||||
move.l 8+_gbls,R9
|
||||
move.b 4(R9),R1
|
||||
ext.w R1
|
||||
not.b R1
|
||||
move.b 12(R13),R2
|
||||
ext.w R2
|
||||
and R2,R1
|
||||
and #31,R1
|
||||
or R1,R0
|
||||
bra L12
|
||||
L12:tst.l (sp)+
|
||||
movem.l (sp)+,R7-R7/R12-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _get_rc
|
||||
.text
|
||||
_get_rc:
|
||||
~~get_rc:
|
||||
~ext=R7
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R6-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l R13,(sp)
|
||||
jsr _calcext
|
||||
move R0,R7
|
||||
move.b 12(R13),R0
|
||||
ext.w R0
|
||||
cmp R0,R7
|
||||
bne L18
|
||||
move.b 15(R13),R0
|
||||
ext.w R0
|
||||
and #255,R0
|
||||
bra L17
|
||||
bra L19
|
||||
L18:
|
||||
move.b 12(R13),R0
|
||||
ext.w R0
|
||||
cmp R0,R7
|
||||
bls L20
|
||||
move #128,R0
|
||||
bra L17
|
||||
bra L21
|
||||
L20:
|
||||
clr R0
|
||||
bra L17
|
||||
L21:L19:L17:tst.l (sp)+
|
||||
movem.l (sp)+,R7-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _seqread
|
||||
.text
|
||||
_seqread:
|
||||
~~seqread:
|
||||
~block=R7
|
||||
~index=R6
|
||||
~bigfile=R4
|
||||
~fcbp=R13
|
||||
~parm=R5
|
||||
link R14,#0
|
||||
movem.l R3-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l 8+_gbls,R8
|
||||
move 6(R8),R4
|
||||
and #-256,R4
|
||||
cmp.b #128,32(R13)
|
||||
bne L23
|
||||
move.l R13,(sp)
|
||||
jsr _new_ext
|
||||
tst R0
|
||||
beq L24
|
||||
move #1,R0
|
||||
bra L22
|
||||
L24:
|
||||
clr.b 32(R13)
|
||||
L23:
|
||||
move.l R13,(sp)
|
||||
jsr _get_rc
|
||||
move.b 32(R13),R1
|
||||
ext.w R1
|
||||
and #255,R1
|
||||
cmp R1,R0
|
||||
bhi L25
|
||||
move #1,R0
|
||||
bra L22
|
||||
L25:
|
||||
move.l R13,(sp)
|
||||
jsr _blkindx
|
||||
move R0,R6
|
||||
move R4,(sp)
|
||||
move R6,-(sp)
|
||||
move.l R13,-(sp)
|
||||
jsr _blknum
|
||||
add #6,sp
|
||||
move R0,R7
|
||||
tst R7
|
||||
bne L26
|
||||
move #1,R0
|
||||
bra L22
|
||||
L26:
|
||||
move.b 32(R13),R0
|
||||
ext.w R0
|
||||
move R0,(sp)
|
||||
move R7,-(sp)
|
||||
jsr _do_io
|
||||
add #2,sp
|
||||
add.b #1,32(R13)
|
||||
bra L22
|
||||
L22:tst.l (sp)+
|
||||
movem.l (sp)+,R4-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.data
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
/********************************************************
|
||||
* *
|
||||
* BIOS definitions for CP/M-68K *
|
||||
* *
|
||||
* Copyright (c) 1982 Digital Research, Inc. *
|
||||
* *
|
||||
* This include file simply defines the BIOS calls *
|
||||
* *
|
||||
********************************************************/
|
||||
|
||||
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,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,parm2)
|
||||
/* set exception vector */
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
***************************************
|
||||
* Information to go on the 256 byte *
|
||||
* boot sector of an ExorMacs *
|
||||
***************************************
|
||||
|
||||
.text
|
||||
.dc.l $4000 * starting stack pointer
|
||||
.dc.l start * starting program counter
|
||||
.dc.w 1 * garbage
|
||||
.dc.w 1 * length of SAT
|
||||
.dc.l 2 * secondary directory start
|
||||
.dc.l 0 * primary directory PSN list start
|
||||
.dc.l 0 * start of boot loader
|
||||
.dc.w 26 * length of boot loader
|
||||
.dc.l $0 * boot execution address
|
||||
.dc.l $0 * boot load address
|
||||
.dc.b '9/30' * generation date
|
||||
.dc.b 'CP/M-68K of 9/30/82 ' * volume descriptor
|
||||
.dc.b '0020' * version/revision
|
||||
.dc.w $0a484 * checksum (god help us)
|
||||
.dc.l $0f1e2d3c * diagnostic test pattern
|
||||
.dc.l $4b5a6978
|
||||
.dc.l $8796a5b4
|
||||
.dc.l $c3d2e1f0
|
||||
.dc.l $0f1e2d3c * diagnostic test pattern
|
||||
.dc.l $4b5a6978
|
||||
.dc.l $8796a5b4
|
||||
.dc.l $c3d2e1f0
|
||||
.dc.l $4f8f0f07 * diagnostic test pattern
|
||||
.dc.l $0b0d0e06
|
||||
.dc.l $0a0c0408
|
||||
.dc.l $04020100
|
||||
.dc.l 00, 00, 00, 00 * diagnostic test pattern
|
||||
.dc.l 0 * diagnostic test area directory
|
||||
.dc.l 0 * start of dump area
|
||||
.dc.w 0 * length of dump area
|
||||
.dc.l 0 * start of sector lockout table
|
||||
.dc.w 0 * length of sector lockout table
|
||||
.dc.l 0,0,0,0,0,0,0 * unused, reserved
|
||||
.dc.l 0,0,0,0,0,0
|
||||
.dc.l 0,0,0,0,0,0,0
|
||||
.dc.l 0,0,0,0,0,0
|
||||
.dc.b 'EXORMACS' * let's hear it for Motorola
|
||||
*
|
||||
* end of volume id
|
||||
*
|
||||
* begin boot info proper
|
||||
*
|
||||
.ds.b $300 * skip over exception vectors
|
||||
.even
|
||||
start: move #$2700,sr
|
||||
move.l #$8,a0
|
||||
move.w #253,d0
|
||||
exlp: move.l #expdef,(a0)+
|
||||
dbf d0,exlp
|
||||
jmp grunt
|
||||
expdef: rte
|
||||
grunt: move #$2000,sr
|
||||
.end
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set nover
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ cc68 :== @[bobh]cc68.com
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ cc68 cpmldr
|
||||
174
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/cpmldr.c
Normal file
174
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/cpmldr.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K Loader *
|
||||
* *
|
||||
* This is the main routine for the CP/M-68K Loader. *
|
||||
* It has one entry point, ldcpm, which is called from *
|
||||
* the assembly language routine called startld found in *
|
||||
* ldrif.s. startld just sets up the stack. *
|
||||
* *
|
||||
* Configured for Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "stdio.h" /* Standard I/O declarations */
|
||||
|
||||
#define ALCYON TRUE /* TRUE if compiling with the ALCYON 68K C compiler */
|
||||
#define SECLEN 128 /* CP/M sector length */
|
||||
|
||||
|
||||
/* Declare EXTERN functions */
|
||||
|
||||
EXTERN WORD _bdos(); /* Loader BDOS entry point */
|
||||
EXTERN startld(); /* Assembly routine to set up stack & retry */
|
||||
EXTERN BYTE *bios1(); /* bios entry point for get segment table */
|
||||
EXTERN move(); /* general purpose byte mover */
|
||||
|
||||
|
||||
#define conout(ch) _bdos(2,ch)
|
||||
#define seldsk(dsk) _bdos(14,dsk)
|
||||
#define open(fcbp) _bdos(15,0,fcbp)
|
||||
#define read(fcbp) _bdos(20,0,fcbp)
|
||||
#define setdma(p) _bdos(26,0,p)
|
||||
|
||||
|
||||
/* Define the data structures used in ldcpm */
|
||||
struct fcb
|
||||
{
|
||||
UBYTE drvcode; /* drive code, must be 0 for loader BDOS */
|
||||
/* (auto disk select not supported) */
|
||||
UBYTE fname[11]; /* includes file name and type fields */
|
||||
UBYTE sys_info[4]; /* ex, s1, s2, rc. These are don't cares */
|
||||
UBYTE dskmap[16]; /* disk map, also a don't care */
|
||||
UBYTE cur_rec; /* current record field */
|
||||
};
|
||||
|
||||
struct hdr
|
||||
{
|
||||
WORD magic; /* magic number. We only recognize 0x601a */
|
||||
LONG size[5]; /* sizes of code, data, bss, sym tbl, stack */
|
||||
BYTE *tstart; /* start address of text segment */
|
||||
WORD rlbflg; /* relocation bits suppressed flag */
|
||||
};
|
||||
|
||||
struct segtbl
|
||||
{ /* memory segment table from LDRBIOS */
|
||||
WORD entrys; /* number of segments, must be 1 */
|
||||
BYTE *start; /* low memory address */
|
||||
LONG length; /* length of segment */
|
||||
};
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Global Variables */
|
||||
/**********************/
|
||||
|
||||
BYTE buffer[SECLEN]; /* 128 byte dma buffer to read program headers */
|
||||
|
||||
/* We need 2 FCB's: one to read CPM.SYS and one to read BIOS.SYS */
|
||||
/* Unfortunately, due to a bug in the Alcyon compiler, we can't initialize */
|
||||
/* them in a straightforward way. So: */
|
||||
|
||||
#if ALCYON
|
||||
|
||||
struct fcb cpmfcb =
|
||||
{ 0x0043, 0x504d, 0x2020, 0x2020, 0x2053, 0x5953, /* drive, name, and type */
|
||||
0,0,0,0,0,0,0,0,0,0,0 /* the rest of the fcb */
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct fcb cpmfcb =
|
||||
{ (BYTE)0 /* drive code */
|
||||
'CPM SYS', /* 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
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**************************/
|
||||
/* Utility Routines */
|
||||
/**************************/
|
||||
|
||||
pstring(p)
|
||||
/* print string */
|
||||
REG BYTE *p;
|
||||
{
|
||||
while (*p) conout(*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();
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
* load subroutine *
|
||||
********************/
|
||||
|
||||
BYTE *load(fcbp)
|
||||
/* load the file pointed to by fcbp and return pointer to load point */
|
||||
REG struct fcb *fcbp;
|
||||
{
|
||||
REG BYTE *p;
|
||||
REG struct hdr *hp;
|
||||
REG LONG length;
|
||||
|
||||
setdma( buffer );
|
||||
if ( open(fcbp) >= 255 ) badload(1);
|
||||
fcbp->cur_rec = 0;
|
||||
if ( read(fcbp) ) badload(1);
|
||||
hp = buffer;
|
||||
if ( (hp->magic != 0x601a) || ! (hp->rlbflg) )
|
||||
badload(2);
|
||||
p = hp->tstart;
|
||||
length = hp->size[0] + hp->size[1];
|
||||
move(&buffer[sizeof *hp], p, SECLEN - (sizeof *hp));
|
||||
/* move the first record minus header to load point */
|
||||
p += SECLEN - (sizeof *hp);
|
||||
length -= SECLEN - (sizeof *hp);
|
||||
while (length > 0L)
|
||||
{
|
||||
setdma(p);
|
||||
if ( read(fcbp) ) badload(1);
|
||||
p += SECLEN;
|
||||
length -= SECLEN;
|
||||
}
|
||||
return(hp->tstart);
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
* ldcpm main routine *
|
||||
***************************/
|
||||
|
||||
ldcpm()
|
||||
|
||||
{
|
||||
WORD (*gocpm)();
|
||||
|
||||
if (seldsk(0)) badload(0);
|
||||
gocpm = load(&cpmfcb); /* load the CP/M system */
|
||||
pstring("\r\n\nCP/M-68K(tm) Version 1.1 ");
|
||||
pstring("\n\rCopyright (c) 1982 Digital Research, Inc.\r\n\n");
|
||||
(*gocpm)(); /* jump to the CCP */
|
||||
}
|
||||
|
||||
202
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/cpmldr.s
Normal file
202
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/cpmldr.s
Normal file
@@ -0,0 +1,202 @@
|
||||
.globl __bdos
|
||||
.globl _startld
|
||||
.globl _bios1
|
||||
.globl _move
|
||||
.globl _buffer
|
||||
.comm _buffer,128
|
||||
.globl _cpmfcb
|
||||
.data
|
||||
_cpmfcb:
|
||||
.dc.w 67
|
||||
.dc.w 20557
|
||||
.dc.w 8224
|
||||
.dc.w 8224
|
||||
.dc.w 8275
|
||||
.dc.w 22867
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.globl _pstring
|
||||
.text
|
||||
_pstring:
|
||||
~~pstring:
|
||||
~p=R13
|
||||
link R14,#0
|
||||
movem.l R7-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
L3:
|
||||
tst.b (R13)
|
||||
beq L2
|
||||
move.b (R13)+,R0
|
||||
ext.w R0
|
||||
move R0,(sp)
|
||||
move #2,-(sp)
|
||||
jsr __bdos
|
||||
add #2,sp
|
||||
bra L3
|
||||
L2:L1:tst.l (sp)+
|
||||
movem.l (sp)+,R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _badload
|
||||
.text
|
||||
_badload:
|
||||
~~badload:
|
||||
~i=R6
|
||||
~errtype=R7
|
||||
link R14,#0
|
||||
movem.l R5-R7,-(sp)
|
||||
move 8(R14),R7
|
||||
move R7,R0
|
||||
bra L6
|
||||
L7:
|
||||
move.l #L8,(sp)
|
||||
jsr _pstring
|
||||
jsr _startld
|
||||
L9:
|
||||
move.l #L10,(sp)
|
||||
jsr _pstring
|
||||
bra L5
|
||||
L11:
|
||||
move.l #L12,(sp)
|
||||
jsr _pstring
|
||||
bra L5
|
||||
L6:tst R0
|
||||
beq L7
|
||||
cmp #1,R0
|
||||
beq L9
|
||||
cmp #2,R0
|
||||
beq L11
|
||||
bra L5
|
||||
L5:
|
||||
move.l #L13,(sp)
|
||||
jsr _pstring
|
||||
jsr _startld
|
||||
L4:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7
|
||||
unlk R14
|
||||
rts
|
||||
.globl _load
|
||||
.text
|
||||
_load:
|
||||
~~load:
|
||||
~p=R12
|
||||
~length=R7
|
||||
~hp=R11
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R6-R7/R11-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l #_buffer,(sp)
|
||||
clr -(sp)
|
||||
move #26,-(sp)
|
||||
jsr __bdos
|
||||
add #4,sp
|
||||
move.l R13,(sp)
|
||||
clr -(sp)
|
||||
move #15,-(sp)
|
||||
jsr __bdos
|
||||
add #4,sp
|
||||
cmp #255,R0
|
||||
blt L15
|
||||
move #1,(sp)
|
||||
jsr _badload
|
||||
L15:
|
||||
clr.b 32(R13)
|
||||
move.l R13,(sp)
|
||||
clr -(sp)
|
||||
move #20,-(sp)
|
||||
jsr __bdos
|
||||
add #4,sp
|
||||
tst R0
|
||||
beq L16
|
||||
move #1,(sp)
|
||||
jsr _badload
|
||||
L16:
|
||||
move.l #_buffer,R11
|
||||
cmp #24602,(R11)
|
||||
bne L10000
|
||||
tst 26(R11)
|
||||
bne L17
|
||||
L10000:move #2,(sp)
|
||||
jsr _badload
|
||||
L17:
|
||||
move.l 22(R11),R12
|
||||
move.l 6(R11),R7
|
||||
add.l 2(R11),R7
|
||||
move #100,(sp)
|
||||
move.l R12,-(sp)
|
||||
move.l #28+_buffer,-(sp)
|
||||
jsr _move
|
||||
add #8,sp
|
||||
add.l #100,R12
|
||||
sub.l #100,R7
|
||||
L19:
|
||||
cmp.l #$0,R7
|
||||
ble L18
|
||||
move.l R12,(sp)
|
||||
clr -(sp)
|
||||
move #26,-(sp)
|
||||
jsr __bdos
|
||||
add #4,sp
|
||||
move.l R13,(sp)
|
||||
clr -(sp)
|
||||
move #20,-(sp)
|
||||
jsr __bdos
|
||||
add #4,sp
|
||||
tst R0
|
||||
beq L20
|
||||
move #1,(sp)
|
||||
jsr _badload
|
||||
L20:
|
||||
add.l #128,R12
|
||||
sub.l #128,R7
|
||||
bra L19
|
||||
L18:
|
||||
move.l 22(R11),R0
|
||||
bra L14
|
||||
L14:tst.l (sp)+
|
||||
movem.l (sp)+,R7-R7/R11-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _ldcpm
|
||||
.text
|
||||
_ldcpm:
|
||||
~~ldcpm:
|
||||
~gocpm=-4
|
||||
link R14,#-8
|
||||
clr (sp)
|
||||
move #14,-(sp)
|
||||
jsr __bdos
|
||||
add #2,sp
|
||||
tst R0
|
||||
beq L22
|
||||
clr (sp)
|
||||
jsr _badload
|
||||
L22:
|
||||
move.l #_cpmfcb,(sp)
|
||||
jsr _load
|
||||
move.l R0,-4(R14)
|
||||
move.l #L23,(sp)
|
||||
jsr _pstring
|
||||
move.l #L24,(sp)
|
||||
jsr _pstring
|
||||
move.l -4(R14),R8
|
||||
jsr (R8)
|
||||
L21:unlk R14
|
||||
rts
|
||||
.data
|
||||
L8:.dc.b 13,10,66,111,111,116,32,101,114,114,111,114,46,0
|
||||
L10:.dc.b 10,13,79,112,101,110,32,111,114,32,82,101,97,100,32,101,114,114,111,114,32,111,110,32,0
|
||||
L12:.dc.b 10,13,66,97,100,32,102,105,108,101,32,102,111,114,109,97,116,32,111,110,32,0
|
||||
L13:.dc.b 67,80,77,46,83,89,83,0
|
||||
L23:.dc.b 13,10,10,67,80,47,77,45,54,56,75,40,116,109,41,32,86,101,114,115,105,111,110,32,49,46,49,32,0
|
||||
L24:.dc.b 10,13,67,111,112,121,114,105,103,104,116,32,40,99,41,32,49,57,56,50,32,68,105,103,105,116,97,108,32,82,101,115,101,97,114,99,104,44,32,73,110,99,46,13,10,10,0
|
||||
109
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/dskutil.c
Normal file
109
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/dskutil.c
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K Loader BDOS Disk Utilities Module *
|
||||
* *
|
||||
* This module contains the miscellaneous utilities *
|
||||
* for manipulating the disk in CP/M-68K. Included are: *
|
||||
* *
|
||||
* dirscan() - general purpose dir scanning *
|
||||
* dir_rd() - read directory sector *
|
||||
* rdsec() - read/write disk sector *
|
||||
* *
|
||||
* *
|
||||
* Configured for Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "stdio.h" /* Standard I/O declarations */
|
||||
|
||||
#include "bdosdef.h" /* Type and structure declarations for BDOS */
|
||||
|
||||
#include "pktio.h" /* Packet I/O definitions */
|
||||
|
||||
|
||||
/* declare external functions and variables */
|
||||
EXTERN UWORD do_phio(); /* external physical disk I/O routine */
|
||||
|
||||
|
||||
/**********************
|
||||
* read/write 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 */
|
||||
UBYTE *dma; /* dma address */
|
||||
|
||||
{
|
||||
struct iopb rwpkt;
|
||||
BSETUP
|
||||
|
||||
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.devnum = GBL.curdsk;
|
||||
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)
|
||||
|
||||
WORD secnum;
|
||||
{
|
||||
BSETUP
|
||||
|
||||
return( rdsec((LONG)secnum, GBL.dirbufp) );
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
* 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(0xffff);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
.globl _do_phio
|
||||
.globl _rdsec
|
||||
.text
|
||||
_rdsec:
|
||||
~~rdsec:
|
||||
~rwpkt=-18
|
||||
~secnum=8
|
||||
~dma=12
|
||||
link R14,#-22
|
||||
move.b #1,-18(R14)
|
||||
clr.b -17(R14)
|
||||
move.l 8(R14),-14(R14)
|
||||
move.l 12(R14),-8(R14)
|
||||
move.l _gbls,-4(R14)
|
||||
move.l R14,(sp)
|
||||
add.l #-18,(sp)
|
||||
jsr _do_phio
|
||||
bra L1
|
||||
L1:unlk R14
|
||||
rts
|
||||
.globl _dir_rd
|
||||
.text
|
||||
_dir_rd:
|
||||
~~dir_rd:
|
||||
~secnum=8
|
||||
link R14,#-4
|
||||
move.l 4+_gbls,(sp)
|
||||
move 8(R14),R8
|
||||
move.l R8,-(sp)
|
||||
jsr _rdsec
|
||||
add #4,sp
|
||||
bra L2
|
||||
L2:unlk R14
|
||||
rts
|
||||
.globl _dirscan
|
||||
.text
|
||||
_dirscan:
|
||||
~~dirscan:
|
||||
~funcp=8
|
||||
~i=R7
|
||||
~dirsec=R6
|
||||
~dparmp=R12
|
||||
~fcbp=R13
|
||||
link R14,#0
|
||||
movem.l R5-R7/R12-R13,-(sp)
|
||||
move.l 12(R14),R13
|
||||
move.l 8+_gbls,R12
|
||||
clr R7
|
||||
L5:
|
||||
cmp 8(R12),R7
|
||||
bhi L4
|
||||
move R7,R0
|
||||
and #3,R0
|
||||
bne L7
|
||||
move R7,R6
|
||||
lsr #2,R6
|
||||
move R6,(sp)
|
||||
jsr _dir_rd
|
||||
tst R0
|
||||
beq L8
|
||||
move #65535,R0
|
||||
bra L3
|
||||
L8:L7:
|
||||
move R7,-(sp)
|
||||
move R7,R0
|
||||
and #3,R0
|
||||
lsl #5,R0
|
||||
swap R0
|
||||
clr R0
|
||||
swap R0
|
||||
add.l 4+_gbls,R0
|
||||
move.l R0,-(sp)
|
||||
move.l R13,-(sp)
|
||||
move.l 8(R14),R8
|
||||
jsr (R8)
|
||||
add #10,sp
|
||||
tst R0
|
||||
beq L9
|
||||
move R7,R0
|
||||
and #3,R0
|
||||
bra L3
|
||||
L9:L6:
|
||||
add #1,R7
|
||||
bra L5
|
||||
L4:
|
||||
move #255,R0
|
||||
bra L3
|
||||
L3:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R12-R13
|
||||
unlk R14
|
||||
rts
|
||||
.data
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ ld68 :== $bin:lo68
|
||||
$ ld68 -Tf900 -o exldr.68k ldrif.o cpmldr.o bdosif.o dskutil.o fileio.o -
|
||||
bdosread.o bdosmain.o iosys.o ldrbiosa.o hdbios.o
|
||||
@@ -0,0 +1,8 @@
|
||||
$ set nover
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ cc68 :== @[bobh]cc68.com
|
||||
$ as68 :== $bin:as68.exe
|
||||
$ ld68 :== $bin:lo68.exe
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ cc68 fileio
|
||||
129
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/fileio.c
Normal file
129
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/fileio.c
Normal file
@@ -0,0 +1,129 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K BDOS File I/O Module *
|
||||
* *
|
||||
* This module contains all file handling BDOS functions *
|
||||
* except for read and write for CP/M-68K. Included are: *
|
||||
* *
|
||||
* seldisk() - select disk *
|
||||
* openfile() - open file *
|
||||
* move() - general purpose byte mover *
|
||||
* *
|
||||
* *
|
||||
* Compiled with Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "stdio.h" /* Standard I/O declarations */
|
||||
|
||||
#include "bdosdef.h" /* Type and structure declarations for BDOS */
|
||||
|
||||
#include "pktio.h" /* Packet I/O definitions */
|
||||
|
||||
/* declare external fucntions */
|
||||
EXTERN UWORD do_phio(); /* packet disk i/o handler */
|
||||
EXTERN UWORD swap(); /* assembly language byte swapper */
|
||||
|
||||
|
||||
/************************
|
||||
* seldisk entry point *
|
||||
************************/
|
||||
|
||||
WORD seldisk(dsknum)
|
||||
|
||||
REG UBYTE dsknum; /* disk number to select */
|
||||
|
||||
{
|
||||
struct iopb selpkt;
|
||||
REG UWORD *p; /* scratch pointer */
|
||||
REG WORD i;
|
||||
BSETUP
|
||||
|
||||
if (UBWORD(dsknum) > 15) return(0xffff);
|
||||
selpkt.iofcn = sel_info;
|
||||
selpkt.devnum = dsknum;
|
||||
selpkt.ioflags = 0;
|
||||
do_phio(&selpkt); /* actually do the disk select */
|
||||
if ((GBL.dphp = selpkt.infop) == NULL)
|
||||
return(0xffff);
|
||||
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)
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
return(rtn);
|
||||
}
|
||||
|
||||
170
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/fileio.s
Normal file
170
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/fileio.s
Normal file
@@ -0,0 +1,170 @@
|
||||
.globl _do_phio
|
||||
.globl _swap
|
||||
.globl _seldisk
|
||||
.text
|
||||
_seldisk:
|
||||
~~seldisk:
|
||||
~i=R6
|
||||
~p=R13
|
||||
~dsknum=R7
|
||||
~selpkt=-18
|
||||
link R14,#-18
|
||||
movem.l R5-R7/R13-R13,-(sp)
|
||||
move.b 9(R14),R7
|
||||
move.b R7,R0
|
||||
ext.w R0
|
||||
and #255,R0
|
||||
cmp #15,R0
|
||||
ble L2
|
||||
move #65535,R0
|
||||
bra L1
|
||||
L2:
|
||||
clr.b -18(R14)
|
||||
move.b R7,-15(R14)
|
||||
clr.b -17(R14)
|
||||
move.l R14,(sp)
|
||||
add.l #-18,(sp)
|
||||
jsr _do_phio
|
||||
move.l -4(R14),_gbls
|
||||
bne L3
|
||||
move #65535,R0
|
||||
bra L1
|
||||
L3:
|
||||
move.l _gbls,R8
|
||||
move.l 10(R8),4+_gbls
|
||||
move.l _gbls,R8
|
||||
move.l 14(R8),8+_gbls
|
||||
clr R0
|
||||
bra L1
|
||||
L1:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _move
|
||||
.text
|
||||
_move:
|
||||
~~move:
|
||||
~i=R7
|
||||
~p1=R13
|
||||
~p2=R12
|
||||
link R14,#0
|
||||
movem.l R6-R7/R12-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l 12(R14),R12
|
||||
move 16(R14),R7
|
||||
L6:
|
||||
move R7,R0
|
||||
sub #1,R7
|
||||
tst R0
|
||||
beq L5
|
||||
move.b (R13)+,(R12)+
|
||||
bra L6
|
||||
L5:L4:tst.l (sp)+
|
||||
movem.l (sp)+,R7-R7/R12-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _match
|
||||
.text
|
||||
_match:
|
||||
~~match:
|
||||
~i=R7
|
||||
~p1=R13
|
||||
~p2=R12
|
||||
~chk_ext=17
|
||||
~temp=R6
|
||||
link R14,#0
|
||||
movem.l R5-R7/R12-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.l 12(R14),R12
|
||||
move #12,R7
|
||||
L10:
|
||||
move.b (R13),R6
|
||||
eor.b #63,R6
|
||||
move.b (R13)+,R0
|
||||
ext.w R0
|
||||
move.b (R12)+,R1
|
||||
ext.w R1
|
||||
eor R1,R0
|
||||
and #127,R0
|
||||
beq L11
|
||||
tst.b R6
|
||||
beq L11
|
||||
clr R0
|
||||
bra L7
|
||||
L11:
|
||||
sub #1,R7
|
||||
L9:
|
||||
tst R7
|
||||
bne L10
|
||||
L8:
|
||||
tst.b 17(R14)
|
||||
beq L12
|
||||
cmp.b #63,(R13)
|
||||
beq L13
|
||||
move.b (R13),R0
|
||||
ext.w R0
|
||||
move.b (R12),R1
|
||||
ext.w R1
|
||||
eor R1,R0
|
||||
move.l 8+_gbls,R9
|
||||
move.b 4(R9),R1
|
||||
ext.w R1
|
||||
not.b R1
|
||||
and R1,R0
|
||||
beq L13
|
||||
clr R0
|
||||
bra L7
|
||||
L13:
|
||||
add.l #2,R13
|
||||
add.l #2,R12
|
||||
move.b (R13),R0
|
||||
ext.w R0
|
||||
move.b (R12),R1
|
||||
ext.w R1
|
||||
eor R1,R0
|
||||
and #63,R0
|
||||
beq L14
|
||||
clr R0
|
||||
bra L7
|
||||
L14:L12:
|
||||
move #1,R0
|
||||
bra L7
|
||||
L7:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R12-R13
|
||||
unlk R14
|
||||
rts
|
||||
.globl _openfile
|
||||
.text
|
||||
_openfile:
|
||||
~~openfile:
|
||||
~fcb_ext=R7
|
||||
~dirindx=16
|
||||
~rtn=R6
|
||||
~fcbp=R13
|
||||
~dirp=12
|
||||
link R14,#0
|
||||
movem.l R5-R7/R13-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move #1,(sp)
|
||||
move.l 12(R14),-(sp)
|
||||
move.l R13,-(sp)
|
||||
jsr _match
|
||||
add #8,sp
|
||||
move.b R0,R6
|
||||
beq L16
|
||||
move.b 12(R13),R7
|
||||
move #32,(sp)
|
||||
move.l R13,-(sp)
|
||||
move.l 12(R14),-(sp)
|
||||
jsr _move
|
||||
add #8,sp
|
||||
move.b R7,12(R13)
|
||||
L16:
|
||||
move.b R6,R0
|
||||
ext.w R0
|
||||
bra L15
|
||||
L15:tst.l (sp)+
|
||||
movem.l (sp)+,R6-R7/R13-R13
|
||||
unlk R14
|
||||
rts
|
||||
.data
|
||||
67
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/iosys.c
Normal file
67
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/iosys.c
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
/****************************************************************
|
||||
* *
|
||||
* CP/M-68K BDOS Disk I/O System Module *
|
||||
* *
|
||||
* This module translates from the packet oriented I/O *
|
||||
* passed from the other BDOS modules into BIOS calls. *
|
||||
* *
|
||||
* It includes only one external entry point:
|
||||
* do_phio() - do physical i/o *
|
||||
* *
|
||||
* *
|
||||
* Configured for Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include "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 */
|
||||
|
||||
{
|
||||
REG struct dph *hdrp; /* pointer to disk parameter header */
|
||||
REG struct dpb *dparmp; /* pointer to disk parameter block */
|
||||
struct
|
||||
{ /* structure for results of external divide */
|
||||
UWORD iotrk;
|
||||
UWORD iosect;
|
||||
} iopdiv;
|
||||
|
||||
LOCK /* lock the disk system while doing physical i/o */
|
||||
|
||||
switch (iop->iofcn)
|
||||
{
|
||||
case sel_info:
|
||||
iop->infop = bseldsk(iop->devnum, iop->ioflags);
|
||||
break;
|
||||
|
||||
case read:
|
||||
hdrp = iop->infop;
|
||||
dparmp = hdrp->dpbp;
|
||||
udiv( iop->devadr, dparmp->spt, &iopdiv );
|
||||
bsettrk( iopdiv.iotrk + dparmp->trk_off );
|
||||
bsetsec( bsectrn( iopdiv.iosect, hdrp->xlt ) );
|
||||
bsetdma(iop->xferadr);
|
||||
return(bread());
|
||||
|
||||
}
|
||||
|
||||
UNLOCK
|
||||
return(0);
|
||||
}
|
||||
77
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/iosys.s
Normal file
77
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/iosys.s
Normal file
@@ -0,0 +1,77 @@
|
||||
.globl _bios1
|
||||
.globl _bios2
|
||||
.globl _bios3
|
||||
.globl _bios4
|
||||
.globl _bios5
|
||||
.globl _udiv
|
||||
.globl _do_phio
|
||||
.text
|
||||
_do_phio:
|
||||
~~do_phio:
|
||||
~dparmp=R11
|
||||
~iopdiv=-4
|
||||
~iop=R13
|
||||
~hdrp=R12
|
||||
link R14,#-4
|
||||
movem.l R7-R7/R11-R13,-(sp)
|
||||
move.l 8(R14),R13
|
||||
move.b (R13),R0
|
||||
ext.w R0
|
||||
bra L3
|
||||
L4:
|
||||
move.b 1(R13),R0
|
||||
ext.w R0
|
||||
move R0,(sp)
|
||||
move.b 3(R13),R0
|
||||
ext.w R0
|
||||
move R0,-(sp)
|
||||
move #9,-(sp)
|
||||
jsr _bios4
|
||||
add #4,sp
|
||||
move.l R0,14(R13)
|
||||
bra L2
|
||||
L5:
|
||||
move.l 14(R13),R12
|
||||
move.l 14(R12),R11
|
||||
move.l R14,(sp)
|
||||
sub.l #4,(sp)
|
||||
move (R11),-(sp)
|
||||
move.l 4(R13),-(sp)
|
||||
jsr _udiv
|
||||
add #6,sp
|
||||
move -4(R14),(sp)
|
||||
move 14(R11),R0
|
||||
add R0,(sp)
|
||||
move #10,-(sp)
|
||||
jsr _bios2
|
||||
add #2,sp
|
||||
move.l (R12),(sp)
|
||||
move -2(R14),-(sp)
|
||||
move #16,-(sp)
|
||||
jsr _bios5
|
||||
add #4,sp
|
||||
move R0,(sp)
|
||||
move #11,-(sp)
|
||||
jsr _bios2
|
||||
add #2,sp
|
||||
move.l 10(R13),(sp)
|
||||
move #12,-(sp)
|
||||
jsr _bios3
|
||||
add #2,sp
|
||||
move #13,(sp)
|
||||
jsr _bios1
|
||||
bra L1
|
||||
bra L2
|
||||
L3:tst R0
|
||||
beq L4
|
||||
cmp #1,R0
|
||||
beq L5
|
||||
bra L2
|
||||
L2:
|
||||
clr R0
|
||||
bra L1
|
||||
L1:tst.l (sp)+
|
||||
movem.l (sp)+,R11-R13
|
||||
unlk R14
|
||||
rts
|
||||
.data
|
||||
@@ -0,0 +1,7 @@
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ ld68 :== $bin:lo68
|
||||
$ ld68 -T900 -o cpmldr.68k ldrif.o cpmldr.o bdosif.o dskutil.o fileio.o -
|
||||
bdosread.o bdosmain.o iosys.o ldrbios.o
|
||||
$ nm68 cpmldr.68k >cpmldr.sym
|
||||
288
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/ldrbios.s
Normal file
288
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/ldrbios.s
Normal file
@@ -0,0 +1,288 @@
|
||||
*****************************************************************
|
||||
* *
|
||||
* CP/M-68K Loader BIOS *
|
||||
* Basic Input/Output Subsystem *
|
||||
* For ERG 68000 with Tarbell floppy disk controller *
|
||||
* *
|
||||
*****************************************************************
|
||||
|
||||
|
||||
.globl _bios * declare external entry point
|
||||
|
||||
|
||||
_bios:
|
||||
cmpi #nfuncs,d0
|
||||
bge nogood
|
||||
lsl #2,d0 * multiply bios function by 4
|
||||
movea.l 6(pc,d0),a0 * get handler address
|
||||
jsr (a0) * call handler
|
||||
nogood:
|
||||
rts
|
||||
|
||||
biosbase:
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l constat
|
||||
.dc.l conin
|
||||
.dc.l conout
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l home
|
||||
.dc.l seldsk
|
||||
.dc.l settrk
|
||||
.dc.l setsec
|
||||
.dc.l setdma
|
||||
.dc.l read
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l sectran
|
||||
.dc.l setdma
|
||||
.dc.l getseg
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l nogood
|
||||
.dc.l setexc
|
||||
|
||||
nfuncs=(*-biosbase)/4
|
||||
|
||||
|
||||
constat: move.b $ffff01,d0 * get status byte
|
||||
andi.w #2,d0 * data available bit on?
|
||||
beq noton * branch if not
|
||||
moveq.l #$1,d0 * set result to true
|
||||
rts
|
||||
|
||||
noton: clr.l d0 * set result to false
|
||||
rts
|
||||
|
||||
conin: bsr constat * see if key pressed
|
||||
tst d0
|
||||
beq conin * wait until key pressed
|
||||
move.b $ffff00,d0 * get key
|
||||
and.l #$7f,d0 * clear all but low 7 bits
|
||||
rts
|
||||
|
||||
conout: move.b $ffff01,d0 * get status
|
||||
and.b #$1,d0 * check for transmitter buffer empty
|
||||
beq conout * wait until our port has aged...
|
||||
move.b d1,$ffff00 * and output it
|
||||
rts * and exit
|
||||
|
||||
|
||||
*
|
||||
* Disk Handlers for Tarbell 1793 floppy disk controller
|
||||
*
|
||||
maxdsk = 2 * this BIOS supports 2 floppy drives
|
||||
dphlen = 26 * length of disk parameter header
|
||||
|
||||
iobase = $00fffff8 * Tarbell floppy disk port base address
|
||||
dcmd = iobase * output port for command
|
||||
dstat = iobase * input status port
|
||||
dtrk = iobase+1 * disk track port
|
||||
dsect = iobase+2 * disk sector port
|
||||
ddata = iobase+3 * disk data port
|
||||
dwait = iobase+4 * input port to wait for op finished
|
||||
dcntrl = iobase+4 * output control port for drive selection
|
||||
|
||||
|
||||
home: clr.b track
|
||||
rts
|
||||
|
||||
seldsk:
|
||||
* select disk A
|
||||
clr.b seldrv * select drive A
|
||||
clr.b selcode * select code is 00 for drv 0, $10 for drv 1
|
||||
move.l #dph0,d0
|
||||
selrtn: rts
|
||||
|
||||
settrk: move.b d1,track
|
||||
rts
|
||||
|
||||
setsec: move.b d1,sector
|
||||
rts
|
||||
|
||||
sectran:
|
||||
* translate sector in d1 with translate table pointed to by d2
|
||||
* result in d0
|
||||
movea.l d2,a0
|
||||
ext.l d1
|
||||
move.b #0(a0,d1),d0
|
||||
ext.l d0
|
||||
rts
|
||||
|
||||
setdma:
|
||||
move.l d1,dma
|
||||
rts
|
||||
|
||||
read:
|
||||
* Read one sector from requested disk, track, sector to dma address
|
||||
* Retry if necessary, return in d0 00 if ok, else non-zero
|
||||
move.b #10,errcnt * set up retry counter
|
||||
rretry:
|
||||
bsr setup
|
||||
ori #$88,d3 * OR read command with head load bit
|
||||
move.b d3,dcmd * output it to FDC
|
||||
rloop: btst #7,dwait
|
||||
beq rdone * if end of read, exit
|
||||
move.b ddata,(a0)+ * else, move next byte of data
|
||||
bra rloop
|
||||
rdone:
|
||||
bsr rstatus * get FDC status
|
||||
bne rerror
|
||||
clr.l d0
|
||||
rts
|
||||
rerror: bsr errchk * go to error handler
|
||||
subq.b #1,errcnt
|
||||
bne rretry
|
||||
move.l #$ffffffff,d0
|
||||
rts
|
||||
|
||||
|
||||
setup:
|
||||
* common read and write setup code
|
||||
* select disk, set track, set sector were all deferred until now
|
||||
move.b #$d0,dcmd * clear controller, get status
|
||||
move.b curdrv,d3
|
||||
cmp.b seldrv,d3
|
||||
bne newdrive * if drive not selected, do it
|
||||
move.b track,d3
|
||||
cmp.b oldtrk,d3
|
||||
bne newtrk * if not on right track, do it
|
||||
clr.l d3 * if head already loaded, no head load delay
|
||||
btst #5,dstat * if head unloaded, treat as new disk
|
||||
bne sexit
|
||||
newdrive:
|
||||
move.b selcode,dcntrl * select the drive
|
||||
move.b seldrv,curdrv
|
||||
newtrk:
|
||||
bsr chkseek * seek to correct track if required
|
||||
moveq #4,d3 * force head load delay
|
||||
sexit:
|
||||
move.b sector,dsect * set up sector number
|
||||
move.b track,dtrk * set up track number
|
||||
move.l dma,a0 * dma address to a0
|
||||
rts
|
||||
|
||||
errchk:
|
||||
btst.b #4,d7
|
||||
bne chkseek * if record not found error, reseek
|
||||
rts
|
||||
|
||||
chkseek:
|
||||
* check for correct track, seek if necessary
|
||||
bsr readid * find out what track we're on
|
||||
beq chks1 * if read id ok, skip restore code
|
||||
restore:
|
||||
* home the drive and reseek to correct track
|
||||
move.b #$0B,dcmd * restore command to command port
|
||||
rstwait:
|
||||
btst #7,dwait
|
||||
bne rstwait * loop until restore completed
|
||||
btst #2,dstat
|
||||
beq restore * if not at track 0, try again
|
||||
clr.l d3 * track number returned in d3 from readid
|
||||
chks1:
|
||||
move.b d3,dtrk * update track register in FDC
|
||||
move.b track,oldtrk * update oldtrk
|
||||
cmp.b track,d3 * are we at right track?
|
||||
beq chkdone * if yes, exit
|
||||
move.b track,ddata * else, put desired track in data reg of FDC
|
||||
move.b #$18,dcmd * and issue a seek command
|
||||
chks2: btst #7,dwait
|
||||
bne chks2 * loop until seek complete
|
||||
move.b dstat,d3 * read status to clear FDC
|
||||
chkdone:
|
||||
rts
|
||||
|
||||
readid:
|
||||
* read track id, return track number in d3
|
||||
move.b #$c4,dcmd * issue read id command
|
||||
move.b dwait,d7 * wait for intrq
|
||||
move.b ddata,d3 * track byte to d3
|
||||
rid2:
|
||||
btst #7,dwait
|
||||
beq rstatus * wait for intrq
|
||||
move.b ddata,d7 * read another byte
|
||||
bra rid2 * and loop
|
||||
rstatus:
|
||||
move.b dstat,d7
|
||||
andi.b #$9d,d7 * set condition codes
|
||||
rts
|
||||
|
||||
|
||||
getseg:
|
||||
move.l #memrgn,d0 * return address of mem region table
|
||||
rts
|
||||
|
||||
|
||||
setexc:
|
||||
andi.l #$ff,d1 * do only for exceptions 0 - 255
|
||||
lsl #2,d1 * multiply exception number by 4
|
||||
movea.l d1,a0
|
||||
move.l (a0),d0 * return old vector value
|
||||
move.l d2,(a0) * insert new vector
|
||||
rts
|
||||
|
||||
|
||||
.data
|
||||
|
||||
seldrv: .dc.b $ff * drive requested by seldsk
|
||||
curdrv: .dc.b $ff * currently selected drive
|
||||
|
||||
track: .dc.b 0 * track requested by settrk
|
||||
oldtrk: .dc.b 0 * track we were on
|
||||
|
||||
sector: .dc.w 0
|
||||
dma: .dc.l 0
|
||||
selcode: .dc.b 0 * drive select code
|
||||
|
||||
errcnt: .dc.b 10 * retry counter
|
||||
|
||||
memrgn: .dc.w 1 * 1 memory region
|
||||
.dc.l $18000 * load the system at 18000 hex
|
||||
.dc.l $8000
|
||||
|
||||
|
||||
* disk parameter headers
|
||||
|
||||
dph0: .dc.l xlt
|
||||
.dc.w 0 * dummy
|
||||
.dc.w 0
|
||||
.dc.w 0
|
||||
.dc.l dirbuf * ptr to directory buffer
|
||||
.dc.l dpb * ptr to disk parameter block
|
||||
.dc.l 0 * ptr to check vector
|
||||
.dc.l 0 * ptr to allocation vector
|
||||
|
||||
|
||||
* disk parameter block
|
||||
|
||||
dpb: .dc.w 26 * sectors per track
|
||||
.dc.b 3 * block shift
|
||||
.dc.b 7 * block mask
|
||||
.dc.b 0 * extent mask
|
||||
.dc.b 0 * dummy fill
|
||||
.dc.w 242 * disk size
|
||||
.dc.w 63 * 64 directory entries
|
||||
.dc.w $c000 * directory mask
|
||||
.dc.w 16 * directory check size
|
||||
.dc.w 2 * track offset
|
||||
|
||||
* sector translate table
|
||||
|
||||
xlt: .dc.b 1, 7,13,19
|
||||
.dc.b 25, 5,11,17
|
||||
.dc.b 23, 3, 9,15
|
||||
.dc.b 21, 2, 8,14
|
||||
.dc.b 20,26, 6,12
|
||||
.dc.b 18,24, 4,10
|
||||
.dc.b 16,22
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
dirbuf: .ds.b 128 * directory buffer
|
||||
|
||||
|
||||
.end
|
||||
44
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/ldrif.s
Normal file
44
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/ldrif.s
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
*****************************************
|
||||
* Assembly Language Interface Routine *
|
||||
* for the CP/M-68K loader, cpmldr *
|
||||
* *
|
||||
* It has one entry point: _startld *
|
||||
* It sets up the stack and jumps to *
|
||||
* _ldcpm *
|
||||
*****************************************
|
||||
|
||||
.globl _startld * public entry point
|
||||
.globl ldr * label for library search
|
||||
|
||||
.globl _bios * external references
|
||||
.globl _ldcpm
|
||||
|
||||
.text
|
||||
|
||||
ldr:
|
||||
_startld:
|
||||
lea stack,sp
|
||||
clr.l d0
|
||||
jsr _bios * init the BIOS
|
||||
move #22,d0
|
||||
move #8,d1
|
||||
move.l #privexc,d2
|
||||
jsr _bios * set exception for privilege violation
|
||||
ori #$2000,sr * set supervisor state
|
||||
* if in user mode, will generate priv violation
|
||||
lea stack,sp
|
||||
bra _ldcpm
|
||||
|
||||
|
||||
privexc:
|
||||
ori.w #$2000,(sp)
|
||||
rte
|
||||
|
||||
|
||||
.bss
|
||||
|
||||
.ds.l 256
|
||||
stack: .ds.w 1
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ ld68 :== $bin:lo68
|
||||
$ ld68 -T900 -o sysgen.68k lib:startup.o sysgen.o lib:clib68.a
|
||||
$ nm68 sysgen.68k >sysgen.sym
|
||||
@@ -0,0 +1,8 @@
|
||||
$ set nover
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ cc68 :== @[bobh]cc68.com
|
||||
$ as68 :== $bin:as68.exe
|
||||
$ ld68 :== $bin:lo68.exe
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ cc68 bdosmain
|
||||
@@ -0,0 +1,15 @@
|
||||
$ set def [cpm68k.release.boot]
|
||||
$ set noon
|
||||
$ cc68 bdosmain
|
||||
$ cc68 bdosread
|
||||
$ cc68 cpmldr
|
||||
$ cc68 dskutil
|
||||
$ cc68 fileio
|
||||
$ cc68 iosys
|
||||
$ as68 -l -u bdosif.s
|
||||
$ as68 -l -u booter.s
|
||||
$ as68 -l -u ldrif.s
|
||||
$ del ldrlib.;*
|
||||
$ ar68 rv ldrlib ldrif.o cpmldr.o bdosif.o dskutil.o fileio.o bdosread.o
|
||||
$ ar68 rv ldrlib bdosmain.o iosys.o
|
||||
$ lo68 -t0 -o exorboot.68k -uldr booter.o ldrlib ldbios.o ldbiosa.o
|
||||
@@ -0,0 +1,6 @@
|
||||
$ cc68s bdosmain
|
||||
$ cc68s bdosread
|
||||
$ cc68s cpmldr
|
||||
$ cc68s dskutil
|
||||
$ cc68s fileio
|
||||
$ cc68s iosys
|
||||
57
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/pktio.h
Normal file
57
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/pktio.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/********************************************************
|
||||
* *
|
||||
* CP/M-68K header file *
|
||||
* Copyright (c) 1982 by Digital Research, Inc. *
|
||||
* Structure definitions for doing I/O in packets *
|
||||
* *
|
||||
********************************************************/
|
||||
|
||||
/* May use this information structure instead of disk parameter header and
|
||||
disk parameter block in future, but for now it's unused
|
||||
struct dskinfo
|
||||
{
|
||||
UBYTE *dbuffp;
|
||||
UBYTE *csv;
|
||||
UBYTE *alv;
|
||||
UBYTE blksize;
|
||||
UBYTE didummy;
|
||||
UWORD dskmax;
|
||||
UWORD dirmax;
|
||||
UWORD chksize;
|
||||
};
|
||||
*/
|
||||
|
||||
struct iopb
|
||||
{
|
||||
UBYTE iofcn; /* function number, see defines below */
|
||||
UBYTE ioflags; /* used for login flag and write flag */
|
||||
UBYTE devtype; /* device type, see defines below */
|
||||
/* currently unused */
|
||||
UBYTE devnum; /* device number, or, devtype and devnum
|
||||
taken together form int device number */
|
||||
LONG devadr; /* item nmbr on device to start xfer at */
|
||||
/* note -- item is sector for disks, byte for char devs */
|
||||
UWORD xferlen; /* number items to transfer */
|
||||
UBYTE *xferadr; /* memory address to xfer to/from */
|
||||
struct dph *infop; /* pointer to disk parameter header */
|
||||
/* return parm for fcn 0, input for rest */
|
||||
};
|
||||
|
||||
|
||||
/* Definitions for iofcn, the function number */
|
||||
#define sel_info 0 /* select and return info on device */
|
||||
#define read 1
|
||||
#define write 2
|
||||
#define flush 3
|
||||
#define status 4 /* not currently used */
|
||||
|
||||
|
||||
/* Definitions for devtype, the device type */
|
||||
/* This field not currently used */
|
||||
#define console 0
|
||||
#define printer 1
|
||||
#define disk 2
|
||||
#define memory 3 /* gets TPA boundaries */
|
||||
#define redir 4 /* read/write IOByte */
|
||||
#define exc_vec 5 /* set exception vector */
|
||||
|
||||
194
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/putboot.s
Normal file
194
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/putboot.s
Normal file
@@ -0,0 +1,194 @@
|
||||
*********************************************************
|
||||
* *
|
||||
* Program to Write Boot Tracks for CP/M-68K (tm) *
|
||||
* *
|
||||
* Copyright Digital Research 1982 *
|
||||
* *
|
||||
*********************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
prntstr = 9 BDOS Functions
|
||||
dseldsk = 14
|
||||
open = 15
|
||||
readseq = 20
|
||||
dsetdma = 26
|
||||
*
|
||||
seldsk = 9 BIOS Functions
|
||||
settrk = 10
|
||||
setsec = 11
|
||||
isetdma = 12
|
||||
write = 14
|
||||
sectran = 16
|
||||
flush = 21
|
||||
*
|
||||
bufcnt = $80
|
||||
bufsize = $80*bufcnt
|
||||
*
|
||||
.text
|
||||
*
|
||||
start: link a6,#0
|
||||
move.l 8(a6),a0 base page address
|
||||
lea $5c(a0),a1
|
||||
move.l a1,fcb
|
||||
clr.b hflag
|
||||
add #$81,a0 first character of command tail
|
||||
scan: cmpi.b #$20,(a0)+ skip over blanks
|
||||
beq scan
|
||||
sub.l #1,a0
|
||||
scan1: tst.b (a0)
|
||||
beq erxit
|
||||
cmpi.b #$2d,(a0)+ check for -H flag
|
||||
bne nohyph
|
||||
cmpi.b #$48,(a0)+
|
||||
bne erxit
|
||||
tst.b hflag
|
||||
bne erxit
|
||||
move.b #$ff,hflag
|
||||
sub.l #$24,fcb change to 2nd default fcb
|
||||
bra scan
|
||||
nohyph: cmpi.b #$20,(a0)
|
||||
bne scan1
|
||||
scan2: cmpi.b #$20,(a0)+
|
||||
beq scan2
|
||||
cmpi.b #$61,-(a0) get disk letter
|
||||
blt upper upshift
|
||||
sub #$20,(a0)
|
||||
upper: cmpi.b #$41,(a0) compare with range A - P
|
||||
blt erxit
|
||||
cmpi.b #$50,(a0)
|
||||
bgt erxit
|
||||
move.b (a0),d0
|
||||
ext.w d0 put disk letter into range 0 - 15
|
||||
sub.w #$41,d0
|
||||
move.w d0,dsk
|
||||
*
|
||||
* open file to copy
|
||||
*
|
||||
move.w #open,d0
|
||||
move.l fcb,d1
|
||||
trap #2
|
||||
cmpi.w #$00ff,d0
|
||||
bne openok
|
||||
move.l #opnfl,d1
|
||||
jmp erx
|
||||
openok: move.l fcb,a0
|
||||
clr.b 32(a0)
|
||||
*
|
||||
* read
|
||||
*
|
||||
move.l #buf,d2
|
||||
clr.w count
|
||||
rloop: move.w #dsetdma,d0
|
||||
move.l d2,d1
|
||||
trap #2
|
||||
move.w #readseq,d0
|
||||
move.l fcb,d1
|
||||
trap #2
|
||||
tst.w d0
|
||||
bne wrtout
|
||||
add.l #128,d2
|
||||
add.w #1,count
|
||||
cmpi.w #bufcnt,count
|
||||
bgt bufoflx
|
||||
bra rloop
|
||||
*
|
||||
* write
|
||||
*
|
||||
wrtout: move.w #seldsk,d0 select the disk
|
||||
move.w dsk,d1
|
||||
clr.b d2
|
||||
trap #3
|
||||
tst.l d0 check for select error
|
||||
beq selerx
|
||||
move.l d0,a0
|
||||
move.l 14(a0),a0 get DPB address
|
||||
move.w (a0),spt get sectors per track
|
||||
move.w 14(a0),off get offset
|
||||
clr.w trk start at trk 0
|
||||
move.w #1,sect start at sector 1
|
||||
lea buf,a0
|
||||
tst.b hflag
|
||||
bne wrt1
|
||||
cmpi.w #$601a,(a0)
|
||||
bne wrt1
|
||||
add.l #28,a0
|
||||
wrt1: move.l a0,bufp
|
||||
*
|
||||
wloop: tst.w count
|
||||
beq exit
|
||||
move.w sect,d1 check for end-of-track
|
||||
cmp.w spt,d1
|
||||
ble sok
|
||||
move.w #1,sect advance to new track
|
||||
move.w trk,d0
|
||||
add.w #1,d0
|
||||
move.w d0,trk
|
||||
cmp.w off,d0
|
||||
bge oflex
|
||||
sok: move.w #settrk,d0 set the track
|
||||
move.w trk,d1
|
||||
trap #3
|
||||
move.w sect,d1 set sector
|
||||
move.w #setsec,d0
|
||||
trap #3
|
||||
move.w #isetdma,d0 set up dma address for write
|
||||
move.l bufp,d1
|
||||
trap #3
|
||||
move.w #write,d0 and write
|
||||
clr.w d1
|
||||
trap #3
|
||||
tst.w d0 check for write error
|
||||
bne wrterx
|
||||
add #1,sect increment sector number
|
||||
sub #1,count
|
||||
add.l #128,bufp
|
||||
bra wloop
|
||||
*
|
||||
exit: move.w #flush,d0 exit location - flush bios buffers
|
||||
trap #3
|
||||
unlk a6
|
||||
rts and exit to CCP
|
||||
*
|
||||
erxit: move.l #erstr,d1 miscellaneous errors
|
||||
erx: move.w #prntstr,d0 print error message and exit
|
||||
trap #2
|
||||
bra exit
|
||||
*
|
||||
selerx: move.l #selstr,d1 disk select error
|
||||
bra erx
|
||||
wrterx: move.l #wrtstr,d1 disk write error
|
||||
bra erx
|
||||
bufoflx: move.l #bufofl,d1 buffer overflow
|
||||
bra erx
|
||||
oflex: move.l #trkofl,d1
|
||||
bra erx
|
||||
*
|
||||
*
|
||||
.bss
|
||||
*
|
||||
.even
|
||||
*
|
||||
buf: .ds.b bufsize+128
|
||||
*
|
||||
fcb: .ds.l 1 fcb address
|
||||
spt: .ds.w 1 sectors per track
|
||||
sect: .ds.w 1 current sector
|
||||
trk: .ds.w 1 current track
|
||||
dsk: .ds.w 1 selected disk
|
||||
off: .ds.w 1 1st track of non-boot area
|
||||
count: .ds.w 1
|
||||
bufp: .ds.l 1
|
||||
hflag: .ds.b 1
|
||||
*
|
||||
.data
|
||||
*
|
||||
erstr: .dc.b 'Invalid Command Line',13,10,'$'
|
||||
selstr: .dc.b 'Select Error',13,10,'$'
|
||||
wrtstr: .dc.b 'Write Error',13,10,'$'
|
||||
opnfl: .dc.b 'Cannot Open Source File',13,10,'$'
|
||||
bufofl: .dc.b 'Buffer Overflow',13,10,'$'
|
||||
trkofl: .dc.b 'Too Much Data for System Tracks',13,10,'$'
|
||||
*
|
||||
*
|
||||
.end
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set def [cpm68k.release.boot]
|
||||
$ set noon
|
||||
$ del ldrlib.;*
|
||||
$ ar68 rv ldrlib ldrif.o cpmldr.o bdosif.o fileio.o
|
||||
$ ar68 rv ldrlib bdosmain.o bdosread.o iosys.o dskutil.o
|
||||
$ lo68 -t0 -o exorboot.68k -uldr booter.o ldrlib ldbios.o ldbiosa.o
|
||||
68
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/stdio.h
Normal file
68
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/stdio.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* C P / M C H E A D E R F I L E
|
||||
* -----------------------------------
|
||||
* Copyright 1982 by Digital Research Inc. All rights reserved.
|
||||
*
|
||||
* This is an include file for assisting the user to write portable
|
||||
* programs for C.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ALCYON 1 /* using Alcyon compiler */
|
||||
/*
|
||||
* Standard type definitions
|
||||
*/
|
||||
/***************************/
|
||||
#define BYTE 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
|
||||
#define UBWORD(a) ((UWORD)a & 0xff)
|
||||
/* Unsigned byte to word cast */
|
||||
#else
|
||||
#define UBYTE unsigned char /* Unsigned byte */
|
||||
#define UBWORD(a) (UWORD)a
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* Miscellaneous Definitions: */
|
||||
/****************************************************************************/
|
||||
#define FAILURE (-1) /* Function failure return val */
|
||||
#define SUCCESS (0) /* Function success return val */
|
||||
#define YES 1 /* "TRUE" */
|
||||
#define NO 0 /* "FALSE" */
|
||||
#define FOREVER for(;;) /* Infinite loop declaration */
|
||||
#define NULL (BYTE *)0 /* Null pointer value */
|
||||
#define EOF (-1) /* EOF Value */
|
||||
#define TRUE (1) /* Function TRUE value */
|
||||
#define FALSE (0) /* Function FALSE value */
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* M A C R O S */
|
||||
/* ----------- */
|
||||
/* */
|
||||
/* Define some stuff as macros .... */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x)) /* Absolute value function */
|
||||
|
||||
#define max(x,y) (((x) > (y)) ? (x) : (y)) /* Max function */
|
||||
#define min(x,y) (((x) < (y)) ? (x) : (y)) /* Min function */
|
||||
|
||||
/*************************** end of stdio.h *********************************/
|
||||
346
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/sysgen.c
Normal file
346
CPM OPERATING SYSTEMS/CPM 68K/1.0X SOURCES/v101/boot/sysgen.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/****************************************************************
|
||||
* *
|
||||
* SYSGEN *
|
||||
* *
|
||||
* This is a stand-alone system generation program for *
|
||||
* CP/M-68K, very similar to the traditional Sysgen on *
|
||||
* CP/M-80. It has two modes of operation: if invoked *
|
||||
* without a command tail (i.e., A>SYSGEN ), it gets and *
|
||||
* puts system tracks (with prompts, just as Sysgen on the *
|
||||
* 8080). If the user types a command tail of a string *
|
||||
* of filenames, SYSGEN concatenates those files and *
|
||||
* allows the user to put the result on the system tracks *
|
||||
* In the file concatenation mode, SYSGEN will detect if *
|
||||
* a file is a CP/M-68K executable file, and if so, will *
|
||||
* "strip" it (remove the header, symbol table, and *
|
||||
* relocation bits) *
|
||||
* *
|
||||
* Configured for Alcyon C on the VAX *
|
||||
* *
|
||||
****************************************************************/
|
||||
|
||||
#include <stdio.h> /* Standard I/O declarations */
|
||||
|
||||
#define SECLEN 128 /* CP/M sector length */
|
||||
#define BUFSIZE 16384 /* size of internal buffer */
|
||||
/* make it long enough to hold the system */
|
||||
#define sectoff 1 /* 0 for sectors 0 .. n-1 */
|
||||
/* 1 for sectors 1 .. n */
|
||||
#define skew 1 /* currently not used */
|
||||
|
||||
|
||||
/* Declare EXTERN functions */
|
||||
|
||||
EXTERN printf(); /* formatted print */
|
||||
EXTERN LONG __BDOS(); /* direct call to BDOS */
|
||||
EXTERN WORD open(); /* open file */
|
||||
EXTERN WORD read(); /* read file */
|
||||
EXTERN LONG lseek(); /* long seek */
|
||||
|
||||
|
||||
/* Define the data structures used in sysgen */
|
||||
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 */
|
||||
};
|
||||
|
||||
struct bpb
|
||||
{ /* BIOS parameter block */
|
||||
WORD d0;
|
||||
LONG d1;
|
||||
LONG d2;
|
||||
};
|
||||
|
||||
|
||||
/*******************/
|
||||
/* error routine */
|
||||
/*******************/
|
||||
|
||||
error(num)
|
||||
WORD num;
|
||||
{
|
||||
switch (num)
|
||||
{
|
||||
case 0: printf("\nDisk read error");
|
||||
break;
|
||||
|
||||
case 1: printf("\nDisk write error");
|
||||
break;
|
||||
|
||||
case 2: printf("\nFile read error");
|
||||
break;
|
||||
|
||||
case 3: printf("\nBuffer overflow");
|
||||
break;
|
||||
}
|
||||
__BDOS(0);
|
||||
}
|
||||
|
||||
|
||||
/******************/
|
||||
/* BIOS callers */
|
||||
/******************/
|
||||
|
||||
/* First define function numbers */
|
||||
#define biosf 50
|
||||
#define seldskf 9
|
||||
#define settrkf 10
|
||||
#define setsecf 11
|
||||
#define setdmaf 12
|
||||
#define readf 13
|
||||
#define writef 14
|
||||
|
||||
BYTE *seldsk(dsk)
|
||||
WORD dsk;
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = seldskf;
|
||||
b.d1 = (LONG)dsk;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
settrk(trk)
|
||||
WORD trk;
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = settrkf;
|
||||
b.d1 = (LONG)trk;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
setsec(sec)
|
||||
WORD sec;
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = setsecf;
|
||||
b.d1 = (LONG)sec;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
setdma(p)
|
||||
BYTE *p;
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = setdmaf;
|
||||
b.d1 = (LONG)p;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
WORD b_read()
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = readf;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
WORD b_write()
|
||||
{
|
||||
struct bpb b;
|
||||
|
||||
b.d0 = writef;
|
||||
b.d1 = (LONG)0;
|
||||
return( __BDOS(biosf, &b) );
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* prompt for disk */
|
||||
/*********************/
|
||||
|
||||
struct dpb *getdsk(msg)
|
||||
BYTE *msg;
|
||||
{
|
||||
REG WORD ch;
|
||||
REG struct dph *dphp;
|
||||
|
||||
do
|
||||
{
|
||||
printf(msg);
|
||||
printf(" (A - P)\nor <return> to reboot ");
|
||||
ch = __BDOS(1);
|
||||
if (ch == '\r') __BDOS(0);
|
||||
if ('A' <= ch && ch <= 'P') ch -= 'A';
|
||||
else if ('a' <= ch && ch <= 'p') ch -= 'a';
|
||||
else ch = -1;
|
||||
} while (ch < 0);
|
||||
if ( (dphp = seldsk(ch)) == NULL) error(0);
|
||||
return(dphp->dpbp);
|
||||
}
|
||||
|
||||
/******************************/
|
||||
/* print completion message */
|
||||
/******************************/
|
||||
|
||||
prt_done()
|
||||
{
|
||||
printf("\nFunction Complete");
|
||||
}
|
||||
|
||||
|
||||
/*******************************/
|
||||
/* Get system tracks routine */
|
||||
/*******************************/
|
||||
|
||||
WORD getsys(p, parmp)
|
||||
|
||||
REG BYTE *p; /* pointer to buffer */
|
||||
REG struct dpb *parmp; /* pointer to disk parm block */
|
||||
{
|
||||
REG WORD nb; /* number bytes in buffer */
|
||||
REG WORD trk, sect;
|
||||
|
||||
trk = nb = 0;
|
||||
do
|
||||
{
|
||||
settrk(trk);
|
||||
sect = 0;
|
||||
do
|
||||
{
|
||||
if (nb > BUFSIZE - SECLEN) error(3); /* buffer overflow */
|
||||
setsec(sect + sectoff);
|
||||
setdma(p);
|
||||
if (b_read()) error(0);
|
||||
sect += 1;
|
||||
p += SECLEN;
|
||||
nb += SECLEN;
|
||||
} while (sect < parmp->spt);
|
||||
trk += 1;
|
||||
} while (trk < parmp->trk_off);
|
||||
return(nb);
|
||||
}
|
||||
|
||||
|
||||
/*******************************/
|
||||
/* Put system tracks routine */
|
||||
/*******************************/
|
||||
|
||||
putsys(p, nbytes, parmp)
|
||||
|
||||
REG BYTE *p; /* pointer to buffer */
|
||||
REG WORD nbytes; /* number bytes to put */
|
||||
REG struct dpb *parmp; /* pointer to disk parm block */
|
||||
{
|
||||
REG WORD trk, sect;
|
||||
|
||||
trk = 0;
|
||||
do
|
||||
{
|
||||
settrk(trk);
|
||||
sect = 0;
|
||||
do
|
||||
{
|
||||
setsec(sect + sectoff);
|
||||
setdma(p);
|
||||
if (b_write(0)) error(1);
|
||||
sect += 1;
|
||||
p += SECLEN;
|
||||
nbytes -= SECLEN;
|
||||
if (nbytes <= 0) return;
|
||||
} while (sect < parmp->spt);
|
||||
trk += 1;
|
||||
} while (trk < parmp->trk_off);
|
||||
}
|
||||
|
||||
|
||||
/******************************/
|
||||
/* Get a File to the Buffer */
|
||||
/******************************/
|
||||
|
||||
getfile(fname, bp, np)
|
||||
|
||||
BYTE *fname; /* name of file */
|
||||
BYTE *bp; /* buffer */
|
||||
WORD *np; /* number of bytes in buffer (passed by reference) */
|
||||
{
|
||||
REG WORD fd; /* file descriptor */
|
||||
REG WORD i;
|
||||
REG WORD rtn;
|
||||
struct
|
||||
{
|
||||
WORD magic; /* magic number */
|
||||
LONG size[5]; /* sizes of code, data, bss, sym tbl, stack */
|
||||
BYTE *tstart; /* start address of text segment */
|
||||
WORD rlbflg; /* relocation bits suppressed flag */
|
||||
} hdr;
|
||||
|
||||
fd = open(fname, 0);
|
||||
if (fd == -1) error(2);
|
||||
if ( read(fd, &hdr, sizeof hdr) != sizeof hdr) error(2);
|
||||
if (hdr.magic == 0x601b) lseek(fd, (sizeof hdr) + 8, 0);
|
||||
if ( (hdr.magic == 0x601a) || (hdr.magic == 0x601b) )
|
||||
{
|
||||
/* CP/M-68K executable file */
|
||||
i = hdr.size[0] + hdr.size[1];
|
||||
if ( *np + i > BUFSIZE) error(3); /* buffer overflow */
|
||||
if (read(fd, bp + *np, i) != i) error(2);
|
||||
*np += i + (WORD)hdr.size[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* miscellaneous binary file */
|
||||
lseek(fd, 0, 0); /* seek to beginning of file */
|
||||
i = BUFSIZE - *np; /* max nmbr bytes we can fit in buffer */
|
||||
if ( i <= 0 ) error(3); /* buffer overflow */
|
||||
rtn = read( fd, bp + *np, i);
|
||||
if (rtn < 0) error(2); /* read error */
|
||||
*np += rtn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
* sysgen main routine *
|
||||
***************************/
|
||||
|
||||
main(argc, argv)
|
||||
|
||||
REG WORD argc; /* number of command line arguments */
|
||||
REG BYTE **argv; /* pointer to array of arguments */
|
||||
{
|
||||
BYTE buff[BUFSIZE]; /* buffer for system */
|
||||
WORD nbytes; /* number of bytes in buff */
|
||||
REG struct dpb *parmp; /* pointer to dpb for selected disk */
|
||||
|
||||
nbytes = 0;
|
||||
if (--argc)
|
||||
while (argc--)
|
||||
getfile( *++argv, buff, &nbytes);
|
||||
else
|
||||
{
|
||||
parmp = getdsk("\nSource Drive?");
|
||||
nbytes = getsys(buff, parmp);
|
||||
prt_done;
|
||||
}
|
||||
while ( TRUE )
|
||||
{
|
||||
parmp = getdsk("\nDestination Drive?");
|
||||
putsys( buff, nbytes, parmp);
|
||||
prt_done;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set nover
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ cc68 :== @[bobh]cc68.com
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ cc68 sysgen
|
||||
@@ -0,0 +1,5 @@
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ ld68 :== $bin:lo68
|
||||
$ ld68 -T800 -o test bdosif.o dskutil.o fileio.o bdosread.o bdosmain.o iosys.o
|
||||
@@ -0,0 +1,6 @@
|
||||
$ set noon
|
||||
$ set def [bobh.cpm68k.boot]
|
||||
$ define SYS$PRINT NOWHERE
|
||||
$ ld68 :== $bin:lo68
|
||||
$ ld68 -T0 -o xldr.68k booter.o ldrif.o cpmldr.o bdosif.o dskutil.o -
|
||||
fileio.o bdosread.o bdosmain.o iosys.o ldrbiosa.o hdbios.o
|
||||
Reference in New Issue
Block a user