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,9 @@
$ set noon
$ as68 -l -u -p BDOSIF.s >BDOSIF.lis
$ as68 -l -u -p CCPBDOS.s >CCPBDOS.lis
$ as68 -l -u -p CCPIF.s >CCPIF.lis
$ as68 -l -u -p CCPLOAD.s >CCPLOAD.lis
$ as68 -l -u -p EXCEPTN.s >EXCEPTN.lis
$ as68 -l -u -p FILETYPS.s >FILETYPS.lis
$ as68 -l -u -p PGMLD.s >PGMLD.lis
$ as68 -l -u -p STACK.s >STACK.lis

View File

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

View File

@@ -0,0 +1,184 @@
1File: BDOSDEF.H Page 1
1
2 /********************************************************
3 * *
4 * CP/M-68K header file *
5 * Copyright (c) 1982 by Digital Research, Inc. *
6 * Structure definitions for BDOS globals *
7 * and BDOS data structures *
8 * *
9 * Desecrated 6-Aug-83 (sw) for type-ahead *
10 * *
11 ********************************************************/
12
13 /**************************************************************************
14 The BDOS data structures, especially those relating to global variables,
15 are structured in a way that hopefully will enable this BDOS, in the future,
16 to easily become a re-entrant multi-tasking file system. Consequently,
17 the BDOS global variables are divided into two classes. Those that are
18 truly global, even in the case of multiple tasks using the file system
19 concurrently, are simply declared as global variables in bdosmain.c.
20 Only a few "globals" are really global in this sense.
21
22 The majority of the "global" variables are actually state variables that
23 relate to the state of the task using the file system. In CP/M-68K, these
24 are "global", since there's only one task, but in a multi-thread model they're
25 not. This type of variables is put into a data structure, with the
26 intention that in the multi-task environment this structure will be based.
27
28 The following declarations take this philosophy into account, and define
29 a simple structure for the single thread environment while leaving the
30 possibilities open for the multi-thread environment.
31 ****************************************************************************/
32
33 #define snglthrd TRUE
34 /* TRUE for single-thread environment
35 FALSE to create based structure for re-entrant model */
36 #if snglthrd
37 #define GBL gbls
38 /* In single thread case, GBL just names
39 the structure */
40 #define BSETUP EXTERN struct stvars gbls;
41 /* and BSETUP defines the extern structure */
42 #endif
43
44 #if ! snglthrd
45 #define GBL (*statep)
46 /* If multi-task, state vars are based */
47 #define BSETUP REG struct stvars *statep; \
48 statep = &gbls;
49 /* set up pointer to state variables */
50 /* This is intended as an example to show the intent */
51 #endif
52
53
54 /* Note that there are a few critical regions in the file system that must
55 execute without interruption. They pertain mostly to the manipulation of
56 the allocation vector. This isn't a problem in a single-thread model, but
57 must be provided for in a multi-tasking file system. Consequently, the
58 primitives LOCK and UNLOCK are defined and used where necessary in the
59 file system. For the single thread model, they are null routines */
1File: BDOSDEF.H Page 2
60
61 #define LOCK /**/
62 #define UNLOCK /**/
63 /* Be sure LOCK and UNLOCK are implemented to allow recursive calls to LOCK.
64 That is, if a process that calls LOCK already owns the lock, let it proceed,
65 but remember that only the outer-most call to UNLOCK really releases the
66 file system. */
67
68
69 #define VERSION 0x2022 /* Version number for CP/M-68K */
70 #define robit 0 /* read-only bit in file type field of fcb */
71 #define arbit 2 /* archive bit in file type field of fcb */
72 #define SECLEN 128 /* length of a CP/M sector */
73
74
75 /* File Control Block definition */
76 struct fcb
77 {
78 UBYTE drvcode; /* 0 = default drive, 1..16 are drives A..P */
79 UBYTE fname[8]; /* File name (ASCII) */
80 UBYTE ftype[3]; /* File type (ASCII) */
81 UBYTE extent; /* Extent number (bits 0..4 used) */
82 UBYTE s1; /* Reserved */
83 UBYTE s2; /* Module field (bits 0..5), write flag (7) */
84 UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
85 union
86 {
87 UBYTE small[16]; /* 16 block numbers of 1 byte */
88 WORD big[8]; /* or 8 block numbers of 1 word */
89 } dskmap;
90 UBYTE cur_rec; /* current record field */
91 UBYTE ran0; /* random record field (3 bytes) */
92 UBYTE ran1;
93 UBYTE ran2;
94 };
95
96
97 /* Declaration of directory entry */
98 struct dirent
99 {
100 UBYTE entry; /* 0 - 15 for user numbers, E5 for empty */
101 /* the rest are reserved */
102 UBYTE fname[8]; /* File name (ASCII) */
103 UBYTE ftype[3]; /* File type (ASCII) */
104 UBYTE extent; /* Extent number (bits 0..4 used) */
105 UBYTE s1; /* Reserved */
106 UBYTE s2; /* Module field (bits 0..5), write flag (7) */
107 UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
108 union
109 {
110 UBYTE small[16]; /* 16 block numbers of 1 byte */
111 WORD big[8]; /* or 8 block numbers of 1 word */
112 } dskmap;
113 };
114
115
116 /* Declaration of disk parameter tables */
117 struct dpb /* disk parameter table */
118 {
1File: BDOSDEF.H Page 3
119 UWORD spt; /* sectors per track */
120 UBYTE bsh; /* block shift factor */
121 UBYTE blm; /* block mask */
122 UBYTE exm; /* extent mask */
123 UBYTE dpbdum; /* dummy byte for fill */
124 UWORD dsm; /* max disk size in blocks */
125 UWORD drm; /* max directory entries */
126 UWORD dir_al; /* initial allocation for dir */
127 UWORD cks; /* number dir sectors to checksum */
128 UWORD trk_off; /* track offset */
129 };
130
131 struct dph /* disk parameter header */
132 {
133 UBYTE *xlt; /* pointer to sector translate table */
134 UWORD hiwater; /* high water mark for this disk */
135 UWORD dum1; /* dummy (unused) */
136 UWORD dum2;
137 UBYTE *dbufp; /* pointer to 128 byte directory buffer */
138 struct dpb *dpbp; /* pointer to disk parameter block */
139 UBYTE *csv; /* pointer to check vector */
140 UBYTE *alv; /* pointer to allocation vector */
141 };
142
143
144 /* Declaration of structure containing "global" state variables */
145 #define TBUFSIZ 126 /*sw # typed-ahead characters */
146 struct stvars
147 {
148 UBYTE kbchar; /* keyboard type-ahead buffer count */
149 UBYTE delim; /* Delimiter for function 9 */
150 BOOLEAN lstecho; /* True if echoing console output to lst: */
151 BOOLEAN echodel; /* Echo char when getting <del> ? */
152 UWORD column; /* CRT column number for expanding tabs */
153 UBYTE *chainp; /* Used for chain to program call */
154 UBYTE curdsk; /* Currently selected disk */
155 UBYTE dfltdsk; /* Default disk (last selected by fcn 14) */
156 UBYTE user; /* Current user number */
157 struct dph *dphp; /* pointer to disk parm hdr for cur disk */
158 struct dirent *dirbufp; /* pointer for directory buff for process */
159 /* stored here so that each process can */
160 /* have a separate dirbuf. */
161 struct dpb *parmp; /* pointer to disk parameter block for cur */
162 /* disk. Stored here to save ref calc */
163 UWORD srchpos; /* position in directory for search next */
164 UBYTE *dmaadr; /* Disk dma address */
165 struct fcb *srchp; /* Pointer to search FCB for function 17 */
166 UBYTE *excvec[18]; /* Array of exception vectors */
167 UBYTE *insptr; /*sw Insertion pointer for typeahead */
168 UBYTE *remptr; /*sw Removal pointer for typeahead */
169 UBYTE t_buff[TBUFSIZ]; /*sw Type-ahead buffer itself */
170 };
171
172
173 /* Console buffer structure declaration */
174 struct conbuf
175 {
176 UBYTE maxlen; /* Maximum length from calling routine */
177 UBYTE retlen; /* Length actually found by BDOS */
1File: BDOSDEF.H Page 4
178 UBYTE cbuf[]; /* Console data */
179 };
180

View File

@@ -0,0 +1,173 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: bdosif.s
1
2 *****************************************************************
3 * *
4 * CP/M-68K Basic Disk Operating System interface module *
5 * For "C" version of CP/M-68K *
6 * *
7 * Copyright (c) 1982 Digital Research, Inc. *
8 * *
9 * Version 0.2 -- September 22, 1982 *
10 * *
11 *****************************************************************
12
13 * Declare Public Routines
14
15 .globl _bios1 * 6 BIOS entry points from BDOS
16 .globl _bios2
17 .globl _bios3
18 .globl _bios4
19 .globl _bios5
20 .globl _bios6
21 .globl _traphnd * trap #2 handler
22 .globl _swap * byte swapper
23 .globl _udiv * unsigned divide routine
24
25 * Declare external routines
26 .globl __bdos * BDOS entry point in bdosmain
27
28 * The following external references were put in just to make sure that all
29 * the BDOS modules were referenced, so we could put them in a library
30 .globl _constat * references conbdos.o
31 .globl _dirscan * references dskutil.o
32 .globl _create * references fileio.o
33 .globl _bdosrw * references bdosrw.o
34
35 biosf = 50
36 setsupf = 62
37
38 _traphnd:
39 *
40 * first save the registers and
41 * check for functions handled by assembly language routines
42 *
43 00000000 0C40003E cmpi #setsupf,d0
44 00000004 672C beq setsup
45 00000006 48E77FFE movem.l d1-d7/a0-a6,-(sp)
46 0000000A 0C400032 cmpi #biosf,d0
47 0000000E 6716 beq bioscall
48 *
49 * function number is passed in D0
50 * byte and word pararmeters are passed in D1.W
51 * address parameters are passed in D1.L
52 *
53 00000010 2F01 move.l d1,-(a7)
54 00000012 3F01 move.w d1,-(a7)
55 00000014 3F00 move.w d0,-(a7)
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: bdosif.s
56 00000016 4EB900000000 jsr __bdos * call BDOS
57 *
58 * now restore the regs
59 *
60 0000001C 48C0 ext.l d0
61 0000001E 504F addq #8,sp * fix up the stack
62 bdone:
63 00000020 4CDF7FFE movem.l (sp)+,a0-a6/d1-d7
64 00000024 4E73 rte * return from trap call
65
66 *
67 * direct BIOS call function
68 *
69 bioscall:
70 00000026 2041 move.l d1,a0 * get address of CPB
71 00000028 3018 move.w (a0)+,d0
72 0000002A 4CD80006 movem.l (a0)+,d1-d2
73 0000002E 4E43 trap #3
74 00000030 60EE bra bdone
75
76 *
77 * Set supervisor mode procedure
78 *
79 setsup:
80 00000032 00572000 ori #$2000,(sp) * turn on supervisor bit in SR
81 00000036 4E73 rte
82
83 *
84 * BIOS Interface Routines
85 *
86 *
87 * Note - there are 6 BIOS entry points from the BDOS, labelled BIOS1 -
88 * BIOS6, depending on the parameters passed.
89
90 _bios5:
91 * For BIOS functions sectran and set exception vector
92 * Has function number and 2 parameters, a word followed by a long word
93 00000038 242F0008 move.l 8(sp),d2 * get 2nd parameter (long word)
94 0000003C 600C bra _bios2 * join common routine
95
96 _bios4:
97 * For BIOS function seldsk
98 * Has function number followed by 2 word parameters
99 0000003E 342F0008 move.w 8(sp),d2 * get 2nd parameter (word)
100 00000042 6006 bra _bios2 * join common routine
101
102 _bios3:
103 * For BIOS function set dma
104 * Has function number followed by 1 long parameter
105 00000044 222F0006 move.l 6(sp),d1 * get long word parameter
106 00000048 6004 bra _bios1 * join common routine
107
108 _bios2:
109 * For all BIOS functions with a word parameter
110 * Word parameter follows function number
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: bdosif.s
111 0000004A 322F0006 move.w 6(sp),d1 * get 1st parameter (word)
112
113 _bios6:
114 _bios1:
115 * For all BIOS functions that have no parameter other than function number
116 0000004E 302F0004 move.w 4(sp),d0 * get function number
117 00000052 48E71F1E movem.l d3-d7/a3-a6,-(sp)
118 * * save C register variables
119 00000056 4E43 trap #3 * do BIOS call
120 * * returns value in d0
121 00000058 4CDF78F8 movem.l (sp)+,d3-d7/a3-a6
122 0000005C 4E75 rts
123
124 *
125 * Utility Subroutines
126 *
127
128 _swap:
129 * Swap bytes of a word, return swapped value in d0
130 0000005E 102F0005 move.b 5(sp),d0
131 00000062 E148 lsl #8,d0
132 00000064 102F0004 move.b 4(sp),d0
133 00000068 4E75 rts
134
135 _udiv:
136 * Unsigned divide routine
137 * returns unsigned quotient in D0.W
138
139 * UWORD udiv( divisor, dividend, remp )
140 *
141 * REG LONG divisor;
142 * UWORD dividend;
143 * UWORD *remp /* pointer to remainder (returned) */
144
145 0000006A 202F0004 move.l 4(sp), d0 * get dividend
146 0000006E 80EF0008 divu 8(sp), d0 * do the divide
147 00000072 206F000A movea.l 10(sp),a0
148 00000076 4840 swap d0
149 00000078 3080 move.w d0, (a0) * store remainder
150 0000007A 4240 clr.w d0
151 0000007C 4840 swap d0 * word quotient in d0
152 0000007E 4E75 rts
153
154 00000080 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 4
Source File: bdosif.s
S y m b o l T a b l e
__bdos ******** EXT _bdosrw ******** EXT _bios1 0000004E TEXT _bios2 0000004A TEXT
_bios3 00000044 TEXT _bios4 0000003E TEXT _bios5 00000038 TEXT _bios6 0000004E TEXT
_constat ******** EXT _create ******** EXT _dirscan ******** EXT _swap 0000005E TEXT
_traphnd 00000000 TEXT _udiv 0000006A TEXT bdone 00000020 TEXT bioscall 00000026 TEXT
biosf 00000032 ABS setsup 00000032 TEXT setsupf 0000003E ABS

View File

@@ -0,0 +1,154 @@
*****************************************************************
* *
* CP/M-68K Basic Disk Operating System interface module *
* For "C" version of CP/M-68K *
* *
* Copyright (c) 1982 Digital Research, Inc. *
* *
* Version 0.2 -- September 22, 1982 *
* *
*****************************************************************
* Declare Public Routines
.globl _bios1 * 6 BIOS entry points from BDOS
.globl _bios2
.globl _bios3
.globl _bios4
.globl _bios5
.globl _bios6
.globl _traphnd * trap #2 handler
.globl _swap * byte swapper
.globl _udiv * unsigned divide routine
* Declare external routines
.globl __bdos * BDOS entry point in bdosmain
* The following external references were put in just to make sure that all
* the BDOS modules were referenced, so we could put them in a library
.globl _constat * references conbdos.o
.globl _dirscan * references dskutil.o
.globl _create * references fileio.o
.globl _bdosrw * references bdosrw.o
biosf = 50
setsupf = 62
_traphnd:
*
* first save the registers and
* check for functions handled by assembly language routines
*
cmpi #setsupf,d0
beq setsup
movem.l d1-d7/a0-a6,-(sp)
cmpi #biosf,d0
beq bioscall
*
* function number is passed in D0
* byte and word pararmeters are passed in D1.W
* address parameters are passed in D1.L
*
move.l d1,-(a7)
move.w d1,-(a7)
move.w d0,-(a7)
jsr __bdos * call BDOS
*
* now restore the regs
*
ext.l d0
addq #8,sp * fix up the stack
bdone:
movem.l (sp)+,a0-a6/d1-d7
rte * return from trap call
*
* direct BIOS call function
*
bioscall:
move.l d1,a0 * get address of CPB
move.w (a0)+,d0
movem.l (a0)+,d1-d2
trap #3
bra bdone
*
* Set supervisor mode procedure
*
setsup:
ori #$2000,(sp) * turn on supervisor bit in SR
rte
*
* 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
* 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)
_bios6:
_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)
* * save C register variables
trap #3 * do BIOS call
* * returns value in d0
movem.l (sp)+,d3-d7/a3-a6
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 routine
* returns unsigned quotient in D0.W
* UWORD udiv( divisor, dividend, remp )
*
* REG LONG divisor;
* UWORD dividend;
* UWORD *remp /* pointer to remainder (returned) */
move.l 4(sp), d0 * get dividend
divu 8(sp), d0 * do the divide
movea.l 10(sp),a0
swap d0
move.w d0, (a0) * store remainder
clr.w d0
swap d0 * word quotient in d0
rts
.end

View File

@@ -0,0 +1,68 @@
/*****************************************************************************
*
* C P / M C H E A D E R F I L E
* -----------------------------------
* Copyright 1982 by Digital Research Inc. All rights reserved.
*
* This is an include file for assisting the user to write portable
* programs for C.
*
*****************************************************************************/
#define ALCYON 1 /* using Alcyon compiler */
/*
* Standard type definitions
*/
/***************************/
#define BYTE 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 *********************************/

View File

@@ -0,0 +1,70 @@
1File: BDOSINC.H Page 1
1 /*****************************************************************************
2 *
3 * C P / M C H E A D E R F I L E
4 * -----------------------------------
5 * Copyright 1982 by Digital Research Inc. All rights reserved.
6 *
7 * This is an include file for assisting the user to write portable
8 * programs for C.
9 *
10 *****************************************************************************/
11 #define ALCYON 1 /* using Alcyon compiler */
12 /*
13 * Standard type definitions
14 */
15 /***************************/
16 #define BYTE char /* Signed byte */
17 #define BOOLEAN char /* 2 valued (true/false) */
18 #define WORD short /* Signed word (16 bits) */
19 #define UWORD unsigned int /* unsigned word */
20 #define LONG long /* signed long (32 bits) */
21 #define ULONG unsigned long /* Unsigned long */
22 #define REG register /* register variable */
23 #define LOCAL auto /* Local var on 68000 */
24 #define EXTERN extern /* External variable */
25 #define MLOCAL static /* Local to module */
26 #define GLOBAL /**/ /* Global variable */
27 #define VOID /**/ /* Void function return */
28 /***************************/
29 #ifdef ALCYON
30 #define UBYTE char
31 #define UBWORD(a) ((UWORD)a & 0xff)
32 /* Unsigned byte to word cast */
33 #else
34 #define UBYTE unsigned char /* Unsigned byte */
35 #define UBWORD(a) (UWORD)a
36 #endif
37
38
39
40 /****************************************************************************/
41 /* Miscellaneous Definitions: */
42 /****************************************************************************/
43 #define FAILURE (-1) /* Function failure return val */
44 #define SUCCESS (0) /* Function success return val */
45 #define YES 1 /* "TRUE" */
46 #define NO 0 /* "FALSE" */
47 #define FOREVER for(;;) /* Infinite loop declaration */
48 #define NULL (BYTE *)0 /* Null pointer value */
49 #define EOF (-1) /* EOF Value */
50 #define TRUE (1) /* Function TRUE value */
51 #define FALSE (0) /* Function FALSE value */
52
53
54 /****************************************************************************/
55 /* */
56 /* M A C R O S */
57 /* ----------- */
58 /* */
59 /* Define some stuff as macros .... */
1File: BDOSINC.H Page 2
60 /* */
61 /****************************************************************************/
62
63 #define abs(x) ((x) < 0 ? -(x) : (x)) /* Absolute value function */
64
65 #define max(x,y) (((x) > (y)) ? (x) : (y)) /* Max function */
66 #define min(x,y) (((x) < (y)) ? (x) : (y)) /* Min function */
67
68 /*************************** end of stdio.h *********************************/

View File

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

View File

@@ -0,0 +1,310 @@
1File: BDOSMAIN.C Page 1
1
2 /****************************************************************
3 * *
4 * CP/M-68K BDOS Main Routine *
5 * *
6 * This is the main routine for the BDOS for CP/M-68K *
7 * It has one entry point, _bdos, which is called from *
8 * the assembly language trap handler found in bdosif.s. *
9 * The parameters are a function number (integer) and an *
10 * information parameter (which is passed from bdosif as *
11 * both an integer and a pointer).
12 * The BDOS can potentially return a pointer, long word, *
13 * or word *
14 * *
15 * Configured for Alcyon C on the VAX *
16 * *
17 ****************************************************************/
18
19 #include "bdosinc.h" /* Standard I/O declarations */
20
21 #include "bdosdef.h" /* Type and structure declarations for BDOS */
22
23 #include "biosdef.h" /* Declarations of BIOS functions */
24
25 /* Declare EXTERN functions */
26
27 EXTERN warmboot(); /* Warm Boot function */
28 EXTERN BOOLEAN constat(); /* Console status */
29 EXTERN UBYTE conin(); /* Console Input function */
30 EXTERN tabout(); /* Console output with tab expansion */
31 EXTERN UBYTE rawconio(); /* Raw console I/O */
32 EXTERN prt_line(); /* Print line until delimiter */
33 EXTERN readline(); /* Buffered console read */
34 EXTERN seldsk(); /* Select disk */
35 EXTERN BOOLEAN openfile(); /* Open File */
36 EXTERN UWORD close_fi(); /* Close File */
37 EXTERN UWORD search(); /* Search first and next fcns */
38 EXTERN UWORD dirscan(); /* General directory scanning routine */
39 EXTERN UWORD bdosrw(); /* Sequential and Random disk read/write */
40 EXTERN BOOLEAN create(); /* Create file */
41 EXTERN BOOLEAN delete(); /* Delete file */
42 EXTERN BOOLEAN rename(); /* Rename file */
43 EXTERN BOOLEAN set_attr(); /* Set file attributes */
44 EXTERN getsize(); /* Get File Size */
45 EXTERN setran(); /* Set Random Record */
46 EXTERN free_sp(); /* Get Disk Free Space */
47 EXTERN UWORD flushit(); /* Flush Buffers */
48 EXTERN UWORD pgmld(); /* Program Load */
49 EXTERN UWORD setexc(); /* Set Exception Vector */
50 EXTERN set_tpa(); /* Get/Set TPA Limits */
51 EXTERN move(); /* general purpose byte mover */
52
53
54 /* Declare "true" global variables; i.e., those which will pertain to the
55 entire file system and thus will remain global even when this becomes
56 a multi-tasking file system */
57
58 GLOBAL UWORD log_dsk; /* 16-bit vector of logged in drives */
59 GLOBAL UWORD ro_dsk; /* 16-bit vector of read-only drives */
1File: BDOSMAIN.C Page 2
60 GLOBAL UWORD crit_dsk; /* 16-bit vector of drives in "critical"
61 state. Used to control dir checksums */
62 GLOBAL BYTE *tpa_lp; /* TPA lower boundary (permanent) */
63 GLOBAL BYTE *tpa_lt; /* TPA lower boundary (temporary) */
64 GLOBAL BYTE *tpa_hp; /* TPA upper boundary (permanent) */
65 GLOBAL BYTE *tpa_ht; /* TPA upper boundary (temporary) */
66
67
68 /* Declare the "state variables". These are globals for the single-thread
69 version of the file system, but are put in a structure so they can be
70 based, with a pointer coming from the calling process */
71
72 GLOBAL struct stvars gbls;
73
74 struct tempstr
75 {
76 UBYTE tempdisk;
77 BOOLEAN reselect;
78 struct fcb *fptr;
79 };
80
81 /****************************************************************
82 * *
83 * _bdos MAIN ROUTINE *
84 * *
85 * Called with _bdos(func, info, infop) *
86 * *
87 * Where: *
88 * func is the BDOS function number (d0.w) *
89 * info is the word parameter (d1.w) *
90 * infop is the pointer parameter (d1.l) *
91 * note that info is the word form of infop*
92 * *
93 ****************************************************************/
94
95
96 UWORD _bdos(func,info,infop)
97 REG WORD func; /* BDOS function number */
98 REG UWORD info; /* d1.w word parameter */
99 REG UBYTE *infop; /* d1.l pointer parameter */
100 {
101 REG UWORD rtnval;
102 LOCAL struct tempstr temp;
103 BSETUP
104
105 temp.reselect = FALSE;
106 temp.fptr = infop;
107 rtnval = 0;
108
109 switch (func) /* switch on function number */
110 {
111 case 0: warmboot(0); /* warm boot function */
112 /* break; */
113
114 case 1: return((UWORD)conin()); /* console input function */
115 /* break; */
116
117 case 2: tabout((UBYTE)info); /* console output with */
118 break; /* tab expansion */
1File: BDOSMAIN.C Page 3
119
120 case 3: return((UWORD)brdr()); /* get reader from bios */
121 /* break; */
122
123 case 4: bpun((UBYTE)info); /* punch output to bios */
124 break;
125
126 case 5: blstout((UBYTE)info); /* list output from bios */
127 break;
128
129 case 6: return((UWORD)rawconio(info)); /* raw console I/O */
130 /* break; */
131
132 case 7: return(bgetiob()); /* get i/o byte */
133 /* break; */
134
135 case 8: bsetiob(info); /* set i/o byte function */
136 break;
137
138 case 9: prt_line(infop); /* print line function */
139 break;
140
141 case 10: readline(infop); /* read buffered con input */
142 break;
143
144 case 11: return((UWORD)constat()); /* console status */
145 /* break; */
146
147 case 12: return(VERSION); /* return version number */
148 /* break; */
149
150 case 13: log_dsk = 0; /* reset disk system */
151 ro_dsk = 0;
152 crit_dsk= 0;
153 GBL.curdsk = 0xff;
154 GBL.dfltdsk = 0;
155 break;
156
157 case 14: seldsk((UBYTE)info); /* select disk */
158 GBL.dfltdsk = (UBYTE)info;
159 break;
160
161 case 15: tmp_sel(&temp); /* open file */
162 infop->extent = 0;
163 infop->s2 = 0;
164 rtnval = dirscan(openfile, infop, 0);
165 break;
166
167 case 16: tmp_sel(&temp); /* close file */
168 rtnval = close_fi(infop);
169 break;
170
171 case 17: GBL.srchp = infop; /* search first */
172 rtnval = search(infop, 0, &temp);
173 break;
174
175 case 18: infop = GBL.srchp; /* search next */
176 temp.fptr = infop;
177 rtnval = search(infop, 1, &temp);
1File: BDOSMAIN.C Page 4
178 break;
179
180 case 19: tmp_sel(&temp); /* delete file */
181 rtnval = dirscan(delete, infop, 2);
182 break;
183
184 case 20: tmp_sel(&temp); /* read sequential */
185 rtnval = bdosrw(infop, TRUE, 0);
186 break;
187
188 case 21: tmp_sel(&temp); /* write sequential */
189 rtnval = bdosrw(infop, FALSE, 0);
190 break;
191
192 case 22: tmp_sel(&temp); /* create file */
193 infop->extent = 0;
194 infop->s1 = 0;
195 infop->s2 = 0;
196 infop->rcdcnt = 0;
197 /* Zero extent, S1, S2, rcrdcnt. create zeros rest */
198 rtnval = dirscan(create, infop, 8);
199 break;
200
201 case 23: tmp_sel(&temp); /* rename file */
202 rtnval = dirscan(rename, infop, 2);
203 break;
204
205 case 24: return(log_dsk); /* return login vector */
206 /* break; */
207
208 case 25: return(UBWORD(GBL.dfltdsk)); /* return current disk */
209 /* break; */
210
211 case 26: GBL.dmaadr = infop; /* set dma address */
212 break;
213
214 /* No function 27 -- Get Allocation Vector */
215
216 case 28: ro_dsk |= 1<<GBL.dfltdsk; /* set disk read-only */
217 break;
218
219 case 29: return(ro_dsk); /* get read-only vector */
220 /* break; */
221
222 case 30: tmp_sel(&temp); /* set file attributes */
223 rtnval = dirscan(set_attr, infop, 2);
224 break;
225
226 case 31: if (GBL.curdsk != GBL.dfltdsk) seldsk(GBL.dfltdsk);
227 move( (GBL.parmp), infop, sizeof *(GBL.parmp) );
228 break; /* return disk parameters */
229
230 case 32: if ( (info & 0xff) <= 15 ) /* get/set user number */
231 GBL.user = (UBYTE)info;
232 return(UBWORD(GBL.user));
233 /* break; */
234
235 case 33: tmp_sel(&temp); /* random read */
236 rtnval = bdosrw(infop, TRUE, 1);
1File: BDOSMAIN.C Page 5
237 break;
238
239 case 34: tmp_sel(&temp); /* random write */
240 rtnval = bdosrw(infop, FALSE, 1);
241 break;
242
243 case 35: tmp_sel(&temp); /* get file size */
244 getsize(infop);
245 break;
246
247 case 36: tmp_sel(&temp); /* set random record */
248 setran(infop);
249 break;
250
251 case 37: info = ~info; /* reset drive */
252 log_dsk &= info;
253 ro_dsk &= info;
254 crit_dsk &= info;
255 break;
256
257 case 40: tmp_sel(&temp); /* write random with 0 fill */
258 rtnval = bdosrw(infop, FALSE, 2);
259 break;
260
261 case 46: free_sp(info); /* get disk free space */
262 break;
263
264 case 47: GBL.chainp = GBL.dmaadr; /* chain to program */
265 warmboot(0); /* terminate calling program */
266 /* break; */
267
268 case 48: return( flushit() ); /* flush buffers */
269 /* break; */
270
271 case 59: return(pgmld(infop,GBL.dmaadr)); /* program load */
272 /* break; */
273
274 case 61: return(setexc(infop)); /* set exception vector */
275 /* break; */
276
277 case 63: set_tpa(infop); /* get/set TPA limits */
278 break;
279
280 default: return(-1); /* bad function number */
281 /* break; */
282
283 }; /* end of switch statement */
284 if (temp.reselect) infop->drvcode = temp.tempdisk;
285 /* if reselected disk, restore it now */
286
287 return(rtnval); /* return the BDOS return value */
288 } /* end _bdos */
289
290
291 tmp_sel(temptr) /* temporarily select disk pointed to by fcb */
292 REG struct tempstr *temptr;
293 {
294 REG struct fcb *fcbp;
295 REG UBYTE tmp_dsk;
1File: BDOSMAIN.C Page 6
296 BSETUP
297
298 fcbp = temptr->fptr; /* get local copy of fcb pointer */
299 tmp_dsk = (temptr->tempdisk = fcbp->drvcode);
300 seldsk( tmp_dsk ? tmp_dsk - 1 : GBL.dfltdsk );
301
302 fcbp->drvcode = GBL.user;
303 temptr->reselect = TRUE;
304 }

