mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 00:14:25 +00:00
642 lines
13 KiB
C
642 lines
13 KiB
C
/*=======================================================================*/
|
|
/*/---------------------------------------------------------------------\*/
|
|
/*| |*/
|
|
/*| CP/M-68K(tm) BIOS for the EXORMACS |*/
|
|
/*| |*/
|
|
/*| Copyright 1982, Digital Research. |*/
|
|
/*| |*/
|
|
/*\---------------------------------------------------------------------/*/
|
|
/*=======================================================================*/
|
|
|
|
|
|
|
|
char copyright[] = "Copyright 1982, Digital Research";
|
|
|
|
struct memb { char byte; };
|
|
struct memw { int word; };
|
|
struct meml { long lword;};
|
|
|
|
|
|
/************************************************************************/
|
|
/* I/O Device Definitions */
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* Define the two ACIA ports on the Debug board */
|
|
/************************************************************************/
|
|
|
|
#define PORT1 0xFFEE011
|
|
#define PORT2 0xFFEE015
|
|
|
|
#define PORTCTRL 0
|
|
#define PORTSTAT 0
|
|
#define PORTRDR 2
|
|
#define PORTTDR 2
|
|
|
|
#define PORTRSET 3
|
|
#define PORTINIT 0x11
|
|
|
|
#define PORTRDRF 1
|
|
#define PORTTDRE 2
|
|
|
|
|
|
/************************************************************************/
|
|
/* Define Disk I/O Addresses and Related Constants */
|
|
/************************************************************************/
|
|
|
|
#define DSKIPC 0xFF0000 /* IPC Base Address */
|
|
|
|
#define DSKINTV 0x3FC /* Address of Disk Interrupt Vector */
|
|
|
|
#define INTTOIPC 0xD /* offsets */
|
|
#define RSTTOIPC 0xF
|
|
#define MSGTOIPC 0x101
|
|
#define ACKFMIPC 0x103
|
|
#define PKTTOIPC 0x105
|
|
#define MSGFMIPC 0x181
|
|
#define ACKTOIPC 0x183
|
|
#define PKTFMIPC 0x185
|
|
|
|
#define STX 0x02
|
|
#define ETX 0x03
|
|
#define ACK 0x06
|
|
#define NAK 0x15
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* BIOS Table Definitions */
|
|
/************************************************************************/
|
|
|
|
struct dpb
|
|
{
|
|
int spt;
|
|
char bsh;
|
|
char blm;
|
|
char exm;
|
|
char dpbjunk;
|
|
int dsm;
|
|
int drm;
|
|
char al0;
|
|
char al1;
|
|
int cks;
|
|
int off;
|
|
};
|
|
|
|
|
|
|
|
struct dph
|
|
{
|
|
char *xltp;
|
|
int dphscr[3];
|
|
char *dirbufp;
|
|
struct dpb *dpbp;
|
|
char *csvp;
|
|
char *alvp;
|
|
};
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* Directory Buffer for use by the BDOS */
|
|
/************************************************************************/
|
|
|
|
char dirbuf[128];
|
|
|
|
|
|
/************************************************************************/
|
|
/* CSV's */
|
|
/************************************************************************/
|
|
|
|
char csv0[16];
|
|
char csv1[16];
|
|
char csv2[16];
|
|
|
|
|
|
/************************************************************************/
|
|
/* ALV's */
|
|
/************************************************************************/
|
|
|
|
char alv0[32]; /* (dsm0 / 8) + 1 */
|
|
char alv1[32]; /* (dsm1 / 8) + 1 */
|
|
char alv2[2002]; /* (dsm2 / 8) + 1 */
|
|
|
|
|
|
/************************************************************************/
|
|
/* Disk Parameter Blocks */
|
|
/************************************************************************/
|
|
|
|
/* The following dpb definitions express the intent of the writer, */
|
|
/* unfortunately, due to a compiler bug, these lines cannot be used. */
|
|
/* Therefore, the obscure code following them has been inserted. */
|
|
|
|
/************* spt, bsh, blm, exm, jnk, dsm, drm, al0, al1, cks, off
|
|
|
|
struct dpb dpb0={ 26, 3, 7, 0, 0, 242, 63, 0xC0, 0, 16, 2};
|
|
struct dpb dpb1={ 26, 4, 15, 0, 0, 242, 63, 0xC0, 0, 16, 2};
|
|
struct dpb dpb2={ 26, 3, 7, 0, 0, 16008, 63, 0xC0, 0, 16, 2};
|
|
|
|
********** end of readable definitions *************/
|
|
|
|
/* The Alcyon C compiler assumes all structures are arrays of int, so */
|
|
/* in the following definitions, adjacent pairs of chars have been */
|
|
/* combined into int constants --- what a kludge! **********************/
|
|
|
|
struct dpb dpb0 = { 26, 1799, 0, 242, 63, -16384, 16, 2 };
|
|
struct dpb dpb1 = { 26, 1039, 0, 242, 63, -16384, 16, 2 };
|
|
struct dpb dpb2 = { 26, 1799, 0, 16008, 63, -16384, 16, 2 };
|
|
|
|
/*************** End of kludge *****************/
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* Sector Translate Table */
|
|
/************************************************************************/
|
|
|
|
char xlt[26] = { 1, 7, 13, 19, 25, 5, 11, 17, 23, 3, 9, 15, 21,
|
|
2, 8, 14, 20, 26, 6, 12, 18, 24, 4, 10, 16, 22 };
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* Disk Parameter Headers */
|
|
/* */
|
|
/* Four disks are defined : dsk a: diskno=0, dev name=#fd04 */
|
|
/* dsk b: diskno=1, dev name=#fd05 */
|
|
/* dsk c: diskno=2, dev name=#hd00 */
|
|
/* dsk d: diskno=3, dev name=#hd01 */
|
|
/************************************************************************/
|
|
|
|
struct dph dphtab[4] =
|
|
{ {&xlt, 0, 0, 0, &dirbuf, &dpb0, &csv0, &alv0}, /*dsk a*/
|
|
{&xlt, 0, 0, 0, &dirbuf, &dpb0, &csv1, &alv1}, /*dsk b*/
|
|
{ 0L, 0, 0, 0, &dirbuf, &dpb2, &csv2, &alv2}, /*dsk c*/
|
|
{ 0L, 0, 0, 0, &dirbuf, &dpb2, &csv2, &alv2}, /*dsk d*/
|
|
};
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
/* Memory Region Table */
|
|
/************************************************************************/
|
|
|
|
struct mrt { int count;
|
|
long tpalow;
|
|
long tpalen;
|
|
}
|
|
memtab = { 1, 0x400L, 0xFC00 };
|
|
|
|
|
|
/************************************************************************/
|
|
/* IOBYTE */
|
|
/************************************************************************/
|
|
|
|
int iobyte;
|
|
|
|
|
|
/************************************************************************/
|
|
/* Currently Selected Disk Stuff */
|
|
/************************************************************************/
|
|
|
|
int settrk, setsec, setdsk;
|
|
char *setdma;
|
|
|
|
|
|
char trkbuf[26 * 128];
|
|
int tbvalid = 0;
|
|
int tbdirty = 0;
|
|
int tbtrk;
|
|
int tbdsk;
|
|
|
|
|
|
/************************************************************************/
|
|
/* Disk I/O Packets for the UDC and other Disk I/O Variables */
|
|
/************************************************************************/
|
|
|
|
struct hmpkst {
|
|
char a1;
|
|
char a2;
|
|
char a3;
|
|
char dskno;
|
|
char com1;
|
|
char com2;
|
|
char a6;
|
|
char a7;
|
|
}
|
|
hmpack = { 512, 1792, 0, 768 }; /* kludge init by words */
|
|
|
|
|
|
struct rwpkst {
|
|
char stxchr;
|
|
char pktid;
|
|
char pktsize;
|
|
char dskno;
|
|
char chcmd;
|
|
char devcmd;
|
|
int numblks;
|
|
int blksize;
|
|
long iobf;
|
|
int cksum;
|
|
long lsect;
|
|
char etxchr;
|
|
char rwpad;
|
|
};
|
|
|
|
struct rwpkst rwpack = { 512, 5376, 4097, 13, 256, 0, 0, 0, 0, 0, 768 };
|
|
|
|
|
|
char cnvdsk[4] = { 4, 5, 0, 1 }; /* convert from CP/M dsk # to Exormacs */
|
|
|
|
char flag2; /* used by the disk interrupt handler */
|
|
char flag3; /* ditto */
|
|
|
|
#define MAXDSK 3
|
|
|
|
/************************************************************************/
|
|
/* Generic Serial Port I/O Procedures */
|
|
/************************************************************************/
|
|
|
|
portinit(port)
|
|
char *port;
|
|
{
|
|
*(port + PORTCTRL) = PORTRSET;
|
|
*(port + PORTCTRL) = PORTINIT;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
portstat(port)
|
|
char *port;
|
|
{
|
|
return ( *(port + PORTSTAT) & PORTRDRF) == PORTRDRF;
|
|
}
|
|
|
|
|
|
|
|
|
|
char portin(port)
|
|
char *port;
|
|
{
|
|
while (portstat(port) == 0) ;
|
|
return *(port + PORTRDR);
|
|
}
|
|
|
|
|
|
|
|
|
|
portout(port, ch)
|
|
char *port;
|
|
char ch;
|
|
{
|
|
while ( (*(port + PORTSTAT) & PORTTDRE) != PORTTDRE) ;
|
|
*(port + PORTTDR) = ch;
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* Error procedure for BIOS */
|
|
/************************************************************************/
|
|
|
|
bioserr(errmsg)
|
|
char *errmsg;
|
|
{
|
|
printstr("\n\rBIOS ERROR -- ");
|
|
printstr(errmsg);
|
|
printstr(".\n\r");
|
|
while(1);
|
|
}
|
|
|
|
printstr(s) /* used by bioserr */
|
|
register char *s;
|
|
{
|
|
while (*s) {portout(PORT1,*s); s += 1; };
|
|
}
|
|
|
|
printnum(n)
|
|
register long n;
|
|
{
|
|
register int i;
|
|
register char c, j;
|
|
|
|
i = 32;
|
|
do {
|
|
i -= 4;
|
|
j = (n>>i) & 0x0F;
|
|
if ( j < 10 ) c = '0' + j;
|
|
else c = 'A' + j - 10;
|
|
portout(PORT2, c);
|
|
} while (i);
|
|
portout(PORT2, ' ');
|
|
}
|
|
|
|
printrace(s)
|
|
register char *s;
|
|
{
|
|
while (*s) {portout(PORT2, *s); s += 1;}
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* Disk I/O Procedures */
|
|
/************************************************************************/
|
|
|
|
|
|
extern dskia();
|
|
|
|
dskic()
|
|
{
|
|
/* Disk Interrupt Handler -- C Language Portion */
|
|
|
|
if ( ! (DSKIPC+MSGFMIPC)->byte )
|
|
{
|
|
if ( (DSKIPC+ACKTOIPC)->byte != ACK )
|
|
{
|
|
(DSKIPC+ACKTOIPC)->byte = 0;
|
|
}
|
|
else
|
|
{
|
|
(DSKIPC+ACKTOIPC)->byte = 0;
|
|
flag2 = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (DSKIPC+PKTFMIPC)->byte == 2 )
|
|
{
|
|
(DSKIPC+ACKFMIPC)->byte = ACK;
|
|
(DSKIPC+MSGFMIPC)->byte = 0;
|
|
(DSKIPC+INTTOIPC)->byte = 0;
|
|
if ( ((DSKIPC+PKTFMIPC+8 )->byte == 0xFF) &&
|
|
((DSKIPC+PKTFMIPC+10)->byte == 0x80) )
|
|
{
|
|
tbtrk = 0xDFFFFFL;
|
|
}
|
|
flag3 = 0;
|
|
}
|
|
}
|
|
|
|
} /* end of dskic */
|
|
|
|
|
|
sendpkt(pktadr, pktsize)
|
|
register char *pktadr;
|
|
register int pktsize;
|
|
{
|
|
int i;
|
|
register char *iopackp;
|
|
|
|
flag2 = 0xFF;
|
|
flag3 = 0xFF;
|
|
DSKINTV->lword = &dskia;
|
|
i = pktsize;
|
|
iopackp = (DSKIPC + PKTTOIPC);
|
|
do { *iopackp = *pktadr++; iopackp += 2; i -= 1;} while (i);
|
|
(DSKIPC+MSGTOIPC)->byte = 0x80;
|
|
(DSKIPC+ACKTOIPC)->byte = 0;
|
|
(DSKIPC+INTTOIPC)->byte = 0;
|
|
while (flag2 == 0xFF);
|
|
while (flag3 == 0xFF);
|
|
}
|
|
|
|
|
|
#define wrongtk ((! tbvalid) || (tbtrk != settrk) || (tbdsk != setdsk))
|
|
#define gettrk if (wrongtk) filltb()
|
|
|
|
|
|
flush()
|
|
{
|
|
|
|
if ( tbvalid ) /* write out the contents of the track buffer */
|
|
{
|
|
rwpack.dskno = cnvdsk[tbdsk];
|
|
rwpack.iobf = &trkbuf;
|
|
rwpack.lsect = tbtrk * 13;
|
|
rwpack.chcmd = 0x20;
|
|
(DSKIPC + ACKFMIPC)->byte = ACK;
|
|
if ( (DSKIPC + MSGTOIPC)->byte ) bioserr("ERR2");
|
|
sendpkt(&rwpack, 21);
|
|
}
|
|
|
|
tbdirty = 0;
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
filltb()
|
|
{
|
|
|
|
if ( tbvalid && tbdirty ) flush();
|
|
|
|
rwpack.dskno = cnvdsk[setdsk];
|
|
rwpack.iobf = &trkbuf;
|
|
rwpack.lsect = settrk * 13;
|
|
rwpack.chcmd = 0x10;
|
|
(DSKIPC + ACKFMIPC)->byte = ACK;
|
|
if ( (DSKIPC + MSGTOIPC)->byte ) bioserr("ERR2");
|
|
sendpkt(&rwpack, 21);
|
|
|
|
tbvalid = 1;
|
|
tbdirty = 0;
|
|
tbtrk = settrk;
|
|
tbdsk = setdsk;
|
|
|
|
}
|
|
|
|
|
|
read()
|
|
{
|
|
register char *p;
|
|
register char *q;
|
|
register int i;
|
|
|
|
gettrk;
|
|
p = &trkbuf[128 * (setsec-1)];
|
|
q = setdma;
|
|
i = 128;
|
|
do {*q++ = *p++; i -= 1;} while (i);
|
|
return(0);
|
|
}
|
|
|
|
|
|
write(mode)
|
|
char mode;
|
|
{
|
|
register char *p;
|
|
register char *q;
|
|
register int i;
|
|
|
|
gettrk;
|
|
p = &trkbuf[128 * (setsec-1)];
|
|
q = setdma;
|
|
i = 128;
|
|
do {*p++ = *q++; i -= 1;} while (i);
|
|
tbdirty = 1;
|
|
if ( mode == 1 ) flush();
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
char sectran(s, xp)
|
|
int s;
|
|
char *xp;
|
|
{
|
|
return xp[s];
|
|
}
|
|
|
|
|
|
setxvect()
|
|
{
|
|
/* dummy */
|
|
}
|
|
|
|
|
|
long seldsk(dsk, logged)
|
|
register char dsk;
|
|
char logged;
|
|
{
|
|
register struct dph *dphp;
|
|
register char check;
|
|
|
|
if (dsk > MAXDSK) return(0L);
|
|
setdsk = dsk;
|
|
dphp = &dphtab[dsk];
|
|
if ( ! logged )
|
|
{
|
|
hmpack.dskno = cnvdsk[setdsk];
|
|
hmpack.com1 = 0x30;
|
|
hmpack.com2 = 0x02;
|
|
(DSKIPC+ACKFMIPC)->byte = 6;
|
|
if ( (DSKIPC+MSGTOIPC)->byte ) bioserr("ERR 6");
|
|
else sendpkt(&hmpack, 7);
|
|
check = (DSKIPC+PKTFMIPC+0x18)->byte;
|
|
switch ( check )
|
|
{
|
|
case 3: dphp->dpbp = &dpb0;
|
|
break;
|
|
|
|
case 7: dphp->dpbp = &dpb1;
|
|
break;
|
|
default: bioserr("ERR 7");
|
|
break;
|
|
}
|
|
}
|
|
return(dphp);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* BIOS PROPER */
|
|
/************************************************************************/
|
|
|
|
|
|
|
|
|
|
biosinit()
|
|
{
|
|
portinit(PORT1);
|
|
portinit(PORT2);
|
|
}
|
|
|
|
|
|
|
|
|
|
long bios(d0, d1, d2)
|
|
int d0;
|
|
long d1, d2;
|
|
{
|
|
if ( d0 > 7) {
|
|
printrace("\n\rBIOS( ");
|
|
printnum((long)d0);
|
|
printnum(d1);
|
|
printnum(d2);
|
|
printrace(")\n\r");
|
|
}
|
|
|
|
switch(d0)
|
|
{
|
|
case 0: init(); /* INIT */
|
|
break;
|
|
|
|
case 1: wboot(); /* WBOOT */
|
|
break;
|
|
|
|
case 2: return(portstat(PORT1)); /* CONST */
|
|
break;
|
|
|
|
case 3: return(portin(PORT1)); /* CONIN */
|
|
break;
|
|
|
|
case 4: portout(PORT1, (char)d1); /* CONOUT */
|
|
break;
|
|
|
|
case 5: ; /* LIST */
|
|
case 6: portout(PORT2, (char)d1); /* PUNCH */
|
|
break;
|
|
|
|
case 7: return(portin(PORT2)); /* READER */
|
|
break;
|
|
|
|
case 8: settrk = 0; /* HOME */
|
|
break;
|
|
|
|
case 9: return(seldsk((char)d1, (char)d2)); /* SELDSK */
|
|
break;
|
|
|
|
case 10: settrk = (int)d1; /* SETTRK */
|
|
break;
|
|
|
|
case 11: setsec = (int)d1; /* SETSEC */
|
|
break;
|
|
|
|
case 12: setdma = d1; /* SETDMA */
|
|
break;
|
|
|
|
case 13: return(read()); /* READ */
|
|
break;
|
|
|
|
case 14: return(write((char)d1)); /* WRITE */
|
|
break;
|
|
|
|
case 15: return(portstat(PORT2)); /* LISTST */
|
|
break;
|
|
|
|
case 16: return(sectran((int)d1, d2)); /* SECTRAN */
|
|
break;
|
|
|
|
case 17: return(&memtab); /* GMRTA */
|
|
break;
|
|
|
|
case 19: return(iobyte); /* GETIOB */
|
|
break;
|
|
|
|
case 20: iobyte = (int)d1; /* SETIOB */
|
|
break;
|
|
|
|
case 21: return(flush()); /* FLUSH */
|
|
break;
|
|
|
|
case 22: return(setxvect((int)d1,d2)); /* SETXVECT */
|
|
break;
|
|
|
|
|
|
|
|
} /* end switch */
|
|
|
|
|
|
} /* end bios procedure */
|
|
|
|
|
|
|
|
/* End of C Bios */
|