mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-27 10:24:19 +00:00
Upload
Digital Research
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
|
||||
|
||||
CP/M-8000
|
||||
---------
|
||||
Features
|
||||
--------
|
||||
o Memory Space Efficient -- Resides in 28K bytes
|
||||
o Can utilize as little as 128Kb or as much as 8Mb
|
||||
of memory
|
||||
o Allows up to 8Gb of on-line disk(ette) storage
|
||||
o Command compatible with CP/M and CP/M-86
|
||||
o File structure compatible with CP/M and CP/M-86
|
||||
o Allows full access to the Z8000 hardware features
|
||||
o Supports all processors in the Z8000 family
|
||||
o Comes with a C language compiler and standard
|
||||
run-time library.
|
||||
`
|
||||
CP/M-8000 Overview
|
||||
------------------
|
||||
CP/M-8000 is a proprietary, general-purpose control
|
||||
program designed especially for microcomputers built
|
||||
around the Zilog Z8000 microprocessor family.
|
||||
CP/M-8000 is efficient and powerful. CP/M-8000 systems
|
||||
can support application programs that range from small
|
||||
to complex. It has a time-tested, modular design. The
|
||||
system modules include:
|
||||
o The Console Command Processor (CCP) -- the human
|
||||
interface of the operating system that parses and
|
||||
executes a user's commands.
|
||||
o The Basic Disk Operating System (BDOS) -- the
|
||||
invariant portion of the operating system
|
||||
that performs system services such as managing
|
||||
disk directories and files.
|
||||
o The Basic Input/Output System (BIOS) -- the
|
||||
variant portion of the operating system that
|
||||
contains hardware-dependent input/output device
|
||||
handlers.
|
||||
`
|
||||
CP/M and CP/M-86 Compatibility
|
||||
------------------------------
|
||||
CP/M-8000 files are completely compatible with CP/M
|
||||
Version 2.2 and CP/M-86 Version 1.1. This simplifies
|
||||
conversions of CP/M and CP/M-86 software to run on
|
||||
CP/M-8000.
|
||||
The end user will notice no significant difference
|
||||
between CP/M-8000 and previous versions of CP/M.
|
||||
Commands such as DIR, TYPE, PIP, STAT, and ED respond the
|
||||
same way in both systems. The program interface is
|
||||
also unchanged -- CP/M-8000 calls for system services have
|
||||
the same function numbers as in CP/M and CP/M-86.
|
||||
It is easy to upgrade existing CP/M and CP/M-86
|
||||
application software to run under CP/M-8000, because
|
||||
CP/M-8000 is so similar to its predecessors. Although
|
||||
assembly language programs will require recoding, high-
|
||||
level language programs will recompile with little or no
|
||||
modification.
|
||||
`
|
||||
File Management
|
||||
---------------
|
||||
CP/M-8000 can support up to 16 logical drives, each
|
||||
containing up to 512 megabytes, for a maximum of 8
|
||||
gigabytes of on-line storage. Any one file can reach 32
|
||||
megabytes, with space dynamically allocated and released.
|
||||
Each device has a directory which maps each file's
|
||||
physical locations on the disk. Disk definition tables
|
||||
in the BIOS translate this logical information to the
|
||||
physical characteristics of the disk. This file system
|
||||
is identical to the file system supported by CP/M 2 and
|
||||
CP/M-86.
|
||||
`
|
||||
Development Tools
|
||||
-----------------
|
||||
Digital Research offers a set of development tools for
|
||||
CP/M-8000 which can be run using CP/M-8000 or on a VAX-11
|
||||
or PDP-11 computer under the UNIX or VMS operating systems,
|
||||
or on a Zilog S8000 under the ZEUS operating system, or
|
||||
an Onyx C8000 running the Onix operating system. These
|
||||
tools can be used to develop CP/M-8000 applications or a
|
||||
custom CP/M-8000 BIOS. The development tools include:
|
||||
o A C compiler and C runtime library compatible with
|
||||
UNIX (R) software.
|
||||
o An assembler, linker, and library utitilies.
|
||||
o A symbolic debugger.
|
||||
o An object file dumper which can display the headers,
|
||||
symbol table and relocation information in easily
|
||||
readable ASCII form.
|
||||
These tools are distributed at no extra charge with
|
||||
CP/M-8000, and can be run on CP/M-8000 systems with at
|
||||
least 128K of memory.
|
||||
`
|
||||
Utilities
|
||||
---------
|
||||
In addition to the development tools described
|
||||
previously, CP/M-8000 is supplied with a set of file
|
||||
management utilities:
|
||||
PIP The Peripheral Interchange Program provides file
|
||||
transfer between devices and disk files. Various
|
||||
reformatting and concatenation operations may also
|
||||
be performed with PIP.
|
||||
ED The CP/M-8000 text editor allows creation and
|
||||
modification of ASCII files using extensive
|
||||
commands: string substitution, string search,
|
||||
insert, delete and block move. ED allows text
|
||||
to be located by context, line number, or
|
||||
relative position. A macro command allows making
|
||||
extensive text changes with a single command line.
|
||||
STAT The STAT utility alters and displays I/O device
|
||||
and file status including free space computations,
|
||||
status of online disk(ette)s and physical-to-logical
|
||||
device assignment.
|
||||
`
|
||||
Hardware Requirements
|
||||
---------------------
|
||||
The version of CP/M-8000 that Digital Research ships and
|
||||
supports requires an Olivetti M20 with at least 256Kb of
|
||||
memory. CP/M-8000 may be reconfigured for a custom
|
||||
hardware environment using the development tools supplied
|
||||
with the system. Custom hardware environments must
|
||||
include:
|
||||
o A Zilog Z8001, Z8002, Z8003 or Z8004 CPU.
|
||||
o At least 128K of RAM.
|
||||
o One to 16 disk drives of up to 512 megabytes each.
|
||||
o An ASCII console Device such as a CRT.
|
||||
`
|
||||
Ordering Information
|
||||
--------------------
|
||||
CP/M-8000 will be available from Digital Research in the
|
||||
first quarter of 1983. At that time, two CP/M-8000
|
||||
products will be made available:
|
||||
o The CP/M-8000 single user system, consisting of
|
||||
5 1/4 inch diskettes plus CP/M-8000 documentation.
|
||||
o CP/M-8000 documentation only, consisting of four
|
||||
manuals:
|
||||
o The CP/M-8000 User's Guide
|
||||
o The CP/M-8000 Programmer's Guide
|
||||
o The CP/M-8000 System Guide
|
||||
o The CP/M-8000 C Language Manual
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*=======================================================================*/
|
||||
/*+---------------------------------------------------------------------+*/
|
||||
/*| |*/
|
||||
/*| Boot Tracks copy program for the OLIVETTI M20 (Z8000) |*/
|
||||
/*| |*/
|
||||
/*| Copyright 1983, Zilog Incorporated. |*/
|
||||
/*| |*/
|
||||
/*+---------------------------------------------------------------------+*/
|
||||
/*=======================================================================*/
|
||||
|
||||
|
||||
char copyright[] = "Copyright 1983, Zilog Incorporated";
|
||||
|
||||
|
||||
/* HISTORY
|
||||
**
|
||||
** 830223 F. Zlotnick (Zilog) -- with assembler routines stolen
|
||||
** from S. Savitzky's BIOS.
|
||||
**
|
||||
*/
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
|
||||
#define SECSIZ 256
|
||||
#define NSECS 16
|
||||
#define TRKSIZE NSECS*SECSIZ
|
||||
#define NTRACKS 5
|
||||
|
||||
#define READ 0 /* Controller command */
|
||||
#define WRITE 1 /* Controller command */
|
||||
|
||||
long map_adr(); /* for physical addresses */
|
||||
|
||||
int bigbuff[NSECS*SECSIZ*5]; /* Will hold 5 tracks, 2 sides each */
|
||||
int drive1, /* Source drive name */
|
||||
drive2, /* Target drive name */
|
||||
err; /* error return from disk_io routine */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int i,j;
|
||||
|
||||
if(argc != 3) usage();
|
||||
if( strcmp( argv[1], "a:") == 0 ) {
|
||||
drive1 = 0;
|
||||
if( strcmp( argv[2], "b:") != 0) usage();
|
||||
else drive2 = 1;
|
||||
}
|
||||
else if( strcmp( argv[1], "b:") == 0 ) {
|
||||
drive1 = 1;
|
||||
if( strcmp( argv[2], "a:") != 0) usage();
|
||||
else drive2 = 0;
|
||||
}
|
||||
else usage();
|
||||
if( j = dotrks()) { /* Do the actual copy of the boot tracks */
|
||||
printf( "Error %d on track %d\n", err, j);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
dotrks()
|
||||
{
|
||||
register int track, secnum;
|
||||
long physaddr, offset;
|
||||
|
||||
physaddr = map_adr((long) bigbuff, 0);
|
||||
offset = 0L;
|
||||
for ( track = 0; track < NTRACKS; track++) {
|
||||
secnum = track * 32;
|
||||
if(err = disk_io(drive1,READ,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
secnum += NSECS;
|
||||
offset += TRKSIZE;
|
||||
if(err = disk_io(drive1,READ,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
offset += TRKSIZE;
|
||||
}
|
||||
offset = 0L;
|
||||
for ( track = 0; track < NTRACKS; track++) {
|
||||
secnum = track * 32;
|
||||
if(err = disk_io(drive2,WRITE,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
secnum += NSECS;
|
||||
offset += TRKSIZE;
|
||||
if(err = disk_io(drive2,WRITE,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
offset += TRKSIZE;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Usage routine tells user he's invoked command incorrectly
|
||||
*/
|
||||
usage()
|
||||
{
|
||||
printf("usage:\n\tcpmcopy source dest\n");
|
||||
printf("where source is 'a:' and dest is 'b:' or vice versa.\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*=======================================================================*/
|
||||
/*+---------------------------------------------------------------------+*/
|
||||
/*| |*/
|
||||
/*| Disk-Disk copy program for the OLIVETTI M20 (Z8000) |*/
|
||||
/*| |*/
|
||||
/*| Copyright 1983, Zilog Incorporated. |*/
|
||||
/*| |*/
|
||||
/*+---------------------------------------------------------------------+*/
|
||||
/*=======================================================================*/
|
||||
|
||||
|
||||
char copyright[] = "Copyright 1983, Zilog Incorporated";
|
||||
|
||||
|
||||
/* HISTORY
|
||||
**
|
||||
** 830221 F. Zlotnick (Zilog) -- with assembler routines stolen
|
||||
** from S. Savitzky's BIOS.
|
||||
**
|
||||
*/
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
|
||||
#define SECSIZ 256
|
||||
#define NSECS 16
|
||||
#define TRKSIZE NSECS*SECSIZ
|
||||
#define NTRACKS 40
|
||||
|
||||
#define READ 0 /* Controller command */
|
||||
#define WRITE 1 /* Controller command */
|
||||
|
||||
long map_adr(); /* for physical addresses */
|
||||
|
||||
int bigbuff[NSECS*SECSIZ*5]; /* Will hold 5 tracks, 2 sides each */
|
||||
int drive1, /* Source drive name */
|
||||
drive2, /* Target drive name */
|
||||
err; /* error return from disk_io routine */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register int i,j;
|
||||
|
||||
if(argc != 3) usage();
|
||||
if( strcmp( argv[1], "a:") == 0 ) {
|
||||
drive1 = 0;
|
||||
if( strcmp( argv[2], "b:") != 0) usage();
|
||||
else drive2 = 1;
|
||||
}
|
||||
else if( strcmp( argv[1], "b:") == 0 ) {
|
||||
drive1 = 1;
|
||||
if( strcmp( argv[2], "a:") != 0) usage();
|
||||
else drive2 = 0;
|
||||
}
|
||||
else usage();
|
||||
if( dotrk0() ) { /* Track 0 is special */
|
||||
printf("Error copying track 0\n");
|
||||
exit(1);
|
||||
}
|
||||
for( i = 1; i<= 40; i += 5)
|
||||
if( j = do5trks(i)) { /* Do the rest, 5 tracks at a time */
|
||||
printf( "Error %d on track %d\n", err, j);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following routine copies track 0, both sides
|
||||
*/
|
||||
dotrk0()
|
||||
{
|
||||
register int j;
|
||||
long physaddr;
|
||||
|
||||
physaddr = map_adr( (long) bigbuff, 0);
|
||||
if( j = disk_io(drive1, READ, 16, 0, physaddr) )
|
||||
return(j); /* Do the read... */
|
||||
if( j = disk_io(drive1, READ, 16, 16, physaddr + TRKSIZE ) )
|
||||
return(j);
|
||||
if( j = disk_io(drive2, WRITE, 16, 0, physaddr) )
|
||||
return(j); /* ...and the write */
|
||||
if( j = disk_io(drive2, WRITE, 16, 16, physaddr + TRKSIZE ) )
|
||||
return(j);
|
||||
return(0);
|
||||
}
|
||||
|
||||
do5trks(i)
|
||||
int i;
|
||||
{
|
||||
register int track, secnum;
|
||||
long physaddr, offset;
|
||||
|
||||
physaddr = map_adr((long) bigbuff, 0);
|
||||
offset = 0L;
|
||||
for ( track = i; track < i + 5; track++) {
|
||||
secnum = track * 32;
|
||||
if(err = disk_io(drive1,READ,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
secnum += NSECS;
|
||||
offset += TRKSIZE;
|
||||
if(err = disk_io(drive1,READ,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
offset += TRKSIZE;
|
||||
}
|
||||
offset = 0L;
|
||||
for ( track = i; track < i + 5; track++) {
|
||||
secnum = track * 32;
|
||||
if(err = disk_io(drive2,WRITE,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
secnum += NSECS;
|
||||
offset += TRKSIZE;
|
||||
if(err = disk_io(drive2,WRITE,NSECS,secnum,physaddr + offset))
|
||||
return(track);
|
||||
offset += TRKSIZE;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Usage routine tells user he's invoked command incorrectly
|
||||
*/
|
||||
usage()
|
||||
{
|
||||
printf("usage:\n\tddcopy source dest\n");
|
||||
printf("where source is 'a:' and dest is 'b:' or vice versa.\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
;************ biosio.z8k **************************
|
||||
;*
|
||||
;* Direct disk I/O for the Disk copy program
|
||||
;* for Olivetti M20 (Z8001) system.
|
||||
;*
|
||||
;* 830214 F. Zlotnick (Zilog) -- created, stolen from
|
||||
;* the M20 Bios routines written by Steve Savitzky.
|
||||
;*
|
||||
;****************************************************
|
||||
|
||||
;****************************************************
|
||||
;*
|
||||
;* Global declarations
|
||||
;*
|
||||
;****************************************************
|
||||
|
||||
|
||||
.global _disk_io
|
||||
.global _bdos
|
||||
|
||||
;****************************************************
|
||||
|
||||
SUPV .equ 62 ; Supervisor state BDOS call
|
||||
BDOS_SC .equ 2 ; System call number 2
|
||||
|
||||
;****************************************************
|
||||
;
|
||||
; Following macro stolen from Steve Savitzky
|
||||
;
|
||||
;****************************************************
|
||||
|
||||
scall .MACRO
|
||||
|
||||
.word 05f00h ; 5F00 = segmented call
|
||||
.long ?1 ; segmented address
|
||||
|
||||
.ENDM
|
||||
|
||||
__text: .sect
|
||||
|
||||
;****************************************************
|
||||
;*
|
||||
;* NOTE The Olivetti PROM routines are segmented.
|
||||
;* The C portion of the copy program is non-segmented.
|
||||
;*
|
||||
;* This assembly-language module is assembled
|
||||
;* non-segmented, and serves as the interface.
|
||||
;*
|
||||
;* Segmented operations are well-isolated, and
|
||||
;* are either the same as their non-segmented
|
||||
;* counterparts, or constructed using macros.
|
||||
;*
|
||||
;****************************************************
|
||||
|
||||
|
||||
|
||||
;****************************************************
|
||||
;*
|
||||
;* C Stack frame equates
|
||||
;*
|
||||
;* A C stack frame consists of the PC on top,
|
||||
;* followed by the arguments, leftmost argument first.
|
||||
;*
|
||||
;* The caller adjusts the stack on return.
|
||||
;* Returned value is in r7 (int) or rr6 (long)
|
||||
;*
|
||||
;****************************************************
|
||||
|
||||
PCSIZE .equ 2 ;PC size non-segmented
|
||||
INTSIZE .equ 2 ;INT data type size
|
||||
LONGSIZE .equ 4 ;LONG data type size
|
||||
|
||||
ARG1 .equ PCSIZE ;integer arguments
|
||||
ARG2 .equ ARG1+INTSIZE
|
||||
ARG3 .equ ARG2+INTSIZE
|
||||
ARG4 .equ ARG3+INTSIZE
|
||||
ARG5 .equ ARG4+INTSIZE
|
||||
|
||||
|
||||
|
||||
;****************************************************
|
||||
;*
|
||||
;* Prom Subroutine Access
|
||||
;*
|
||||
;****************************************************
|
||||
|
||||
_disk_io: ;err=disk_io(drv, cmd, count, blk, addr)
|
||||
|
||||
dec r15,#14 ;save registers
|
||||
ldm @r15,r8,#7
|
||||
|
||||
ldb rh7,14+ARG1+1(r15) ;get args
|
||||
ldb rl7,14+ARG2+1(r15)
|
||||
ld r8, 14+ARG3(r15)
|
||||
ld r9, 14+ARG4(r15)
|
||||
ldl rr10,14+ARG5(r15)
|
||||
|
||||
;rh7 = drive #
|
||||
;rl7 = command
|
||||
;r8 = block count
|
||||
;r9 = block number
|
||||
;rr10 = segmented address
|
||||
|
||||
;
|
||||
; Now we must call the BDOS to get into segmented supervisor
|
||||
; mode. Dangerous!
|
||||
;
|
||||
; First save r7, which gets stepped on by the ldl instruction
|
||||
;
|
||||
ld r12, r7 ; r12 is available
|
||||
;
|
||||
ldl rr6,#0 ; Must be long
|
||||
ld r5,#SUPV ; BDOS function
|
||||
sc #BDOS_SC
|
||||
;
|
||||
; Watch it! Now in system mode, and the stack pointer isn't yours!
|
||||
;
|
||||
; Now restore r7
|
||||
;
|
||||
ld r7, r12
|
||||
;
|
||||
scall 84000068h
|
||||
;
|
||||
; That's all in segmented mode; Now lets get back to
|
||||
; user nonseg as fast as possible.
|
||||
;
|
||||
ldctl r1,FCW ; Get FCW in r1
|
||||
and r1,#03FFFh ; Mask seg and sysmode
|
||||
ldctl FCW,r1 ; BOOM!
|
||||
;r8 = block count not transferred
|
||||
;rh7 = #retries
|
||||
;rl7 = final error code (RETURNED)
|
||||
;rh6 = error retried
|
||||
|
||||
and r7,#0FFh ;value returned in r7
|
||||
|
||||
ldm r8,@r15,#7 ;restore regs
|
||||
inc r15,#14
|
||||
ret
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* COMDEX El-kludgo display program.
|
||||
*
|
||||
* disp file d
|
||||
*
|
||||
* Where "file" is a text file containing 24 x 64 pages, delineated by
|
||||
* "`" characters. "d" is the number of seconds to delay.
|
||||
*
|
||||
*/
|
||||
#include "stdio.h"
|
||||
FILE *fopen();
|
||||
main(argc,argv)
|
||||
WORD argc;
|
||||
BYTE **argv;
|
||||
{ /****************************/
|
||||
BYTE buffer[2048]; /* Buffer for screen text */
|
||||
REG FILE *ifp; /* Input file pointer */
|
||||
REG WORD delay; /* Delay for pages */
|
||||
REG BYTE c; /* Character temporary */
|
||||
REG WORD i,k,l; /* Count temporary */
|
||||
/****************************/
|
||||
if(argc != 3) /* Check the arg count */
|
||||
{ /* */
|
||||
printf("Bad Argument count\n"); /* Give error */
|
||||
exit(); /* Quit */
|
||||
} /****************************/
|
||||
/* */
|
||||
if((ifp=fopen(argv[1],"r")) <= 0) /* Open Input */
|
||||
{ /* */
|
||||
printf("Cannot open %s\n",argv[1]); /* Give error */
|
||||
exit(); /* Quit in disgust */
|
||||
} /* */
|
||||
/****************************/
|
||||
delay=atoi(argv[2]); /* Convert delay quantity */
|
||||
if(delay < 0 || delay > 10000) /* Range check */
|
||||
{ /* */
|
||||
printf("Illegal delay = %d\n",delay); /* Print delay nfg */
|
||||
exit(); /* Quit */
|
||||
} /****************************/
|
||||
/* */
|
||||
while(1) /* Always */
|
||||
{ /* */
|
||||
i = 0; /* Subscript init */
|
||||
c = 1; /* Initialize char */
|
||||
while(c != '`' && c > 0) /* While c in page & not EOF*/
|
||||
{ /****************************/
|
||||
c = getc(ifp); /* Read next character */
|
||||
buffer[i++] = c; /* Put next character in buf*/
|
||||
} /****************************/
|
||||
i--; /* Decrement count back to 0*/
|
||||
l = 0; /* Initially no lfs in buff */
|
||||
for(k=0; k <= i; k++) /* Count line feeds */
|
||||
if(buffer[k] == '\n') l++; /* L = # line feeds */
|
||||
k = 23 - l; /* K = # line feeds desired */
|
||||
write(1,buffer,i); /* Write buffer to stdout */
|
||||
loop(delay); /* Do the delay */
|
||||
/****************************/
|
||||
if(c <= 0) /* Check for EOF */
|
||||
fseek(ifp,0L,0); /* Seek back to beginning */
|
||||
} /****************************/
|
||||
}
|
||||
loop(delay) /* Delay loop */
|
||||
WORD delay; /* # counts */
|
||||
{ /****************************/
|
||||
REG WORD i; /* Inner loop count */
|
||||
while(delay > 0) /****************************/
|
||||
{ /* */
|
||||
for (i = 0; i < 10000; i++); /* Do nothing */
|
||||
delay--; /* Down count */
|
||||
} /****************************/
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* This program formats a 5 1/4 inch floppy disk in drive 0 or drive 1
|
||||
* of the Olivetti M20. The format is ECMA standard for the headers.
|
||||
* The data fields are filled with 0xE5, which CP/M thinks is a new
|
||||
* IBM disk. This gives the disk the appearance of having an empty
|
||||
* directory as far as CP/M is concerned.
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
/* densities */
|
||||
#define SINGLE 0
|
||||
#define DOUBLE 1
|
||||
|
||||
#define BADTRACK -1
|
||||
#define MAXBAD 2
|
||||
|
||||
#define NTRACKS 40
|
||||
|
||||
/* Space for humongous buffer */
|
||||
#define TRACKSIZ 10000
|
||||
char trakbuf[TRACKSIZ];
|
||||
int track,
|
||||
sector,
|
||||
side,
|
||||
density,
|
||||
drive;
|
||||
|
||||
int intrlv[16] = { 9, 1, 10, 2,
|
||||
11, 3, 12, 4,
|
||||
13, 5, 14, 6,
|
||||
15, 7, 16, 8};
|
||||
|
||||
extern long map_adr();
|
||||
long physaddr; /* Segmented address of trakbuf */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register char c, *p;
|
||||
|
||||
physaddr = map_adr((long)trakbuf,0); /* get seg addr */
|
||||
while(--argc) {
|
||||
p = *++argv;
|
||||
if (strcmp(p,"a:") == 0) {
|
||||
drive = 0;
|
||||
warn(p);
|
||||
format(p);
|
||||
}
|
||||
else if (strcmp(p,"b:") == 0) {
|
||||
drive = 1;
|
||||
warn(p);
|
||||
format(p);
|
||||
}
|
||||
else printf("Unknown drive: %s\n",p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Routine to format a disk in a given drive */
|
||||
format(p)
|
||||
char *p;
|
||||
{
|
||||
register int i,j,k;
|
||||
int badtracks;
|
||||
|
||||
badtracks = 0;
|
||||
|
||||
/* Start with track 0; this track is special. */
|
||||
printf("Formatting track %2d",0);
|
||||
track = 0;
|
||||
density = SINGLE;
|
||||
if ( (j = make_zero()) == BADTRACK) {
|
||||
printf("Can't format track zero; bad diskette\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Now do the other tracks */
|
||||
density = DOUBLE;
|
||||
for(track = 1; track<=40; track++) {
|
||||
printf("%2d",track);
|
||||
if( (j = dotrack(track)) == BADTRACK) badtracks++;
|
||||
if (badtracks > MAXBAD) {
|
||||
printf("%d bad tracks; too many.\n",badtracks);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
printf("\nFormatting of disk in drive %s complete.\n\n",p);
|
||||
return(badtracks);
|
||||
}
|
||||
|
||||
/* Routine to do one track */
|
||||
dotrack(track)
|
||||
{
|
||||
register int j;
|
||||
|
||||
if( (j = doside(0,track)) == BADTRACK) return(BADTRACK);
|
||||
if( (j = doside(1,track)) == BADTRACK) return(BADTRACK);
|
||||
return(track);
|
||||
}
|
||||
|
||||
/* Routine to do one double density side */
|
||||
doside(side,track)
|
||||
int side,track;
|
||||
{ register int j,sector;
|
||||
char *p;
|
||||
|
||||
p = trakbuf;
|
||||
for(j = 0; j < 32; j++) *p++ = 0x4e; /* Index Gap: 32 hx 4E's */
|
||||
for(sector = 0; sector < 16; sector++) {
|
||||
for(j = 0; j < 12; j++) *p++ = '\0';
|
||||
for(j = 0; j < 3; j++) *p++ = 0xf5;
|
||||
*p++ = 0xfe;
|
||||
*p++ = track;
|
||||
*p++ = side;
|
||||
*p++ = intrlv[sector]; /* use interleave table */
|
||||
*p++ = (char)DOUBLE;
|
||||
*p++ = 0xf7; /* Puts two CRC bytes out */
|
||||
for(j = 0; j < 22; j++) *p++ = 0x4e;
|
||||
for(j = 0; j < 12; j++) *p++ = '\0';
|
||||
for(j = 0; j < 3; j++) *p++ = 0xf5;
|
||||
*p++ = 0xfb;
|
||||
/* Magic with the data buffer: fill it with hex E5's, and CP/M will think */
|
||||
/* that it has an empty directory! */
|
||||
for(j = 0; j < 256; j++) *p++ = 0xe5;
|
||||
*p++ = 0xf7; /* More CRC's */
|
||||
for(j = 0; j < 50; j++) *p++ = 0x4e; /* sector gap */
|
||||
}
|
||||
/* Now do the end of track gap: 400 hex 4E's */
|
||||
for(j = 0; j < 400; j++) *p++ = 0x4e;
|
||||
|
||||
/* Finally, use assembler magic to write the track image. */
|
||||
return(writ_im(drive,track,side,physaddr));
|
||||
}
|
||||
|
||||
/* Routine to make track zero, which is special. It's single-density
|
||||
* on side zero, and double density on side one. Each of these has a
|
||||
* different header encoding standard.
|
||||
*/
|
||||
|
||||
make_zero()
|
||||
{
|
||||
register int j,sector;
|
||||
char *p;
|
||||
|
||||
p = trakbuf;
|
||||
for( j = 0; j < 16; j++) *p++ = 0xff; /* Index Gap */
|
||||
for(sector = 0; sector < 16; sector++) {
|
||||
for(j = 0; j < 6; j++) *p++ = '\0';
|
||||
*p++ = 0xfe;
|
||||
*p++ = 0; /* Track # */
|
||||
*p++ = 0; /* Side # */
|
||||
*p++ = intrlv[sector];
|
||||
*p++ = '\0';
|
||||
*p++ = 0xf7; /* CRC */
|
||||
for(j = 0; j < 11; j++) *p++ = 0xff;
|
||||
for(j = 0; j < 6; j++) *p++ = '\0';
|
||||
*p++ = 0xfb;
|
||||
for(j = 0; j < 128; j++) *p++ = 0xe5; /* Magic data */
|
||||
*p++ = 0xf7; /* CRC */
|
||||
for(j = 0; j < 24; j++) *p++ = 0xff; /* Sector Gap */
|
||||
}
|
||||
for(j = 0; j < 200; j++) *p++ = 0xff; /* End-of-track Gap */
|
||||
j = writ_im(drive,0,0,physaddr); /* Write side 0 special */
|
||||
if(j == BADTRACK) return(j);
|
||||
return(doside(1,0)); /* Write side 1 normal */
|
||||
}
|
||||
|
||||
warn(p)
|
||||
char *p;
|
||||
{
|
||||
register int c,cc;
|
||||
|
||||
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
|
||||
printf("Warning: This will destroy all files on disk %s!\n\n",p);
|
||||
printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
|
||||
printf("Do you wish to continue? ");
|
||||
c = getchar();
|
||||
if(c == '\n') exit(1);
|
||||
else while( (cc = getchar()) != '\n') ;
|
||||
if(c != 'y' && c != 'Y') exit(1);
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
;////////////////////////////////////////////////////////////////////////
|
||||
; /
|
||||
; Interface between the disk formatter program and the disk /
|
||||
; driver. The formatter is running in user non-seg mode, and /
|
||||
; the disk driver must run supervisor segmented. Thus this /
|
||||
; routine must bridge the gap both ways. /
|
||||
; /
|
||||
; /
|
||||
; Written by F Zlotnick (Zilog) 29 Oct 82 /
|
||||
; /
|
||||
;////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.global _writ_im
|
||||
.global _bdos
|
||||
|
||||
|
||||
ARG1 .equ 2
|
||||
ARG2 .equ 4
|
||||
ARG3 .equ 6
|
||||
ARG4 .equ 8
|
||||
|
||||
SUPV .equ 62 ; Supervisor State BDOS call
|
||||
BDOS_SC .equ 2 ; System call number
|
||||
|
||||
;
|
||||
; Space to save registers
|
||||
;
|
||||
regsave:
|
||||
.block 14
|
||||
;
|
||||
; Following macro stolen from Steve Savitzky
|
||||
;
|
||||
|
||||
scall .MACRO ; segmented address argument
|
||||
|
||||
.word 05F00h ; 5F00 = segmented call
|
||||
.long ?1
|
||||
|
||||
.ENDM
|
||||
|
||||
|
||||
.code .sect
|
||||
;
|
||||
; Start by saving registers 8 - 14. C expects this.
|
||||
;
|
||||
|
||||
_writ_im:
|
||||
sub r15,#14 ; Make space on the stack...
|
||||
ldm @r15,r8,#7 ; ...and copy r8-r14 there.
|
||||
;
|
||||
; Put arguments where the driver expects them:
|
||||
; rr10 = segmented address of the buffer
|
||||
; r9 = logical block number (see description below)
|
||||
; r8 = number of blocks to transfer = 1
|
||||
; rh7 = drive number (0, or 1, or 10 for a hard disk)
|
||||
; rl7 = Command = 2 for format (Write Track Cmd)
|
||||
;
|
||||
ldl rr10,ARG4+14(r15) ; Segmented buffer address
|
||||
ld r9,#0 ; Block #
|
||||
ld r8,#1 ; # Blocks
|
||||
ldb rh7,ARG1+15(r15) ; Drive
|
||||
ldb rl7,#2 ; Command
|
||||
;
|
||||
; Must set up r9 to contain the track and side number in a strange
|
||||
; way. The track number goes in shifted left logical, 5 bits, and
|
||||
; then bit 4 is set if it's side 1, or don't set it if it's side zero.
|
||||
; Weird. We use r1 as a scratch register.
|
||||
;
|
||||
ld r1,ARG2+14(r15) ; Track
|
||||
sll r1,#5 ; That's what the driver expects
|
||||
test ARG3+14(r15) ; Side
|
||||
jr z,side0
|
||||
set r1,#4 ; Side flag in logical block #
|
||||
side0:
|
||||
ld r9,r1 ; Where driver expects it.
|
||||
; Before calling the BDOS, save regs 7-13.
|
||||
;
|
||||
ldm regsave,r7,#7
|
||||
;
|
||||
; Now we must call the BDOS to get into segmented supervisor
|
||||
; mode. Dangerous!
|
||||
;
|
||||
ldl rr6,#0 ; Must be long
|
||||
ld r5,#SUPV ; BDOS function
|
||||
sc #BDOS_SC
|
||||
;
|
||||
; Restore registers 7-13
|
||||
;
|
||||
.word 05C01h
|
||||
.word 0706h
|
||||
.word 8A00h
|
||||
.word regsave
|
||||
;
|
||||
; Watch it! Now in system mode, and the stack pointer isn't yours!
|
||||
;
|
||||
scall 84000068h
|
||||
;
|
||||
; That's all in segmented mode; Now lets get back to
|
||||
; user nonseg as fast as possible.
|
||||
;
|
||||
ldctl r1,FCW ; Get FCW in r1
|
||||
and r1,#03FFFh ; Mask seg and sysmode
|
||||
;
|
||||
;//////////////////////////////////////////////////////////////////
|
||||
; /
|
||||
; The following sequence has been restored from diskio.z8k, /
|
||||
; because the original file was corrupt. I'm not sure if /
|
||||
; it works, so please let me know the results if you have /
|
||||
; the possibility to try. Thanks, Gaby Chaudry /
|
||||
; /
|
||||
;//////////////////////////////////////////////////////////////////
|
||||
;
|
||||
ldctl FCW,r1 ; BOOM!
|
||||
;r8 = block count not transferred
|
||||
;rh7 = #retries
|
||||
;rl7 = final error code (RETURNED)
|
||||
;rh6 = error retried
|
||||
|
||||
and r7,#0FFh ;value returned in r7
|
||||
|
||||
ldm r8,@r15,#7 ;restore regs
|
||||
inc r15,#14
|
||||
ret
|
||||
|
||||
|
||||
Reference in New Issue
Block a user