View File

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

View File

@@ -0,0 +1,314 @@
1File: BDOSMISC.C Page 1
1
2 /****************************************************************
3 * *
4 * CP/M-68K BDOS Miscellaneous Module *
5 * *
6 * This module contains miscellaneous loose ends for *
7 * CP/M-68K. Included are: *
8 * *
9 * bdosinit() - BDOS initialization routine *
10 * called from CCP for system init *
11 * warmboot() - BDOS warm boot exit routine *
12 * error() - BDOS error printing routine *
13 * ro_err() - BDOS read-only file error routine *
14 * setexc() - BDOS set exception vector *
15 * set_tpa() - BDOS get/set TPA limits *
16 * serial # and copyright notice, machine readable *
17 * *
18 * *
19 * Configured for Alcyon C on the VAX *
20 * *
21 ****************************************************************/
22
23 #include "bdosinc.h" /* Standard I/O declarations */
24
25 #include "bdosdef.h" /* Type and structure declarations for BDOS */
26
27 #include "biosdef.h" /* BIOS definitions, needed for bios wboot */
28
29
30 /* serial # and copyright notice */
31
32 char *copyrt="CP/M-68K(tm), Version 1.1, Copyright (c) 1983, Digital Research";
33 char *serial="XXXX-0000-654321";
34
35
36
37 /* Declare external functions */
38 EXTERN conout(); /* Console Output function */
39 EXTERN UBYTE conin(); /* Console Input function */
40 EXTERN prt_line(); /* Print String function */
41 EXTERN UWORD _bdos(); /* BDOS main routine */
42 EXTERN UBYTE *traphndl(); /* assembly language trap handler */
43 EXTERN initexc(); /* init the exception handler in */
44 /* exceptn.s */
45 EXTERN UWORD dirscan(); /* Directory scanning routine */
46 EXTERN BOOLEAN set_attr(); /* Set File attributes function */
47 EXTERN UWORD dir_rd(); /* Read directory sector routine */
48
49 /* Declare external variables */
50 EXTERN UWORD log_dsk; /* logged-on disk vector */
51 EXTERN UWORD ro_dsk; /* read-only disk vector */
52 EXTERN UWORD crit_dsk; /* vector of critical disks */
53 EXTERN BYTE *tpa_lt; /* TPA lower limit (temporary) */
54 EXTERN BYTE *tpa_lp; /* TPA lower limit (permanent) */
55 EXTERN BYTE *tpa_ht; /* TPA upper limit (temporary) */
56 EXTERN BYTE *tpa_hp; /* TPA upper limit (permanent) */
57 EXTERN BOOLEAN submit; /* external variables from CCP */
58 EXTERN BOOLEAN morecmds;
59
1File: BDOSMISC.C Page 2
60
61 #define trap2v 34 /* trap 2 vector number */
62 #define ctrlc 3 /* control-c */
63
64
65 /********************************
66 * bdos initialization routine *
67 ********************************/
68
69 bdosinit()
70 /* Initialize the File System */
71 {
72 REG struct
73 {
74 WORD nmbr;
75 BYTE *low;
76 LONG length;
77 } *segp;
78 BSETUP
79
80 bsetvec(trap2v, &traphndl); /* set up trap vector */
81 GBL.kbchar = 0; /* initialize the "global" variables */
82 GBL.insptr = GBL.remptr = &(GBL.t_buff[0]);
83 GBL.delim = '$';
84 GBL.lstecho = FALSE;
85 GBL.echodel = TRUE;
86 GBL.chainp = NULL;
87 _bdos(13); /* reset disk system function */
88 segp = bgetseg(); /* get pointer to memory segment table */
89 tpa_lt = tpa_lp = segp->low;
90 tpa_ht = tpa_hp = tpa_lp + segp->length;
91 initexc( &(GBL.excvec[0]) );
92 }
93
94
95 /************************
96 * warmboot entry point *
97 ************************/
98
99 warmboot(parm)
100 /* Warm Boot the system */
101 WORD parm; /* 1 to reset submit flag */
102 {
103 BSETUP
104
105 log_dsk &= ~ro_dsk; /* log off any disk marked read-only */
106 /* note that this code is specifically for a single-
107 thread system. It won't work in a multi-task sys */
108 ro_dsk = 0;
109 crit_dsk = 0;
110 if (parm)
111 submit = morecmds = FALSE;
112 GBL.curdsk = 0xff; /* set current disk to "unknown" */
113 tpa_lt = tpa_lp;
114 tpa_ht = tpa_hp;
115 initexc( &(GBL.excvec[0]) );
116 bwboot();
117 }
118
1File: BDOSMISC.C Page 3
119
120 /*************************/
121 /* disk error handlers */
122 /*************************/
123
124 prt_err(p)
125 /* print the error message */
126
127 BYTE *p;
128 {
129 BSETUP
130
131 prt_line(p);
132 prt_line(" error on drive $");
133 conout(GBL.curdsk + 'A');
134 }
135
136
137 abrt_err(p)
138 /* print the error message and always abort */
139
140 BYTE *p;
141 {
142 prt_err(p);
143 warmboot(1);
144 }
145
146
147 ext_err(cont,p)
148 /* print the error message, and allow for retry, abort, or ignore */
149
150 REG BOOLEAN cont; /* Boolean for whether continuing is allowed */
151 BYTE *p; /* pointer to error message */
152 {
153 REG UBYTE ch;
154
155 prt_err(p);
156 do
157 {
158 prt_line("\n\rDo you want to: Abort (A), Retry (R)$");
159 if (cont) prt_line(", or Continue with bad data (C)$");
160 prt_line("? $");
161 ch = conin() & 0x5f;
162 prt_line("\r\n$");
163
164 switch ( ch )
165 {
166 case ctrlc: warmboot(1);
167 case 'A': warmboot(1);
168 case 'C': if (cont) return(1);
169 break;
170 case 'R': return(0);
171 }
172 } while (TRUE);
173 }
174
175
176 /********************************/
177 /* Read-only File Error Routine */
1File: BDOSMISC.C Page 4
178 /********************************/
179
180 ro_err(fcbp,dirindx)
181 /* File R/O error */
182
183 REG struct fcb *fcbp;
184 WORD dirindx;
185 {
186 REG BYTE *p;
187 REG UWORD i;
188 REG UBYTE ch;
189
190 p = (BYTE *)fcbp;
191 prt_line("CP/M Disk file error: $");
192 i = 8;
193 do conout(*++p & 0x7f); while (--i);
194 conout('.');
195 i = 3;
196 do conout(*++p & 0x7f); while (--i);
197 prt_line(" is read-only.$");
198 do
199 {
200 prt_line("\r\nDo you want to: Change it to read/write (C), or Abort (A)? $");
201 ch = conin() & 0x5f;
202 prt_line("\r\n$");
203
204 switch ( ch )
205 {
206 case ctrlc: warmboot(1);
207 case 'A': warmboot(1);
208 case 'C': fcbp->ftype[robit] &= 0x7f;
209 dirscan(set_attr, fcbp, 2);
210 return(dir_rd(dirindx >> 2));
211 } /* Reset the directory buffer !!!! */
212 } while (TRUE);
213 }
214
215
216 /************************
217 * error entry point *
218 ************************/
219
220 error(errnum)
221 /* Print error message, do appropriate response */
222
223 UWORD errnum; /* error number */
224 {
225 BSETUP
226
227 prt_line("\r\nCP/M Disk $");
228 switch (errnum)
229 {
230 case 0: return( ext_err(TRUE,"read$") );
231 /* break; */
232
233 case 1: return( ext_err(TRUE,"write$") );
234 /* break; */
235
236 case 2: abrt_err("select$");
1File: BDOSMISC.C Page 5
237 /* break; */
238
239 case 3: return( ext_err(FALSE,"select$") );
240 /* break; */
241
242 case 4: abrt_err("change$");
243 /* break; */
244
245 }
246 }
247
248
249 /*****************************
250 * set exception entry point *
251 *****************************/
252
253 setexc(epbp)
254 /* Set Exception Vector */
255 REG struct
256 {
257 WORD vecnum;
258 BYTE *newvec;
259 BYTE *oldvec;
260 } *epbp;
261
262 {
263 REG WORD i;
264 BSETUP
265
266 i = epbp->vecnum-2;
267 if ( i==32 || i==33) return(-1);
268 if ( (30 <= i) && (i <= 37) ) i -= 20;
269 else if ( (i < 0) || (i > 9) ) return(255);
270 epbp->oldvec = GBL.excvec[i];
271 GBL.excvec[i] = epbp->newvec;
272 return(0);
273 }
274
275
276 /*****************************
277 * get/set TPA entry point *
278 *****************************/
279
280 set_tpa(p)
281 /* Get/Set TPA Limits */
282 REG struct
283 {
284 UWORD parms;
285 BYTE *low;
286 BYTE *high;
287 } *p;
288
289 #define set 1
290 #define sticky 2
291
292 {
293 if (p->parms & set)
294 {
295 tpa_lt = p->low;
1File: BDOSMISC.C Page 6
296 tpa_ht = p->high;
297 if (p->parms & sticky)
298 {
299 tpa_lp = tpa_lt;
300 tpa_hp = tpa_ht;
301 }
302 }
303 else
304 {
305 p->low = tpa_lt;
306 p->high = tpa_ht;
307 }
308 }

View File

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

View File

@@ -0,0 +1,320 @@
1File: BDOSRW.C Page 1
1
2 /****************************************************************
3 * *
4 * CP/M-68K BDOS Disk Read/Write Module *
5 * *
6 * This module contains functions to perform sequential *
7 * or random access read or write to the disk for CP/M-68K *
8 * *
9 * It includes the following external functions: *
10 * *
11 * bdosrw() - sequential and random disk I/O *
12 * *
13 * *
14 * Compiled with Alcyon C on the VAX *
15 * *
16 ****************************************************************/
17
18 #include "bdosinc.h" /* Standard I/O declarations */
19
20 #include "bdosdef.h" /* Type and structure declarations for BDOS */
21
22
23 /* External function definitions */
24 EXTERN UWORD rdwrt(); /* disk read/write routine */
25 EXTERN WORD getaloc(); /* allocate a block of disk space */
26 EXTERN WORD swap(); /* assembly language byte swapper */
27 EXTERN UWORD dirscan(); /* directory scanning routine */
28 EXTERN BOOLEAN openfile(); /* open file function passed to dirscan */
29 EXTERN UWORD close_fi(); /* close file function */
30 EXTERN BOOLEAN create(); /* create file function passed to dirscan */
31 EXTERN UWORD ro_err(); /* read-only file error handler */
32
33 /* External variable definitions */
34 EXTERN UWORD ro_dsk; /* read-only disk vector */
35
36
37 /**********************************************************/
38 /* First, some utility functions used by seqio and ranio */
39 /**********************************************************/
40
41 /******************************
42 * FCB block number routines *
43 ******************************/
44
45 WORD blkindx(fcbp)
46 /* return index into fcb disk map */
47
48 REG struct fcb *fcbp; /* pointer to fcb */
49 {
50 REG struct dpb *dparmp; /* pointer to disk parameter block */
51 REG WORD i;
52 REG WORD blkshf;
53 BSETUP
54
55 dparmp = GBL.parmp;
56 blkshf = dparmp->bsh;
57 i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf);
58 return (i + (UBWORD(fcbp->cur_rec) >> blkshf) );
59 }
1File: BDOSRW.C Page 2
60
61
62 UWORD blknum(fcbp, index, wrdfcb)
63 /* return block number in fcb indicated by index */
64
65 REG struct fcb *fcbp; /* pointer to fcb */
66 REG WORD index; /* index into disk map of fcb */
67 WORD wrdfcb; /* boolean, fcb disk map of words */
68 {
69 if (wrdfcb)
70 return( swap(fcbp->dskmap.big[index]) );
71 else return( UBWORD(fcbp->dskmap.small[index]) );
72 }
73
74
75 setblk(fcbp, index, wrdfcb, block)
76 /* put block number into fcb */
77
78 REG struct fcb *fcbp; /* pointer to fcb */
79 REG WORD index; /* index into disk map of fcb */
80 WORD wrdfcb; /* boolean, fcb disk map of words */
81 REG UWORD block; /* block number */
82 {
83 fcbp->s2 &= 0x7f; /* set file write flag */
84 if (wrdfcb)
85 fcbp->dskmap.big[index] = swap(block);
86 else fcbp->dskmap.small[index] = (UBYTE)block;
87 }
88
89
90 /***************************
91 * disk read/write routine *
92 ***************************/
93
94 UWORD do_io(block, rcrd, parm)
95
96 UWORD block; /* block number */
97 UBYTE rcrd; /* record number */
98 REG WORD parm; /* write parameter */
99 {
100 REG LONG lsec;
101 REG struct dpb *dparmp;
102 BSETUP
103
104 dparmp = GBL.parmp; /* init dpb pointer */
105 lsec = ((LONG)block << (dparmp->bsh)) +
106 (LONG)(rcrd & (dparmp->blm));
107 return( rdwrt(lsec, GBL.dmaadr, parm) );
108 }
109
110
111 /*******************************************
112 * routine for crossing extent boundaries *
113 *******************************************/
114
115 WORD new_ext(fcbp, reading, ran)
116 /* If sequential I/O, open the next extent */
117 /* If random I/O, compute new extent from random record field */
118
1File: BDOSRW.C Page 3
119 REG struct fcb *fcbp; /* pointer to fcb */
120 BOOLEAN reading; /* read/write flag */
121 WORD ran; /* random I/O flag */
122 {
123 REG UBYTE mod; /* module number */
124 REG UBYTE ext; /* extent number */
125 REG UBYTE t_mod; /* temp mod number */
126 REG UBYTE t_ext; /* temp extent */
127 BSETUP
128
129 if (ran)
130 {
131 mod = ( (fcbp->ran0) << 4) | ( (fcbp->ran1) >> 4);
132 ext = ( ((fcbp->ran1) & 0x0f) << 1);
133 if ((fcbp->ran2) & 0x80) ext |= 1;
134 /* the calculation of ext was coded this way because of a */
135 /* compiler bug from Alcyon */
136 }
137 else
138 {
139 mod = (fcbp->s2) & 0x3f;
140 ext = (fcbp->extent) + 1; /* for sequential, incr extent */
141 }
142 if (ext >= 32)
143 {
144 ext = 0;
145 mod += 1;
146 }
147 if (mod >= 64) return(6); /* past maximum file size */
148 if ( mod == ((fcbp->s2) & 0x3f) )
149 if ( ! ((ext ^ (fcbp->extent)) & ~((GBL.parmp)->exm) & 0x1f) )
150 { /* we're in same logical extent */
151 fcbp->extent = ext;
152 return(0);
153 }
154 /* Extent or Module numbers don't match */
155 /* Close the old extent and open a one */
156 if ( close_fi(fcbp) >= 255 ) return(3);
157 /* can't close old extent */
158 t_mod = fcbp->s2;
159 t_ext = fcbp->extent;
160 fcbp->s2 = mod;
161 fcbp->extent = ext;
162 if ( dirscan(openfile, fcbp, 0) >= 255 ) /* open extent */
163 {
164 if (reading)
165 { /* reading unwritten extent */
166 fcbp->s2 = t_mod;
167 fcbp->extent = t_ext;
168 return(4);
169 }
170 if ( dirscan(create, fcbp, 8) >= 255 )
171 return(5); /* can't create new extent */
172 }
173 return(0);
174 }
175
176
177 /************************************
1File: BDOSRW.C Page 4
178 * Routine to calculate the maximum *
179 * extent number of an FCB in a *
180 * extent-folded environment *
181 ************************************/
182
183 UWORD calcext(fcbp)
184
185 REG struct fcb *fcbp;
186
187 {
188 REG UWORD i;
189 REG BYTE *p;
190 BSETUP
191
192 i = 15;
193 p = &(fcbp->dskmap.small[16]);
194 do
195 {
196 if (*--p) break;
197 i -= 1;
198 } while (i);
199 /* Now i contains the index of the last non-zero block in the FCB */
200 if ((GBL.parmp)->dsm > 255) i >>= 1;
201 i >>= 7 - ((GBL.parmp)->bsh);
202 return ( (fcbp->extent) & ~((GBL.parmp)->exm) & 0x1f | i );
203 }
204
205
206 /*********************************
207 * Routine to get the actual *
208 * record count of the currently *
209 * active logical extent of a FCB *
210 *********************************/
211
212 UWORD get_rc(fcbp)
213
214 REG struct fcb *fcbp;
215
216 {
217 REG UWORD ext;
218
219 ext = calcext(fcbp); /* find last active extent in fcb */
220 if (ext == fcbp->extent) return(UBWORD(fcbp->rcdcnt));
221 /* if this is the last active fcb, return fcb's rc */
222 else if (ext > fcbp->extent) return(128);
223 /* if the fcb has more extents past this one, then */
224 /* the current one is logically full */
225 else return (0);
226 /* if we seeked past the last active extent, rc = 0 */
227 }
228
229
230 /************************
231 * bdosrw entry point *
232 ************************/
233
234 UWORD bdosrw(fcbp, reading, random)
235
236 REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
1File: BDOSRW.C Page 5
237 REG BOOLEAN reading; /* boolean to tell whether to read or write */
238 WORD random; /* 0 = sequential, 1 = random (normal), */
239 /* 2 = random with zero fill */
240 {
241 REG UWORD block; /* block number from fcb */
242 REG WORD index; /* index into disk map of fcb */
243 REG BYTE *old_dma; /* temp holding spot for dmaadr */
244 REG WORD parm; /* parameter to do-io */
245 REG WORD bigfile; /* file system is in word mode */
246 REG UWORD rtn; /* return parameter */
247 REG UBYTE rc; /* temp storage for rcdcnt */
248 BSETUP
249
250 bigfile = ((GBL.parmp)->dsm) & ~0xff;
251 if ( ( ! reading) && (fcbp->ftype[robit] & 0x80) )
252 ro_err(fcbp,((GBL.dpbp)->dpbp)->drm);
253 /* check for read-only file */
254 if (random)
255 {
256 if ( rtn = new_ext(fcbp, reading, TRUE) ) return(rtn);
257 /* open new extent if necessary, return if error */
258 fcbp->cur_rec = (fcbp->ran2) & 0x7f;
259 }
260 else /* sequential */
261 if (fcbp->cur_rec == 128)
262 { /* time to try next extent */
263 if ( new_ext(fcbp, reading, FALSE) )
264 return(1); /* if can't open new extent, error */
265 fcbp->cur_rec = 0; /* opened new extent, zero cur_rec */
266 }
267
268 /* record is now in active fcb */
269 rc = fcbp->rcdcnt;
270 if ( UBWORD(fcbp->cur_rec) >= get_rc(fcbp) )
271 {
272 if (reading) return(1); /* reading unwritten data */
273 fcbp->s2 &= 0x7f; /* set file write flag */
274 rc = fcbp->cur_rec + 1;
275 }
276 index = blkindx(fcbp); /* get index into fcb disk map */
277 block = blknum(fcbp, index, bigfile);
278 if (block) parm = (reading ? 0 : 1);
279 else /* if allocated block, parm is just read or write */
280 { /* unallocated block */
281 if (reading) return(1); /* reading unwritten data */
282
283 /* Writing to new block */
284 /* The parm passed to getaloc is the previously allocated block */
285 /* or 0, if the previous block is not allocated */
286
287 block = getaloc(blknum(fcbp, (index ? (index - 1) : 0), bigfile));
288 if (block == ~0) return(2); /* out of space */
289 setblk(fcbp, index, bigfile, block);
290 parm = 3;
291 if (random == 2)
292 { /* Write random with zero fill */
293 old_dma = GBL.dmaadr;
294 GBL.dmaadr = GBL.dirbufp; /* Do DMA from dir_buf */
295 index = SECLEN;
1File: BDOSRW.C Page 6
296 do GBL.dmaadr[--index] = 0;
297 while (index); /* zero the dma buffer */
298 for (index = 0; index <= ((GBL.parmp)->blm); index++)
299 {
300 do_io(block, (UBYTE)index, parm);
301 /* write zeros to the block */
302 parm = 1; /* next write is not to new block */
303 }
304 GBL.dmaadr = old_dma; /* restore dma address */
305 }
306 }
307 rtn = do_io(block, fcbp->cur_rec, parm);
308 if ( rtn == 0 )
309 {
310 fcbp->rcdcnt = rc;
311 if ( ! random ) fcbp->cur_rec += 1;
312 }
313 return(rtn);
314 }

View File

@@ -0,0 +1,46 @@
/********************************************************
* *
* 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 */
EXTERN BYTE *bios6(); /* for get memory segment table */
#define bwboot() bios1(1) /* warm boot */
#define bconstat() bios1(2) /* console status */
#define bconin() bios1(3) /* console input */
#define bconout(parm) bios2(4,parm) /* console output parm */
#define blstout(parm) bios2(5,parm) /* list device output */
#define bpun(parm) bios2(6,parm) /* punch char output */
#define brdr() bios1(7) /* reader input */
#define bhome() bios1(8) /* recalibrate drive */
#define bseldsk(parm1,parm2) bios4(9,parm1,parm2)
/* select disk and return info */
#define bsettrk(parm) bios2(10,parm) /* set track on disk */
#define bsetsec(parm) bios2(11,parm) /* set sector for disk */
#define bsetdma(parm) bios3(12,parm) /* set dma address */
#define bread() bios1(13) /* read sector from disk */
#define bwrite(parm) bios2(14,parm) /* write sector to disk */
#define blistst() bios1(15) /* list device status */
#define bsectrn(parm1,parm2) bios5(16,parm1,parm2)
/* sector translate */
#define bgetseg() bios6(18) /* get memory segment tbl */
#define bgetiob() bios1(19) /* get I/O byte */
#define bsetiob(parm) bios2(20,parm) /* set I/O byte */
#define bflush() bios1(21) /* flush buffers */
#define bsetvec(parm1,parm2) bios5(22,parm1,parm2)
/* set exception vector */

View File

