Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

163 lines
4.0 KiB
C

/****************************************************************
* *
* CP/M-68K Loader *
* *
* This is the main routine for the CP/M-68K Loader. *
* It has one entry point, ldcpm, which is called from *
* the assembly language routine called startld found in *
* ldrif.s. startld just sets up the stack. *
* *
* Configured for Alcyon C on the VAX *
* *
****************************************************************/
#include "stdio.h" /* Standard I/O declarations */
#define ALCYON TRUE /* TRUE if compiling with the ALCYON 68K C compiler */
#define SECLEN 128 /* CP/M sector length */
/* Declare EXTERN functions */
EXTERN WORD _bdos(); /* Loader BDOS entry point */
EXTERN startld(); /* Assembly routine to set up stack & retry */
EXTERN BYTE *bios1(); /* bios entry point for get segment table */
EXTERN move(); /* general purpose byte mover */
#define conout(ch) _bdos(2,ch)
#define seldsk(dsk) _bdos(14,dsk)
#define open(fcbp) _bdos(15,0,fcbp)
#define read(fcbp) _bdos(20,0,fcbp)
#define setdma(p) _bdos(26,0,p)
/* Define the data structures used in ldcpm */
struct fcb
{
UBYTE drvcode; /* drive code, must be 0 for loader BDOS */
/* (auto disk select not supported) */
UBYTE fname[11]; /* includes file name and type fields */
UBYTE sys_info[4]; /* ex, s1, s2, rc. These are don't cares */
UBYTE dskmap[16]; /* disk map, also a don't care */
UBYTE cur_rec; /* current record field */
};
struct hdr
{
WORD magic; /* magic number. We only recognize 0x601a */
LONG size[5]; /* sizes of code, data, bss, sym tbl, stack */
BYTE *tstart; /* start address of text segment */
WORD rlbflg; /* relocation bits suppressed flag */
};
struct segtbl
{ /* memory segment table from LDRBIOS */
WORD entrys; /* number of segments, must be 1 */
BYTE *start; /* low memory address */
LONG length; /* length of segment */
};
/**********************/
/* Global Variables */
/**********************/
BYTE buffer[SECLEN]; /* 128 byte dma buffer to read program headers */
/* We need 1 FCB to read CPM.SYS. */
/* Unfortunately, due to a bug in the Alcyon compiler, we can't initialize */
/* them in a straightforward way. So: */
/*sw No longer true. Deleted klutz. */
struct fcb cpmfcb =
{ 0, /* drive code */
'C','P','M',' ',' ',' ',' ',' ','S','Y','S'
};
/**************************/
/* Utility Routines */
/**************************/
pstring(p)
/* print string */
REG BYTE *p;
{
while (*p) conout(*p++);
}
badload(errtype)
/* Load failed. Print message and try again */
REG WORD errtype;
{
REG WORD i;
switch (errtype)
{
case 0: pstring("\r\nBoot error.");
startld();
case 1: pstring("\n\rOpen or Read error on ");
break;
case 2: pstring("\n\rBad file format on ");
}
pstring("CPM.SYS");
startld();
}
/********************
* load subroutine *
********************/
BYTE *load(fcbp)
/* load the file pointed to by fcbp and return pointer to load point */
REG struct fcb *fcbp;
{
REG BYTE *p;
REG struct hdr *hp;
REG LONG length;
setdma( buffer );
if ( open(fcbp) >= 255 ) badload(1);
fcbp->cur_rec = 0;
if ( read(fcbp) ) badload(1);
hp = buffer;
if ( (hp->magic != 0x601a) || ! (hp->rlbflg) )
badload(2);
p = hp->tstart;
length = hp->size[0] + hp->size[1];
move(&buffer[sizeof *hp], p, SECLEN - (sizeof *hp));
/* move the first record minus header to load point */
p += SECLEN - (sizeof *hp);
length -= SECLEN - (sizeof *hp);
while (length > 0L)
{
setdma(p);
if ( read(fcbp) ) badload(1);
p += SECLEN;
length -= SECLEN;
}
return(hp->tstart);
}
/***************************
* ldcpm main routine *
***************************/
ldcpm()
{
WORD (*gocpm)();
if (seldsk(0)) badload(0);
gocpm = load(&cpmfcb); /* load the CP/M system */
pstring("\r\n\nCP/M-68K(tm) Version 1.2 03/20/84 ");
pstring("\n\rCopyright (c) 1984 Digital Research, Inc.\r\n\n");
(*gocpm)(); /* jump to the CCP */
}