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,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


View File

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

View File

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

View File

@@ -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

View File

@@ -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 */
} /****************************/
}

View File

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

View File

@@ -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