@@ -0,0 +1,47 @@
1File: BIOSDEF.H Page 1
1
2 /********************************************************
3 * *
4 * BIOS definitions for CP/M-68K *
5 * *
6 * Copyright (c) 1982 Digital Research, Inc. *
7 * *
8 * This include file simply defines the BIOS calls *
9 * *
10 ********************************************************/
11
12 EXTERN UBYTE bios1(); /* used for character I/O functions */
13 EXTERN bios2(); /* parm1 is word, no return value */
14 EXTERN bios3(); /* used for set dma only */
15 /* parm1 is a pointer, no return */
16 EXTERN UBYTE *bios4(); /* seldsk only, parm1 and parm2 are */
17 /* words, returns a pointer to dph */
18 EXTERN UWORD bios5(); /* for sectran and set exception */
19 EXTERN BYTE *bios6(); /* for get memory segment table */
20
21
22 #define bwboot() bios1(1) /* warm boot */
23 #define bconstat() bios1(2) /* console status */
24 #define bconin() bios1(3) /* console input */
25 #define bconout(parm) bios2(4,parm) /* console output parm */
26 #define blstout(parm) bios2(5,parm) /* list device output */
27 #define bpun(parm) bios2(6,parm) /* punch char output */
28 #define brdr() bios1(7) /* reader input */
29 #define bhome() bios1(8) /* recalibrate drive */
30 #define bseldsk(parm1,parm2) bios4(9,parm1,parm2)
31 /* select disk and return info */
32 #define bsettrk(parm) bios2(10,parm) /* set track on disk */
33 #define bsetsec(parm) bios2(11,parm) /* set sector for disk */
34 #define bsetdma(parm) bios3(12,parm) /* set dma address */
35 #define bread() bios1(13) /* read sector from disk */
36 #define bwrite(parm) bios2(14,parm) /* write sector to disk */
37 #define blistst() bios1(15) /* list device status */
38 #define bsectrn(parm1,parm2) bios5(16,parm1,parm2)
39 /* sector translate */
40 #define bgetseg() bios6(18) /* get memory segment tbl */
41 #define bgetiob() bios1(19) /* get I/O byte */
42 #define bsetiob(parm) bios2(20,parm) /* set I/O byte */
43 #define bflush() bios1(21) /* flush buffers */
44 #define bsetvec(parm1,parm2) bios5(22,parm1,parm2)
45 /* set exception vector */
46

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: ccpbdos.s
1 *************************************************************************
2 * *
3 * INTERFACE MODULE BETWEEN *
4 * CCP and THE BDOS *
5 * *
6 * *
7 * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
8 * ================================================== *
9 * *
10 * (C) Copyright Digital Research 1983 all rights reserved *
11 * *
12 *************************************************************************
13
14 .globl _bdos
15 00000000 302F0004 _bdos: move.w 4(sp),d0
16 00000004 222F0006 move.l 6(sp),d1
17 00000008 4E42 trap #2
18 0000000A 4E75 rts
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: ccpbdos.s
S y m b o l T a b l e
_bdos 00000000 TEXT

View File

@@ -0,0 +1,18 @@
*************************************************************************
* *
* INTERFACE MODULE BETWEEN *
* CCP and THE BDOS *
* *
* *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ================================================== *
* *
* (C) Copyright Digital Research 1983 all rights reserved *
* *
*************************************************************************
.globl _bdos
_bdos: move.w 4(sp),d0
move.l 6(sp),d1
trap #2
rts

View File

@@ -0,0 +1,158 @@
/*--------------------------------------------------------------*\
| ccp_def.c DEFINES v1.0 |
| ======= |
| |
| CP/M 68k: A CP/M derived operating system |
| |
| File contents: |
| ------------- |
| This file contains all of the #defines |
| used by the console command processor. |
| |
| created by : Tom Saulpaugh Date: 7/13/82 |
| ---------- |
| last modified: 10/29/82 |
| ------------- |
| |
| (c) COPYRIGHT Digital Research 1982 |
| all rights reserved |
| |
\*--------------------------------------------------------------*/
/*-------------------------------------------*\
| CP/M Transient Commands |
\*-------------------------------------------*/
#define DIRCMD 0
#define TYPECMD 1
#define RENCMD 2
#define ERACMD 3
#define UCMD 4
#define CH_DISK 5
#define SUBCMD 6
#define SUB_FILE 7
#define FILE 8
#define DIRSCMD 9
#define SEARCH 10
/*-------------------------------------------*\
| 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 signed short
#define UWORD unsigned int
#define LONG signed 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 5
#define SCR_HEIGHT 23
#define BIG_WIDTH 80
#define SMALL_WIDTH 40
/*-------------------------------------------*\
| BDOS Function Calls |
\*-------------------------------------------*/
#define WARMBOOT 0
#define CONIN 1
#define CONSOLE_OUTPUT 2
#define READER_INPUT 3
#define PUNCH_OUTPUT 4
#define LIST_OUTPUT 5
#define DIR_CONS_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,161 @@
1File: CCPDEF.H Page 1
1 /*--------------------------------------------------------------*\
2 | ccp_def.c DEFINES v1.0 |
3 | ======= |
4 | |
5 | CP/M 68k: A CP/M derived operating system |
6 | |
7 | File contents: |
8 | ------------- |
9 | This file contains all of the #defines |
10 | used by the console command processor. |
11 | |
12 | created by : Tom Saulpaugh Date: 7/13/82 |
13 | ---------- |
14 | last modified: 10/29/82 |
15 | ------------- |
16 | |
17 | (c) COPYRIGHT Digital Research 1982 |
18 | all rights reserved |
19 | |
20 \*--------------------------------------------------------------*/
21
22
23 /*-------------------------------------------*\
24 | CP/M Transient Commands |
25 \*-------------------------------------------*/
26
27 #define DIRCMD 0
28 #define TYPECMD 1
29 #define RENCMD 2
30 #define ERACMD 3
31 #define UCMD 4
32 #define CH_DISK 5
33 #define SUBCMD 6
34 #define SUB_FILE 7
35 #define FILE 8
36 #define DIRSCMD 9
37 #define SEARCH 10
38
39 /*-------------------------------------------*\
40 | Modes and Flags |
41 \*-------------------------------------------*/
42
43 #define ON 1
44 #define OFF 0
45 #define MATCH 0
46 #define GOOD 1
47 #define BAD 0
48 #define FILL 1
49 #define NOFILL 0
50 #define VOID /*no return value*/
51 #define NO_FILE 98
52 #define STOP 99
53 #define USER_ZERO 0
54 #define DISK_A 1
55 #define SOURCEDRIVE 88
56 #define DESTDRIVE 99
57 #define BYTE char
58 #define REG register
59 #define WORD signed short
1File: CCPDEF.H Page 2
60 #define UWORD unsigned int
61 #define LONG signed long
62 #define ULONG unsigned long
63 #define GET_MEM_REG 18
64 #define ZERO 0
65 #define NULL '\0'
66 #define TRUE 1
67 #define FALSE 0
68 #define NO_READ 255
69 #define BLANK ' '
70 #define BACKSLH '\\'
71 #define EXLIMPT '!'
72 #define CMASK 0177
73 #define ONE (long)49
74 #define TAB 9
75 #define Cr 13
76 #define Lf 10
77 #define CR (long)13
78 #define LF (long)10
79 #define EOF 26
80 #define BLANKS (long)32
81 #define PERIOD (long)46
82 #define COLON (long)58
83 #define ARROW (long)62
84
85 /*-------------------------------------------*\
86 | Data Structure Size Constants |
87 \*-------------------------------------------*/
88
89 #define CMD_LEN 128
90 #define BIG_CMD_LEN 255
91 #define MAX_ARGS 4
92 #define ARG_LEN 26
93 #define NO_OF_DRIVES 16
94 #define NUMDELS 16
95 #define FCB_LEN 36
96 #define DMA_LEN 128
97 #define FILES_PER_LINE 5
98 #define SCR_HEIGHT 23
99 #define BIG_WIDTH 80
100 #define SMALL_WIDTH 40
101
102 /*-------------------------------------------*\
103 | BDOS Function Calls |
104 \*-------------------------------------------*/
105
106 #define WARMBOOT 0
107 #define CONIN 1
108 #define CONSOLE_OUTPUT 2
109 #define READER_INPUT 3
110 #define PUNCH_OUTPUT 4
111 #define LIST_OUTPUT 5
112 #define DIR_CONS_I/O 6
113 #define GET_I/O_BYTE 7
114 #define SET_I/O_BYTE 8
115 #define PRINT_STRING 9
116 #define READ_CONS_BUF 10
117 #define GET_CONS_STAT 11
118 #define RET_VERSION_NO 12
1File: CCPDEF.H Page 3
119 #define RESET_DISK_SYS 13
120 #define SELECT_DISK 14
121 #define OPEN_FILE 15
122 #define CLOSE_FILE 16
123 #define SEARCH_FIRST 17
124 #define SEARCH_NEXT 18
125 #define DELETE_FILE 19
126 #define READ_SEQ 20
127 #define WRITE_SEQ 21
128 #define MAKE_FILE 22
129 #define RENAME_FILE 23
130 #define RET_LOGIN_VEC 24
131 #define RET_CUR_DISK 25
132 #define SET_DMA_ADDR 26
133 #define GET_ADDR(ALLOC) 27
134 #define WRITE_PROT_DISK 28
135 #define GET_READ/O_VEC 29
136 #define SET_FILE_ATTRIB 30
137 #define GET_ADDR_D_PARM 31
138 #define GET_USER_NO 32
139 #define READ_RANDOM 33
140 #define WRITE_RANDOM 34
141 #define COMP_FILE-SIZE 35
142 #define SET_RANDOM_REC 36
143 #define RESET_DRIVE 37
144 #define WRITE_RAN_ZERO 40
145 #define BIOS_CALL 50
146 #define LOAD_PROGRAM 59
147
148 /*----------------------------------------------*\
149 | MACROS |
150 \*----------------------------------------------*/
151
152 #define isalpha(c) (islower(c) || isupper(c))
153 #define islower(c) ('a' <= (c) && (c) <= 'z')
154 #define isupper(c) ('A' <= (c) && (c) <= 'Z')
155 #define tolower(c) (isupper(c) ? ((c)+040):(c))
156 #define toupper(c) (islower(c) ? ((c)-040):(c))
157 #define isdigit(c) ('0' <= (c) && (c) <= '9')
158

View File

@@ -0,0 +1,131 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: ccpif.s
1 *************************************************************************
2 * *
3 * CPM68K INTERFACE MODULE FOR *
4 * THE CONSOLE COMMAND PROCESSOR *
5 * *
6 * THIS IS THE DUAL-PROCESSOR,ROMABLE CP/M-68K SYSTEM *
7 * ================================================== *
8 * *
9 * (C) Copyright Digital Research 1983 all rights reserved *
10 * *
11 *************************************************************************
12
13
14 .globl _bios1
15 .globl _bdos
16 .globl _load68k
17 .globl _load_tbl
18 .globl init_tbl
19 .globl _load_try
20 .globl _autorom
21 .globl flags
22 .globl TPAB
23 .globl stack
24 .globl _bdosini
25 .globl _main
26 .globl _submit
27 .globl _morecmds
28 .globl _autost
29 .globl _usercmd
30 .globl _init
31 .globl _ccp
32 .globl _patch
33 .globl cpm
34
35 00000000 .text
36 cpm:
37 00000000 4EF900000038 jmp.l ccpstart * start ccp with possible initial command
38 00000006 4EF900000032 jmp.l ccpclear * clear auto start flag
39
40
41
42 00000000 .bss
43 00000000 _autost: .ds.b 1 * autostart command flag
44 00000001 _usercmd: .ds.b 130 * user command buffer
45
46 00000084 .text
46 0000000C
47 0000000C 434F505952494748 copy: .dc.b 'COPYRIGHT (C) 1982, Digital Research '
47 00000014 5420284329203139
47 0000001C 38322C2044696769
47 00000024 74616C2052657365
47 0000002C 6172636820
48
49
50 00000032 .text
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: ccpif.s
50 00000032
51 ccpclear:
52 00000032 423900000000 clr.b _autost * clear the autostart flag
53
54 ccpstart:
55 00000038 4FF900000000 lea stack,sp * set up the stack pointer
56 0000003E 423900000000 clr.b _autost * clear the auto start flag
57 00000044 4EB900000000 jsr _init * call bios init
58 0000004A 33C000000084 move.w d0,dskuser * save user # & disk
59 *
60 *
61 * ROM SYSTEM INITIALIZATION
62 * OF BSS VARIABLES
63 *
64 *
65
66 00000050 423900000000 clr.b _load_try
67 00000056 423900000086 clr.b _submit
68 0000005C 423900000088 clr.b _morecmds
69 00000062 13FC000100000000 move.b #$1,_autorom
70 0000006A 427900000000 clr.w flags
71 00000070 427900000000 clr.w TPAB
72 00000076 4EB900000000 jsr init_tbl
73
74
75
76 0000007C 4EB900000000 jsr _bdosini * do bdos init
77 00000082 303C0020 move.w #32,d0 * get user bdos func #
78 00000086 4281 clr.l d1 * clear out d1
79 00000088 123900000084 move.b dskuser,d1 * get the user #
80 0000008E 4E42 trap #2 * set the user number
81 00000090 4280 clr.l d0 * clear d0
82 00000092 303C000E move.w #14,d0 * select function
83 00000096 4281 clr.l d1 * clear d1
84 00000098 323900000084 move.w dskuser,d1 * get disk to be selected
85 0000009E 024100FF andi #$0ff,d1 * mask off the user #
86 000000A2 4E42 trap #2 * select the disk
87
88 _ccp:
89 000000A4 4FF900000000 lea stack,sp * set up the stack pointer
90 000000AA 4EB900000000 jsr _main * call the CCP
91 000000B0 60F2 bra _ccp
92
93 00000084 .bss
94 .even
95
96 00000084 dskuser: .ds.w 1
97 .even
98 00000086 _submit: .ds.b 1
99 00000088 .even
99 00000088
100 00000088 _morecmds: .ds.b 1
101 0000008A .even
101 0000008A
102 0000008A _patch .ds.l 25
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: ccpif.s
103 000000EE .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 4
Source File: ccpif.s
S y m b o l T a b l e
TPAB ******** EXT _autorom ******** EXT _autost 00000000 BSS _bdos ******** EXT
_bdosini ******** EXT _bios1 ******** EXT _ccp 000000A4 TEXT _init ******** EXT
_load68k ******** EXT _load_tb ******** EXT _load_tr ******** EXT _main ******** EXT
_morecmd 00000088 BSS _patch 0000008A BSS _submit 00000086 BSS _usercmd 00000001 BSS
ccpclear 00000032 TEXT ccpstart 00000038 TEXT copy 0000000C TEXT cpm 00000000 TEXT
dskuser 00000084 BSS flags ******** EXT init_tbl ******** EXT stack ******** EXT

View File

@@ -0,0 +1,113 @@
*************************************************************************
* *
* CPM68K INTERFACE MODULE FOR *
* THE CONSOLE COMMAND PROCESSOR *
* *
* THIS IS THE DUAL-PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ================================================== *
* *
* (C) Copyright Digital Research 1983 all rights reserved *
* *
*************************************************************************
.globl _bios1
.globl _bdos
.globl _load68k
.globl _load_tbl
.globl init_tbl
.globl _load_try
.globl _autorom
.globl flags
.globl TPAB
.globl stack
.globl _bdosini
.globl _main
.globl _submit
.globl _morecmds
.globl _autost
.globl _usercmd
.globl _init
.globl _ccp
.globl _patch
.globl cpm
.text
cpm:
jmp.l ccpstart * start ccp with possible initial command
jmp.l ccpclear * clear auto start flag
.bss
_autost: .ds.b 1 * autostart command flag
_usercmd: .ds.b 130 * user command buffer
.text
copy: .dc.b 'COPYRIGHT (C) 1982, Digital Research '
.text
ccpclear:
clr.b _autost * clear the autostart flag
ccpstart:
lea stack,sp * set up the stack pointer
clr.b _autost * clear the auto start flag
jsr _init * call bios init
move.w d0,dskuser * save user # & disk
*
*
* ROM SYSTEM INITIALIZATION
* OF BSS VARIABLES
*
*
clr.b _load_try
clr.b _submit
clr.b _morecmds
move.b #$1,_autorom
clr.w flags
clr.w TPAB
jsr init_tbl
jsr _bdosini * do bdos init
move.w #32,d0 * get user bdos func #
clr.l d1 * clear out d1
move.b dskuser,d1 * get the user #
trap #2 * set the user number
clr.l d0 * clear d0
move.w #14,d0 * select function
clr.l d1 * clear d1
move.w dskuser,d1 * get disk to be selected
andi #$0ff,d1 * mask off the user #
trap #2 * select the disk
_ccp:
lea stack,sp * set up the stack pointer
jsr _main * call the CCP
bra _ccp
.bss
.even
dskuser: .ds.w 1
.even
_submit: .ds.b 1
.even
_morecmds: .ds.b 1
.even
_patch .ds.l 25
.end

View File

@@ -0,0 +1,212 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: ccpload.s
1 *****************************************************************
2 * *
3 * COMMAND FILE LOADER FOR CPM68K *
4 * ============================== *
5 * *
6 * (c) COPYRIGHT Digital Research 1983 *
7 * all rights reserved *
8 * *
9 * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
10 * ================================================== *
11 * *
12 * Description: *
13 * ----------- The command file loader is envoked by *
14 * the CCP after the CCP has successfully *
15 * opened that file. The loader must *
16 * call the BDOS to obtain the boundries *
17 * of the TPA. The load parameter block *
18 * defined in this loader holds all the *
19 * memory size and location details. *
20 * Next the loader returns the system to *
21 * its original user #. The CCP might *
22 * have switched to user zero during its *
23 * search for the file. Next the default *
24 * dma address is set for the loaded *
25 * program. Next the command tail is *
26 * placed,along with the first two parsed *
27 * fcb's,into the user basepage. *
28 * Lastly the user stack pointer is set up *
29 * and the return address is put on the *
30 * user stack. An RTE transferes control. *
31 * If a load was not successfull, the *
32 * appropriate error message is printed. *
33 * *
34 * Created by: Tom Saulpaugh *
35 * *
36 * Last Modified: 3/02/83 *
37 * *
38 *****************************************************************
39
40
41
42 .globl _load68k * make this procedure public
43 .globl _user * global user # before load occured
44 .globl _cmdfcb * parsed fcb
45 .globl _tail * global pointer to command tail
46 .globl _fill_fcb * procedure to fill fcb's
47 .globl flags * ROM SYSTEM INITIALIZATION
48 .globl TPAB * ROM SYSTEM INITIALIZATION
49
50
51 reboot = 0
52 printstr = 9
53 setdma = 26
54 chuser = 32
55 pgmldf = 59
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: ccpload.s
56 gettpa = 63
57
58 _load68k:
59 *
60 * Load the 68k file into the TPA
61 * ------------------------------
62 *
63 00000000 .text
64
65 00000000 223C00000016 move.l #TPAB,d1 * move in address of tpa parameter block
66 00000006 303C003F move.w #gettpa,d0 * get function number
67 0000000A 4E42 trap #2 * get the tpa limits
68 0000000C 23F90000001800000004 move.l low,lowadr * put it in the lpb
69 00000016 23F90000001C00000008 move.l high,hiadr * put high tpa addr in lpb
70 00000020 23FC0000000000000000 move.l #_cmdfcb,LPB * get address of opened fcb
71 0000002A 703B move.l #pgmldf,d0 * move in bdos function no
72 0000002C 223C00000000 move.l #LPB,d1 * d1 points to load block
73 00000032 4E42 trap #2 * do the program load
74 00000034 4A40 tst d0 * was the load successful?
75 00000036 66000096 bne lderr * if not print error message and return
76 *
77 * return to original user #
78 * -------------------------
79 0000003A 323900000000 move.w _user,d1 * put user # to switch to in d1
80 00000040 7020 move.l #chuser,d0 * put bdos func # in d0
81 00000042 4E42 trap #2 * do the user # change
82 *
83 * set the default dma address
84 * ---------------------------
85 00000044 4281 clr.l d1 * clear d1 register
86 00000046 22390000000C move.l baspag,d1 * d1 points to user base page
87 0000004C D27C0080 add #$80,d1 * d1 points to default dma in base page
88 00000050 2241 movea.l d1,a1 * save it for later use
89 00000052 701A move #setdma,d0 * move in bdos function no
90 00000054 4E42 trap #2 * set the default dma address
91 *
92 * move in the command tail
93 * ------------------------
94 00000056 2449 move.l a1,a2 * save a pointer to the count field
95 00000058 5289 add.l #$01,a1 * point past count field
96 0000005A 207900000000 move.l _tail,a0 * point to command tail
97 00000060 4280 clr.l d0 * clear out d0
98 00000062 0C100000 mvtail: cmpi.b #$00,(a0) * check for a NULL ending byte
99 00000066 670C beq done * NULL byte terminates command
100 00000068 0C100021 cmpi.b #$21,(a0) * check for an '!'
101 0000006C 6706 beq done * '!' ends the command
102 0000006E 12D8 move.b (a0)+,(a1)+ * move a byte of the command tail
103 00000070 5240 addq #1,d0 * bump up the character count
104 00000072 60EE bra mvtail * continue byte move
105 00000074 1480 done: move.b d0,(a2) * put in the character count
106 00000076 12BC0000 move.b #$00,(a1) * terminate cmd tail with a NULL byte
107 *
108 * fill fcb1 & fcb2
109 * ----------------
110 0000007A 2F3C00000000 move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: ccpload.s
111 00000080 3F3C0001 move.w #1,-(sp) * put 1 on stack(parm1)
112 00000084 4EB900000000 jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm1
113 0000008A 5C8F add.l #6,sp * clean off the stack
114 0000008C 4280 clr.l d0 * clear register d0
115 0000008E 705C moveq #$5c,d0 * put basepage address of fcb1 in d0
116 00000090 6142 bsr movfcb * put fcb1 in the basepage
117 00000092 2F3C00000000 move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack
118 00000098 3F3C0002 move.w #2,-(sp) * put 2 on stack(parm2)
119 0000009C 4EB900000000 jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm2
120 000000A2 5C8F add.l #6,sp * clean off the stack
121 000000A4 4280 clr.l d0 * clear register d0
122 000000A6 7038 moveq #$38,d0 * put basepage address of fcb1 in d0
123 000000A8 612A bsr movfcb * put fcb2 in the basepage
124 *
125 * now push rte stuff on stack
126 * ---------------------------
127 000000AA 207900000010 movea.l usrstk,a0 * get user stack pointer
128 000000B0 22790000000C move.l baspag,a1 * get basepage address
129 000000B6 2F290008 move.l 8(a1),-(sp) * push address we want to jump to
130 000000BA 40C0 move sr,d0 * get the status register in d0
131 000000BC 02405F00 andi #$5f00,d0 * mask trace,system bits,user flags
132 000000C0 3F00 move.w d0,-(sp) * push it on stack
133 000000C2 2109 move.l a1,-(a0) * push addr of basepage onto user stack
134 000000C4 213C000000D0 move.l #cmdrtn,-(a0) * push return address onto user stack
135 000000CA 4E60 move.l a0,usp * set up user stack pointer
136 000000CC 4E73 rte
137 *
138 * load error
139 * ----------
140 lderr:
141 000000CE 4E75 rts * return with error code in d0
142 cmdrtn:
143 000000D0 7000 move #reboot,d0 * reboot CPM
144 000000D2 4E42 trap #2
145 movfcb:
146 000000D4 D0B90000000C add.l baspag,d0 * get offset into basepage
147 000000DA 2040 move.l d0,a0 * move address into a0
148 000000DC 227C00000000 move.l #_cmdfcb,a1 * a1 points to fcb to be moved
149 000000E2 4280 clr.l d0 * clear register d0
150 000000E4 7023 moveq #35,d0 * get length of fcb
151 mov1:
152 000000E6 10D9 move.b (a1)+,(a0)+ * move a byte into the basepage
153 000000E8 51C8FFFC dbf d0,mov1 * if not done branch to mov1
154 000000EC 4E75 rts
155
156
157 00000000 .bss
158
159 .even
160 *
161 * LOAD PARAMETER BLOCK
162 *
163 00000000 LPB: .ds.l 1
164 00000004 lowadr: .ds.l 1
165 00000008 hiadr: .ds.l 1
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 4
Source File: ccpload.s
166 0000000C baspag: .ds.l 1
167 00000010 usrstk: .ds.l 1
168 00000014 flags: .ds.w 1
169
170 *
171 * TPA Parameter Block
172 *
173 .even
174 00000016 TPAB: .ds.w 1
175 00000018 low: .ds.l 1
176 0000001C high: .ds.l 1
177
178
179
180
181
182
183
184
185
186
187
188 00000020 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 5
Source File: ccpload.s
S y m b o l T a b l e
LPB 00000000 BSS TPAB 00000016 BSS _cmdfcb ******** EXT _fill_fc ******** EXT
_load68k 00000000 TEXT _tail ******** EXT _user ******** EXT baspag 0000000C BSS
chuser 00000020 ABS cmdrtn 000000D0 TEXT done 00000074 TEXT flags 00000014 BSS
gettpa 0000003F ABS hiadr 00000008 BSS high 0000001C BSS lderr 000000CE TEXT
low 00000018 BSS lowadr 00000004 BSS mov1 000000E6 TEXT movfcb 000000D4 TEXT
mvtail 00000062 TEXT pgmldf 0000003B ABS printstr 00000009 ABS reboot 00000000 ABS
setdma 0000001A ABS usrstk 00000010 BSS

View File

