/* *************************************************************************** This is the Master/requestor portion of a Dual processor P-CP/M BIOS. It should be designed such that only the low level inter-processor transfer protocols and BIOS primitives should have to be modified to accomplish porting to different hardware configurations. Error checking and report- ing is necessary because I/O channel may be unplugged or unreliable. *************************************************************************** */ /* ************************************************* * * * Author: David Heintz * * Module: Biosmasc.c * * Creation Date: 10/20/82 * * Language: Standard C * * Version: 1.0 * * Last Mod: 01/20/83 * * * ************************************************* */ /* ************************************************* * * * STANDARD HEADERS * * * ************************************************* */ #include "unstdsys.h" #include "stdcpm.h" #include "stdbios.h" #include "chnequ.h" /* ************************************************* * * * EXTERNAL DECLARATIONS * * * ************************************************* */ /* extern wboot(); ************************************************* * * * BIOS Entry Point declaration * * * ************************************************* */ extern LONG _bios(); /* ************************************************* * * * Other Globals * * * ************************************************* */ extern biosinit(); /* Initialize system */ extern flush(); /* Flush buffer */ /* ************************************************* * * * I/O Channel Related Externals * * * ************************************************* */ extern BYTE rcv_cmd(); extern BYTE rcv_byte(); extern BYTE rcv_word(); extern BYTE rcv_long(); extern BYTE rcv_data(); extern BYTE snd_cmd(); extern BYTE snd_byte(); extern BYTE snd_word(); extern BYTE snd_long(); extern BYTE snd_data(); extern chn_err(); /* ************************************************* * * * Machine and Processor Dependent * * Externals * * * ************************************************* */ extern *memtab; extern LONG trapvec[]; extern mem_cpy(); extern LONG map_adr(); /* ************************************************* * * * LOCAL DEFINITIONS * * * ************************************************* */ static char signon[] = "\n\rKontron Z8000 BIOS v. 1.0 11/23/82\n\r"; /* ************************************************* * * * Check Vectors * * 512 Directory Entries Maximum * * * ************************************************* */ BYTE csvtab[8][128] = {{0}}; /* ************************************************* * * * Allocation Vectors * * 2048 Allocation Blocks Maximum * * * ************************************************* */ BYTE alvtab[8][256] = {{0}}; /* ************************************************* * * * Data Parameter Blocks * * Unitialized * * * ************************************************* */ DPB dpbtab[8] = {0}; /* ************************************************* * * * Directory Buffer * * * ************************************************* */ BYTE dirbuf[128] = {0}; /* ************************************************* * * * Disk Parameter Headers * * Maximum of 8 defined * * * ************************************************* */ DPH dphtab[8] = /* { *xltp, dphscr[3], *dirbufp, *dpbp, *csvp, *alvp} */ { {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[0], csvtab[0], alvtab[0]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[1], csvtab[1], alvtab[1]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[2], csvtab[2], alvtab[2]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[3], csvtab[3], alvtab[3]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[4], csvtab[4], alvtab[4]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[5], csvtab[5], alvtab[5]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[6], csvtab[6], alvtab[6]}, {(BYTE *) 0L, {0,0,0}, &dirbuf[0], &dpbtab[7], csvtab[7], alvtab[7]}, }; /* ************************************************* * * * Time-Honored BIOS Variables * * * ************************************************* */ static LONG dmaadr = 0; /* Caller's data transfer address */ static WORD sector = 0; /* Current sector (Unused) */ static WORD track = 0; /* Current track (Unused) */ static BYTE disk = 0; /* Current drive number (Unused) */ static BYTE IOBYTE = 0; /* Logical to physical mapping (Unused) */ static BYTE retry = 0xff; /* I/O channel retry boolean */ /* ************************************************* * * * Sector Buffer * * * ************************************************* */ static BYTE secbuf[seclen] = {0}; /* ************************************************* * * * MISCELLANEOUS FUNCTIONS * * * ************************************************* */ /* /-------------------------------- / | / Print a Message | / | /-------------------------------- / Inputs: Pointer to message / terminated by '\0' / Outputs: None / Actions: Send message to slave / console output. / */ prtmsg(pbyte) BYTE *pbyte; { char c; while(c = *(pbyte++)) _bios((WORD)coreq, (LONG)c, 0L); } /* /-------------------------------- / | / Illegal Command | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Currently unused / */ ill_cmd() { } /* /-------------------------------- / | / biosinit(); | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Initialize hardware / */ biosinit() { prtmsg(signon); _bios((WORD)inreq, 0L, 0L); /* Make BIOS request */ } /* /-------------------------------- / | / Flush Disk Buffer | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Flush Disk Buffer on Slave / */ flush() { _bios((WORD)fbreq, 0L, 0L); /* Ignore return code? */ } /* /-------------------------------- / | / snd_rcv(): | / send a command and | / receive a parameter | / | /-------------------------------- / Inputs: BIOS parameters d0, d1, d2 / Outputs: LONG return parameter / Actions: Send command through fifo and / receive return parameter / */ LONG snd_rcv(d0, d1, d2) WORD d0; LONG d1, d2; { BYTE code; LONG temp; do { code = snd_cmd(d0, d1, d2); if (code == chsuc) code = rcv_long(&temp); if (code != chsuc) { chn_err(d0, code); temp = cherr; } } while (retry && (code != chsuc)); return(temp); } /* ************************************************* * * * P-CP/M BIOS ENTRY POINT * * * ************************************************* */ LONG _bios(d0, d1, d2) WORD d0; LONG d1, d2; { char zzz = {"kludge "}; switch(d0) { /* /-------------------------------- / | / Function 4: | / Console Output | / | /-------------------------------- / Inputs: (BYTE) d1 contains character / to output to slave console / Outputs: None / Actions: Output character from master / to slave console I/O. */ case coreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 5: | / List Output | / | /-------------------------------- / Inputs: (BYTE) d1 contains character / to output to slave list device. / Outpus: None / Actions: Output character from master / to slave list I/O. */ case loreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 6: | / Auxilliary Output | / | /-------------------------------- / Inputs: (BYTE) d1 contains character / to output to slave aux. device. / Outputs: None / Actions: Output character from master / to slave auxilliary (punch) I/O. */ case aoreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 8: | / Home disk | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Perform slave home disk function. */ case hdreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 10: | / Set Track | / | /-------------------------------- / Inputs: (WORD) d1 contains track number. / Outputs: None / Actions: Set track number from master on slave. */ case streq: /* Fall through to next case */ /* /-------------------------------- / | / Function 11: | / Set Sector | / | /-------------------------------- / Inputs: (WORD) d1 contains sector number / Outputs: None / Actions: Set sector number from master on slave. */ case ssreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 20: | / Set I/O byte | / | /-------------------------------- / Inputs: BYTE d1 contains IOBYTE value / Outputs: None / Actions: Send contents of slave / location IOBYTE to master. */ case sireq: /* Fall through to next case */ /* All degenerate cases of BIOS functions */ /* end up falling through to here. Request */ /* is forwarded to the slave BIOS and no */ /* parameters are returned to the master. */ { BYTE code; code = snd_cmd(d0, d1, d2); if (code != chsuc) chn_err(d0, code); } break; /* Request completed. */ /* /-------------------------------- / | / Function 2: | / Console Status | / | /-------------------------------- / Inputs: None / Outputs: returns console status. / Actions: receive 1-byte slave con- / sole status. */ case csreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 7: | / Auxilliary Input | / | /-------------------------------- / Inputs: None / Outputs: Return character from aux device / Actions: Input a character from slave / auxilliary (reader) I/O to master. */ case aireq: /* Fall through to next case */ /* /-------------------------------- / | / Function 15: | / List Status | / | /-------------------------------- / Inputs: None / Outputs: Return status of slave list device. / Actions: Send 1-byte slave list / status to master. */ case lsreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 16: | / Translate Sector | / | /-------------------------------- / Inputs: (LONG) d1 is sector translation table address / (WORD) d2 is sector number to be translated / Outputs: Return translated sector. / Actions: Perform slave BIOS sector / translation call */ case tsreq: /* Fall through to next case */ /* /-------------------------------- / | / Function 19: | / Get I/O byte | / | /-------------------------------- / Inputs: None / Outputs: Returns IOBYTE value from slave. / Actions: Receive byte from master and / store in slave location IOBYTE. */ case gireq: /* Fall through to next case */ /* /-------------------------------- / | / Function 21: | / Flush disk buffer | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Send request to slave / */ case fbreq: /* Fall through to next case */ /* All cases which return status or data */ /* end up falling through to here. Request */ /* passed on to the slave BIOS and a long */ /* parameter is returned to the master. */ return(snd_rcv(d0, d1, d2)); /* /-------------------------------- / | / Function 0: | / System Init | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Initialize Master. / Just print message, so far. */ case inreq: break; /* /-------------------------------- / | / Function 1: | / Warm Boot | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Warm boot master. */ case wbreq: wboot(); break; /* /-------------------------------- / | / Function 3: | / Console Input | / | /-------------------------------- / Inputs: None / Outputs: returns console character. / Actions: Input character from / slave console to master. */ case cireq: while(!_bios(csreq, 0L, 0L)); return(snd_rcv(d0, d1, d2)); /* /-------------------------------- / | / Function 9: | / Select Disk | / | /-------------------------------- / Inputs: None / Outputs: Pointer to DPH for selected drive. / Null if illegal drive. / Actions: Select drive number from master on slave. / Return condition code from slave to master. / Pass selected drive's DPB from slave to master, / if drive selected. */ case sdreq: { BYTE code; LONG temp; DPH *dphptr; DPB *dpbptr; do { code = snd_cmd(d0, d1, d2); if (code == chsuc) code = rcv_long(&temp); if (code == chsuc) if ((DPH *)temp != NULL) { dphptr = &dphtab[d1]; dpbptr = dphptr -> dpbp; if (!((BYTE)d2 & 0x1)) { code = rcv_long(&temp); if (code == chsuc) (dphptr -> xltp) = (BYTE *)temp; if (code == chsuc) code = rcv_word(&(dpbptr -> spt)); if (code == chsuc) code = rcv_byte(&(dpbptr -> bsh)); if (code == chsuc) code = rcv_byte(&(dpbptr -> blm)); if (code == chsuc) code = rcv_byte(&(dpbptr -> exm)); if (code == chsuc) code = rcv_word(&(dpbptr -> dsm)); if (code == chsuc) code = rcv_word(&(dpbptr -> drm)); if (code == chsuc) code = rcv_byte(&(dpbptr -> al0)); if (code == chsuc) code = rcv_byte(&(dpbptr -> al1)); if (code == chsuc) code = rcv_word(&(dpbptr -> cks)); if (code == chsuc) code = rcv_word(&(dpbptr -> off)); } temp = (LONG)dphptr; } else temp = (LONG)NULL; if (code != chsuc) { chn_err(sdreq, code); temp = (LONG)cherr; } } while (retry && (code != chsuc)); return(temp); } /* /-------------------------------- / | / Function 13: | / Read Sector | / | /-------------------------------- / Inputs: None / Outputs: Read completion status / Actions: Receive a 128 byte sector specified by / current drive, sector, track from slave / and place it at the current DMA add- / ress. */ case rsreq: { BYTE stat, code; LONG temp; do { code = snd_cmd(d0, d1, d2); if (code == chsuc) code = rcv_byte(&stat); if ((stat == rssuc) && (code == chsuc)) code = rcv_data(&secbuf[0], seclen); if (code == chsuc) temp = (LONG)stat; else { chn_err(d0, code); temp = cherr; } } while (retry && (code != chsuc)); if (temp == rssuc) mem_cpy(map_adr((LONG)secbuf, 0),(LONG)dmaadr,(LONG)seclen); return(temp); } /* /-------------------------------- / | / Function 14: | / Write Sector | / | /-------------------------------- / Inputs: Write type. / Outputs: Write sector completion status. / Actions: Send a 128 byte sector from current DMA / address to slave. / Receive a 1-byte completion code, in- / dicating if write successful or not. */ case wsreq: { BYTE stat, code; LONG temp; do { mem_cpy((LONG)dmaadr,map_adr((LONG)secbuf,0),(LONG)seclen); code = snd_cmd(d0, d1, d2); if (code == chsuc) code = snd_data(&secbuf[0], seclen); if (code == chsuc) code = rcv_byte(&stat); if (code == chsuc) temp = (LONG)stat; else { chn_err(d0, code); temp = cherr; } } while (retry && (code != chsuc)); return(temp); } /* /-------------------------------- / | / Function 12: | / Set DMA Address | / | /-------------------------------- / Inputs: (LONG) d1 contains DMA address. / Outputs: None / Actions: Set DMA address from master. */ case sareq: dmaadr = d1; break; /* /-------------------------------- / | / Function 17: | / Get Memory Table | / | /-------------------------------- / Inputs: None / Outputs: Return pointer to memory region table / Actions: None */ case gmreq: return((long)&memtab); /* /-------------------------------- / | / Function 22: | / Set Exception Vector | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Currently unused / */ case svreq: { LONG oldval; oldval = trapvec[(int)d1]; trapvec[(int)d1] = d2; return(oldval); } /* /-------------------------------- / | / Illegal Request | / | /-------------------------------- / Inputs: None / Outputs: None / Actions: Currently unused / */ default: ill_cmd(); /* Illegal command */ break; } /* End of Switch */ } /* End of BIOS */