mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 00:14:25 +00:00
1079 lines
25 KiB
C
1079 lines
25 KiB
C
/*=======================================================================*/
|
||
/*+---------------------------------------------------------------------+*/
|
||
/*| |*/
|
||
/*| P-CP/M(tm) BIOS for the OLIVETTI M20 (Z8000) |*/
|
||
/*| |*/
|
||
/*| Copyright 1982, Zilog Incorporated. |*/
|
||
/*| |*/
|
||
/*+---------------------------------------------------------------------+*/
|
||
/*=======================================================================*/
|
||
|
||
/* #define DEBUG 1 */
|
||
|
||
char copyright[] = "Copyright 1982, Zilog Incorporated";
|
||
|
||
|
||
/* HISTORY
|
||
**
|
||
** 820803 S. Savitzky (Zilog) -- derived from 68000 EXORMACS bios
|
||
**
|
||
** 830614 F. Zlotnick (Zilog) -- removed initialization of iobyte
|
||
** upon each warmboot. Changed seldisk to test for
|
||
** overflow of the dphtab (to fix the "dir d:" bug).
|
||
**
|
||
** 830804 F. Zlotnick (Zilog) -- Added conditional compilation for
|
||
** loader BIOS, which only needs a few of the BIOS
|
||
** functions. The loader DOES require the definition
|
||
** of a context structure, for transfer of control to
|
||
** the system proper.
|
||
**
|
||
** 830804 F. Zlotnick (Zilog) -- Changed Disk Parameter Blocks to
|
||
** reflect new bootstrap method.
|
||
**
|
||
** 830809 F. Zlotnick (Zilog) -- Added escape character to keyboard
|
||
** map, as ctrl'['.
|
||
**
|
||
*/
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/* */
|
||
/* I/O Device Definitions */
|
||
/* */
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/* Define Interrupt Controller constants */
|
||
/************************************************************************/
|
||
|
||
/* The interrupt controller is an Intel 8259 left-shifted one bit */
|
||
/* to allow for the word-alligned interrupt vectors of the Z8000. */
|
||
|
||
/* === I am going to assume that this is set up in the PROM === */
|
||
|
||
|
||
/************************************************************************/
|
||
/* Define the two USART ports */
|
||
/************************************************************************/
|
||
|
||
/* The USARTs are Intel 8251's */
|
||
|
||
#define KBD 0xA1 /* Keyboard USART base */
|
||
#define RS232 0xC1 /* RS-232 terminal */
|
||
|
||
#define SERDATA 0 /* data port offset */
|
||
#define SERCTRL 2 /* control port offset */
|
||
#define SERSTAT 2 /* status port offset */
|
||
|
||
#define SERINIT 0x37 /* init (3 times) */
|
||
#define SERRES 0x40 /* reset */
|
||
#define SERMODE 0xEE /* mode (2 stop, even parity */
|
||
/* parity disable, 8 bits */
|
||
/* divide by 16 */
|
||
/* DUBIOUS. 15?? */
|
||
#define SERCMD 0x37 /* cmd (no hunt, no reset, */
|
||
/* RTS=0, error reset, */
|
||
/* no break, rcv enable, */
|
||
/* DTR=0, xmt enable */
|
||
|
||
#define SERRRDY 0x02 /* RCV ready bit mask */
|
||
#define SERXRDY 0x01 /* XMT ready bit mask */
|
||
|
||
|
||
/************************************************************************/
|
||
/* Define the counter/timer ports */
|
||
/************************************************************************/
|
||
|
||
/* The counter-timer is an Intel 8253 */
|
||
|
||
#define CT_232 0x121 /* counter/timer 0 -- RS232 baud rate */
|
||
#define CT_KBD 0x123 /* counter/timer 1 -- kbd baud rate */
|
||
#define CT_RTC 0x125 /* counter/timer 2 -- NVI (rt clock) */
|
||
#define CT_CTRL 0x127 /* counter/timer control port */
|
||
|
||
#define CT0CTL 0x36 /* c/t 0 control byte */
|
||
#define CT1CTL 0x76 /* c/t 1 control byte */
|
||
#define CT2CTL 0xB4 /* c/t 2 control byte */
|
||
|
||
/* control byte is followed by LSB, then MSB of count to data register */
|
||
/* baud rate table follows: */
|
||
|
||
#ifndef LOADER
|
||
|
||
int baudRates[10] = {
|
||
1538, /* 50 */
|
||
699, /* 110 */
|
||
256, /* 300 */
|
||
128, /* 600 */
|
||
64, /* 1200 */
|
||
32, /* 2400 */
|
||
16, /* 4800 */
|
||
8, /* 9600 */
|
||
4, /* 19200 */
|
||
2 /* 38400 */
|
||
};
|
||
|
||
|
||
#endif
|
||
|
||
/************************************************************************/
|
||
/* Define Parallel Port constants */
|
||
/************************************************************************/
|
||
|
||
/* The parallel (printer) port is an Intel 8255 */
|
||
|
||
#define PAR_A 0x81 /* port A data */
|
||
#define PAR_B 0x83 /* port B data */
|
||
#define PAR_C 0x85 /* port C data */
|
||
#define PARCTRL 0x87 /* control port */
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/* */
|
||
/* PROM AND HARDWARE INTERFACE */
|
||
/* */
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
/************************************************************************/
|
||
/* Define PROM I/O Addresses and Related Constants */
|
||
/************************************************************************/
|
||
|
||
extern int disk_io(); /* (char drive, cmd -- disk I/O */
|
||
/* int blk_count, */
|
||
/* int blk_num, */
|
||
/* char *dest) -> int error? */
|
||
|
||
extern crt_put(); /* (char character) -- put byte to CRT */
|
||
|
||
extern cold_boot(); /* boot operating system */
|
||
|
||
#define DSKREAD 0 /* disk read command */
|
||
#define DSKWRITE 1 /* disk write command */
|
||
#define DSKFMT 2 /* disk format command */
|
||
#define DSKVFY 3 /* disk verify command */
|
||
#define DSKINIT 4 /* disk init. command */
|
||
|
||
|
||
/************************************************************************/
|
||
/* Define external I/O routines and addresses */
|
||
/************************************************************************/
|
||
|
||
extern output(); /* (port, data: int) -- output */
|
||
extern int input(); /* (port: int) -- input */
|
||
|
||
/************************************************************************/
|
||
/* Define external memory management routines */
|
||
/************************************************************************/
|
||
|
||
extern mem_cpy(); /* (src, dest, len: long)-- copy data */
|
||
extern long map_adr(); /* paddr = (laddr: long; space: int) */
|
||
|
||
#define CDATA 0 /* caller data space */
|
||
#define CCODE 1 /* caller code space */
|
||
#define SDATA 2 /* system data space */
|
||
#define SCODE 3 /* system code space */
|
||
#define NDATA 4 /* normal data space */
|
||
#define NCODE 5 /* normal code space */
|
||
|
||
|
||
/************************************************************************/
|
||
/* System Entry and Stack Pointer */
|
||
/************************************************************************/
|
||
|
||
#define SYSENTRY 0x0b000006L /* entry point */
|
||
#define SYSSTKPTR 0x0b00bffeL /* system's stack pointer start */
|
||
|
||
/************************************************************************/
|
||
/* Memory Region Table */
|
||
/************************************************************************/
|
||
|
||
#ifndef LOADER
|
||
|
||
struct mrt { int count;
|
||
struct {long tpalow;
|
||
long tpalen;
|
||
} regions[4];
|
||
}
|
||
memtab = {4,
|
||
0x0A000000L, 0x10000L, /* merged I and D */
|
||
0x08000000L, 0x10000L, /* separated I */
|
||
0x08000000L, 0x10000L, /* and D */
|
||
0x0B000000L, 0x10000L /* accessing I as D */
|
||
};
|
||
#endif
|
||
#ifdef LOADER
|
||
|
||
struct mrt { int count;
|
||
struct {long tpalow;
|
||
long tpalen;
|
||
} regions[1];
|
||
}
|
||
memtab = {1,
|
||
0x0B000000L, 0x0C000L, /* system space: merged I and D */
|
||
};
|
||
|
||
struct context /* Startup context for user's program */
|
||
{
|
||
short regs[14];
|
||
long segstkptr;
|
||
short ignore;
|
||
short FCW;
|
||
long PC;
|
||
};
|
||
struct context context =
|
||
|
||
{ /* Regs 0-13 cleared, sp set up below */
|
||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||
SYSSTKPTR, /* Loaded system's stack pointer */
|
||
0, /* Ignore: value is zero */
|
||
0xD800, /* FCW: segmented system, VI, NVI set */
|
||
SYSENTRY /* Entry point to system */
|
||
};
|
||
#endif
|
||
|
||
/************************************************************************/
|
||
/* Set Exception Vector entry */
|
||
/************************************************************************/
|
||
|
||
extern long trapvec[]; /* trap vector */
|
||
|
||
long setxvect(vnum, vval)
|
||
int vnum;
|
||
long vval;
|
||
{
|
||
register long oldval;
|
||
|
||
oldval = trapvec[vnum];
|
||
trapvec[vnum] = vval;
|
||
|
||
return(oldval);
|
||
|
||
}
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/* */
|
||
/* CHARACTER I/O */
|
||
/* */
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
/************************************************************************/
|
||
/* Generic Serial Port I/O Procedures */
|
||
/************************************************************************/
|
||
|
||
|
||
/* define as extern the dirty flag, which is actually defined later */
|
||
/* on in this file. Used to flush the buffer at an opportune moment. */
|
||
|
||
extern int tbdirty;
|
||
|
||
serinit(port)
|
||
int port;
|
||
{
|
||
output(port+SERCTRL, SERINIT);
|
||
output(port+SERCTRL, SERINIT);
|
||
output(port+SERCTRL, SERINIT);
|
||
|
||
output(port+SERCTRL, SERRES);
|
||
output(port+SERCTRL, SERMODE);
|
||
output(port+SERCTRL, SERCMD);
|
||
|
||
/* === worry about baud rate. assume the PROM sets it up. === */
|
||
}
|
||
|
||
|
||
int serirdy(port)
|
||
int port;
|
||
{
|
||
return(((input(port+SERSTAT) & SERRRDY) == SERRRDY) ? 0xFF : 0);
|
||
}
|
||
|
||
|
||
char serin(port)
|
||
int port;
|
||
{
|
||
while (serirdy(port) == 0) ;
|
||
return input(port+SERDATA);
|
||
}
|
||
|
||
|
||
int serordy(port)
|
||
int port;
|
||
{
|
||
return(((input(port+SERSTAT) & SERXRDY) == SERXRDY) ? 0xFF : 0);
|
||
}
|
||
|
||
|
||
serout(port, ch)
|
||
int port;
|
||
char ch;
|
||
{
|
||
while ( (input(port + SERSTAT) & SERXRDY) != SERXRDY) ;
|
||
output(port+SERDATA, ch);
|
||
}
|
||
|
||
|
||
/************************************************************************/
|
||
/* Olivetti keyboard translation table. */
|
||
/************************************************************************/
|
||
|
||
#ifndef LOADER
|
||
|
||
char kbtran[256] = {
|
||
|
||
/* Raw key codes for main keypad:
|
||
|
||
RE \ A B C D E F G H I J K L M N
|
||
O P Q R S T U V W X Y Z 0 1 2 3
|
||
4 5 6 7 8 9 - ^ @ [ ; : ] , . /
|
||
*/
|
||
|
||
/* main keyboard UNSHIFTED. */
|
||
|
||
0xDD,'\\', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||
'4', '5', '6', '7', '8', '9', '-', '^', '@', '[', ';', ':', ']', ',', '.', '/',
|
||
|
||
/* main keyboard SHIFTED */
|
||
|
||
0xDE, '|', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', '!', '"', '#',
|
||
'$', '%', '&','\'', '(', ')', '=', '~', '`', '{', '+', '*', '}', '<', '>', '?',
|
||
|
||
/* main keyboard CONTROL -- CTL B and C differ from Olivetti. */
|
||
|
||
0xA0,0x7F,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
|
||
0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0xE0,0xE1,0xE2,0xE3,
|
||
0xE4,0xE5,0xD6,0xE7,0xE8,0xE9,0xEA,0xEB,0x00,0x1B,0x1E,0x1F,0x1D,0xFE,0xFF,0xA4,
|
||
|
||
/* main keyboard COMMAND */
|
||
|
||
0xDF,0xF8,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,
|
||
0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xEC,0xED,0xEE,0xEF,
|
||
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0x13,0x1C,0xFC,0xFD,0x9F,0xF9,0xFA,0xA5,
|
||
|
||
/* other keys
|
||
|
||
SP CR S1 S2
|
||
KEYPAD . 0 00 1
|
||
2 3 4 5
|
||
6 7 8 9
|
||
+ - * /
|
||
*/
|
||
|
||
/* other keys UNSHIFTED -- CR differs from Olivetti */
|
||
|
||
' ','\r',0x7f,0x08,
|
||
'.', '0',0xA6, '1',
|
||
'2', '3', '4', '5',
|
||
'6', '7', '8', '9',
|
||
'+', '-', '*', '/',
|
||
|
||
/* other keys SHIFTED -- CR differs from Olivetti */
|
||
|
||
' ','\r',0xA8,0xA9,
|
||
'.', '0',0xA6,0x1C,
|
||
0x9A,0x1D,0x9B,0x9C,
|
||
0x9D,0x1E,0x9E,0x1F,
|
||
0x2B,0x2D,0x2A,0x2F,
|
||
|
||
/* other keys CONTROL */
|
||
|
||
' ','\r',0xA8,0xA9,
|
||
0xB0,0xB1,0xB2,0xB3,
|
||
0xB4,0xB5,0xB6,0x1B,
|
||
0xB8,0xB9,0xBA,0xBB,
|
||
0xBC,0xBD,0xBE,0xBF,
|
||
|
||
|
||
/* special -- substitute \r for Olivetti's 0xAF. */
|
||
|
||
'\r','\r','\r','\r'
|
||
};
|
||
|
||
#endif
|
||
|
||
/************************************************************************/
|
||
/* specific I/O procedures for use with iobyte */
|
||
/************************************************************************/
|
||
|
||
/* CRT status, read, write routines */
|
||
|
||
int crtrs()
|
||
{
|
||
return( serirdy(KBD));
|
||
}
|
||
|
||
#ifndef LOADER
|
||
|
||
char crtrd()
|
||
{
|
||
return( kbtran[serin(KBD) & 0xff]);
|
||
}
|
||
#endif
|
||
#ifdef LOADER
|
||
#define crtrd nulrd
|
||
#endif
|
||
|
||
int crtws()
|
||
{
|
||
return(0xFF);
|
||
}
|
||
|
||
#define crtwr crt_put /* output routine in PROM */
|
||
|
||
|
||
/* TTY status, read, write routines */
|
||
|
||
int ttyrs()
|
||
{
|
||
return(serirdy(RS232));
|
||
}
|
||
|
||
char ttyrd()
|
||
{
|
||
return(serin(RS232));
|
||
}
|
||
|
||
int ttyws()
|
||
{
|
||
return(serordy(RS232));
|
||
}
|
||
|
||
ttywr(ch)
|
||
char ch;
|
||
{
|
||
serout(RS232, ch);
|
||
}
|
||
|
||
/* LPT status, output routines */
|
||
|
||
int lptws()
|
||
{
|
||
}
|
||
|
||
lptwr(ch) /* ARGSUSED */
|
||
char ch;
|
||
{
|
||
}
|
||
|
||
/************************************************************************/
|
||
/* generic device names, batch, and null devices */
|
||
/************************************************************************/
|
||
|
||
/* the device names are the offset of the proper field in iobyte */
|
||
|
||
#define CON 0
|
||
#define READER 2
|
||
#define PUNCH 4
|
||
#define LIST 6
|
||
|
||
|
||
/* BATCH status, read, write routines */
|
||
|
||
#ifndef LOADER
|
||
int batrs()
|
||
{
|
||
int genstat();
|
||
|
||
return genstat(READER);
|
||
}
|
||
|
||
char batrd()
|
||
{
|
||
int genread();
|
||
|
||
return genread(READER);
|
||
}
|
||
|
||
batwr(ch)
|
||
char ch;
|
||
{
|
||
genwrite(LIST, ch);
|
||
}
|
||
|
||
#endif
|
||
#ifdef LOADER
|
||
#define batrd nulrd
|
||
#define batrs nulst
|
||
#define batwr nulwr
|
||
#endif
|
||
|
||
/* NULL status, read, write routines */
|
||
|
||
int nulst()
|
||
{
|
||
return 0xFF;
|
||
}
|
||
|
||
char nulrd()
|
||
{
|
||
return 0xFF;
|
||
}
|
||
|
||
nulwr(ch) /* ARGSUSED */
|
||
char ch;
|
||
{
|
||
}
|
||
|
||
/************************************************************************/
|
||
/* Generic I/O routines using iobyte */
|
||
/************************************************************************/
|
||
|
||
/*
|
||
** IObyte itself.
|
||
*/
|
||
|
||
char iobyte = 0x41;;
|
||
|
||
/*
|
||
** Device operation tables. DEVINDEX is the index into the
|
||
** table appropriate to a device (row) and its iobyte index (column)
|
||
**
|
||
** nonexistent devices are mapped into NUL.
|
||
*/
|
||
|
||
#define DEVINDEX (((iobyte>>dev) & 3) + (dev * 2) )
|
||
|
||
|
||
int (*sttbl[16])() = {
|
||
ttyrs, crtrs, batrs, nulst, /* con */
|
||
ttyrs, nulst, nulst, nulst, /* reader */
|
||
ttyws, nulst, nulst, nulst, /* punch */
|
||
ttyws, crtws, lptws, nulst /* list */
|
||
};
|
||
|
||
char (*rdtbl[16])() = {
|
||
ttyrd, crtrd, batrd, nulrd,
|
||
ttyrd, nulrd, nulrd, nulrd,
|
||
nulrd, nulrd, nulrd, nulrd,
|
||
nulrd, nulrd, nulrd, nulrd
|
||
};
|
||
|
||
int (*wrtbl[16])() = {
|
||
ttywr, crtwr, batwr, nulwr,
|
||
nulwr, nulwr, nulwr, nulwr,
|
||
ttywr, nulwr, nulwr, nulwr,
|
||
ttywr, crtwr, lptwr, nulwr
|
||
};
|
||
|
||
/*
|
||
** the generic service routines themselves
|
||
*/
|
||
|
||
int genstat(dev)
|
||
int dev;
|
||
{
|
||
return( (*sttbl[DEVINDEX])() );
|
||
}
|
||
|
||
int genread(dev)
|
||
int dev;
|
||
{
|
||
return( (*rdtbl[DEVINDEX])() );
|
||
}
|
||
|
||
genwrite(dev, ch)
|
||
int dev;
|
||
char ch;
|
||
{
|
||
(*wrtbl[DEVINDEX])(ch);
|
||
}
|
||
|
||
#ifndef LOADER
|
||
|
||
|
||
/************************************************************************/
|
||
/* Error procedure for BIOS */
|
||
/************************************************************************/
|
||
|
||
bioserr(errmsg)
|
||
register char *errmsg;
|
||
{
|
||
printstr("\n\rBIOS ERROR -- ");
|
||
printstr(errmsg);
|
||
printstr(".\n\r");
|
||
while(1);
|
||
}
|
||
|
||
printstr(s) /* used by bioserr */
|
||
register char *s;
|
||
{
|
||
while (*s) {crtwr(*s); s += 1; };
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/* */
|
||
/* DISK I/O */
|
||
/* */
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
|
||
/************************************************************************/
|
||
/* BIOS Table Definitions */
|
||
/************************************************************************/
|
||
|
||
struct dpb
|
||
{
|
||
int spt; /* sectors per track */
|
||
char bsh; /* block shift = log2(blocksize/128) */
|
||
char blm; /* block mask = 2**bsh - 1 */
|
||
char exm; /* extent mask */
|
||
char dpbjunk; /* dummy field to allign words */
|
||
int dsm; /* size of disk less offset, in blocks */
|
||
int drm; /* size of directory - 1 */
|
||
char al0; /* reservation bits for directory */
|
||
char al1; /* ... */
|
||
int cks; /* size of checksum vector = (drm+1)/4 */
|
||
int off; /* track offset for OS boot */
|
||
char psh; /* log2(sectorsize/128) */
|
||
char psm; /* physical size mask = 2**psh - 1 */
|
||
};
|
||
|
||
|
||
|
||
struct dph
|
||
{
|
||
char *xltp; /* -> sector translation table */
|
||
int dphscr[3]; /* scratchpad for BDOS */
|
||
char *dirbufp; /* -> directory buffer (128 bytes) */
|
||
struct dpb *dpbp; /* -> disk parameter block */
|
||
char *csvp; /* -> software check vector (cks bytes) */
|
||
char *alvp; /* -> alloc vector ((dsm/8)+1 bytes) */
|
||
};
|
||
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/* Disk Parameter Blocks */
|
||
/************************************************************************/
|
||
|
||
/*
|
||
** CP/M assumes that disks are made of 128-byte logical sectors.
|
||
**
|
||
** The Olivetti uses 256-byte sectors on its disks. This BIOS buffers
|
||
** a track at a time, so sector address translation is not needed.
|
||
**
|
||
** Sample tables are included for several different disk sizes.
|
||
*/
|
||
|
||
/* === Olivetti has 3 floppy formats & a hard disk === */
|
||
|
||
#define SECSZ 128 /* CP/M logical sector size */
|
||
#define TRKSZ 32 /* track size for floppies, 1/2 track sz for hd */
|
||
#define PSECSZ 256 /* Olivetti physical sector size */
|
||
#define PTRKSZ 16 /* physical track size */
|
||
#ifndef TRANSFER
|
||
#define MAXDSK 3 /* max. number of disks */
|
||
#endif
|
||
#ifdef TRANSFER
|
||
#define MAXDSK 4 /* Disk 4 is a pseudonym for disk 2, with */
|
||
#endif /* an old-style dpb to rescue those files. */
|
||
|
||
|
||
/***** spt, bsh, blm, exm, jnk, dsm, drm, al0, al1, cks, off, psh, psm */
|
||
|
||
struct dpb dpb0= /* --- 1 side, 16*256 sector, 35 track. 140kb --- */
|
||
{ 32, 4, 15, 1, 0, 64, 63, 0xC0, 0, 16, 3};
|
||
struct dpb dpb1= /* --- 2 side, 16*256 sector, 35 track. 280kb --- */
|
||
{ 32, 4, 15, 1, 0, 134, 63, 0xC0, 0, 16, 3};
|
||
struct dpb dpb2= /* --- 2 side, 16*256 sector, 80 track. 640kb --- */
|
||
{ 32, 4, 15, 0, 0, 314, 63, 0xC0, 0, 16, 3};
|
||
struct dpb dpb3= /* --- 6 side, 32*256 sector, 180 trk. 8640kb --- */
|
||
{ 64, 4, 15, 0, 0, 4308, 63, 0xC0, 0, 16, 3};
|
||
#ifdef TRANSFER
|
||
struct dpb dpb4= /* --- 2 side, 16*256 sector, 35 track. 280kb --- */
|
||
{ 32, 4, 15, 1, 0, 120, 63, 0xC0, 0, 16, 10};
|
||
#endif
|
||
|
||
/* bls = 2K dsm = (disk size - 3 reserved tracks) / bls */
|
||
|
||
#ifdef SECT26
|
||
|
||
/* === The Olivetti does not have 26-sector disks, but many people do.
|
||
** The following parameter blocks are provided for their use.
|
||
*/
|
||
|
||
struct dpb dpbS= /* --- 1 side, 26*128 sector, 72 trk --- */
|
||
{ 26, 3, 7, 0, 0, 242, 63, 0xC0, 0, 16, 2};
|
||
struct dpb dpbD= /* --- 1 side, 26*256 sector, 72 trk --- */
|
||
{ 52, 4, 15, 0, 0, 242, 63, 0xC0, 0, 16, 2};
|
||
|
||
#endif
|
||
|
||
/************************************************************************/
|
||
/* BDOS Scratchpad Areas */
|
||
/************************************************************************/
|
||
|
||
char dirbuf[SECSZ];
|
||
|
||
|
||
char csv0[16];
|
||
char csv1[16];
|
||
char csv2[16];
|
||
#ifdef TRANSFER
|
||
char csv3[16];
|
||
#endif
|
||
|
||
|
||
char alv0[32]; /* (dsm0 / 8) + 1 */
|
||
char alv1[32]; /* (dsm1 / 8) + 1 */
|
||
char alv2[2002]; /* (dsm2 / 8) + 1 */
|
||
#ifdef TRANSFER
|
||
char alv3[32];
|
||
#endif
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/* Sector Translate Table */
|
||
/************************************************************************/
|
||
|
||
|
||
|
||
#ifdef SECT26
|
||
|
||
/* === The Olivetti does not have 26-sector disks, but many people do.
|
||
** The following translate table is provided for their use.
|
||
*/
|
||
|
||
char xlt26[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 };
|
||
|
||
#endif
|
||
|
||
char xlt16[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,
|
||
17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};
|
||
|
||
|
||
/************************************************************************/
|
||
/* Disk Parameter Headers */
|
||
/* */
|
||
/* Three disks are defined: dsk a: diskno=0, drive 0 */
|
||
/* dsk b: diskno=1, drive 1 */
|
||
/* dsk c: diskno=2, drive 10 */
|
||
/************************************************************************/
|
||
|
||
#ifndef TRANSFER
|
||
struct dph dphtab[3] =
|
||
{ {xlt16, {0, 0, 0}, dirbuf, &dpb1, csv0, alv0}, /*dsk a*/
|
||
{xlt16, {0, 0, 0}, dirbuf, &dpb1, csv1, alv1}, /*dsk b*/
|
||
{(char *) 0L, {0, 0, 0}, dirbuf, &dpb2, csv2, alv2}, /*dsk c*/
|
||
};
|
||
#endif
|
||
|
||
#ifdef TRANSFER
|
||
struct dph dphtab[4] =
|
||
{ {xlt16, {0, 0, 0}, dirbuf, &dpb1, csv0, alv0}, /*dsk a*/
|
||
{xlt16, {0, 0, 0}, dirbuf, &dpb1, csv1, alv1}, /*dsk b*/
|
||
{(char *) 0L, {0, 0, 0}, dirbuf, &dpb2, csv2, alv2}, /*dsk c*/
|
||
{xlt16, {0, 0, 0}, dirbuf, &dpb4, csv3, alv3}, /*dsk d*/
|
||
};
|
||
#endif
|
||
|
||
/************************************************************************/
|
||
/* Currently Selected Disk Stuff */
|
||
/************************************************************************/
|
||
|
||
int settrk, setsec, setdsk; /* track, sector, disk # */
|
||
long setdma; /* dma address with segment info: long */
|
||
|
||
|
||
char trkbuf[TRKSZ * SECSZ]; /* track buffer */
|
||
int tbvalid = 0; /* track buffer valid */
|
||
int tbdirty = 0; /* track buffer dirty */
|
||
int tbtrk; /* track buffer track # */
|
||
int tbdsk; /* track buffer disk # */
|
||
int dskerr; /* disk error */
|
||
|
||
|
||
/************************************************************************/
|
||
/* Disk I/O Procedures */
|
||
/************************************************************************/
|
||
|
||
|
||
|
||
dskxfer(dsk, trk, bufp, cmd) /* transfer a disk track */
|
||
register int dsk, trk, cmd;
|
||
register char *bufp;
|
||
{
|
||
if (dsk==2) dsk = 10; /* convert hard disk drive # */
|
||
#ifdef TRANSFER
|
||
if(dsk==3) dsk = 1; /* for transfer disks */
|
||
#endif
|
||
dskerr=0; /* assume no error */
|
||
/* do transfer */
|
||
if (0 != disk_io(dsk, cmd, PTRKSZ, trk*PTRKSZ, map_adr((long)bufp,0)))
|
||
dskerr=1;
|
||
}
|
||
|
||
|
||
#define wrongtk ((! tbvalid) || (tbtrk != settrk) || (tbdsk != setdsk))
|
||
#define gettrk if (wrongtk) filltb()
|
||
|
||
#ifndef LOADER
|
||
|
||
flush()
|
||
{
|
||
|
||
if ( tbdirty && tbvalid ) dskxfer(tbdsk, tbtrk, trkbuf, DSKWRITE);
|
||
|
||
tbdirty = 0;
|
||
|
||
}
|
||
|
||
|
||
#endif
|
||
|
||
|
||
filltb()
|
||
{
|
||
|
||
#ifndef LOADER
|
||
if ( tbvalid && tbdirty ) flush();
|
||
#endif
|
||
dskxfer(setdsk, settrk, trkbuf, DSKREAD);
|
||
|
||
tbvalid = 1;
|
||
tbdirty = 0;
|
||
tbtrk = settrk;
|
||
tbdsk = setdsk;
|
||
|
||
}
|
||
|
||
|
||
dskread()
|
||
{
|
||
register char *p;
|
||
|
||
gettrk;
|
||
p = &trkbuf[SECSZ * (setsec-1)];
|
||
|
||
/* transfer between memory spaces. setdma is physical address */
|
||
|
||
mem_cpy(map_adr((long)p, CDATA), setdma, (long)SECSZ);
|
||
|
||
return(dskerr);
|
||
}
|
||
|
||
#ifndef LOADER
|
||
|
||
dskwrite(mode)
|
||
char mode;
|
||
{
|
||
register char *p;
|
||
|
||
gettrk;
|
||
p = &trkbuf[SECSZ * (setsec-1)];
|
||
|
||
/* transfer between memory spaces. setdma is physical address */
|
||
|
||
mem_cpy(setdma, map_adr((long) p, CDATA), (long)SECSZ);
|
||
tbdirty = 1;
|
||
if ( mode == 1 ) flush();
|
||
return(dskerr);
|
||
}
|
||
|
||
#endif
|
||
|
||
char sectran(s, xp)
|
||
int s;
|
||
char *xp;
|
||
{
|
||
if (xp != 0) return xp[s]; else return s;
|
||
}
|
||
|
||
|
||
struct dph *seldisk(dsk, logged)
|
||
register char dsk;
|
||
char logged;
|
||
{
|
||
register struct dph *dphp;
|
||
|
||
if (dsk > MAXDSK) return(0L);
|
||
setdsk = dsk;
|
||
dphp = &dphtab[dsk];
|
||
if (dphp >= dphtab + (sizeof(dphtab)/sizeof(struct dph)) ) return(0L);
|
||
if ( ! logged )
|
||
{
|
||
|
||
/* === disk not logged in. select density, etc. === */
|
||
|
||
}
|
||
return(dphp);
|
||
}
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/* */
|
||
/* BIOS PROPER */
|
||
/* */
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
|
||
|
||
|
||
biosinit()
|
||
{
|
||
#ifdef DEBUG
|
||
printstr("\r\nP-CP/M: Olivetti M20 BIOS.");
|
||
#endif
|
||
/* serinit(KBD);*/ /* DON'T init keyboard serial port */
|
||
serinit(RS232); /* init rs232 serial port */
|
||
|
||
tbvalid = 0; /* init disk flags */
|
||
tbdirty = 0;
|
||
|
||
/* Following reset of iobyte on each warm boot has been */
|
||
/* removed, so that STAT can reassign devices. iobyte */
|
||
/* is now initialized on cold boot only. */
|
||
/* iobyte = 0x41; */ /* con, list = CRT; rdr, punch = TTY */
|
||
}
|
||
|
||
/* In the LOADER bios, the main routine is called "bios", not "_bios" */
|
||
#ifdef LOADER
|
||
#define _bios bios
|
||
#endif
|
||
|
||
long _bios(d0, d1, d2)
|
||
int d0;
|
||
long d1, d2;
|
||
{
|
||
|
||
switch(d0)
|
||
{
|
||
case 0: /* INIT */
|
||
biosinit();
|
||
break;
|
||
|
||
#ifndef LOADER
|
||
case 1: /* WBOOT */
|
||
wboot();
|
||
break;
|
||
|
||
#endif
|
||
|
||
case 2: /* CONST */
|
||
return(genstat(CON));
|
||
break;
|
||
|
||
case 3: /* CONIN */
|
||
return(genread(CON));
|
||
break;
|
||
|
||
case 4: /* CONOUT */
|
||
genwrite(CON, (char)d1);
|
||
break;
|
||
|
||
#ifndef LOADER
|
||
|
||
case 5: /* LIST */
|
||
genwrite(LIST, (char)d1);
|
||
break;
|
||
|
||
case 6: /* PUNCH */
|
||
genwrite(PUNCH, (char)d1);
|
||
break;
|
||
|
||
case 7: /* READER */
|
||
return(genread(READER));
|
||
break;
|
||
|
||
case 8: /* HOME */
|
||
settrk = 0;
|
||
break;
|
||
|
||
#endif
|
||
|
||
case 9: /* SELDSK */
|
||
return((long)seldisk((char)d1, (char)d2));
|
||
break;
|
||
|
||
case 10: /* SETTRK */
|
||
settrk = (int)d1;
|
||
break;
|
||
|
||
case 11: /* SETSEC */
|
||
setsec = (int)d1;
|
||
break;
|
||
|
||
case 12: /* SETDMA */
|
||
setdma = d1;
|
||
break;
|
||
|
||
case 13: /* READ */
|
||
return(dskread());
|
||
break;
|
||
|
||
#ifndef LOADER
|
||
case 14: /* WRITE */
|
||
return(dskwrite((char)d1));
|
||
break;
|
||
|
||
case 15: /* LISTST */
|
||
return(genstat(LIST));
|
||
break;
|
||
|
||
#endif
|
||
|
||
case 16: /* SECTRAN */
|
||
return(sectran((int)d1, (char*)d2));
|
||
break;
|
||
|
||
case 18: /* GMRTA */
|
||
return((long)&memtab);
|
||
break;
|
||
|
||
#ifndef LOADER
|
||
case 19: /* GETIOB */
|
||
return((long)iobyte);
|
||
break;
|
||
|
||
case 20: /* SETIOB */
|
||
iobyte = (char)d1;
|
||
break;
|
||
|
||
case 21: /* FLUSH */
|
||
flush();
|
||
return((long)dskerr);
|
||
break;
|
||
|
||
#endif
|
||
|
||
case 22: /* SETXVECT */
|
||
return(setxvect((int)d1, d2));
|
||
break;
|
||
|
||
|
||
|
||
} /* end switch */
|
||
|
||
return(0);
|
||
|
||
|
||
} /* end bios procedure */
|
||
|
||
|
||
|
||
/* End of C Bios */
|