@@ -0,0 +1,188 @@
*****************************************************************
* *
* COMMAND FILE LOADER FOR CPM68K *
* ============================== *
* *
* (c) COPYRIGHT Digital Research 1983 *
* all rights reserved *
* *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ================================================== *
* *
* Description: *
* ----------- The command file loader is envoked by *
* the CCP after the CCP has successfully *
* opened that file. The loader must *
* call the BDOS to obtain the boundries *
* of the TPA. The load parameter block *
* defined in this loader holds all the *
* memory size and location details. *
* Next the loader returns the system to *
* its original user #. The CCP might *
* have switched to user zero during its *
* search for the file. Next the default *
* dma address is set for the loaded *
* program. Next the command tail is *
* placed,along with the first two parsed *
* fcb's,into the user basepage. *
* Lastly the user stack pointer is set up *
* and the return address is put on the *
* user stack. An RTE transferes control. *
* If a load was not successfull, the *
* appropriate error message is printed. *
* *
* Created by: Tom Saulpaugh *
* *
* Last Modified: 3/02/83 *
* *
*****************************************************************
.globl _load68k * make this procedure public
.globl _user * global user # before load occured
.globl _cmdfcb * parsed fcb
.globl _tail * global pointer to command tail
.globl _fill_fcb * procedure to fill fcb's
.globl flags * ROM SYSTEM INITIALIZATION
.globl TPAB * ROM SYSTEM INITIALIZATION
reboot = 0
printstr = 9
setdma = 26
chuser = 32
pgmldf = 59
gettpa = 63
_load68k:
*
* Load the 68k file into the TPA
* ------------------------------
*
.text
move.l #TPAB,d1 * move in address of tpa parameter block
move.w #gettpa,d0 * get function number
trap #2 * get the tpa limits
move.l low,lowadr * put it in the lpb
move.l high,hiadr * put high tpa addr in lpb
move.l #_cmdfcb,LPB * get address of opened fcb
move.l #pgmldf,d0 * move in bdos function no
move.l #LPB,d1 * d1 points to load block
trap #2 * do the program load
tst d0 * was the load successful?
bne lderr * if not print error message and return
*
* return to original user #
* -------------------------
move.w _user,d1 * put user # to switch to in d1
move.l #chuser,d0 * put bdos func # in d0
trap #2 * do the user # change
*
* set the default dma address
* ---------------------------
clr.l d1 * clear d1 register
move.l baspag,d1 * d1 points to user base page
add #$80,d1 * d1 points to default dma in base page
movea.l d1,a1 * save it for later use
move #setdma,d0 * move in bdos function no
trap #2 * set the default dma address
*
* move in the command tail
* ------------------------
move.l a1,a2 * save a pointer to the count field
add.l #$01,a1 * point past count field
move.l _tail,a0 * point to command tail
clr.l d0 * clear out d0
mvtail: cmpi.b #$00,(a0) * check for a NULL ending byte
beq done * NULL byte terminates command
cmpi.b #$21,(a0) * check for an '!'
beq done * '!' ends the command
move.b (a0)+,(a1)+ * move a byte of the command tail
addq #1,d0 * bump up the character count
bra mvtail * continue byte move
done: move.b d0,(a2) * put in the character count
move.b #$00,(a1) * terminate cmd tail with a NULL byte
*
* fill fcb1 & fcb2
* ----------------
move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack
move.w #1,-(sp) * put 1 on stack(parm1)
jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm1
add.l #6,sp * clean off the stack
clr.l d0 * clear register d0
moveq #$5c,d0 * put basepage address of fcb1 in d0
bsr movfcb * put fcb1 in the basepage
move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack
move.w #2,-(sp) * put 2 on stack(parm2)
jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm2
add.l #6,sp * clean off the stack
clr.l d0 * clear register d0
moveq #$38,d0 * put basepage address of fcb1 in d0
bsr movfcb * put fcb2 in the basepage
*
* now push rte stuff on stack
* ---------------------------
movea.l usrstk,a0 * get user stack pointer
move.l baspag,a1 * get basepage address
move.l 8(a1),-(sp) * push address we want to jump to
move sr,d0 * get the status register in d0
andi #$5f00,d0 * mask trace,system bits,user flags
move.w d0,-(sp) * push it on stack
move.l a1,-(a0) * push addr of basepage onto user stack
move.l #cmdrtn,-(a0) * push return address onto user stack
move.l a0,usp * set up user stack pointer
rte
*
* load error
* ----------
lderr:
rts * return with error code in d0
cmdrtn:
move #reboot,d0 * reboot CPM
trap #2
movfcb:
add.l baspag,d0 * get offset into basepage
move.l d0,a0 * move address into a0
move.l #_cmdfcb,a1 * a1 points to fcb to be moved
clr.l d0 * clear register d0
moveq #35,d0 * get length of fcb
mov1:
move.b (a1)+,(a0)+ * move a byte into the basepage
dbf d0,mov1 * if not done branch to mov1
rts
.bss
.even
*
* LOAD PARAMETER BLOCK
*
LPB: .ds.l 1
lowadr: .ds.l 1
hiadr: .ds.l 1
baspag: .ds.l 1
usrstk: .ds.l 1
flags: .ds.w 1
*
* TPA Parameter Block
*
.even
TPAB: .ds.w 1
low: .ds.l 1
high: .ds.l 1
.end

View File

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

View File

@@ -0,0 +1,352 @@
1File: CONBDOS.C Page 1
1
2 /********************************************************
3 * *
4 * CP/M-68K BDOS Character I/O Routines *
5 * *
6 * This module does BDOS functions 1 thru 11 *
7 * *
8 * It contains the following functions which *
9 * are called from the BDOS main routine: *
10 * constat(); *
11 * conin(); *
12 * tabout(); *
13 * rawconio(); *
14 * prt_line(); *
15 * readline(); *
16 * *
17 * Copyright (c) 1982 Digital Research, Inc. *
18 * *
19 ********************************************************/
20
21 #include "bdosinc.h"
22
23 #include "bdosdef.h"
24
25 #include "biosdef.h"
26
27
28 #define ctrlc 0x03
29 #define ctrle 0x05
30 #define ctrlp 0x10
31 #define ctrlq 0x11
32 #define ctrlr 0x12
33 #define ctrls 0x13
34 #define ctrlu 0x15
35 #define ctrlx 0x18
36
37 #define cr 0x0d
38 #define lf 0x0a
39 #define tab 0x09
40 #define rub 0x7f
41 #define bs 0x08
42 #define space 0x20
43
44
45 EXTERN warmboot(); /* External function definition */
46
47
48 /******************/
49 /* console status */
50 /******************/
51
52 BOOLEAN constat()
53 {
54 BSETUP
55
56 return( GBL.kbchar ? TRUE : bconstat() );
57 }
58
59 /********************/
1File: CONBDOS.C Page 2
60 /* check for ctrl/s */
61 /* used internally */
62 /********************/
63 conbrk()
64 {
65 REG UBYTE ch;
66 REG BOOLEAN stop;
67 BSETUP
68
69 stop = FALSE;
70 if ( bconstat() ) do
71 {
72 if ( (ch = bconin()) == ctrlc ) warmboot(1);
73 if ( ch == ctrls ) stop = TRUE;
74 else if (ch == ctrlq) stop = FALSE;
75 else if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
76 else /* Insert character in ring buffer */
77 { /* */
78 if(GBL.kbchar < TBUFSIZ) /* Room? */
79 { /************************************/
80 *GBL.insptr++ = ch; /* Yes, insert the character in buff*/
81 GBL.kbchar++; /* Up count */
82 } /************************************/
83 } /* Note if no room, character is */
84 /* Ignomiously discarded (!) */
85 /************************************/
86 } while (stop);
87 }
88
89
90 /******************/
91 /* console output */
92 /* used internally*/
93 /******************/
94
95 conout(ch)
96 REG UBYTE ch;
97 {
98 BSETUP
99
100 conbrk(); /* check for control-s break */
101 bconout(ch); /* output character to console */
102 if (GBL.lstecho) blstout(ch); /* if ctrl-p on, echo to list dev */
103 if (ch >= ' ') GBL.column++; /* keep track of screen column */
104 else if (ch == cr) GBL.column = 0;
105 else if (ch == bs) GBL.column--;
106 }
107
108
109 /*************************************/
110 /* console output with tab expansion */
111 /*************************************/
112
113 tabout(ch)
114 REG UBYTE ch; /* character to output to console */
115 {
116 BSETUP
117
118 if (ch == tab) do
1File: CONBDOS.C Page 3
119 conout(' ');
120 while (GBL.column & 7);
121 else conout(ch);
122 }
123
124 /*******************************/
125 /* console output with tab and */
126 /* control character expansion */
127 /*******************************/
128
129 cookdout(ch)
130 REG UBYTE ch; /* character to output to console */
131 {
132 if (ch == tab) tabout(ch); /* if tab, expand it */
133 else
134 {
135 if ( (UWORD)ch < (UWORD)' ' )
136 {
137 conout( '^' );
138 ch |= 0x40;
139 }
140 conout(ch); /* output the character */
141 }
142 }
143
144
145 /*****************/
146 /* console input */
147 /*****************/
148
149 UBYTE getch() /* Get char from buffer or bios */
150 /* For internal use only */
151 {
152 REG UBYTE temp;
153 BSETUP
154
155 if(GBL.kbchar)
156 {
157 temp = *GBL.remptr++; /* Fetch the character */
158 GBL.kbchar--; /* Decrement the count */
159 if(!GBL.kbchar) /* Gone to zero? */
160 GBL.remptr = GBL.insptr = &(GBL.t_buff[0]);
161 return(temp);
162 }
163 return( bconin() ); /* else get char from bios */
164 }
165
166 UBYTE conin() /* BDOS console input function */
167 {
168 REG UBYTE ch;
169 BSETUP
170
171 conout( ch = getch() );
172 if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
173 return(ch);
174 }
175
176 /******************
177 * raw console i/o *
1File: CONBDOS.C Page 4
178 ******************/
179
180 UBYTE rawconio(parm) /* BDOS raw console I/O function */
181
182 REG UWORD parm;
183 {
184 BSETUP
185
186 if (parm == 0xff) return(getch());
187 else if (parm == 0xfe) return(constat());
188 else bconout(parm & 0xff);
189 }
190
191
192 /****************************************************/
193 /* print line up to delimiter($) with tab expansion */
194 /****************************************************/
195
196 prt_line(p)
197 REG UBYTE *p;
198 {
199 BSETUP
200
201 while( *p != GBL.delim ) tabout( *p++ );
202 }
203
204
205 /**********************************************/
206 /* read line with editing and bounds checking */
207 /**********************************************/
208
209 /* Two subroutines first */
210
211 newline(startcol)
212 REG UWORD startcol;
213 {
214 BSETUP
215
216 conout(cr); /* go to new line */
217 conout(lf);
218 while(startcol)
219 {
220 conout(' ');
221 startcol -= 1; /* start output at starting column */
222 }
223 }
224
225
226 backsp(bufp, col)
227 /* backspace one character position */
228 REG struct conbuf *bufp; /* pointer to console buffer */
229 REG WORD col; /* starting console column */
230 {
231 REG UBYTE ch; /* current character */
232 REG WORD i;
233 REG UBYTE *p; /* character pointer */
234 BSETUP
235
236 if (bufp->retlen) --(bufp->retlen);
1File: CONBDOS.C Page 5
237 /* if buffer non-empty, decrease it by 1 */
238 i = UBWORD(bufp->retlen); /* get new character count */
239 p = &(bufp->cbuf[0]); /* point to character buffer */
240 while (i--) /* calculate column position */
241 { /* across entire char buffer */
242 ch = *p++; /* get next char */
243 if ( ch == tab )
244 {
245 col += 8;
246 col &= ~7; /* for tab, go to multiple of 8 */
247 }
248 else if ( (UWORD)ch < (UWORD)' ' ) col += 2;
249 /* control chars put out 2 printable chars */
250 else col += 1;
251 }
252 while (GBL.column > col)
253 {
254 conout(bs); /* backspace until we get to proper column */
255 conout(' ');
256 conout(bs);
257 }
258 }
259
260
261 readline(p) /* BDOS function 10 */
262 REG struct conbuf *p;
263
264 {
265 REG UBYTE ch;
266 REG UWORD i;
267 REG UWORD j;
268 REG UBYTE *q;
269 UWORD stcol;
270
271 BSETUP
272
273 stcol = GBL.column; /* set up starting column */
274 if (GBL.chainp != NULL) /* chain to program code */
275 {
276 i = UBWORD(*(GBL.chainp++));
277 j = UBWORD(p->maxlen);
278 if (j < i) i = j; /* don't overflow console buffer! */
279 p->retlen = (UBYTE)i;
280 q = p->cbuf;
281 while (i)
282 {
283 cookdout( *q++ = *(GBL.chainp++) );
284 i -= 1;
285 }
286 GBL.chainp = NULL;
287 return;
288 }
289
290 p->retlen = 0; /* start out with empty buffer */
291 while ( UBWORD(p->retlen) < UBWORD(p->maxlen) )
292 { /* main loop for read console buffer */
293
294 if ( ((ch=getch()) == ctrlc) && !(p->retlen) )
295 {
1File: CONBDOS.C Page 6
296 cookdout(ctrlc);
297 warmboot(1);
298 }
299
300 else if ( (ch == cr) || (ch == lf) )
301 { /* if cr or lf, exit */
302 conout(cr);
303 break;
304 }
305
306 else if (ch == bs) backsp(p, stcol); /* backspace */
307
308 else if (ch == rub) /* delete character */
309 {
310 if (GBL.echodel)
311 {
312 if (p->retlen)
313 {
314 i = UBWORD(--(p->retlen));
315 conout( p->cbuf[i] );
316 }
317 }
318 else backsp(p, stcol);
319 }
320
321 else if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
322 /* control-p */
323 else if (ch == ctrlx) /* control-x */
324 do backsp(p,stcol); while (p->retlen);
325
326 else if (ch == ctrle) newline(stcol); /* control-e */
327
328 else if (ch == ctrlu) /* control-u */
329 {
330 conout('#');
331 newline(stcol);
332 p->retlen = 0;
333 }
334
335 else if (ch == ctrlr) /* control-r */
336 {
337 conout('#');
338 newline(stcol);
339 for (i=0; i < UBWORD(p->retlen); i++)
340 cookdout( p->cbuf[i] );
341 }
342
343 else /* normal character */
344 cookdout( p->cbuf[UBWORD((p->retlen)++)] = ch );
345 }
346 }

View File

@@ -0,0 +1,41 @@
The following is a list of the modules that form the BDOS for the
C language version of CP/M-68K:
SOURCE FILES
bdosif.s - assembly language interface, trap handler,
BIOS caller, function 62 (set supervisor)
conbdos.c - BDOS functions 1 thru 11 (console functions)
bdosmisc.c - BDOS initialization, warmboot, error handler, set exception,
(used for miscellaneous BDOS routines)
dskutil.c - bit map handlers, directory read & write, dirscan
(miscellaneous disk handling utilities)
fileio.c - all file handling calls except read & write
includes open, close, delete, rename, etc.
bdosrw.c - sequential and random read & write
bdosmain.c - the BDOS case statement, global variable declarations
iosys.c - packet I/O to BIOS interface
pgmld.s - program load (function 59)
exceptn.s - exception handler
INCLUDE FILES
bdosinc.h - standard i/o stuff, universal declarations
bdosdef.h - BDOS data structure declarations
biosdef.h - procedure declarations to interface to BIOS
pktio.h - definition of data structure for packet I/O

View File

@@ -0,0 +1,31 @@
e:vax BDOSDEF.H r
e:vax BDOSIF.S r
e:vax BDOSINC.H r
e:vax BDOSMAIN.C r
e:vax BDOSMISC.C r
e:vax BDOSRW.C r
e:vax BIOSDEF.H r
e:vax CCP.C r
e:vax CCPBDOS.S r
e:vax CCPDEF.H r
e:vax CCPIF.S r
e:vax CCPLOAD.S r
e:vax CONBDOS.C r
e:vax CPMC.DOC r
e:vax CPMLIB. r
e:vax DOWN.SUB r
e:vax DOWN2.SUB r
e:vax DSKUTIL.C r
e:vax EXCEPTN.S r
e:vax FILEIO.C r
e:vax FILETYPS.S r
e:vax IOSYS.C r
e:vax MAKE.SUB r
e:vax PGMLD.S r
e:vax PKTIO.H r
e:vax REAR.SUB r
e:vax SEND2.SUB r
e:vax STACK.S r
e:vax UP2.SUB r
e:vax VMAKE.COM r
e:vax VSEND.COM r

View File

@@ -0,0 +1,26 @@
vax REAR.SUB r
vax MAKE.SUB r
vax BDOSDEF.H r
vax BDOSIF.S r
vax BDOSINC.H r
vax BDOSMAIN.C r
vax BDOSMISC.C r
vax BDOSRW.C r
vax BIOSDEF.H r
vax CONBDOS.C r
vax CPMC.DOC r
vax DSKUTIL.C r
vax EXCEPTN.S r
vax FILEIO.C r
vax IOSYS.C r
vax PGMLD.S r
vax PKTIO.H r
vax CCP.C r
vax CCPBDOS.S r
vax CCPDEF.H r
vax CCPIF.S r
vax CCPLOAD.S r
vax FILETYPS.S r
vax STACK.S r
vax SEND2.SUB r
vax up2.sub r

View File

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

View File

@@ -0,0 +1,303 @@
1File: DSKUTIL.C Page 1
1
2 /****************************************************************
3 * *
4 * CP/M-68K BDOS Disk Utilities Module *
5 * *
6 * This module contains the miscellaneous utilities *
7 * for manipulating the disk in CP/M-68K. Included are: *
8 * *
9 * dirscan() - general purpose dir scanning *
10 * setaloc() - set bit in allocation vector *
11 * clraloc() - clear bit in allocation vector *
12 * getaloc() - get free allocation block *
13 * dchksum() - directory checksum calculator *
14 * dir_rd() - read directory sector *
15 * dir_wr() - write directory sector *
16 * rdwrt() - read/write disk sector *
17 * *
18 * *
19 * Configured for Alcyon C on the VAX *
20 * *
21 ****************************************************************/
22
23 #include "bdosinc.h" /* Standard I/O declarations */
24
25 #include "bdosdef.h" /* Type and structure declarations for BDOS */
26
27 #include "pktio.h" /* Packet I/O definitions */
28
29
30 /* declare external functions and variables */
31 EXTERN UWORD do_phio(); /* external physical disk I/O routine */
32 EXTERN UWORD error(); /* external error routine */
33
34 EXTERN UWORD log_dsk; /* logged-on disk vector */
35 EXTERN UWORD ro_dsk; /* read-only disk vector */
36 EXTERN UWORD crit_dsk; /* critical disk vector */
37
38
39 /**********************
40 * read/write routine *
41 **********************/
42
43 UWORD rdwrt(secnum, dma, parm)
44 /* General disk sector read/write routine */
45 /* It simply sets up a I/O packet and sends it to do_phio */
46
47 LONG secnum; /* logical sector number to read/write */
48 UBYTE *dma; /* dma address */
49 REG WORD parm; /* 0 for read, write parm + 1 for write */
50
51 {
52 struct iopb rwpkt;
53 BSETUP
54
55 rwpkt.devnum = GBL.curdsk; /* disk to read/write */
56 if (parm)
57 {
58 rwpkt.iofcn = (BYTE)write; /* if parm non-zero, we're doing a write */
59 rwpkt.ioflags = (BYTE)(parm-1); /* pass write parm */
1File: DSKUTIL.C Page 2
60 if ( ro_dsk & (1 << (rwpkt.devnum)) ) error(4);
61 /* don't write on read-only disk */
62 }
63 else
64 {
65 rwpkt.iofcn = (BYTE)read;
66 rwpkt.ioflags = (BYTE)0;
67 }
68 rwpkt.devadr = secnum; /* sector number */
69 rwpkt.xferadr = dma; /* dma address */
70
71 /* parameters that are currently not used by do_phio
72 rwpkt.devtype = disk;
73 rwpkt.xferlen = 1;
74 */
75 rwpkt.infop = GBL.dphp; /* pass ptr to dph */
76 while ( do_phio(&rwpkt) )
77 if ( error( parm ? 1 : 0 ) ) break;
78 return(0);
79 }
80
81
82 /***************************
83 * directory read routine *
84 ***************************/
85
86 UWORD dir_rd(secnum)
87
88 WORD secnum;
89 {
90 BSETUP
91
92 return( rdwrt((LONG)secnum, GBL.dirbufp, 0) );
93 }
94
95
96 /****************************
97 * directory write routine *
98 ****************************/
99
100 UWORD dir_wr(secnum)
101
102 REG WORD secnum;
103 {
104 REG UWORD rtn;
105 BSETUP
106
107 rtn = rdwrt( (LONG)secnum, GBL.dirbufp, 2);
108 if ( secnum < (GBL.parmp)->cks )
109 *((GBL.dphp)->csv + secnum) = dchksum();
110 return(rtn);
111 }
112
113
114 /*******************************
115 * directory checksum routine *
116 *******************************/
117
118 UBYTE dchksum()
1File: DSKUTIL.C Page 3
119 /* Compute checksum over one directory sector */
120 /* Note that this implementation is dependant on the representation */
121 /* of a LONG and is therefore not very portable. But it's fast */
122 {
123 REG LONG *p; /* local temp variables */
124 REG LONG lsum;
125 REG WORD i;
126
127 BSETUP
128
129 p = GBL.dirbufp; /* point to directory buffer */
130 lsum = 0;
131 i = SECLEN / (sizeof lsum);
132 do
133 {
134 lsum += *p++; /* add next 4 bytes of directory */
135 i -= 1;
136 } while (i);
137 lsum += (lsum >> 16);
138 lsum += (lsum >> 8);
139 return( (UBYTE)(lsum & 0xff) );
140 }
141
142
143 /************************
144 * dirscan entry point *
145 ************************/
146
147 UWORD dirscan(funcp, fcbp, parms)
148
149 BOOLEAN (*funcp)(); /* funcp is a pointer to a Boolean function */
150 REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
151 REG UWORD parms; /* parms is 16 bit set of bit parameters */
152
153 /* Parms & 1 = 0 to start at beginning of dir, 1 to continue from last */
154 /* Parms & 2 = 0 to stop when *funcp is true, 1 to go until end */
155 /* Parms & 4 = 0 to check the dir checksum, 1 to store new checksum */
156 /* Parms & 8 = 0 to stop at hiwater, 1 to go until end of directory */
157
158 #define continue 1
159 #define full 2
160 #define initckv 4
161 #define pasthw 8
162
163 {
164 REG UWORD i; /* loop counter */
165 REG struct dpb *dparmp; /* pointer to disk parm block */
166 REG UWORD dirsec; /* sector number we're working on */
167 REG UWORD rtn; /* return value */
168 REG UBYTE *p; /* scratch pointer */
169 REG UWORD bitvec; /* disk nmbr represented as a vector */
170
171 BSETUP
172
173 dparmp = GBL.parmp; /* init ptr to dpb */
174 rtn = 255; /* assume it doesn't work */
175
176 i = ( (parms & continue) ? GBL.srchpos + 1 : 0 );
177 while ( (parms & pasthw) || (i <= ((GBL.dphp)->hiwater + 1)) )
1File: DSKUTIL.C Page 4
178 { /* main directory scanning loop */
179 if ( i > dparmp->drm ) break;
180 if ( ! (i & 3) )
181 { /* inside loop happens when we need to
182 read another directory sector */
183 retry: dirsec = i >> 2;
184 dir_rd(dirsec); /* read the directory sector */
185 if ( dirsec < (dparmp->cks) ) /* checksumming on this sector? */
186 {
187 p = ((GBL.dphp)->csv) + dirsec;
188 /* point to checksum vector byte */
189 if (parms & initckv) *p = dchksum();
190 else if (*p != dchksum())
191 { /* checksum error! */
192 (GBL.dphp)->hiwater = dparmp->drm; /* reset hi water */
193 bitvec = 1 << (GBL.curdsk);
194 if (crit_dsk & bitvec) /* if disk in critical mode */
195 ro_dsk |= bitvec; /* then set it to r/o */
196 else
197 {
198 log_dsk &= ~bitvec; /* else log it off */
199 seldsk(GBL.curdsk); /* and re-select it */
200 goto retry; /* and re-do current op */
201 }
202 }
203 }
204 }
205
206 GBL.srchpos = i;
207 if ( (*funcp)(fcbp, (GBL.dirbufp) + (i&3), i) )
208 /* call function with parms of (1) fcb ptr,
209 (2) pointer to directory entry, and
210 (3) directory index */
211 {
212 if (parms & full) rtn = 0; /* found a match, but keep going */
213 else return(i & 3); /* return directory code */
214 }
215 i += 1;
216 }
217 return(rtn);
218 }
219
220
221 /****************************************
222 * Routines to manage allocation vector *
223 * setaloc() *
224 * clraloc() *
225 * getaloc() *
226 ****************************************/
227
228 setaloc(bitnum)
229 /* Set bit in allocation vector */
230 REG UWORD bitnum;
231 {
232 BSETUP
233
234 if (bitnum >= 0 && bitnum <= (GBL.parmp)->dsm)
235 *((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7);
236 }
1File: DSKUTIL.C Page 5
237
238
239 clraloc(bitnum)
240 /* Clear bit in allocation vector */
241 REG UWORD bitnum;
242 {
243 BSETUP
244
245 if (bitnum > 0 && bitnum <= (GBL.parmp)->dsm)
246 *((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7));
247 }
248
249
250 UWORD chkaloc(i)
251 /* Check bit i in allocation vector */
252 /* Return non-zero if block free, else return zero */
253 REG UWORD i;
254 {
255 BSETUP
256
257 return( ~(*( (GBL.dphp)->alv + (i >> 3) )) & (0x80 >> (i&7)) );
258 }
259
260
261 UWORD getaloc(leftblk)
262 /* Get a free block in the file system and set the bit in allocation vector */
263 /* It is passed the block number of the last block allocated to the file */
264 /* It tries to allocate the block closest to the block that was passed */
265 REG UWORD leftblk;
266 {
267 REG UWORD blk; /* block number to allocate */
268 REG UWORD rtblk; /* high block number to try */
269 REG UWORD diskmax; /* # bits in alv - 1 */
270
271 BSETUP
272 LOCK /* need to lock the file system while messing
273 with the allocation vector */
274
275 diskmax = (GBL.parmp)->dsm;
276 /* get disk max field from dpb */
277 rtblk = leftblk;
278 blk = ~0; /* -1 returned if no free block found */
279 while (leftblk || rtblk < diskmax)
280 {
281 if (leftblk)
282 if (chkaloc(--leftblk))
283 {
284 blk = leftblk;
285 break;
286 }
287 if (rtblk < diskmax)
288 if (chkaloc(++rtblk))
289 {
290 blk = rtblk;
291 break;
292 }
293 }
294 if (blk != ~0) setaloc(blk);
295 UNLOCK
1File: DSKUTIL.C Page 6
296 return(blk);
297 }

View File

@@ -0,0 +1,328 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: exceptn.s
1
2 *************************************************
3 * *
4 * CP/M-68k Basic Disk Operating System *
5 * Exception Handling Module *
6 * *
7 * Version 0.0 -- July 21, 1982 *
8 * Version 0.1 -- July 25, 1982 *
9 * Version 0.2 -- October 6, 1982 *
10 * Version 0.3 -- December 21, 1982 *
11 * *
12 *************************************************
13
14
15 .globl _initexc
16 .globl _tpa_lp
17 .globl _tpa_hp
18
19 bgetseg = 18
20 bsetexc = 22
21 buserr = 2
22 spurious = 24
23 trap0 = 32
24 trap2 = 34
25 trap3 = 35
26 endvec = 48
27
28 _initexc:
29 * Initialize Exception Vector Handlers
30 * It has 1 passed parameter: the address of the exception vector array
31 00000000 7016 move #bsetexc,d0
32 00000002 7202 moveq #2,d1
33 00000004 243C00000072 move.l #exchndl,d2
34 init1:
35 0000000A 48E7E000 movem.l d0-d2,-(sp)
36 0000000E 4E43 trap #3 * BIOS call to set exception vector
37 00000010 4CDF0007 movem.l (sp)+,d0-d2
38 00000014 5241 init2: addq #1,d1
39 00000016 5882 add.l #4,d2
40 00000018 0C410018 cmpi #spurious,d1
41 0000001C 6602 bne init3
42 0000001E 7220 move #trap0,d1
43 00000020 0C410022 init3: cmpi #trap2,d1
44 00000024 67EE beq init2 * don't init trap 2 or trap 3
45 00000026 0C410023 cmpi #trap3,d1
46 0000002A 67E8 beq init2
47 0000002C 0C410030 cmpi #endvec,d1
48 00000030 6DD8 blt init1
49 * initialize the exception vector array
50
51 00000032 7012 moveq #bgetseg,d0
52 00000034 4E43 trap #3 * get the original TPA limits
53 00000036 2040 movea.l d0,a0
54 00000038 4A58 tst.w (a0)+
55 0000003A 2218 move.l (a0)+,d1 * d1 = original low TPA limit
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: exceptn.s
56 0000003C 2401 move.l d1,d2
57 0000003E D490 add.l (a0),d2 * d2 = original high TPA limit
58 00000040 263900000000 move.l _tpa_lp,d3 * d3 = new low TPA limit
59 00000046 283900000000 move.l _tpa_hp,d4 * d4 = new high TPA limit
60 0000004C 7011 move #17,d0
61 0000004E 206F0004 movea.l 4(sp),a0
62 00000052 23C800000000 move.l a0,evec_adr * save exception vector address
63 init4:
64 00000058 B290 cmp.l (a0),d1
65 0000005A 620C bhi do_init * if old exception outside orig TPA, clear it
66 0000005C B490 cmp.l (a0),d2
67 0000005E 6308 bls do_init
68 * current exception array entry is in original TPA
69 00000060 B690 cmp.l (a0),d3
70 00000062 6206 bhi dontinit * if old exception in old TPA but outside new
71 00000064 B890 cmp.l (a0),d4 * TPA, don't clear it
72 00000066 6302 bls dontinit
73 do_init:
74 00000068 4290 clr.l (a0)
75 dontinit:
76 0000006A 4A98 tst.l (a0)+
77 0000006C 51C8FFEA dbf d0,init4
78 00000070 4E75 rts
79
80 exchndl:
81 00000072 61000056 bsr.w except
82 excrtn0:
83 00000076 61000052 bsr.w except
84 0000007A 6100004E bsr.w except
85 0000007E 6100004A bsr.w except
86 00000082 61000046 bsr.w except
87 00000086 61000042 bsr.w except
88 0000008A 613E bsr.w except
89 0000008C 613C bsr.w except
90 0000008E 613A bsr.w except
91 00000090 6138 bsr.w except
92 00000092 6136 bsr.w except
93 00000094 6134 bsr.w except
94 00000096 6132 bsr.w except
95 00000098 6130 bsr.w except
96 0000009A 612E bsr.w except
97 0000009C 612C bsr.w except
98 0000009E 612A bsr.w except
99 000000A0 6128 bsr.w except
100 000000A2 6126 bsr.w except
101 000000A4 6124 bsr.w except
102 000000A6 6122 bsr.w except
103 000000A8 6120 bsr.w except
104 000000AA 611E bsr.w except
105 000000AC 611C bsr.w except
106 000000AE 611A bsr.w except
107 000000B0 6118 bsr.w except
108 000000B2 6116 bsr.w except
109 000000B4 6114 bsr.w except
110 000000B6 6112 bsr.w except
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: exceptn.s
111 000000B8 6110 bsr.w except
112 000000BA 610E bsr.w except
113 000000BC 610C bsr.w except
114 000000BE 610A bsr.w except
115 000000C0 6108 bsr.w except
116 000000C2 6106 bsr.w except
117 000000C4 6104 bsr.w except
118 000000C6 6102 bsr.w except
119 000000C8 4E71 bsr.w except
120
121
122 except:
123 000000CA 4267 clr.w -(sp)
124 000000CC 48E78080 movem.l a0/d0,-(sp) * 10 words now on stack in following order:
125 * _______________________________
126 * |____________D0.L_______________|
127 * |____________A0.L_______________|
128 * |____0000______|________________
129 * |_______Handler Return__________|
130 * If bus error, extra 2 longs are here
131 * ______________
132 * |__Status Reg__|________________
133 * |_____Exception Return__________|
134
135 000000D0 202F000A move.l 10(sp),d0 * get return address from above array
136 000000D4 90BC00000076 sub.l #excrtn0,d0 * d0 now has 4 * (encoded excptn nmbr), where
137 * encoded excptn nmbr is in [0..21,22..37]
138 * representing [2..23,32..47]
139 000000DA 0C400024 cmpi #36,d0 * if d0/4 is in [0..9,22..29] then
140 000000DE 6F10 ble chkredir * the exception may be redirected
141 000000E0 0C400058 cmpi #88,d0
142 000000E4 6D20 blt dfltexc
143 000000E6 0C400074 cmpi #116,d0
144 000000EA 6E1A bgt dfltexc
145 * in range of redirected exceptions
146 000000EC 04400030 subi #48,d0 * subtract 4*12 to normalize [0..9,22..29]
147 * into [0..9,10..17]
148 chkredir:
149 000000F0 207900000000 movea.l evec_adr,a0
150 000000F6 D0C0 adda d0,a0 * index into exception vector array
151 000000F8 4A90 tst.l (a0) * if 00000000, then not redirected
152 000000FA 6658 bne usrexc
153 * not redirected, do default handler
154 000000FC 0C400028 cmpi #40,d0
155 00000100 6D04 blt dfltexc
156 00000102 06400030 addi #48,d0 * add 4*12 that was sub'd above
157 dfltexc:
158 00000106 DEFC000E adda #14,sp * throw away 7 words that we added to stack
159 0000010A E440 asr #2,d0 * divide d0 by 4
160 * now d0 is in [0..21,22..37]
161 * to represent [2..23,32..47]
162 0000010C 0C400002 cmpi #2,d0 * bus or address error?
163 00000110 6C04 bge nobusexc
164 00000112 4CDF0300 movem.l (sp)+,a0-a1 * if yes, throw away 4 words from stack
165 nobusexc:
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 4
Source File: exceptn.s
166 00000116 4A5F tst.w (sp)+ * throw away stacked SR
167 00000118 5440 addi #2,d0
168 0000011A 0C400017 cmpi #23,d0 * get back real excptn nmbr in [2..23,32..47]
169 0000011E 6F02 ble lowexc
170 00000120 5040 addi #8,d0
171 00000122 3F00 lowexc: move d0,-(sp) * save excptn nmbr
172 00000124 41F900000000 lea excmsg1,a0
173 0000012A 6100009A bsr print * print default exception message
174 0000012E 301F move (sp)+,d0
175 00000130 610000B2 bsr prtbyte
176 00000134 41F90000000F lea excmsg2, a0
177 0000013A 6100008A bsr print
178 0000013E 201F move.l (sp)+,d0
179 00000140 61000092 bsr prtlong
180 00000144 41F900000022 lea excmsg3, a0
181 0000014A 6100007A bsr print
182 0000014E 4280 clr.l d0
183 00000150 4E42 trap #2 * warm boot
184 00000152 4E73 rte
185
186 usrexc:
187 * Call user exception handler
188 * make sure exception information is on his stack
189 00000154 2F50000A move.l (a0),10(sp) * put user handler address on our stack
190 00000158 4E68 move.l usp,a0 * user stack pointer to a0
191 0000015A 0C400008 cmpi #8,d0 * address or bus error?
192 0000015E 6D24 blt addrexc * if yes, skip
193 00000160 082F000D000E btst #13,14(sp) * exception occured in user state?
194 00000166 664A bne supstat1 * if no, go to supervisor handler
195 00000168 212F0010 move.l 16(sp),-(a0) * put exception return on user stack
196 0000016C 312F000E move.w 14(sp),-(a0) * put SR on user stack
197 00000170 4E60 move.l a0,usp * update user stack pointer
198 00000172 4CDF0101 movem.l (sp)+,a0/d0 * restore regs
199 00000176 2F6F00020008 move.l 2(sp),8(sp) * move address of user handler to excptn rtn
200 0000017C 5C4F addq #6,sp * clear junk from stack
201 0000017E 02577FFF andi #$7fff,(sp) * clear trace bit
202 00000182 4E73 rte * go to user handler
203 addrexc:
204 00000184 082F000D0016 btst #13,22(sp) * exception occured in user state?
205 0000018A 662E bne supstat2 * if no, go to supervisor handler
206 0000018C 212F0018 move.l 24(sp),-(a0) * put exception return on user stack
207 00000190 312F0016 move.w 22(sp),-(a0) * put SR on user stack
208 00000194 212F0012 move.l 18(sp),-(a0) * put extra 2 longs on user stack
209 00000198 212F000E move.l 14(sp),-(a0)
210 0000019C 4E60 move.l a0,usp * update user stack pointer
211 0000019E 4CDF0101 movem.l (sp)+,a0/d0 * restore regs
212 000001A2 2F6F00020010 move.l 2(sp),16(sp) * move address of user handler to excptn rtn
213 000001A8 DEFC000E adda #14,sp * clear junk from stack
214 000001AC 02577FFF andi #$7fff,(sp) * clear trace bit
215 000001B0 4E73 rte * go to user handler
216
217 supstat1:
218 000001B2 3F6F000E0008 move.w 14(sp),8(sp) * move SR to our exception return
219 000001B8 6006 bra supstat3
220 supstat2:
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 5
Source File: exceptn.s
221 000001BA 3F6F00160008 move.w 22(sp),8(sp)
222 supstat3:
223 000001C0 4CDF0101 movem.l (sp)+,a0/d0
224 000001C4 4E73 rte
225
226 *
227 * Subroutines
228 *
229
230 print:
231 000001C6 4281 clr.l d1
232 000001C8 1218 move.b (a0)+, d1
233 000001CA 6706 beq prtdone
234 000001CC 7002 move #2, d0
235 000001CE 4E42 trap #2
236 000001D0 60F4 bra print
237 prtdone:
238 000001D2 4E75 rts
239
240 prtlong:
241 * Print d0.l in hex format
242 000001D4 3F00 move d0,-(sp)
243 000001D6 4840 swap d0
244 000001D8 6102 bsr prtword
245 000001DA 301F move (sp)+,d0
246
247 prtword:
248 * Print d0.w in hex format
249 000001DC 3F00 move d0,-(sp)
250 000001DE E048 lsr #8,d0
251 000001E0 6102 bsr prtbyte
252 000001E2 301F move (sp)+,d0
253
254 prtbyte:
255 * Print d0.b in hex format
256 000001E4 3F00 move d0,-(sp)
257 000001E6 E848 lsr #4,d0
258 000001E8 6102 bsr prtnib
259 000001EA 301F move (sp)+,d0
260
261 prtnib:
262 000001EC 0240000F andi #$f,d0
263 000001F0 0C40000A cmpi #10,d0
264 000001F4 6D04 blt lt10
265 000001F6 06000007 addi.b #'A'-'9'-1,d0
266 lt10:
267 000001FA 06000030 addi.b #'0',d0
268 000001FE 3200 move d0,d1
269 00000200 7002 move #2,d0
270 00000202 4E42 trap #2
271 00000204 4E75 rts
272
273
274 00000000 .data
275
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 6
Source File: exceptn.s
276 excmsg1:
277 00000000 0D0A0A4578636570 .dc.b 13,10,10,'Exception $',0
277 00000008 74696F6E202400
278
279 excmsg2:
280 0000000F 2061742075736572 .dc.b ' at user address $',0
280 00000017 2061646472657373
280 0000001F 202400
281
282 excmsg3:
283 00000022 2E202041626F7274 .dc.b '. Aborted.',0
283 0000002A 65642E00
284
285
286 00000000 .bss
287
288 evec_adr:
289 00000000 .ds.l 1
290
291 00000004 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 7
Source File: exceptn.s
S y m b o l T a b l e
_initexc 00000000 TEXT _tpa_hp ******** EXT _tpa_lp ******** EXT addrexc 00000184 TEXT
bgetseg 00000012 ABS bsetexc 00000016 ABS buserr 00000002 ABS chkredir 000000F0 TEXT
dfltexc 00000106 TEXT do_init 00000068 TEXT dontinit 0000006A TEXT endvec 00000030 ABS
evec_adr 00000000 BSS except 000000CA TEXT exchndl 00000072 TEXT excmsg1 00000000 DATA
excmsg2 0000000F DATA excmsg3 00000022 DATA excrtn0 00000076 TEXT init1 0000000A TEXT
init2 00000014 TEXT init3 00000020 TEXT init4 00000058 TEXT lowexc 00000122 TEXT
lt10 000001FA TEXT nobusexc 00000116 TEXT print 000001C6 TEXT prtbyte 000001E4 TEXT
prtdone 000001D2 TEXT prtlong 000001D4 TEXT prtnib 000001EC TEXT prtword 000001DC TEXT
spurious 00000018 ABS supstat1 000001B2 TEXT supstat2 000001BA TEXT supstat3 000001C0 TEXT
trap0 00000020 ABS trap2 00000022 ABS trap3 00000023 ABS usrexc 00000154 TEXT

View File

@@ -0,0 +1,291 @@
*************************************************
* *
* CP/M-68k Basic Disk Operating System *
* Exception Handling Module *
* *
* Version 0.0 -- July 21, 1982 *
* Version 0.1 -- July 25, 1982 *
* Version 0.2 -- October 6, 1982 *
* Version 0.3 -- December 21, 1982 *
* *
*************************************************
.globl _initexc
.globl _tpa_lp
.globl _tpa_hp
bgetseg = 18
bsetexc = 22
buserr = 2
spurious = 24
trap0 = 32
trap2 = 34
trap3 = 35
endvec = 48
_initexc:
* Initialize Exception Vector Handlers
* It has 1 passed parameter: the address of the exception vector array
move #bsetexc,d0
moveq #2,d1
move.l #exchndl,d2
init1:
movem.l d0-d2,-(sp)
trap #3 * BIOS call to set exception vector
movem.l (sp)+,d0-d2
init2: addq #1,d1
add.l #4,d2
cmpi #spurious,d1
bne init3
move #trap0,d1
init3: cmpi #trap2,d1
beq init2 * don't init trap 2 or trap 3
cmpi #trap3,d1
beq init2
cmpi #endvec,d1
blt init1
* initialize the exception vector array
moveq #bgetseg,d0
trap #3 * get the original TPA limits
movea.l d0,a0
tst.w (a0)+
move.l (a0)+,d1 * d1 = original low TPA limit
move.l d1,d2
add.l (a0),d2 * d2 = original high TPA limit
move.l _tpa_lp,d3 * d3 = new low TPA limit
move.l _tpa_hp,d4 * d4 = new high TPA limit
move #17,d0
movea.l 4(sp),a0
move.l a0,evec_adr * save exception vector address
init4:
cmp.l (a0),d1
bhi do_init * if old exception outside orig TPA, clear it
cmp.l (a0),d2
bls do_init
* current exception array entry is in original TPA
cmp.l (a0),d3
bhi dontinit * if old exception in old TPA but outside new
cmp.l (a0),d4 * TPA, don't clear it
bls dontinit
do_init:
clr.l (a0)
dontinit:
tst.l (a0)+
dbf d0,init4
rts
exchndl:
bsr.w except
excrtn0:
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
bsr.w except
except:
clr.w -(sp)
movem.l a0/d0,-(sp) * 10 words now on stack in following order:
* _______________________________
* |____________D0.L_______________|
* |____________A0.L_______________|
* |____0000______|________________
* |_______Handler Return__________|
* If bus error, extra 2 longs are here
* ______________
* |__Status Reg__|________________
* |_____Exception Return__________|
move.l 10(sp),d0 * get return address from above array
sub.l #excrtn0,d0 * d0 now has 4 * (encoded excptn nmbr), where
* encoded excptn nmbr is in [0..21,22..37]
* representing [2..23,32..47]
cmpi #36,d0 * if d0/4 is in [0..9,22..29] then
ble chkredir * the exception may be redirected
cmpi #88,d0
blt dfltexc
cmpi #116,d0
bgt dfltexc
* in range of redirected exceptions
subi #48,d0 * subtract 4*12 to normalize [0..9,22..29]
* into [0..9,10..17]
chkredir:
movea.l evec_adr,a0
adda d0,a0 * index into exception vector array
tst.l (a0) * if 00000000, then not redirected
bne usrexc
* not redirected, do default handler
cmpi #40,d0
blt dfltexc
addi #48,d0 * add 4*12 that was sub'd above
dfltexc:
adda #14,sp * throw away 7 words that we added to stack
asr #2,d0 * divide d0 by 4
* now d0 is in [0..21,22..37]
* to represent [2..23,32..47]
cmpi #2,d0 * bus or address error?
bge nobusexc
movem.l (sp)+,a0-a1 * if yes, throw away 4 words from stack
nobusexc:
tst.w (sp)+ * throw away stacked SR
addi #2,d0
cmpi #23,d0 * get back real excptn nmbr in [2..23,32..47]
ble lowexc
addi #8,d0
lowexc: move d0,-(sp) * save excptn nmbr
lea excmsg1,a0
bsr print * print default exception message
move (sp)+,d0
bsr prtbyte
lea excmsg2, a0
bsr print
move.l (sp)+,d0
bsr prtlong
lea excmsg3, a0
bsr print
clr.l d0
trap #2 * warm boot
rte
usrexc:
* Call user exception handler
* make sure exception information is on his stack
move.l (a0),10(sp) * put user handler address on our stack
move.l usp,a0 * user stack pointer to a0
cmpi #8,d0 * address or bus error?
blt addrexc * if yes, skip
btst #13,14(sp) * exception occured in user state?
bne supstat1 * if no, go to supervisor handler
move.l 16(sp),-(a0) * put exception return on user stack
move.w 14(sp),-(a0) * put SR on user stack
move.l a0,usp * update user stack pointer
movem.l (sp)+,a0/d0 * restore regs
move.l 2(sp),8(sp) * move address of user handler to excptn rtn
addq #6,sp * clear junk from stack
andi #$7fff,(sp) * clear trace bit
rte * go to user handler
addrexc:
btst #13,22(sp) * exception occured in user state?
bne supstat2 * if no, go to supervisor handler
move.l 24(sp),-(a0) * put exception return on user stack
move.w 22(sp),-(a0) * put SR on user stack
move.l 18(sp),-(a0) * put extra 2 longs on user stack
move.l 14(sp),-(a0)
move.l a0,usp * update user stack pointer
movem.l (sp)+,a0/d0 * restore regs
move.l 2(sp),16(sp) * move address of user handler to excptn rtn
adda #14,sp * clear junk from stack
andi #$7fff,(sp) * clear trace bit
rte * go to user handler
supstat1:
move.w 14(sp),8(sp) * move SR to our exception return
bra supstat3
supstat2:
move.w 22(sp),8(sp)
supstat3:
movem.l (sp)+,a0/d0
rte
*
* Subroutines
*
print:
clr.l d1
move.b (a0)+, d1
beq prtdone
move #2, d0
trap #2
bra print
prtdone:
rts
prtlong:
* Print d0.l in hex format
move d0,-(sp)
swap d0
bsr prtword
move (sp)+,d0
prtword:
* Print d0.w in hex format
move d0,-(sp)
lsr #8,d0
bsr prtbyte
move (sp)+,d0
prtbyte:
* Print d0.b in hex format
move d0,-(sp)
lsr #4,d0
bsr prtnib
move (sp)+,d0
prtnib:
andi #$f,d0
cmpi #10,d0
blt lt10
addi.b #'A'-'9'-1,d0
lt10:
addi.b #'0',d0
move d0,d1
move #2,d0
trap #2
rts
.data
excmsg1:
.dc.b 13,10,10,'Exception $',0
excmsg2:
.dc.b ' at user address $',0
excmsg3:
.dc.b '. Aborted.',0
.bss
evec_adr:
.ds.l 1
.end

View File

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

View File

@@ -0,0 +1,671 @@
1File: FILEIO.C Page 1
1
2 /****************************************************************
3 * *
4 * CP/M-68K BDOS File I/O Module *
5 * *
6 * This module contains all file handling BDOS functions *
7 * except for read and write for CP/M-68K. Included are: *
8 * *
9 * seldsk() - select disk *
10 * openfile() - open file *
11 * close_fi() - close file *
12 * search() - search for first/next file match *
13 * create() - create file *
14 * delete() - delete file *
15 * rename() - rename file *
16 * set_attr() - set file attributes *
17 * getsize() - get file size *
18 * setran() - set random record field *
19 * free_sp() - get disk free space *
20 * move() - general purpose byte mover *
21 * *
22 * *
23 * Compiled with Alcyon C on the VAX *
24 * *
25 ****************************************************************/
26
27 #include "bdosinc.h" /* Standard I/O declarations */
28
29 #include "bdosdef.h" /* Type and structure declarations for BDOS */
30
31 #include "pktio.h" /* Packet I/O definitions */
32
33 /* declare external fucntions */
34 EXTERN UWORD dirscan(); /* directory scanning routine */
35 EXTERN UWORD error(); /* disk error routine */
36 EXTERN UWORD ro_err(); /* read-only file error routine */
37 EXTERN UWORD do_phio(); /* packet disk i/o handler */
38 EXTERN clraloc(); /* clear bit in allocation vector */
39 EXTERN setaloc(); /* set bit in allocation vector */
40 EXTERN UWORD swap(); /* assembly language byte swapper */
41 EXTERN UWORD dir_wr(); /* directory write routine */
42 EXTERN tmp_sel(); /* temporary select disk routine */
43 EXTERN UWORD calcext(); /* calc max extent allocated for fcb */
44 EXTERN UWORD udiv(); /* unsigned divide routine */
45
46
47 /* declare external variables */
48 EXTERN UWORD log_dsk; /* logged-on disk vector */
49 EXTERN UWORD ro_dsk; /* read-only disk vector */
50 EXTERN UWORD crit_dsk; /* vector of disks in critical state */
51
52
53 /************************************
54 * This function passed to dirscan *
55 * from seldsk (below) *
56 ************************************/
57
58 BOOLEAN alloc(fcbp, dirp, dirindx)
59 /* Set up allocation vector for directory entry pointed to by dirp */
1File: FILEIO.C Page 2
60
61 struct fcb *fcbp; /* not used in this function */
62 REG struct dirent *dirp; /* pointer to directory entry */
63 WORD dirindx; /* index into directory for *dirp */
64 {
65 REG WORD i; /* loop counter */
66 BSETUP
67
68 if ( UBWORD(dirp->entry) < 0x10 ) /* skip MP/M 2.x and CP/M 3.x XFCBs */
69 {
70 (GBL.dphp)->hiwater = dirindx; /* set up high water mark for disk */
71 i = 0;
72 if ((GBL.parmp)->dsm < 256)
73 {
74 do setaloc( UBWORD(dirp->dskmap.small[i++]) );
75 while (i <= 15);
76 }
77 else
78 {
79 do setaloc(swap(dirp->dskmap.big[i++]));
80 while (i <= 7);
81 }
82 }
83 }
84
85
86 /************************
87 * seldsk entry point *
88 ************************/
89
90 seldsk(dsknum)
91
92 REG UBYTE dsknum; /* disk number to select */
93
94 {
95 struct iopb selpkt;
96 REG WORD i;
97 UWORD j;
98 REG UBYTE logflag;
99 BSETUP
100
101 logflag = ~(log_dsk >> dsknum) & 1;
102 if ((GBL.curdsk != dsknum) || logflag)
103 { /* if not last used disk or not logged on */
104 selpkt.iofcn = sel_info;
105 GBL.curdsk = (selpkt.devnum = dsknum);
106 if (UBWORD(dsknum) > 15) error(2);
107 selpkt.ioflags = logflag ^ 1;
108 do
109 {
110 do_phio(&selpkt); /* actually do the disk select */
111 if ( (GBL.dphp = selpkt.infop) != NULL ) break;
112 } while ( ! error(3) );
113
114 GBL.dirbufp = (GBL.dphp)->dbufp;
115 /* set up GBL copies of dir_buf and dpb ptrs */
116 GBL.parmp = (GBL.dphp)->dpbp;
117 }
118 if (logflag)
1File: FILEIO.C Page 3
119 { /* if disk not previously logged on, do it now */
120 LOCK /* must lock the file system while messing with alloc vec */
121 i = (GBL.parmp)->dsm;
122 do clraloc(i); while (i--); /* clear the allocation vector */
123 i = udiv( (LONG)(((GBL.parmp)->drm) + 1),
124 4 * (((GBL.parmp)->blm) + 1), &j);
125 /* calculate nmbr of directory blks */
126 if (j) i++; /* round up */
127 do setaloc(--i); while (i); /* alloc directory blocks */
128 dirscan(alloc, NULL, 0x0e); /* do directory scan & alloc blocks */
129 log_dsk |= 1 << dsknum; /* mark disk as logged in */
130 }
131 }
132
133
134 /*******************************
135 * General purpose byte mover *
136 *******************************/
137
138 move(p1, p2, i)
139
140 REG BYTE *p1;
141 REG BYTE *p2;
142 REG WORD i;
143 {
144 while (i--)
145 *p2++ = *p1++;
146 }
147
148
149 /*************************************
150 * General purpose filename matcher *
151 *************************************/
152
153 BOOLEAN match(p1, p2, chk_ext)
154
155 REG UBYTE *p1;
156 REG UBYTE *p2;
157 BOOLEAN chk_ext;
158 {
159 REG WORD i;
160 REG UBYTE temp;
161 BSETUP
162
163 i = 12;
164 do
165 {
166 temp = (*p1 ^ '?');
167 if ( ((*p1++ ^ *p2++) & 0x7f) && temp )
168 return(FALSE);
169 i -= 1;
170 } while (i);
171 if (chk_ext)
172 {
173 if ( (*p1 != '?') && ((*p1 ^ *p2) & ~((GBL.parmp)->exm)) )
174 return(FALSE);
175 p1 += 2;
176 p2 += 2;
177 if ((*p1 ^ *p2) & 0x3f) return(FALSE);
1File: FILEIO.C Page 4
178 }
179 return(TRUE);
180 }
181
182
183 /************************
184 * openfile entry point *
185 ************************/
186
187 BOOLEAN openfile(fcbp, dirp, dirindx)
188
189 REG struct fcb *fcbp; /* pointer to fcb for file to open */
190 struct dirent *dirp; /* pointer to directory entry */
191 WORD dirindx;
192
193 {
194 REG UBYTE fcb_ext; /* extent field from fcb */
195 REG BOOLEAN rtn;
196 BSETUP
197
198 if ( rtn = match(fcbp, dirp, TRUE) )
199 {
200 fcb_ext = fcbp->extent; /* save extent number from user's fcb */
201 move(dirp, fcbp, sizeof *dirp);
202 /* copy dir entry into user's fcb */
203 fcbp->extent = fcb_ext;
204 fcbp->s2 |= 0x80; /* set hi bit of S2 (write flag) */
205 crit_dsk |= 1 << (GBL.curdsk);
206 }
207 return(rtn);
208 }
209
210
211 /*************************/
212 /* flush buffers routine */
213 /*************************/
214
215 UWORD flushit()
216 {
217 REG UWORD rtn; /* return code from flush buffers call */
218 struct iopb flushpkt; /* I/O packet for flush buffers call */
219
220 flushpkt.iofcn = flush;
221 while ( rtn = do_phio(&flushpkt) )
222 if ( error(1) ) break;
223 return(rtn);
224 }
225
226
227 /*********************************
228 * file close routine for dirscan *
229 *********************************/
230
231 BOOLEAN close(fcbp, dirp, dirindx)
232
233 REG struct fcb *fcbp; /* pointer to fcb */
234 REG struct dirent *dirp; /* pointer to directory entry */
235 WORD dirindx; /* index into directory */
236
1File: FILEIO.C Page 5
237 {
238 REG WORD i;
239 REG UBYTE *fp;
240 REG UBYTE *dp;
241 REG UWORD fcb_ext;
242 REG UWORD dir_ext;
243 BSETUP
244
245 if ( match(fcbp, dirp, TRUE) )
246 { /* Note that FCB merging is done here as a final
247 confirmation that disks haven't been swapped */
248 LOCK
249 fp = &(fcbp->dskmap.small[0]);
250 dp = &(dirp->dskmap.small[0]);
251 if ((GBL.parmp)->dsm < 256)
252 { /* Small disk map merge routine */
253 i = 16;
254 do
255 {
256 if (*dp)
257 {
258 if (*fp)
259 {
260 if (*dp != *fp) goto badmerge;
261 }
262 else *fp = *dp;
263 }
264 else *dp = *fp;
265 fp += 1;
266 dp += 1;
267 i -= 1;
268 } while (i);
269 }
270 else
271 { /* Large disk map merge routine */
272 i = 8;
273 do
274 {
275 if (*(UWORD *)dp)
276 {
277 if (*(UWORD *)fp)
278 {
279 if (*(UWORD *)dp != *(UWORD *)fp) goto badmerge;
280 }
281 else *(UWORD *)fp = *(UWORD *)dp;
282 }
283 else *(UWORD *)dp = *(UWORD *)fp;
284 (UWORD *)fp += 1;
285 (UWORD *)dp += 1;
286 i -= 1;
287 } while (i);
288 }
289 /* Disk map merging complete */
290 fcb_ext = calcext(fcbp); /* calc max extent for fcb */
291 dir_ext = (UWORD)(dirp->extent) & 0x1f;
292 if ( (fcb_ext > dir_ext) ||
293 ((fcb_ext == dir_ext) &&
294 (UBWORD(fcbp->rcdcnt) > UBWORD(dirp->rcdcnt))) )
295 /* if fcb points to larger file than dirp */
1File: FILEIO.C Page 6
296 {
297 dirp->rcdcnt = fcbp->rcdcnt; /* set up rc, ext from fcb */
298 dirp->extent = (BYTE)fcb_ext;
299 }
300 dirp->s1 = fcbp->s1;
301 if ( (dirp->ftype[robit]) & 0x80) ro_err(fcbp,dirindx);
302 /* read-only file error */
303 dirp->ftype[arbit] &= 0x7f; /* clear archive bit */
304 dir_wr(dirindx >> 2);
305 UNLOCK
306 return(TRUE);
307
308 badmerge:
309 UNLOCK
310 ro_dsk |= (1 << GBL.curdsk);
311 return(FALSE);
312 }
313 else return(FALSE);
314 }
315
316
317 /************************
318 * close_fi entry point *
319 ************************/
320
321 UWORD close_fi(fcbp)
322
323 struct fcb *fcbp; /* pointer to fcb for file to close */
324 {
325 flushit(); /* first, flush the buffers */
326 if ((fcbp->s2) & 0x80) return(0); /* if file write flag not on,
327 don't need to do physical close */
328 return( dirscan(close, fcbp, 0)); /* call dirscan with close function */
329 }
330
331
332 /************************
333 * search entry point *
334 ************************/
335
336 /* First two functions for dirscan */
337
338 BOOLEAN alltrue(p1, p2, i)
339 UBYTE *p1;
340 UBYTE *p2;
341 WORD i;
342 {
343 return(TRUE);
344 }
345
346 BOOLEAN matchit(p1, p2, i)
347 UBYTE *p1;
348 UBYTE *p2;
349 WORD i;
350 {
351 return(match(p1, p2, TRUE));
352 }
353
354
1File: FILEIO.C Page 7
355 /* search entry point */
356 UWORD search(fcbp, dsparm, p)
357
358 REG struct fcb *fcbp; /* pointer to fcb for file to search */
359 REG UWORD dsparm; /* parameter to pass through to dirscan */
360 UBYTE *p; /* pointer to pass through to tmp_sel */
361
362 {
363 REG UWORD rtn; /* return value */
364 BSETUP
365
366 if (fcbp->drvcode == '?')
367 {
368 seldsk(GBL.dfltdsk);
369 rtn = dirscan(alltrue, fcbp, dsparm);
370 }
371 else
372 {
373 tmp_sel(p); /* temporarily select disk */
374 if (fcbp->extent != '?') fcbp->extent = 0;
375 fcbp->s2 = 0;
376 rtn = dirscan(matchit, fcbp, dsparm);
377 }
378 move( GBL.dirbufp, GBL.dmaadr, SECLEN);
379 return(rtn);
380 }
381
382
383 /************************
384 * create entry point *
385 ************************/
386
387 BOOLEAN create(fcbp, dirp, dirindx)
388
389 REG struct fcb *fcbp; /* pointer to fcb for file to create */
390 REG struct dirent *dirp; /* pointer to directory entry */
391 REG WORD dirindx; /* index into directory */
392
393 {
394 REG BYTE *p;
395 REG WORD i;
396 REG BOOLEAN rtn;
397 BSETUP
398
399 if ( rtn = ((dirp->entry) == 0xe5) )
400 {
401 p = &(fcbp->rcdcnt);
402 i = 17;
403 do
404 { /* clear fcb rcdcnt and disk map */
405 *p++ = 0;
406 i -= 1;
407 } while (i);
408 move(fcbp, dirp, sizeof *dirp); /* move the fcb to the directory */
409 dir_wr(dirindx >> 2); /* write the directory sector */
410 if ( dirindx > (GBL.dphp)->hiwater )
411 (GBL.dphp)->hiwater = dirindx;
412 crit_dsk |= 1 << (GBL.curdsk);
413 }
1File: FILEIO.C Page 8
414 return(rtn);
415 }
416
417
418 /************************
419 * delete entry point *
420 ************************/
421
422 BOOLEAN delete(fcbp, dirp, dirindx)
423
424 REG struct fcb *fcbp; /* pointer to fcb for file to delete */
425 REG struct dirent *dirp; /* pointer to directory entry */
426 REG WORD dirindx; /* index into directory */
427
428 {
429 REG WORD i;
430 REG BOOLEAN rtn;
431 BSETUP
432
433 if ( rtn = match(fcbp, dirp, FALSE) )
434 {
435 if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx);
436 /* check for read-only file */
437 dirp->entry = 0xe5;
438 LOCK
439 dir_wr(dirindx >> 2);
440 /* Now free up the space in the allocation vector */
441 if ((GBL.parmp)->dsm < 256)
442 {
443 i = 16;
444 do clraloc(UBWORD(dirp->dskmap.small[--i]));
445 while (i);
446 }
447 else
448 {
449 i = 8;
450 do clraloc(swap(dirp->dskmap.big[--i]));
451 while (i);
452 }
453 UNLOCK
454 }
455 return(rtn);
456 }
457
458
459 /************************
460 * rename entry point *
461 ************************/
462
463 BOOLEAN rename(fcbp, dirp, dirindx)
464
465 REG struct fcb *fcbp; /* pointer to fcb for file to delete */
466 REG struct dirent *dirp; /* pointer to directory entry */
467 REG WORD dirindx; /* index into directory */
468
469 {
470 REG UWORD i;
471 REG BYTE *p; /* general purpose pointers */
472 REG BYTE *q;
1File: FILEIO.C Page 9
473 REG BOOLEAN rtn;
474 BSETUP
475
476 if ( rtn = match(fcbp, dirp, FALSE) )
477 {
478 if ( (dirp->ftype[robit]) & 0x80 ) ro_err(fcbp,dirindx);
479 /* check for read-only file */
480 p = &(fcbp->dskmap.small[1]);
481 q = &(dirp->fname[0]);
482 i = 11;
483 do
484 {
485 *q++ = *p++ & 0x7f;
486 i -= 1;
487 } while (i);
488 dir_wr(dirindx >> 2);
489 }
490 return(rtn);
491 }
492
493
494 /************************
495 * set_attr entry point *
496 ************************/
497
498 BOOLEAN set_attr(fcbp, dirp, dirindx)
499
500 REG struct fcb *fcbp; /* pointer to fcb for file to delete */
501 REG struct dirent *dirp; /* pointer to directory entry */
502 REG WORD dirindx; /* index into directory */
503
504 {
505 REG BOOLEAN rtn;
506 BSETUP
507
508 if ( rtn = match(fcbp, dirp, FALSE) )
509 {
510 move(&fcbp->fname[0], &dirp->fname[0], 11);
511 dir_wr(dirindx >> 2);
512 }
513 return(rtn);
514 }
515
516
517 /****************************
518 * utility routine used by *
519 * setran and getsize *
520 ****************************/
521
522 LONG extsize(fcbp)
523 /* Return size of extent pointed to by fcbp */
524 REG struct fcb *fcbp;
525
526 {
527 return( ((LONG)(fcbp->extent & 0x1f) << 7)
528 | ((LONG)(fcbp->s2 & 0x3f) << 12) );
529 }
530
531
1File: FILEIO.C Page 10
532 /************************
533 * setran entry point *
534 ************************/
535
536 setran(fcbp)
537
538 REG struct fcb *fcbp; /* pointer to fcb for file to set ran rec */
539
540 {
541 struct
542 {
543 BYTE b3;
544 BYTE b2;
545 BYTE b1;
546 BYTE b0;
547 };
548 LONG random;
549
550 random = (LONG)UBWORD(fcbp->cur_rec) + extsize(fcbp);
551 /* compute random record field */
552 fcbp->ran0 = random.b2;
553 fcbp->ran1 = random.b1;
554 fcbp->ran2 = random.b0;
555 }
556
557
558 /**********************************/
559 /* fsize is a funtion for dirscan */
560 /* passed from getsize */
561 /**********************************/
562
563 BOOLEAN fsize(fcbp, dirp, dirindx)
564
565 REG struct fcb *fcbp; /* pointer to fcb for file to delete */
566 REG struct dirent *dirp; /* pointer to directory entry */
567 WORD dirindx; /* index into directory */
568
569 {
570 REG BOOLEAN rtn;
571 struct
572 {
573 BYTE b3;
574 BYTE b2;
575 BYTE b1;
576 BYTE b0;
577 };
578 LONG temp;
579
580 if ( rtn = match(fcbp, dirp, FALSE) )
581 {
582 temp = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp);
583 /* compute file size */
584 fcbp->ran0 = temp.b2;
585 fcbp->ran1 = temp.b1;
586 fcbp->ran2 = temp.b0;
587 }
588 return(rtn);
589 }
590
1File: FILEIO.C Page 11
591 /************************
592 * getsize entry point *
593 ************************/
594
595 getsize(fcbp)
596 /* get file size */
597 REG struct fcb *fcbp; /* pointer to fcb to get file size for */
598
599 {
600 LONG maxrcd;
601 LONG temp;
602 REG WORD dsparm;
603 struct
604 {
605 BYTE b3;
606 BYTE b2;
607 BYTE b1;
608 BYTE b0;
609 };
610
611 maxrcd = 0;
612 dsparm = 0;
613 temp = 0;
614 while ( dirscan(fsize, fcbp, dsparm) < 255 )
615 { /* loop until no more matches */
616 temp.b2 = fcbp->ran0;
617 temp.b1 = fcbp->ran1;
618 temp.b0 = fcbp->ran2;
619 if (temp > maxrcd) maxrcd = temp;
620 dsparm = 1;
621 }
622 fcbp->ran0 = maxrcd.b2;
623 fcbp->ran1 = maxrcd.b1;
624 fcbp->ran2 = maxrcd.b0;
625 }
626
627
628 /************************
629 * free_sp entry point *
630 ************************/
631
632 free_sp(dsknum)
633
634 UBYTE dsknum; /* disk number to get free space of */
635 {
636 REG LONG records;
637 REG UWORD *alvec;
638 REG UWORD bitmask;
639 REG UWORD alvword;
640 REG WORD i;
641 BSETUP
642
643 seldsk(dsknum); /* select the disk */
644 records = (LONG)0; /* initialize the variables */
645 alvec = (GBL.dphp)->alv;
646 bitmask = 0;
647 for (i = 0; i <= (GBL.parmp)->dsm; i++) /* for loop to compute */
648 {
649 if ( ! bitmask)
1File: FILEIO.C Page 12
650 {
651 bitmask = 0x8000;
652 alvword = ~(*alvec++);
653 }
654 if ( alvword & bitmask)
655 records += (LONG)( ((GBL.parmp)->blm) + 1 );
656 bitmask >>= 1;
657 }
658 *(LONG *)GBL.dmaadr = records; /* move # records to DMA address */
659 }

View File

@@ -0,0 +1,113 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: filetyps.s
1
2 *
3 * CP/M-68K table driven file search module
4 * ========================================
5 *
6
7 * GLOBALS
8
9
10 .globl _load_tbl * loader table
11 .globl _load68k * default load program
12 .globl init_tbl * initializes table on COLD BOOT
13
14 00000000 .text
15 *************************************************************************
16 * *
17 * This is the DUAL PROCESSOR,ROMABLE version of CP/M-68K *
18 * ====================================================== *
19 * *
20 * (c) Copyright Digital Research 1983 *
21 * all rights reserved *
22 * *
23 *************************************************************************
24
25 *
26 * The following code allows CP/M-68K to be ROM-able.
27 * -------------------------------------------------
28 *
29
30 init_tbl:
31 00000000 23FC0000000000000000 move.l #typ1,typ1p
32 0000000A 23FC000000040000000A move.l #typ2,typ2p * init the pointers to the filetypes
33 00000014 23FC0000000800000014 move.l #typ3,typ3p
34 0000001E 23FC0000000C0000001E move.l #null,typ4p
35
36 00000028 23FC0000000000000004 move.l #_load68k,pgld1
37 00000032 23FC000000000000000E move.l #_load68k,pgld2 * init the pointers to the loaders
38 0000003C 23FC0000000000000018 move.l #_load68k,pgld3
39 00000046 23FC0000000000000022 move.l #_load68k,pgld4
40
41 00000050 4E75 rts
42 00000000 .bss
43 .even
44 *************************************************************************
45 * *
46 * CP/M-68K LOADER TABLE *
47 * ===================== *
48 * *
49 *-----------------------------------------------------------------------*
50 * *
51 * STRUCTURE OF A LOADER TABLE ENTRY: *
52 * ================================= *
53 * *
54 * (1) LONG WORD pointer to a filetype *
55 * (2) LONG WORD address of the program loader for the above type *
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: filetyps.s
56 * (3) BYTE flag #1 *
57 * (4) BYTE flag #2 *
58 * *
59 *************************************************************************
60
61
62 _load_tbl:
63 00000000 typ1p: .ds.l 1
64 00000004 pgld1: .ds.l 1
65 00000008 .ds.b 1
66 00000009 .ds.b 1
67 0000000A typ2p: .ds.l 1
68 0000000E pgld2: .ds.l 1
69 00000012 .ds.b 1
70 00000013 .ds.b 1
71 00000014 typ3p: .ds.l 1
72 00000018 pgld3: .ds.l 1
73 0000001C .ds.b 1
74 0000001D .ds.b 1
75 0000001E typ4p: .ds.l 1
76 00000022 pgld4: .ds.l 1
77 00000026 .ds.b 1
78 00000027 .ds.b 1
79
80
81 *****************************************
82 * *
83 * FILETYPE TABLE *
84 * ============== *
85 * *
86 *****************************************
87
88
89 00000000 .data
90 .even
91 00000000 36384B00 typ1: .dc.b '68K',0
92 .even
93 00000004 20202000 typ2: .dc.b ' ',0
94 .even
95 00000008 53554200 typ3: .dc.b 'SUB',0
96 .even
97 0000000C 00000000 null: .dc.l 0
98 00000010 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: filetyps.s
S y m b o l T a b l e
_load68k ******** EXT _load_tb 00000000 BSS init_tbl 00000000 TEXT null 0000000C DATA
pgld1 00000004 BSS pgld2 0000000E BSS pgld3 00000018 BSS pgld4 00000022 BSS
typ1 00000000 DATA typ1p 00000000 BSS typ2 00000004 DATA typ2p 0000000A BSS
typ3 00000008 DATA typ3p 00000014 BSS typ4p 0000001E BSS

View File

@@ -0,0 +1,106 @@
*
* CP/M-68K table driven file search module
* ========================================
*
* GLOBALS
.globl _load_tbl * loader table
.globl _load68k * default load program
.globl init_tbl * initializes table on COLD BOOT
.text
*************************************************************************
* *
* This is the DUAL PROCESSOR,ROMABLE version of CP/M-68K *
* ====================================================== *
* *
* (c) Copyright Digital Research 1983 *
* all rights reserved *
* *
*************************************************************************
*
* The following code allows CP/M-68K to be ROM-able.
* -------------------------------------------------
*
init_tbl:
move.l #typ1,typ1p
move.l #typ2,typ2p * init the pointers to the filetypes
move.l #typ3,typ3p
move.l #null,typ4p
move.l #_load68k,pgld1
move.l #_load68k,pgld2 * init the pointers to the loaders
move.l #_load68k,pgld3
move.l #_load68k,pgld4
rts
.bss
.even
*************************************************************************
* *
* CP/M-68K LOADER TABLE *
* ===================== *
* *
*-----------------------------------------------------------------------*
* *
* STRUCTURE OF A LOADER TABLE ENTRY: *
* ================================= *
* *
* (1) LONG WORD pointer to a filetype *
* (2) LONG WORD address of the program loader for the above type *
* (3) BYTE flag #1 *
* (4) BYTE flag #2 *
* *
*************************************************************************
_load_tbl:
typ1p: .ds.l 1
pgld1: .ds.l 1
.ds.b 1
.ds.b 1
typ2p: .ds.l 1
pgld2: .ds.l 1
.ds.b 1
.ds.b 1
typ3p: .ds.l 1
pgld3: .ds.l 1
.ds.b 1
.ds.b 1
typ4p: .ds.l 1
pgld4: .ds.l 1
.ds.b 1
.ds.b 1
*****************************************
* *
* FILETYPE TABLE *
* ============== *
* *
*****************************************
.data
.even
typ1: .dc.b '68K',0
.even
typ2: .dc.b ' ',0
.even
typ3: .dc.b 'SUB',0
.even
null: .dc.l 0
.end

View File

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

View File

@@ -0,0 +1,79 @@
1File: IOSYS.C Page 1
1 /****************************************************************
2 * *
3 * CP/M-68K BDOS Disk I/O System Module *
4 * *
5 * This module translates from the packet oriented I/O *
6 * passed from the other BDOS modules into BIOS calls. *
7 * *
8 * It includes only one external entry point:
9 * do_phio() - do physical i/o *
10 * *
11 * *
12 * Configured for Alcyon C on the VAX *
13 * *
14 ****************************************************************/
15
16 #include "bdosinc.h" /* Standard I/O declarations */
17
18 #include "bdosdef.h" /* Type and structure declarations for BDOS */
19
20 #include "pktio.h" /* Packet I/O definitions */
21
22 #include "biosdef.h" /* Declarations for BIOS entry points */
23
24 EXTERN udiv(); /* Assembly language unsigned divide routine */
25 /* in bdosif.s. It's used because Alcyon C */
26 /* can't do / or % without an external */
27
28 /************************
29 * do_phio entry point *
30 ************************/
31
32 UWORD do_phio(iop)
33
34 REG struct iopb *iop; /* iop is a pointer to a i/o parameter block */
35
36 {
37 MLOCAL UBYTE last_dsk; /* static variable to tell which disk
38 was last used, to avoid disk selects */
39 REG struct dph *hdrp; /* pointer to disk parameter header */
40 REG struct dpb *dparmp; /* pointer to disk parameter block */
41 REG UWORD rtn; /* return parameter */
42 UWORD iosect; /* sector number returned from divide rtn */
43
44 LOCK /* lock the disk system while doing physical i/o */
45
46 rtn = 0;
47 switch (iop->iofcn)
48 {
49 case sel_info:
50 last_dsk = iop->devnum;
51 iop->infop = bseldsk(last_dsk, iop->ioflags);
52 break;
53
54 case read:
55 case write:
56 if (last_dsk != iop->devnum)
57 bseldsk((last_dsk = iop->devnum), 0);
58 /* guaranteed disk is logged on, because temp_sel in
59 BDOSMAIN does it */
1File: IOSYS.C Page 2
60 hdrp = iop->infop;
61 dparmp = hdrp->dpbp;
62
63 bsettrk( udiv( iop->devadr, dparmp->spt, &iosect )
64 + dparmp->trk_off );
65 bsetsec( bsectrn( iosect, hdrp->xlt ) );
66 bsetdma(iop->xferadr);
67 if ((iop->iofcn) == read) rtn = bread();
68 else rtn = bwrite(iop->ioflags);
69 break;
70
71 case flush:
72 rtn = bflush();
73 }
74
75 UNLOCK
76 return(rtn);
77 }

View File

@@ -0,0 +1,39 @@
$ num
BDOSMAIN.C
BDOSMAIN.lis
$ num
BDOSMISC.C
BDOSMISC.lis
$ num
BDOSRW.C
BDOSRW.lis
$ num
CCP.C
CCP.lis
$ num
CONBDOS.C
CONBDOS.lis
$ num
DSKUTIL.C
DSKUTIL.lis
$ num
FILEIO.C
FILEIO.lis
$ num
IOSYS.C
IOSYS.lis
$ num
BDOSDEF.H
BDOSDEF.lst
$ num
BDOSINC.H
BDOSINC.lst
$ num
BIOSDEF.H
BIOSDEF.lst
$ num
CCPDEF.H
CCPDEF.lst
$ num
PKTIO.H
PKTIO.lst

View File

@@ -0,0 +1,83 @@
$1cp68 bdosmain.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic bdosmain.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 bdosmain.s
era bdosmain.s
$1cp68 bdosmisc.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic bdosmisc.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 bdosmisc.s
era bdosmisc.s
$1cp68 bdosrw.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic bdosrw.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 bdosrw.s
era bdosrw.s
$1cp68 conbdos.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic conbdos.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 conbdos.s
era conbdos.s
$1cp68 dskutil.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic dskutil.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 dskutil.s
era dskutil.s
$1cp68 fileio.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic fileio.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 fileio.s
era fileio.s
$1cp68 iosys.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic iosys.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 iosys.s
era iosys.s
$1cp68 ccp.c $1x.i
$1c068 $1x.i $1x.ic $1x.st
era $1x.i
era $1x.st
$1c168 $1x.ic ccp.s -ld
era $1x.ic
$1as68 -s 0$1 -l -u -f $1 ccp.s
era ccp.s
$1as68 -s 0$1 -l -u -f $1 bdosif.s
$1as68 -s 0$1 -l -u -f $1 -n exceptn.s
$1as68 -s 0$1 -l -u -f $1 pgmld.s
$1as68 -s 0$1 -l -u -f $1 ccpbdos.s
$1as68 -s 0$1 -l -u -f $1 ccpif.s
$1as68 -s 0$1 -l -u -f $1 ccpload.s
$1as68 -s 0$1 -l -u -f $1 filetyps.s
$1as68 -s 0$1 -l -u -f $1 stack.s
rear $1

View File

@@ -0,0 +1,595 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: pgmld.s
1
2 *********************************
3 * *
4 * Function 59 -- Program Load *
5 * Assembly language version *
6 * *
7 * June 8, 1982 *
8 * *
9 *********************************
10
11 .globl _pgmld * this routine is public
12
13 secsize = 128 * CP/M sector size
14
15 * d0 always contains the return parameter from pgmld
16 * d1 is the return register from local subroutines
17 * a0 contains the pointer to the Load Parm Block passed to pgmld
18
19 * Return parameters in d0 are:
20 * 00 - function successful
21 * 01 - insufficient memory or bad header in file
22 * 02 - read error on file
23 * 03 - bad relocation information in file
24
25
26 * Entry point for Program Load routine
27 _pgmld:
28 00000000 48E77FFE movem.l d1-d7/a0-a6, -(sp) * save everything, just to be safe
29 00000004 206F003C move.l 60(sp),a0 * get pointer to LPB
30 00000008 4280 clr.l d0 * start with return parm cleared
31 0000000A 6154 bsr gethdr * get header
32 0000000C 4A40 tst d0
33 0000000E 662A bne lddone * if unsuccessful, return
34 00000010 61000108 bsr setaddr * set up load addresses
35 00000014 4A40 tst d0
36 00000016 6622 bne lddone * if unsuccessful, return
37 00000018 61000258 bsr rdtxt * read code and data text segments into mem
38 0000001C 4A40 tst d0
39 0000001E 661A bne lddone * if unsuccessful, return
40 00000020 2E3900000016 move.l tstart,d7
41 00000026 BEB900000024 cmp.l cseg,d7
42 0000002C 6704 beq noreloc
43 0000002E 61000350 bsr reloc * do relocation if necessary
44 noreloc:
45 00000032 4A40 tst d0
46 00000034 6604 bne lddone
47 00000036 610003E8 bsr setrtn * set up return parameters
48 lddone:
49 0000003A 222F0040 move.l 64(sp), d1
50 0000003E 6116 bsr setdma * restore dma address
51 00000040 4CDF7FFE movem.l (sp)+,d1-d7/a0-a6
52 00000044 4E75 rts
53
54 * Subroutines
55
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: pgmld.s
56 readseq:
57 * CP/M read sequential function
58 00000046 2F00 move.l d0,-(sp) * save return parm
59 00000048 22280000 move.l FCBPtr(a0),d1
60 0000004C 7014 moveq #20,d0 * read seq function
61 0000004E 4E42 trap #2 * call bdos
62 00000050 2200 move.l d0,d1 * return parm in d1
63 00000052 201F move.l (sp)+,d0
64 00000054 4E75 rts
65
66
67 setdma:
68 * CP/M set dma function
69 00000056 2F00 move.l d0,-(sp) * save return parm
70 00000058 701A moveq #26,d0 * set dma function
71 0000005A 4E42 trap #2 * call bdos
72 0000005C 201F move.l (sp)+,d0 * restore d0
73 0000005E 4E75 rts
74
75
76 gethdr:
77 * Get header into buffer in data segment
78 00000060 22280004 move.l LoAdr(a0),d1
79 00000064 61F0 bsr setdma
80 00000066 61DE bsr readseq
81 00000068 4A41 tst d1 * read ok?
82 0000006A 6614 bne badhdr * if no, return bad
83 0000006C 7E12 moveq #18,d7
84 0000006E 2A680004 movea.l LoAdr(a0),a5
85 00000072 2C7C00000000 movea.l #hdr,a6
86 00000078 3CDD geth1: move.w (a5)+,(a6)+ * move header into hdr
87 0000007A 51CFFFFC dbf d7,geth1
88 0000007E 4E75 rts
89 00000080 7002 badhdr: moveq #2,d0
90 00000082 4E75 rts
91
92
93 conflict:
94 * input parms: d2, d3 = 4 * segment nmbr
95 * if segment d2/4 overlaps segment d3/4, then return 1 in d1
96 * else return 0 in d1
97 * uses d7, a2, a3
98 00000084 4281 clr.l d1 * assume it will work
99 00000086 247C00000024 movea.l #cseg,a2 * a2 points to start of segment addresses
100 0000008C 267C00000002 movea.l #csize,a3 * a3 points to start of segment lengths
101 00000092 2E322000 move.l 0(a2,d2),d7 * get 1st seg start
102 00000096 BEB23000 cmp.l 0(a2,d3),d7 * is 1st seg above 2nd seg?
103 0000009A 6C0C bge conf1
104 0000009C DEB32000 add.l 0(a3,d2),d7 * yes, find top of 1st seg
105 000000A0 BEB23000 cmp.l 0(a2,d3),d7 * above start of 2nd seg?
106 000000A4 6E10 bgt confbd * if yes, we have a conflict
107 000000A6 4E75 rts * else, return good
108 conf1:
109 000000A8 2E323000 move.l 0(a2,d3),d7
110 000000AC DEB33000 add.l 0(a3,d3),d7 * find top of 2nd seg
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 3
Source File: pgmld.s
111 000000B0 BEB22000 cmp.l 0(a2,d2),d7 * above start of 1st seg?
112 000000B4 6F02 ble confgd * if no, we're ok
113 000000B6 7201 confbd: moveq.l #1,d1
114 000000B8 4E75 confgd: rts
115
116
117 trymemtp:
118 * entry: d2 is a segment nmbr [0..4]
119 * try to fit it at top of memory
120 * uses d3, d6, d7, a5, a6
121 * returns 0 in d1 if ok
122 000000BA 2C02 move.l d2,d6 * d6 is loop counter for chksegs
123 000000BC 5346 subq #1,d6
124 000000BE E54A lsl #2,d2 * multiply d2 by 4
125 000000C0 2E280008 move.l HiAdr(a0),d7 * top of mem to d7
126
127 chksegs:
128 * entry: d2 = 4 * (segment nmbr to try)
129 * d6 = (d2/4) - 1 (loop counter)
130 * d7 = address below which to try it
131 * check for conflicts with segments [0..d6] and low memory boundary
132 * return 0 in d1 if no conflicts, else d1 = 1
133 * uses d3, a5, a6
134 000000C4 2A7C00000024 movea.l #cseg,a5
135 000000CA 2C7C00000002 movea.l #csize,a6
136 000000D0 9EB62000 sub.l 0(a6,d2),d7 * subtract size of segment to try
137 000000D4 08870000 bclr #0,d7 * make it even address
138 000000D8 2B872000 move.l d7,0(a5,d2) * insert address in segment table
139 000000DC BEA80004 cmp.l LoAdr(a0),d7 * check for conflict with low memory
140 000000E0 6DD4 blt confbd
141 000000E2 4283 clr.l d3 * check for conflicts with 0..d6
142 chk1:
143 000000E4 619E bsr conflict
144 000000E6 5883 addq.l #4,d3
145 000000E8 4A81 tst.l d1 * conflict with this seg?
146 000000EA 56CEFFF8 dbne d6,chk1 * if no, try next
147 000000EE 4E75 rts
148
149
150 fndseg:
151 * entry: d2 is a segment nmbr [0..4]
152 * try to fit segment d2 directly below segments 0..(d2-1)
153 * uses d3-d7, a5, a6
154 000000F0 2A02 move.l d2,d5 * d5 is loop counter to find fit
155 000000F2 5385 subq.l #1,d5
156 000000F4 23C50000003C move.l d5,temp
157 000000FA E58A lsl.l #2,d2 * multiply segment by 4
158 000000FC 4284 clr.l d4 * d4 is segment to try to fit below
159 fnd1:
160 000000FE 2C390000003C move.l temp,d6 * d6 is loop counter for chksegs
161 00000104 2A7C00000024 movea.l #cseg,a5
162 0000010A 2E354000 move.l 0(a5,d4),d7 * segment address to d7
163 0000010E 61B4 bsr chksegs * check for conflicts
164 00000110 5884 addq.l #4,d4
165 00000112 4A81 tst.l d1
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 4
Source File: pgmld.s
166 00000114 57CDFFE8 dbeq d5,fnd1 * if conflict, try next
167 00000118 4E75 rts
168
169
170 setaddr:
171 * Set up load addresses for cseg, dseg, bss, basepg, and stack
172 0000011A 3C3900000000 move.w magic,d6
173 00000120 0246FFFE andi.w #$fffe,d6
174 00000124 0C46601A cmpi.w #$601a,d6
175 00000128 66000120 bne badadr * if magic nmbr <> 601a or 601b, skip
176 0000012C 23F90000000E00000038 move.l bpsize,symsize
177 00000136 2E3C00000100 move.l #256,d7
178 0000013C 23C70000000E move.l d7,bpsize * base page is 256 bytes
179 00000142 45F900000012 lea stksize,a2
180 00000148 BE52 cmp (a2),d7
181 0000014A 6D02 blt set0 * if stack size < 256, set to 256
182 0000014C 2487 move.l d7,(a2)
183 0000014E 0C79601B00000000 set0: cmpi.w #$601b,magic
184 00000156 6708 beq seta
185 00000158 4A790000001A tst.w rlbflg
186 0000015E 670C beq set1
187 00000160 23F90000001600000024 seta: move.l tstart,cseg * if not relocatable or hdr = $601b,
188 0000016A 6040 bra set2 * cseg starts at tstart
189 0000016C 082800000015 set1: btst #0,Flags(a0)
190 00000172 6616 bne sldhi
191 * relocatable, load low
192 00000174 2E280004 move.l LoAdr(a0),d7
193 00000178 DEBC00000101 add.l #$101,d7 * leave room for base page
194 0000017E 08870000 bclr #0,d7
195 00000182 23C700000024 move.l d7,cseg * cseg is bottom of mem + $100 (even boundary)
196 00000188 6022 bra set2
197 sldhi:
198 * relocatable, load high
199 0000018A 2E280008 move.l HiAdr(a0),d7
200 0000018E 9EB900000002 sub.l csize,d7
201 00000194 9EB900000006 sub.l dsize,d7
202 0000019A 9EB90000000A sub.l bsize,d7
203 000001A0 5987 subq.l #4,d7
204 000001A2 08870000 bclr #0,d7 * put cseg at next even address below
205 000001A6 23C700000024 move.l d7,cseg * high memory - (sum of sizes)
206 set2:
207 * Cseg has been set up. Now do dseg, bseg
208 000001AC 0C79601B00000000 cmpi.w #$601b,magic
209 000001B4 6616 bne set3
210 * if magic # = 601b, take addr from hdr
211 000001B6 23F90000001C00000028 move.l dstart,dseg
212 000001C0 23F9000000200000002C move.l bstart,bseg
213 000001CA 602A bra set4
214 set3:
215 * if short header, dseg and bseg follow cseg
216 000001CC 2E3900000024 move.l cseg,d7
217 000001D2 DEB900000002 add.l csize,d7
218 000001D8 5287 addq.l #1,d7
219 000001DA 08870000 bclr #0,d7
220 000001DE 23C700000028 move.l d7,dseg
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 5
Source File: pgmld.s
221 000001E4 DEB900000006 add.l dsize,d7
222 000001EA 5287 addq.l #1,d7
223 000001EC 08870000 bclr #0,d7
224 000001F0 23C70000002C move.l d7,bseg
225 set4:
226 * cseg, dseg, bseg set up
227 * now find a place for the base page and stack
228 000001F6 7403 moveq.l #3,d2
229 000001F8 6100FEF6 bsr fndseg * try to fit base page below cseg, dseg, bseg
230 000001FC 4A81 tst.l d1
231 000001FE 670A beq set5 * if found, skip
232 00000200 7403 moveq.l #3,d2
233 00000202 6100FEB6 bsr trymemtp * else, try top of memory
234 00000206 4A81 tst.l d1
235 00000208 6640 bne badadr * if fail, exit
236 0000020A 7404 set5: moveq.l #4,d2
237 0000020C 6100FEAC bsr trymemtp * try to fit stack at top of memory
238 00000210 4A81 tst.l d1
239 00000212 670A beq set6 * if ok, skip
240 00000214 7404 moveq.l #4,d2
241 00000216 6100FED8 bsr fndseg * else, try to fit below other segs
242 0000021A 4A81 tst.l d1
243 0000021C 662C bne badadr
244 set6:
245 * now check all segments for conflicts with low and high memory boundaries
246 0000021E 2A7C00000024 movea.l #cseg,a5
247 00000224 2C7C00000002 movea.l #csize,a6
248 0000022A 4282 clr.l d2
249 0000022C 7604 moveq #4,d3 * loop counter
250 0000022E 2E352000 set7: move.l 0(a5,d2),d7 * get segment base
251 00000232 BEA80004 cmp.l LoAdr(a0),d7 * above bottom of memory?
252 00000236 6D12 blt badadr
253 00000238 DEB62000 add.l 0(a6,d2),d7 * find top of segment
254 0000023C BEA80008 cmp.l HiAdr(a0),d7 * below top of memory?
255 00000240 6E08 bgt badadr
256 00000242 5882 addq.l #4,d2 * point to next segment
257 00000244 51CBFFE8 dbf d3,set7
258 00000248 4E75 rts
259 0000024A 7001 badadr: moveq.l #1,d0
260 0000024C 4E75 rts
261
262
263 movebuf:
264 * move (d3) bytes from the base page buffer to (a2)
265 * uses d6
266 0000024E 227900000030 movea.l basepg,a1
267 00000254 2C3C00000080 move.l #secsize,d6
268 0000025A 9C7900000042 sub.w bufbyts,d6 * address to move from =
269 00000260 D2C6 adda.w d6,a1 * (basepg) + secsize - (bufbyts)
270 00000262 977900000042 sub.w d3,bufbyts * update # bytes buffered
271 00000268 6002 bra moveb2
272 0000026A 14D9 moveb1: move.b (a1)+,(a2)+ * do the move
273 0000026C 51CBFFFC moveb2: dbf d3,moveb1
274 00000270 4E75 rts
275
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 6
Source File: pgmld.s
276
277 rdtxt:
278 * Read code and data text into memory
279 * during this routine, a2 is always the load address,
280 * d2 is number of bytes left to load
281 00000272 7E3F moveq #63,d7
282 00000274 2A680004 movea.l LoAdr(a0),a5
283 00000278 2C7900000030 movea.l basepg,a6
284 0000027E 3CDD rdtxt1: move.w (a5)+,(a6)+ * move header sector to base page
285 00000280 51CFFFFC dbf d7,rdtxt1
286 00000284 3E3C0064 move.w #secsize-28,d7
287 00000288 0C79601A00000000 cmpi.w #$601a,magic * short header?
288 00000290 6702 beq rdtxt2
289 00000292 5147 subq.w #8,d7
290 00000294 33C700000042 rdtxt2: move.w d7,bufbyts * indicate # bytes of text in buffer
291 0000029A 33FC000200000040 move.w #2,loop * do for code, data segments
292 000002A2 247900000024 move.l cseg,a2 * start at cseg
293 000002A8 243900000002 move.l csize,d2 * for csize bytes
294 rdtxt3:
295 000002AE 4283 clr.l d3
296 000002B0 363900000042 move.w bufbyts,d3
297 000002B6 B682 cmp.l d2,d3 * # bytes in buffer >= # bytes to load?
298 000002B8 6D06 blt rdtxt4
299 000002BA 2602 move.l d2,d3
300 000002BC 6190 bsr movebuf * if yes, move # bytes to load
301 000002BE 6048 bra finrd
302 rdtxt4:
303 000002C0 9483 sub.l d3,d2 * if no, update # bytes to load
304 000002C2 618A bsr movebuf * move remainder of buffer
305 000002C4 263C00000080 move.l #secsize,d3 * d3 = secsize fo following loop
306 rdtxt5:
307 000002CA B483 cmp.l d3,d2 * have at least one more full sector?
308 000002CC 6D18 blt rdtxt6
309 000002CE 220A move.l a2,d1
310 000002D0 6100FD84 bsr setdma * if yes, set up dma address
311 000002D4 6100FD70 bsr readseq * read next sector
312 000002D8 4A41 tst.w d1
313 000002DA 6656 bne rdbad * if no good, exit
314 000002DC 9483 sub.l d3,d2 * decrement # bytes to load
315 000002DE D5FC00000080 adda.l #secsize,a2 * increment dma address
316 000002E4 60E4 bra rdtxt5
317 rdtxt6:
318 000002E6 4A82 tst.l d2 * any more bytes to read?
319 000002E8 671E beq finrd
320 000002EA 223900000030 move.l basepg,d1
321 000002F0 6100FD64 bsr setdma
322 000002F4 6100FD50 bsr readseq * if yes, read into base page
323 000002F8 4A41 tst.w d1
324 000002FA 6636 bne rdbad
325 000002FC 33C300000042 move.w d3,bufbyts * indicate that we've buffered a sector
326 00000302 2602 move.l d2,d3
327 00000304 6100FF48 bsr movebuf * move remainder of segment
328 finrd:
329 00000308 247900000028 move.l dseg,a2 * set up to load data segment
330 0000030E 243900000006 move.l dsize,d2
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 7
Source File: pgmld.s
331 00000314 537900000040 sub.w #1,loop
332 0000031A 6692 bne rdtxt3
333 0000031C 24790000002C move.l bseg,a2 * clear the bss segment
334 00000322 24390000000A move.l bsize,d2
335 00000328 6706 beq rdtxt8
336 0000032A 421A rdtxt7: clr.b (a2)+
337 0000032C 5382 subq.l #1,d2
338 0000032E 66FA bne rdtxt7
339 00000330 4E75 rdtxt8: rts
340
341 00000332 7002 rdbad: moveq.l #2,d0
342 00000334 4E75 rts
343
344
345 relocword:
346 * relocate word at (a2) based on reloc bits at (a3)
347 * lsb of d2 indicates whether previous word was 1st half of long-word
348 00000336 3E1B move.w (a3)+,d7 * get relocation info
349 00000338 02470007 andi.w #7,d7 * strip off symbol table bits
350 0000033C E34F lsl #1,d7 * multiply by 2
351 0000033E 4EFB7002 jmp 2(pc,d7)
352
353 00000342 6014 bra relabs
354 00000344 6022 bra reldata
355 00000346 6020 bra relcode
356 00000348 601E bra relbss
357 0000034A 6006 bra relbad
358 0000034C 6012 bra rellong
359 0000034E 6002 bra relbad
360 00000350 6006 bra relop
361
362 00000352 201F relbad: move.l (sp)+,d0 * pop return address
363 00000354 7003 moveq #3,d0 * return bad relocation to main routine
364 00000356 4E75 rts
365
366 relabs:
367 00000358 08820000 relop: bclr #0,d2 * reset long word flag
368 0000035C 4A5A tst.w (a2)+ * point to next word of segment
369 0000035E 4E75 rts
370
371 rellong:
372 00000360 08C20000 bset #0,d2 * set long word flag
373 00000364 4A5A tst.w (a2)+ * point to next word of segment
374 00000366 4E75 rts
375
376 reldata:
377 relbss:
378 relcode:
379 00000368 08820000 bclr #0,d2 * long word flag set?
380 0000036C 6608 bne relc1 * if yes, skip
381 0000036E 3C12 move.w (a2),d6
382 00000370 DC45 add.w d5,d6
383 00000372 34C6 move.w d6,(a2)+
384 00000374 4E75 rts
385
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 8
Source File: pgmld.s
386 00000376 4A62 relc1: tst.w -(a2) * point to first word of long
387 00000378 2C12 move.l (a2),d6
388 0000037A DC85 add.l d5,d6
389 0000037C 24C6 move.l d6,(a2)+ * note that a2 points past long word
390 0000037E 4E75 rts
391
392
393 reloc:
394 * Modify address references of code and data segments based on relocation bits
395 * During this routine,
396 * a2 points to text file to relocate
397 * a3 points to relocation word in basepg
398 * lsb of d2 is long word flag (set on reloc type 5, reset on next word)
399 * d3 is # words in relocation buffer
400 * d4 is nmbr of words left to relocate
401 * d5 is relocation offset
402
403 00000380 223900000030 move.l basepg,d1
404 00000386 6100FCCE bsr setdma * we will always read into base page
405 * skip past the symbol table
406 0000038A 2E3900000038 move.l symsize,d7
407 00000390 8EFC0080 divu #secsize,d7 * calculate how many sectors to skip
408 * note that max # symbols is 8k, which is 896 sectors of 128 bytes
409 00000394 3C07 move.w d7,d6 * d6 is nmbr sectors to skip
410 00000396 4847 swap d7 * d7 is nmbr bytes to skip
411 00000398 363900000042 move.w bufbyts,d3
412 0000039E 9647 sub.w d7,d3 * subtract bytes to skip from buffer
413 000003A0 6C06 bge skip1
414 000003A2 06430080 addi #secsize,d3 *if amt in buffer < # bytes to skip,
415 000003A6 5246 addq #1,d6 * read in 1 extra sector
416 000003A8 267900000030 skip1: move.l basepg,a3
417 000003AE D6FC0080 adda #secsize,a3
418 000003B2 96C3 suba.w d3,a3 * set up a3 to point to buffer
419 000003B4 E24B lsr #1,d3 * d3 is nmbr words in buffer
420 000003B6 600A bra skip3
421 skip2:
422 000003B8 6100FC8C bsr readseq * read next symbol table sector
423 000003BC 4A41 tst.w d1
424 000003BE 6600FF72 bne rdbad
425 000003C2 51CEFFF4 skip3: dbf d6,skip2
426 * we got past symbol table
427 * a3, d3 are set up
428 000003C6 2A3900000024 move.l cseg,d5
429 000003CC 2445 move.l d5,a2 * relocate cseg first
430 000003CE 9AB900000016 sub.l tstart,d5 * d5 contains the relocation offset
431 000003D4 283900000002 move.l csize,d4 * nmbr of bytes to relocate
432 000003DA 33FC000200000040 move.w #2,loop * we're going to relocate 2 segments
433 reloc1:
434 * relocate one segment
435 000003E2 4282 clr.l d2 * clear long word flag
436 000003E4 E28C lsr.l #1,d4 * make d4 indicate # words
437 000003E6 601E bra reloc4
438 reloc2:
439 000003E8 5343 subq.w #1,d3
440 000003EA 6A14 bpl reloc3
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 9
Source File: pgmld.s
441 000003EC 6100FC58 bsr readseq * if no more words in buffer, refill it
442 000003F0 4A41 tst.w d1
443 000003F2 6600FF3E bne rdbad
444 000003F6 267900000030 move.l basepg,a3
445 000003FC 363C003F move.w #(secsize/2)-1,d3
446 reloc3:
447 00000400 6100FF34 bsr relocword * relocate one word
448 00000404 5384 subq.l #1,d4
449 reloc4:
450 00000406 4A84 tst.l d4 * any more to relocate in this segment?
451 00000408 66DE bne reloc2 * if yes, do it
452 0000040A 247900000028 move.l dseg,a2 * else, set up for dseg
453 00000410 283900000006 move.l dsize,d4
454 00000416 537900000040 sub.w #1,loop
455 0000041C 66C4 bne reloc1
456 0000041E 4E75 rts
457
458
459 setrtn:
460 * Set up the return parameters in Ld Parm Blk and Base Page
461 00000420 217900000030000C move.l basepg,BasPage(a0)
462 00000428 2E3900000034 move.l stk,d7
463 0000042E DEB900000012 add.l stksize,d7
464 00000434 08870000 bclr #0,d7
465 00000438 21470010 move.l d7,Stack(a0)
466 0000043C 227900000030 move.l basepg,a1
467 00000442 22E80004 move.l LoAdr(a0),(a1)+
468 00000446 22E80008 move.l HiAdr(a0),(a1)+
469 0000044A 22F900000024 move.l cseg,(a1)+
470 00000450 22F900000002 move.l csize,(a1)+
471 00000456 22F900000028 move.l dseg,(a1)+
472 0000045C 22F900000006 move.l dsize,(a1)+
473 00000462 22F90000002C move.l bseg,(a1)+
474 00000468 22B90000000A move.l bsize,(a1)
475 * find size of free memory after bss segment
476 0000046E 2E280008 move.l HiAdr(a0),d7 * d7 contains next segment above bss
477 00000472 2C29FFFC move.l -4(a1),d6
478 00000476 DC99 add.l (a1)+,d6 * d6 points to start of free mem after bss
479 00000478 2C7C00000024 movea.l #cseg,a6 * a6 points to segment to try
480 0000047E 7A04 moveq #4,d5 * try for all segments
481 00000480 42B90000002C clr.l bseg * but force bss not to appear
482 00000486 BC96 setb1: cmp.l (a6),d6 * segment above bss?
483 00000488 6206 bhi setb2
484 0000048A BE96 cmp.l (a6),d7 * segment is above bss. Is it below previous?
485 0000048C 6302 bls setb2
486 0000048E 2E16 move.l (a6),d7
487 00000490 4A9E setb2: tst.l (a6)+ * point to next segment
488 00000492 51CDFFF2 dbf d5,setb1
489 00000496 9E86 sub.l d6,d7 * diff between bss top and next segment abv
490 00000498 22C7 move.l d7,(a1)+
491 * now put disk number that we loaded from into base page
492 0000049A 24680000 movea.l FCBPtr(a0),a2
493 0000049E 1012 move.b (a2),d0 * get disk select byte
494 000004A0 6606 bne setb3 * if not auto-select, skip
495 000004A2 7019 move #25,d0
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 10
Source File: pgmld.s
496 000004A4 4E42 trap #2 * get default disk
497 000004A6 5240 addq #1,d0 * we want it in range of 1..16
498 000004A8 12C0 setb3: move.b d0,(a1)+ * move disk number into base page
499 000004AA 4280 clr.l d0 * function OK
500 000004AC 4E75 rts
501
502
503 00000000 .bss
504
505 * offsets from start of parameter block
506 FCBPtr = 0
507 LoAdr = 4
508 HiAdr = 8
509 BasPage = 12 * return parameters
510 Stack = 16
511 Flags = 21
512
513 hdr:
514 * load file header is read into here
515 00000000 magic: .ds.w 1
516 00000002 csize: .ds.l 1
517 00000006 dsize: .ds.l 1
518 0000000A bsize: .ds.l 1
519 0000000E bpsize: .ds.l 1 * symb tbl size is swapped with base page size
520 00000012 stksize: .ds.l 1
521 00000016 tstart: .ds.l 1
522 0000001A rlbflg: .ds.w 1
523 0000001C dstart: .ds.l 1
524 00000020 bstart: .ds.l 1
525
526 00000024 cseg: .ds.l 1
527 00000028 dseg: .ds.l 1
528 0000002C bseg: .ds.l 1
529 00000030 basepg: .ds.l 1
530 00000034 stk: .ds.l 1
531
532 00000038 symsize: .ds.l 1
533 0000003C temp: .ds.l 1
534 00000040 loop: .ds.w 1
535 00000042 bufbyts: .ds.w 1
536
537 00000044 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 11
Source File: pgmld.s
S y m b o l T a b l e
BasPage 0000000C ABS FCBPtr 00000000 ABS Flags 00000015 ABS HiAdr 00000008 ABS
LoAdr 00000004 ABS Stack 00000010 ABS _pgmld 00000000 TEXT badadr 0000024A TEXT
badhdr 00000080 TEXT basepg 00000030 BSS bpsize 0000000E BSS bseg 0000002C BSS
bsize 0000000A BSS bstart 00000020 BSS bufbyts 00000042 BSS chk1 000000E4 TEXT
chksegs 000000C4 TEXT conf1 000000A8 TEXT confbd 000000B6 TEXT confgd 000000B8 TEXT
conflict 00000084 TEXT cseg 00000024 BSS csize 00000002 BSS dseg 00000028 BSS
dsize 00000006 BSS dstart 0000001C BSS finrd 00000308 TEXT fnd1 000000FE TEXT
fndseg 000000F0 TEXT geth1 00000078 TEXT gethdr 00000060 TEXT hdr 00000000 BSS
lddone 0000003A TEXT loop 00000040 BSS magic 00000000 BSS moveb1 0000026A TEXT
moveb2 0000026C TEXT movebuf 0000024E TEXT noreloc 00000032 TEXT rdbad 00000332 TEXT
rdtxt 00000272 TEXT rdtxt1 0000027E TEXT rdtxt2 00000294 TEXT rdtxt3 000002AE TEXT
rdtxt4 000002C0 TEXT rdtxt5 000002CA TEXT rdtxt6 000002E6 TEXT rdtxt7 0000032A TEXT
rdtxt8 00000330 TEXT readseq 00000046 TEXT relabs 00000358 TEXT relbad 00000352 TEXT
relbss 00000368 TEXT relc1 00000376 TEXT relcode 00000368 TEXT reldata 00000368 TEXT
rellong 00000360 TEXT reloc 00000380 TEXT reloc1 000003E2 TEXT reloc2 000003E8 TEXT
reloc3 00000400 TEXT reloc4 00000406 TEXT relocwor 00000336 TEXT relop 00000358 TEXT
rlbflg 0000001A BSS secsize 00000080 ABS set0 0000014E TEXT set1 0000016C TEXT
set2 000001AC TEXT set3 000001CC TEXT set4 000001F6 TEXT set5 0000020A TEXT
set6 0000021E TEXT set7 0000022E TEXT seta 00000160 TEXT setaddr 0000011A TEXT
setb1 00000486 TEXT setb2 00000490 TEXT setb3 000004A8 TEXT setdma 00000056 TEXT
setrtn 00000420 TEXT skip1 000003A8 TEXT skip2 000003B8 TEXT skip3 000003C2 TEXT
sldhi 0000018A TEXT stk 00000034 BSS stksize 00000012 BSS symsize 00000038 BSS
temp 0000003C BSS trymemtp 000000BA TEXT tstart 00000016 BSS

View File

@@ -0,0 +1,537 @@
*********************************
* *
* Function 59 -- Program Load *
* Assembly language version *
* *
* June 8, 1982 *
* *
*********************************
.globl _pgmld * this routine is public
secsize = 128 * CP/M sector size
* d0 always contains the return parameter from pgmld
* d1 is the return register from local subroutines
* a0 contains the pointer to the Load Parm Block passed to pgmld
* Return parameters in d0 are:
* 00 - function successful
* 01 - insufficient memory or bad header in file
* 02 - read error on file
* 03 - bad relocation information in file
* Entry point for Program Load routine
_pgmld:
movem.l d1-d7/a0-a6, -(sp) * save everything, just to be safe
move.l 60(sp),a0 * get pointer to LPB
clr.l d0 * start with return parm cleared
bsr gethdr * get header
tst d0
bne lddone * if unsuccessful, return
bsr setaddr * set up load addresses
tst d0
bne lddone * if unsuccessful, return
bsr rdtxt * read code and data text segments into mem
tst d0
bne lddone * if unsuccessful, return
move.l tstart,d7
cmp.l cseg,d7
beq noreloc
bsr reloc * do relocation if necessary
noreloc:
tst d0
bne lddone
bsr setrtn * set up return parameters
lddone:
move.l 64(sp), d1
bsr setdma * restore dma address
movem.l (sp)+,d1-d7/a0-a6
rts
* Subroutines
readseq:
* CP/M read sequential function
move.l d0,-(sp) * save return parm
move.l FCBPtr(a0),d1
moveq #20,d0 * read seq function
trap #2 * call bdos
move.l d0,d1 * return parm in d1
move.l (sp)+,d0
rts
setdma:
* CP/M set dma function
move.l d0,-(sp) * save return parm
moveq #26,d0 * set dma function
trap #2 * call bdos
move.l (sp)+,d0 * restore d0
rts
gethdr:
* Get header into buffer in data segment
move.l LoAdr(a0),d1
bsr setdma
bsr readseq
tst d1 * read ok?
bne badhdr * if no, return bad
moveq #18,d7
movea.l LoAdr(a0),a5
movea.l #hdr,a6
geth1: move.w (a5)+,(a6)+ * move header into hdr
dbf d7,geth1
rts
badhdr: moveq #2,d0
rts
conflict:
* input parms: d2, d3 = 4 * segment nmbr
* if segment d2/4 overlaps segment d3/4, then return 1 in d1
* else return 0 in d1
* uses d7, a2, a3
clr.l d1 * assume it will work
movea.l #cseg,a2 * a2 points to start of segment addresses
movea.l #csize,a3 * a3 points to start of segment lengths
move.l 0(a2,d2),d7 * get 1st seg start
cmp.l 0(a2,d3),d7 * is 1st seg above 2nd seg?
bge conf1
add.l 0(a3,d2),d7 * yes, find top of 1st seg
cmp.l 0(a2,d3),d7 * above start of 2nd seg?
bgt confbd * if yes, we have a conflict
rts * else, return good
conf1:
move.l 0(a2,d3),d7
add.l 0(a3,d3),d7 * find top of 2nd seg
cmp.l 0(a2,d2),d7 * above start of 1st seg?
ble confgd * if no, we're ok
confbd: moveq.l #1,d1
confgd: rts
trymemtp:
* entry: d2 is a segment nmbr [0..4]
* try to fit it at top of memory
* uses d3, d6, d7, a5, a6
* returns 0 in d1 if ok
move.l d2,d6 * d6 is loop counter for chksegs
subq #1,d6
lsl #2,d2 * multiply d2 by 4
move.l HiAdr(a0),d7 * top of mem to d7
chksegs:
* entry: d2 = 4 * (segment nmbr to try)
* d6 = (d2/4) - 1 (loop counter)
* d7 = address below which to try it
* check for conflicts with segments [0..d6] and low memory boundary
* return 0 in d1 if no conflicts, else d1 = 1
* uses d3, a5, a6
movea.l #cseg,a5
movea.l #csize,a6
sub.l 0(a6,d2),d7 * subtract size of segment to try
bclr #0,d7 * make it even address
move.l d7,0(a5,d2) * insert address in segment table
cmp.l LoAdr(a0),d7 * check for conflict with low memory
blt confbd
clr.l d3 * check for conflicts with 0..d6
chk1:
bsr conflict
addq.l #4,d3
tst.l d1 * conflict with this seg?
dbne d6,chk1 * if no, try next
rts
fndseg:
* entry: d2 is a segment nmbr [0..4]
* try to fit segment d2 directly below segments 0..(d2-1)
* uses d3-d7, a5, a6
move.l d2,d5 * d5 is loop counter to find fit
subq.l #1,d5
move.l d5,temp
lsl.l #2,d2 * multiply segment by 4
clr.l d4 * d4 is segment to try to fit below
fnd1:
move.l temp,d6 * d6 is loop counter for chksegs
movea.l #cseg,a5
move.l 0(a5,d4),d7 * segment address to d7
bsr chksegs * check for conflicts
addq.l #4,d4
tst.l d1
dbeq d5,fnd1 * if conflict, try next
rts
setaddr:
* Set up load addresses for cseg, dseg, bss, basepg, and stack
move.w magic,d6
andi.w #$fffe,d6
cmpi.w #$601a,d6
bne badadr * if magic nmbr <> 601a or 601b, skip
move.l bpsize,symsize
move.l #256,d7
move.l d7,bpsize * base page is 256 bytes
lea stksize,a2
cmp (a2),d7
blt set0 * if stack size < 256, set to 256
move.l d7,(a2)
set0: cmpi.w #$601b,magic
beq seta
tst.w rlbflg
beq set1
seta: move.l tstart,cseg * if not relocatable or hdr = $601b,
bra set2 * cseg starts at tstart
set1: btst #0,Flags(a0)
bne sldhi
* relocatable, load low
move.l LoAdr(a0),d7
add.l #$101,d7 * leave room for base page
bclr #0,d7
move.l d7,cseg * cseg is bottom of mem + $100 (even boundary)
bra set2
sldhi:
* relocatable, load high
move.l HiAdr(a0),d7
sub.l csize,d7
sub.l dsize,d7
sub.l bsize,d7
subq.l #4,d7
bclr #0,d7 * put cseg at next even address below
move.l d7,cseg * high memory - (sum of sizes)
set2:
* Cseg has been set up. Now do dseg, bseg
cmpi.w #$601b,magic
bne set3
* if magic # = 601b, take addr from hdr
move.l dstart,dseg
move.l bstart,bseg
bra set4
set3:
* if short header, dseg and bseg follow cseg
move.l cseg,d7
add.l csize,d7
addq.l #1,d7
bclr #0,d7
move.l d7,dseg
add.l dsize,d7
addq.l #1,d7
bclr #0,d7
move.l d7,bseg
set4:
* cseg, dseg, bseg set up
* now find a place for the base page and stack
moveq.l #3,d2
bsr fndseg * try to fit base page below cseg, dseg, bseg
tst.l d1
beq set5 * if found, skip
moveq.l #3,d2
bsr trymemtp * else, try top of memory
tst.l d1
bne badadr * if fail, exit
set5: moveq.l #4,d2
bsr trymemtp * try to fit stack at top of memory
tst.l d1
beq set6 * if ok, skip
moveq.l #4,d2
bsr fndseg * else, try to fit below other segs
tst.l d1
bne badadr
set6:
* now check all segments for conflicts with low and high memory boundaries
movea.l #cseg,a5
movea.l #csize,a6
clr.l d2
moveq #4,d3 * loop counter
set7: move.l 0(a5,d2),d7 * get segment base
cmp.l LoAdr(a0),d7 * above bottom of memory?
blt badadr
add.l 0(a6,d2),d7 * find top of segment
cmp.l HiAdr(a0),d7 * below top of memory?
bgt badadr
addq.l #4,d2 * point to next segment
dbf d3,set7
rts
badadr: moveq.l #1,d0
rts
movebuf:
* move (d3) bytes from the base page buffer to (a2)
* uses d6
movea.l basepg,a1
move.l #secsize,d6
sub.w bufbyts,d6 * address to move from =
adda.w d6,a1 * (basepg) + secsize - (bufbyts)
sub.w d3,bufbyts * update # bytes buffered
bra moveb2
moveb1: move.b (a1)+,(a2)+ * do the move
moveb2: dbf d3,moveb1
rts
rdtxt:
* Read code and data text into memory
* during this routine, a2 is always the load address,
* d2 is number of bytes left to load
moveq #63,d7
movea.l LoAdr(a0),a5
movea.l basepg,a6
rdtxt1: move.w (a5)+,(a6)+ * move header sector to base page
dbf d7,rdtxt1
move.w #secsize-28,d7
cmpi.w #$601a,magic * short header?
beq rdtxt2
subq.w #8,d7
rdtxt2: move.w d7,bufbyts * indicate # bytes of text in buffer
move.w #2,loop * do for code, data segments
move.l cseg,a2 * start at cseg
move.l csize,d2 * for csize bytes
rdtxt3:
clr.l d3
move.w bufbyts,d3
cmp.l d2,d3 * # bytes in buffer >= # bytes to load?
blt rdtxt4
move.l d2,d3
bsr movebuf * if yes, move # bytes to load
bra finrd
rdtxt4:
sub.l d3,d2 * if no, update # bytes to load
bsr movebuf * move remainder of buffer
move.l #secsize,d3 * d3 = secsize fo following loop
rdtxt5:
cmp.l d3,d2 * have at least one more full sector?
blt rdtxt6
move.l a2,d1
bsr setdma * if yes, set up dma address
bsr readseq * read next sector
tst.w d1
bne rdbad * if no good, exit
sub.l d3,d2 * decrement # bytes to load
adda.l #secsize,a2 * increment dma address
bra rdtxt5
rdtxt6:
tst.l d2 * any more bytes to read?
beq finrd
move.l basepg,d1
bsr setdma
bsr readseq * if yes, read into base page
tst.w d1
bne rdbad
move.w d3,bufbyts * indicate that we've buffered a sector
move.l d2,d3
bsr movebuf * move remainder of segment
finrd:
move.l dseg,a2 * set up to load data segment
move.l dsize,d2
sub.w #1,loop
bne rdtxt3
move.l bseg,a2 * clear the bss segment
move.l bsize,d2
beq rdtxt8
rdtxt7: clr.b (a2)+
subq.l #1,d2
bne rdtxt7
rdtxt8: rts
rdbad: moveq.l #2,d0
rts
relocword:
* relocate word at (a2) based on reloc bits at (a3)
* lsb of d2 indicates whether previous word was 1st half of long-word
move.w (a3)+,d7 * get relocation info
andi.w #7,d7 * strip off symbol table bits
lsl #1,d7 * multiply by 2
jmp 2(pc,d7)
bra relabs
bra reldata
bra relcode
bra relbss
bra relbad
bra rellong
bra relbad
bra relop
relbad: move.l (sp)+,d0 * pop return address
moveq #3,d0 * return bad relocation to main routine
rts
relabs:
relop: bclr #0,d2 * reset long word flag
tst.w (a2)+ * point to next word of segment
rts
rellong:
bset #0,d2 * set long word flag
tst.w (a2)+ * point to next word of segment
rts
reldata:
relbss:
relcode:
bclr #0,d2 * long word flag set?
bne relc1 * if yes, skip
move.w (a2),d6
add.w d5,d6
move.w d6,(a2)+
rts
relc1: tst.w -(a2) * point to first word of long
move.l (a2),d6
add.l d5,d6
move.l d6,(a2)+ * note that a2 points past long word
rts
reloc:
* Modify address references of code and data segments based on relocation bits
* During this routine,
* a2 points to text file to relocate
* a3 points to relocation word in basepg
* lsb of d2 is long word flag (set on reloc type 5, reset on next word)
* d3 is # words in relocation buffer
* d4 is nmbr of words left to relocate
* d5 is relocation offset
move.l basepg,d1
bsr setdma * we will always read into base page
* skip past the symbol table
move.l symsize,d7
divu #secsize,d7 * calculate how many sectors to skip
* note that max # symbols is 8k, which is 896 sectors of 128 bytes
move.w d7,d6 * d6 is nmbr sectors to skip
swap d7 * d7 is nmbr bytes to skip
move.w bufbyts,d3
sub.w d7,d3 * subtract bytes to skip from buffer
bge skip1
addi #secsize,d3 *if amt in buffer < # bytes to skip,
addq #1,d6 * read in 1 extra sector
skip1: move.l basepg,a3
adda #secsize,a3
suba.w d3,a3 * set up a3 to point to buffer
lsr #1,d3 * d3 is nmbr words in buffer
bra skip3
skip2:
bsr readseq * read next symbol table sector
tst.w d1
bne rdbad
skip3: dbf d6,skip2
* we got past symbol table
* a3, d3 are set up
move.l cseg,d5
move.l d5,a2 * relocate cseg first
sub.l tstart,d5 * d5 contains the relocation offset
move.l csize,d4 * nmbr of bytes to relocate
move.w #2,loop * we're going to relocate 2 segments
reloc1:
* relocate one segment
clr.l d2 * clear long word flag
lsr.l #1,d4 * make d4 indicate # words
bra reloc4
reloc2:
subq.w #1,d3
bpl reloc3
bsr readseq * if no more words in buffer, refill it
tst.w d1
bne rdbad
move.l basepg,a3
move.w #(secsize/2)-1,d3
reloc3:
bsr relocword * relocate one word
subq.l #1,d4
reloc4:
tst.l d4 * any more to relocate in this segment?
bne reloc2 * if yes, do it
move.l dseg,a2 * else, set up for dseg
move.l dsize,d4
sub.w #1,loop
bne reloc1
rts
setrtn:
* Set up the return parameters in Ld Parm Blk and Base Page
move.l basepg,BasPage(a0)
move.l stk,d7
add.l stksize,d7
bclr #0,d7
move.l d7,Stack(a0)
move.l basepg,a1
move.l LoAdr(a0),(a1)+
move.l HiAdr(a0),(a1)+
move.l cseg,(a1)+
move.l csize,(a1)+
move.l dseg,(a1)+
move.l dsize,(a1)+
move.l bseg,(a1)+
move.l bsize,(a1)
* find size of free memory after bss segment
move.l HiAdr(a0),d7 * d7 contains next segment above bss
move.l -4(a1),d6
add.l (a1)+,d6 * d6 points to start of free mem after bss
movea.l #cseg,a6 * a6 points to segment to try
moveq #4,d5 * try for all segments
clr.l bseg * but force bss not to appear
setb1: cmp.l (a6),d6 * segment above bss?
bhi setb2
cmp.l (a6),d7 * segment is above bss. Is it below previous?
bls setb2
move.l (a6),d7
setb2: tst.l (a6)+ * point to next segment
dbf d5,setb1
sub.l d6,d7 * diff between bss top and next segment abv
move.l d7,(a1)+
* now put disk number that we loaded from into base page
movea.l FCBPtr(a0),a2
move.b (a2),d0 * get disk select byte
bne setb3 * if not auto-select, skip
move #25,d0
trap #2 * get default disk
addq #1,d0 * we want it in range of 1..16
setb3: move.b d0,(a1)+ * move disk number into base page
clr.l d0 * function OK
rts
.bss
* offsets from start of parameter block
FCBPtr = 0
LoAdr = 4
HiAdr = 8
BasPage = 12 * return parameters
Stack = 16
Flags = 21
hdr:
* load file header is read into here
magic: .ds.w 1
csize: .ds.l 1
dsize: .ds.l 1
bsize: .ds.l 1
bpsize: .ds.l 1 * symb tbl size is swapped with base page size
stksize: .ds.l 1
tstart: .ds.l 1
rlbflg: .ds.w 1
dstart: .ds.l 1
bstart: .ds.l 1
cseg: .ds.l 1
dseg: .ds.l 1
bseg: .ds.l 1
basepg: .ds.l 1
stk: .ds.l 1
symsize: .ds.l 1
temp: .ds.l 1
loop: .ds.w 1
bufbyts: .ds.w 1
.end

View 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 */

View File

@@ -0,0 +1,58 @@
1File: PKTIO.H Page 1
1 /********************************************************
2 * *
3 * CP/M-68K header file *
4 * Copyright (c) 1982 by Digital Research, Inc. *
5 * Structure definitions for doing I/O in packets *
6 * *
7 ********************************************************/
8
9 /* May use this information structure instead of disk parameter header and
10 disk parameter block in future, but for now it's unused
11 struct dskinfo
12 {
13 UBYTE *dbuffp;
14 UBYTE *csv;
15 UBYTE *alv;
16 UBYTE blksize;
17 UBYTE didummy;
18 UWORD dskmax;
19 UWORD dirmax;
20 UWORD chksize;
21 };
22 */
23
24 struct iopb
25 {
26 UBYTE iofcn; /* function number, see defines below */
27 UBYTE ioflags; /* used for login flag and write flag */
28 UBYTE devtype; /* device type, see defines below */
29 /* currently unused */
30 UBYTE devnum; /* device number, or, devtype and devnum
31 taken together form int device number */
32 LONG devadr; /* item nmbr on device to start xfer at */
33 /* note -- item is sector for disks, byte for char devs */
34 UWORD xferlen; /* number items to transfer */
35 UBYTE *xferadr; /* memory address to xfer to/from */
36 struct dph *infop; /* pointer to disk parameter header */
37 /* return parm for fcn 0, input for rest */
38 };
39
40
41 /* Definitions for iofcn, the function number */
42 #define sel_info 0 /* select and return info on device */
43 #define read 1
44 #define write 2
45 #define flush 3
46 #define status 4 /* not currently used */
47
48
49 /* Definitions for devtype, the device type */
50 /* This field not currently used */
51 #define console 0
52 #define printer 1
53 #define disk 2
54 #define memory 3 /* gets TPA boundaries */
55 #define redir 4 /* read/write IOByte */
56 #define exc_vec 5 /* set exception vector */
57

View File

@@ -0,0 +1,4 @@
$1ar68 rvf $1 cpmlib ccpif.o ccpbdos.o ccpload.o ccp.o bdosif.o conbdos.o
$1ar68 rvf $1 cpmlib bdosmisc.o dskutil.o fileio.o bdosrw.o bdosmain.o
$1ar68 rvf $1 cpmlib iosys.o pgmld.o exceptn.o filetyps.o stack.o
era *.o

View File

@@ -0,0 +1,25 @@
E:SEND REAR.SUB
E:SEND MAKE.SUB
E:SEND BDOSDEF.H
E:SEND BDOSIF.S
E:SEND BDOSINC.H
E:SEND BDOSMAIN.C
E:SEND BDOSMISC.C
E:SEND BDOSRW.C
E:SEND BIOSDEF.H
E:SEND CONBDOS.C
E:SEND CPMC.DOC
E:SEND DSKUTIL.C
E:SEND EXCEPTN.S
E:SEND FILEIO.C
E:SEND IOSYS.C
E:SEND PGMLD.S
E:SEND PKTIO.H
E:SEND CCP.C
E:SEND CCPBDOS.S
E:SEND CCPDEF.H
E:SEND CCPIF.S
E:SEND CCPLOAD.S
E:SEND FILETYPS.S
E:SEND STACK.S
E:SEND SEND2.SUB

View File

@@ -0,0 +1,24 @@
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 1
Source File: stack.s
1 *************************************************************************
2 * *
3 * THIS IS THE SYSTEM STACK AREA *
4 * *
5 * *
6 * THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
7 * ================================================== *
8 *************************************************************************
9
10 .globl stack
11 00000000 .bss
12 00000000 .ds.l 400
13 stack:
14 00000640 .ds.w 1
15 00000642 .end
C P / M 6 8 0 0 0 A s s e m b l e r Revision 02.03 Page 2
Source File: stack.s
S y m b o l T a b l e
stack 00000640 BSS

View File

@@ -0,0 +1,15 @@
*************************************************************************
* *
* THIS IS THE SYSTEM STACK AREA *
* *
* *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ================================================== *
*************************************************************************
.globl stack
.bss
.ds.l 400
stack:
.ds.w 1
.end

View File

@@ -0,0 +1,26 @@
vax REAR.SUB s
vax MAKE.SUB s
vax BDOSDEF.H s
vax BDOSIF.S s
vax BDOSINC.H s
vax BDOSMAIN.C s
vax BDOSMISC.C s
vax BDOSRW.C s
vax BIOSDEF.H s
vax CONBDOS.C s
vax CPMC.DOC s
vax DSKUTIL.C s
vax EXCEPTN.S s
vax FILEIO.C s
vax IOSYS.C s
vax PGMLD.S s
vax PKTIO.H s
vax CCP.C s
vax CCPBDOS.S s
vax CCPDEF.H s
vax CCPIF.S s
vax CCPLOAD.S s
vax FILETYPS.S s
vax STACK.S s
vax SEND2.SUB s
vax up2.sub s

View File

@@ -0,0 +1,25 @@
$ bdos
$ !
$ ! VMS command file to build CPMLIB using cross tools
$ !
$ set noon
$ cc68 bdosmain
$ cc68 bdosmisc
$ cc68 bdosrw
$ cc68 conbdos
$ cc68 dskutil
$ cc68 fileio
$ cc68 iosys
$ cc68 ccp
$ as68 -l -u bdosif.s
$ as68 -l -u -n exceptn.s
$ as68 -l -u pgmld.s
$ as68 -l -u ccpbdos.s
$ as68 -l -u ccpif.s
$ as68 -l -u ccpload.s
$ as68 -l -u filetyps.s
$ as68 -l -u stack.s
$ ar68 r cpmlib ccpif.o ccpbdos.o ccpload.o ccp.o bdosif.o conbdos.o
$ ar68 r cpmlib bdosmisc.o dskutil.o fileio.o bdosrw.o bdosmain.o
$ ar68 r cpmlib iosys.o pgmld.o exceptn.o filetyps.o stack.o
$ del *.o;*

View File

@@ -0,0 +1,30 @@
$ set noon
$ vsend BDOSDEF.H
$ vsend BDOSIF.S
$ vsend BDOSINC.H
$ vsend BDOSMAIN.C
$ vsend BDOSMISC.C
$ vsend BDOSRW.C
$ vsend BIOSDEF.H
$ vsend CCP.C
$ vsend CCPBDOS.S
$ vsend CCPDEF.H
$ vsend CCPIF.S
$ vsend CCPLOAD.S
$ vsend CONBDOS.C
$ vsend CPMC.DOC
$ vsend DOWN2.SUB
$ vsend DSKUTIL.C
$ vsend EXCEPTN.S
$ vsend FILEIO.C
$ vsend FILETYPS.S
$ vsend IOSYS.C
$ vsend MAKE.SUB
$ vsend PGMLD.S
$ vsend PKTIO.H
$ vsend REAR.SUB
$ vsend SEND2.SUB
$ vsend STACK.S
$ vsend UP2.SUB
$ vsend VMAKE.COM
$ vsend done

View File

@@ -0,0 +1,13 @@
$ xer BDOSMAIN.LIS
$ xer BDOSMISC.LIS
$ xer BDOSRW.LIS
$ xer CCP.LIS
$ xer CONBDOS.LIS
$ xer DSKUTIL.LIS
$ xer FILEIO.LIS
$ xer IOSYS.LIS
$ xer BDOSDEF.LST
$ xer BDOSINC.LST
$ xer BIOSDEF.LST
$ xer CCPDEF.LST
$ xer PKTIO.LST

View File

@@ -0,0 +1,8 @@
$ xer BDOSIF.lis
$ xer CCPBDOS.lis
$ xer CCPIF.lis
$ xer CCPLOAD.lis
$ xer EXCEPTN.lis
$ xer FILETYPS.lis
$ xer PGMLD.lis
$ xer STACK.lis