************************************************************************* * * * MORROW DESIGNS CBIOS FOR CP/M VERSION 2.2. * * * * THIS CBIOS CAN BE CONFIGURED TO RUN WITH THE FOLLOWING DEVICES. * * THE DISKS MAY BE CONFIGURED TO RUN WITH ANY OR ALL OF THE DISK * * SYSTEMS. THE LOGICAL ORDER OF THE DISKS CAN BE SET TO ANY ORDER. * * * * DISK SYSTEMS: * * DJ 2D/B FLOPPY DISK CONTROLLER WITH 8 INCH DISKS. * * * * CONSOLE I/O: * * NORTH STAR MOTHERBOARD * * * * PRINTER I/O: * * NORTH STAR MOTHERBOARD * * * * NOTE: FLOPPY SYSTEMS DISKETTE (DRIVE A:) HAS TO HAVE 1024 BYTE * * SECTORS IN ORDER FOR THE COLD AND WARM BOOT LOADERS TO * * WORK. BE SURE TO FORMAT ALL NEW SYSTEM DISKETTES WITH * * 1024 BYTE SECTORS. THE SYSTEM DISKETTE CAN BE EITHER * * SINGLE OR DOUBLE SIDED. THE SECTOR SIZE ON NORMAL (NON * * A: DRIVE) DISKETTES IS NOT RESTRICTED. THUS IF YOU HAVE * * A DISKETTE WITH SOFTWARE THAT IS SUPPOSED TO RUN ON THE * * A: DRIVE THEN YOU SHOULD MOUNT THE DISKETTE IN THE B: * * DRIVE AND THEN PIP IT OVER TO A 1024 BYTE SECTOR * * SYSTEM DISKETTE. * * * * WRITTEN BY LES KENT AND MARC KUPPER 3/4/82 * * * * DATE PROGRAMMER DESCRIPTION * * * **11 20 82 MARC PUBLIC RELEASE OF REVISION E.31 * * * ************************************************************************* TITLE 'CBIOS REVISION E FOR CP/M VERSION 2.2 - MARCH 4, 1982' REVNUM EQU 53 ;CBIOS REVISION NUMBER 5.X = E CPMREV EQU 22 ;CP/M REVISION NUMBER 2.2 ************************************************************************* * * * THE FOLLOWING FLAG SETS AN ASSEMBLY TIME DEBUGGER. * * * * THE DEBUG FLAG MERELY CAUSES VARIOUS INTERNAL VALUES AND * * ADDRESSES TO BE PRINTED DURING THE ASSEMBLY PROCESS. THIS * * PRINTING IS FORCED VIA ASSEMBLY ERRORS AND THUS SHOULD NOT * * AFFECT THE RESULTING CODE IN ANY WAY. * * * ************************************************************************* DEBUG EQU 0 ;SET TO 1 FOR DEBUGGING MODE ************************************************************************* * * * THE FOLLOWING IS SET TO THE MEMORY SIZE OF THE CP/M THE CBIOS IS * * BEING CREATED FOR. * * * ************************************************************************* MSIZE EQU 56 ;MEMORY SIZE OF TARGET CP/M BIOSLN EQU 10H ;BIOS LENGTH. ALSO IN ABOOT&.ASM ************************************************************************* * * * THE FOLLOWING EQUATES SET UP THE DISK SYSTEMS TO BE INCLUDED * * ALONG WITH THE TYPES OF DRIVES AND THE LOGICAL ORDER OF THE * * DRIVES. * * * ************************************************************************* MAXFD EQU 2 ;SET TO NUMBER OF 2D/B FLOPPIES FDORDER EQU 1 ;SET THE ORDER OF LOGICAL DRIVES ELSE 0 IF ; NOT INCLUDED. WMDRIVE EQU 0 ;DEVICE TO WARM BOOT FROM. THIS IS THE ; CP/M LOGICAL DRIVE NUMBER. BADSIZ EQU 1 ;LEAVE ONE ENTRY AS FILLER ************************************************************************* * * * THE FOLLOWING EQUATES ARE INTERNAL TO THE CBIOS. * * * ************************************************************************* MWSPT EQU 9 ;SECTORS PER TRACK MAXLOG EQU MAXFD ************************************************************************* * * * CP/M SYSTEM EQUATES. * * * ************************************************************************* CCPLN EQU 800H BDOSLN EQU 0E00H SIZE EQU (MSIZE*1024) CCP EQU SIZE-(BIOSLN*100H+CCPLN+BDOSLN) BDOS EQU CCP+CCPLN BIOS EQU CCP+CCPLN+BDOSLN OFFSETC EQU 2100H-BIOS ;OFFSET FOR SYSGEN IF DEBUG DBGTMP SET OFFSETC ;DDT OFFSET ! DBGTMP SET CCP ;CCP ADDRESS ! DBGTMP SET BDOS ;BDOS ADDRESS ! DBGTMP SET BIOS ;CBIOS ADDRESS ! ENDIF CDISK EQU 4 ;ADDRESS OF LAST LOGGED DISK BUFF EQU 80H ;DEFAULT BUFFER ADDRESS TPA EQU 100H ;TRANSIENT MEMORY IOBYTE EQU 3 ;IOBYTE LOCATION WBOT EQU 0 ;WARM BOOT JUMP ADDRESS ENTRY EQU 5 ;BDOS ENTRY JUMP ADDRESS ************************************************************************* * * * THE FOLLOWING ARE INTERNAL CBIOS EQUATES. MOST ARE MISC. CONSTANTS. * * * ************************************************************************* RETRIES EQU 10 ;MAX RETRIES ON DISK I/O BEFORE ERROR CLEAR EQU 'Z'-64 ;CLEAR SCREEN ON AN ADM 3 ANUL EQU 0 ;NULL AETX EQU 'C'-64 ;ETX CHARACTER AACK EQU 'F'-64 ;ACK CHARACTER ABEL EQU 'G'-64 ;BELL ABS EQU 'H'-64 ;BACK SPACE AHT EQU 'I'-64 ;HORIZONTAL TAB ALF EQU 'J'-64 ;LINE FEED AVT EQU 'K'-64 ;VERTICAL TAB AFF EQU 'L'-64 ;FORM FEED ACR EQU 'M'-64 ;CARRIAGE RETURN XON EQU 'Q'-64 ;XON CHARACTER XOFF EQU 'S'-64 ;XOFF CHARACTER AESC EQU 1BH ;ESCAPE CHARACTER ARS EQU 1EH ;RS CHARACTER AUS EQU 1FH ;US CHARACTER ASP EQU ' ' ;SPACE ADEL EQU 7FH ;DELETE ************************************************************************* * * * THE FOLLOWING ARE THE MACROS USED IN GENERATING THE DPH, DPB AND * * ALLOCATION TABLES. * * * ************************************************************************* DPBGEN MACRO NAM,LOG,DSPT,DBSH,DBLM,DEXM,DDSM,DDRM,DAL0,DAL1,DCKS,DOFF,SSIZ DPB&NAM&LOG EQU $ DW DSPT DB DBSH DB DBLM DB DEXM DW DDSM DW DDRM DB DAL0 DB DAL1 DW DCKS DW DOFF DB SSIZ ENDM DPHGEN MACRO NAM,LOG,DPB1,DPB2 DPH&NAM&LOG EQU $ DW 0 DW 0,0,0 DW DIRBUF DW &DPB1&DPB2 DW CSV&NAM&LOG DW ALV&NAM&LOG ENDM ALLOC MACRO NAM,LOG,AL,CS CSV&NAM&LOG: DS CS ALV&NAM&LOG: DS AL ENDM ************************************************************************* * * * THE FOLLOWING MACRO IS USED IN GENERATING THE LOGICAL ORDER OF THE * * CP/M DRIVES. * * * ************************************************************************* ORDER MACRO NUM IF NUM EQ FDORDER DW FDDST ENDIF ENDM ************************************************************************* * * * THE FOLLOWING ARE OFFSET NUMBERS OF DEVICE SPECIFICATION TABLES. * * * ************************************************************************* D$WBOOT EQU 0 ;WARM BOOT D$STRAN EQU 1 ;SECTOR TRANSLATION D$SEL1 EQU 2 ;DRIVE SELECT, RETURN DPH D$SEL2 EQU 3 ;DRIVE SELECT D$HOME EQU 4 ;HOME DRIVE D$STRK EQU 5 ;SET TRACK D$SSEC EQU 6 ;SET SECTOR D$SDMA EQU 7 ;SET DMA ADDRESS D$READ EQU 8 ;READ A PHYSICAL SECTOR D$WRITE EQU 9 ;WRITE A PHYSICAL SECTOR D$BAD EQU 10 ;RETURN POINTER TO BAD SECTOR INFO ************************************************************************* * * * THE JUMP TABLE BELOW MUST REMAIN IN THE SAME ORDER, THE ROUTINES * * MAY BE CHANGED, BUT THE FUNCTION EXECUTED MUST BE THE SAME. * * * ************************************************************************* ORG BIOS ;CBIOS STARTING ADDRESS JMP CBOOT ;COLD BOOT ENTRY POINT WBOOTE: JMP WBOOT ;WARM BOOT ENTRY POINT CONST: JMP CONIST ;CONSOLE STATUS ROUTINE CIN: JMP CONIN ;CONSOLE INPUT COUT: JMP COSTRP ;CONSOLE OUTPUT POUT: JMP LSTOUT ;LIST DEVICE OUTPUT JMP PUNOUT ;PUNCH DEVICE OUTPUT JMP RDRIN ;READER DEVICE INPUT JMP HOME ;HOME DRIVE JMP SETDRV ;SELECT DISK JMP SETTRK ;SET TRACK JMP SETSEC ;SET SECTOR JMP SETDMA ;SET DMA ADDRESS JMP READ ;READ THE DISK JMP WRITE ;WRITE THE DISK JMP LSTOST ;LIST DEVICE STATUS JMP SECTRAN ;SECTOR TRANSLATION ; ; THE FOLLOWING JUMPS ARE EXTENDED BIOS CALLS DEFINED BY MORROW DESIGNS ; JMP FDSEL ;HOOKUP FOR SINGLE.COM PROGRAM JMP 0 ;END OF THE JUMP TABLE ************************************************************************* * * * DRIVE CONFIGURATION TABLE. * * * ************************************************************************* DRCONF: DB 0 ;REVISION 0 STRUCTURE DB 32 ;32 BYTES LONG NOW ************************************************************************* * * * THE FOLLOWING IS THE TABLE OF POINTERS TO THE DEVICE * * SPECIFICATION TABLES. THE ORDER OF THIS TABLE DEFINES THE * * LOGICAL ORDER OF THE CP/M DRIVES. * * * ************************************************************************* DSTTAB: EQU $ DN SET 1 REPT 16 ORDER %DN DN SET DN+1 ENDM ************************************************************************* * * * THIS ROUTINE IS AN EXPERIMENT TO REDUCE MISSED AND GARBLED * * CHARACTERS ON CONSOLE OUTPUT. * * * ************************************************************************* COSTRP: MOV A,C ;STRIP PARITY ON CONOUT ANI 7FH MOV C,A JMP CONOUT ***************************************************************** * * * THE FOLLOWING BYTE DETERMINES IF AN INITIAL COMMAND IS TO BE * * GIVEN TO CP/M ON WARM OR COLD BOOTS. THE VALUE OF THE BYTE IS * * USED TO GIVE THE COMMAND TO CP/M: * * * * 0 = NEVER GIVE COMMAND. * * 1 = GIVE COMMAND ON COLD BOOTS ONLY. * * 2 = GIVE THE COMMAND ON WARM BOOTS ONLY. * * 3 = GIVE THE COMMAND ON WARM AND COLD BOOTS. * * * ***************************************************************** AUTOST: DB 0 ;REVISION 0 STRUCTURE DB 100H - (LOW $) ;THE REST OF THE PAGE IS USED FOR THIS STUFF AUTOFLG:DB 0 ;AUTO COMMAND FEATURE ENABLE FLAG COLDMES:DW COLDCM ;POINTER TO THE COLD START COMMAND WARMES: DW WARMCM ;POINTER TO THE WARM START COMMAND ***************************************************************** * * * IF THERE IS A COMMAND INSERTED HERE, IT WILL BE PASSED TO THE * * CCP IF THE AUTO FEATURE IS ENABLED. FOR EXAMPLE: * * * * COLDCM: DB COLDEND-COLDCM * * DB 'MBASIC MYPROG' * * COLDEND EQU $ * * * * WILL EXECUTE MICROSOFT BASIC, AND MBASIC WILL EXECUTE THE * * "MYPROG" BASIC PROGRAM. NOTE: THE COMMAND LINE MUST BE IN * * UPPER CASE FOR MOST COMMANDS. * * * ***************************************************************** COLDCM: DB COLDEND-COLDCM ;LENGTH OF COLD BOOT COMMAND DB '' ;COLD BOOT COMMAND GOES HERE COLDEND EQU $ WARMCM: DB WARMEND-WARMCM ;LENGTH OF WARM BOOT COMMAND DB '' ;WARM BOOT COMMAND GOES HERE WARMEND EQU $ ************************************************************************* * * * AT THE FIRST PAGE BOUNDRY FOLLOWING THE CBIOS WE HAVE A SERIES OF * * POINTERS THAT POINT TO VARIOUS INTERNAL TABLES. AT THE START OF * * EACH OF THESE TABLES WE HAVE A REVISION BYTE AND A LENGTH BYTE. * * THE REVISION BYTE IS THE CURRENT REVISION NUMBER FOR THAT * * PARTICULAR STRUCTURE AND THE LENGTH BYTE IS THE LENGTH OF THAT * * STRUCTURE. THIS LENGTH DOES NOT INCLUDE THE REVISION BYTE NOR * * THE LENGTH BYTE ITSELF. * * * * REVISION DESCRIPTION * * E.0 1 AND 2 DEFINED * * E.3 THIS TABLE IS MOVED TO A PAGE BOUNDRY * * E.3 0, 3 AND 4 DEFINED * * * * THE POINTERS DEFINED SO FAR ARE AS FOLLOWS: * * * * 0) HIGH BYTE IS THE PAGE NUMBER OF THE CBIOS. LOW BYTE IS * * THE CBIOS REVISION NUMBER. USED TO DETERMINE POINTER * * STRUCTURE. * * * * 1) THIS POINTS TO THE DRIVE CONFIGURATION TABLE. * * * * 2) THIS POINTS TO THE I/O CONFIGURATION BYTES FOR THE SERIAL * * DRIVERS. EG, THE CONSOLE, PRINTER, READER, AND PUNCH * * DEVICES. * * * * 3) THIS POINTS TO THE DRIVE PARAMETER TABLE FOR DJDMA FLOPPY * * DISK DRIVES. IF NO DJDMA IS PRESENT THEN THIS POINTER IS * * NULL (0). * * * * 4) THIS POINTS TO THE AUTOSTART COMMAND STRUCTURES. USED TO * * AUTOMATICALLY INVOKE A COMMAND ON COLD OR WARM BOOT * * * * 5) THIS WILL BE A NULL (0) POINTER. IT MARKS THE END OF THE * * TABLE. * * * ************************************************************************* IF $ GT BIOS+256 ;TEST FOR CODE OVERLAP 'FATAL ERROR, POINTER TABLE PLACEMENT.' ELSE DS BIOS+256-$ ;START AT A PAGE BOUNDRY ENDIF DB HIGH ($-1) ;CBIOS PAGE NUMBER DB REVNUM ;CBIOS REVISION NUMBER DW DRCONF ;DRIVE CONFIGURATION TABLE POINTER DW 0 DW AUTOST ;AUTO COMMAND STRUCTURE POINTER DW 0 ;END OF TABLE MARKER ************************************************************************* * * * THE FOLLOWING CODE PERFORMS THE MAPPING OF LOGICAL TO PHYSICAL * * SERIAL I/O DEVICES. THE PHYSICAL ENTRY POINTS ARE CONIN, CONOUT, * * CONIST, RDRIN, PUNOUT, LSTOUT, AND LSTOST. THESE ENTRY POINTS * * ARE MAPPED VIA THE INTEL STANDARD I/O BYTE (IOBYTE) AT LOCATION 3 * * IN THE BASE PAGE TO THE LOW LEVEL DEVICE DRIVERS. * * * * NOTE: A NAMING CONVENTION HAS BEEN CHOSEN TO REDUCE LABEL * * COLISIONS. THE FIRST THREE CHARACTERS OF A NAME INDICATE THE * * DEVICE DRIVERS NAME, THE FOLLOWING THREE CHARACTERS INDICATED THE * * FUNCTION PERFORMED BY THAT PARTICULAR DEVICE ROUTINE. THE DEVICE * * NAMES ARE DEFINED AND DESCRIBED IN THE "AN INTRODUCTION TO CP/M * * FEATURES AND FACILITIES" MANUAL IN THE SECTION ON THE STAT * * COMMAND AND IN THE "CP/M INTERFACE GUIDE" IN THE IOBYTE SECTION. * * THE DEVICE FUNCTION POSTFIXES ARE AS FOLLOWS. * * * * DEVSET INITIAL DEVICE SETUP AND INITIALZATION * * DEVIN READ ONE CHARACTER FROM THE DEVICE * * DEVOUT WRITE ONE CHARACTER TO THE DEVICE * * DEVIST RETURN THE DEVICE CHARACTER INPUT READY STATUS * * DEVOST RETURN THE DEVICE CHARACTER OUTPUT READY STATUS * * * * THE SETUP ROUTINE INITIALIZES THE DEVICE AND RETURNS. THE INPUT * * ROUTINE RETURNS ONE CHARACTER IN THE A REGISTER (PARITY RESET). * * THE OUTPUT ROUTINE WRITE ONE CHARACTER FROM THE C REGISTER. THE * * INPUT STATUS ROUTINE RETURNS IN THE A REGISTER A 0 IF THE DEVICE * * DOES NOT HAVE A CHARACTER READY FOR INPUT FOR 0FFH IF A CHARACTER * * IS READY FOR INPUT. THE OUTPUT STATUS ROUTINE RETURNS IN THE A * * REGISTER A 0 IF THE DEVICE IS NOT READY ACCEPT A CHARACTER AND A * * 0FFH IF THE DEVICE IS READY. THE INPUT AND OUTPUT ROUTINES * * SHOULD WAIT UNTILL THE DEVICE IS READY FOR THE DESIRED OPERATION * * BEFORE THE DOING THE OPERATION AND RETURNING. * * * * NOT ALL OF THESE FUNCTIONS NEED TO BE IMPLEMENTED FOR ALL THE * * DEVICES. THE FOLLOWING IS A TABLE OF THE ENTRY POINTS NEEDED FOR * * EACH DEVICE HANDLER. * * * * DEVICE SETUP INPUT OUTPUT INPUT OUTPUT * * NAME STATUS STATUS * * * * CON: CONIN CONOUT CONIST * * RDR: RDRIN RDRIST * * PUN: PUNOUT * * LST: LSTOUT LSTOST * * * * TTY: TTYSET TTYIN TTYOUT TTYIST TTYOST * * CRT: CRTSET CRTIN CRTOUT CRTIST CRTOST * * UC1: UC1SET UC1IN UC1OUT UC1IST * * * * PTR: PTRSET PTRIN PTRIST * * UR1: UR1SET UR1IN UR1IST * * UR2: UR2SET UR2IN UR2IST * * * * PTP: PTPSET PTPOUT * * UP1: UP1SET UP1OUT * * UP2: UP2SET UP2OUT * * * * LPT: LPTSET LPTOUT LPTOST * * UL1: UL1SET UL1OUT UL1OST * * * * THE CONIN, CONOUT, CONIST, RDRIN, RDRIST, PUNOUT, LSTOUT, AND * * LSTOST ROUTINES ARE THE LOGICAL DEVICE DRIVER ENTRY POINTS * * PROVIDED BY THIS DEVICE MAPPER. THE OTHER ENTRY NAMES MUST BE * * PROVIDED BY THE PHYSICAL DEVICE DRIVERS. * * * ************************************************************************* ;I/O BYTE IMPLEMENTED FOR NORTH STAR CONIN: MVI E,1 ;CONSOLE INPUT CALL REDIR ; IOBYTE: 76543210 DW TTYIN ;CON: = TTY: XXXXXX00 DW CRTIN ;CON: = CRT: XXXXXX01 DW RDRIN ;CON: = BAT: XXXXXX10 DW UC1IN ;CON: = UC1: XXXXXX11 CONOUT: MVI E,1 ;CONSOLE OUTPUT CALL REDIR ; IOBYTE: 76543210 DW TTYOUT ;CON: = TTY: XXXXXX00 DW CRTOUT ;CON: = CRT: XXXXXX01 DW LSTOUT ;CON: = BAT: XXXXXX10 DW UC1OUT ;CON: = UC1: XXXXXX11 CONIST: MVI E,1 ;CONSOLE INPUT STATUS CALL REDIR ; IOBYTE: 76543210 DW TTYIST ;CON: = TTY: XXXXXX00 DW CRTIST ;CON: = CRT: XXXXXX01 DW RDRIST ;CON: = BAT: XXXXXX10 DW UC1IST ;CON: = UC1: XXXXXX11 RDRIN: MVI E,7 ;READER INPUT CALL REDIR ; IOBYTE: 76543210 DW TTYIN ;RDR: = TTY: XXXX00XX DW PTRIN ;RDR: = PTR: XXXX01XX DW UR1IN ;RDR: = UR1: XXXX10XX DW UR2IN ;RDR: = UR2: XXXX11XX RDRIST: MVI E,7 ;READER INPUT STATUS CALL REDIR ; IOBYTE: 76543210 DW TTYIST ;RDR: = TTY: XXXX00XX DW PTRIST ;RDR: = PTR: XXXX01XX DW UR1IST ;RDR: = UR1: XXXX10XX DW UR2IST ;RDR: = UR2: XXXX11XX PUNOUT: MVI E,5 ;PUNCH OUTPUT CALL REDIR ; IOBYTE: 76543210 DW TTYOUT ;PUN: = TTY: XX00XXXX DW PTPOUT ;PUN: = PTP: XX01XXXX DW UP1OUT ;PUN: = UP1: XX10XXXX DW UP2OUT ;PUN: = UP2: XX11XXXX LSTOUT: MVI E,3 ;LIST OUTPUT CALL REDIR ; IOBYTE: 76543210 DW TTYOUT ;LST: = TTY: 00XXXXXX DW CRTOUT ;LST: = CRT: 01XXXXXX DW LPTOUT ;LST: = LPT: 10XXXXXX DW UL1OUT ;LST: = UL1: 11XXXXXX LSTOST: MVI E,3 ;LIST OUTPUT STATUS CALL REDIR ; IOBYTE: 76543210 DW TTYOST ;LST: = TTY: 00XXXXXX DW CRTOST ;LST: = CRT: 01XXXXXX DW LPTOST ;LST: = LPT: 10XXXXXX DW UL1OST ;LST: = UL1: 11XXXXXX REDIR: LDA IOBYTE ;GET THE INTEL STANDARD IOBYTE REDIR0: RLC ;SHIFT THE NEXT FIELD IN DCR E ;BUMP THE SHIFT COUNT JNZ REDIR0 REDIR1: ANI 110B ;MASK THE REDIRECTION FIELD MOV E,A ;MAKE THE WORD TABLE OFFSET MVI D,0 POP H ;GET THE TABLE BASE DAD D ;OFFSET INTO OUR TABLE MOV A,M ;LOAD THE LOW LEVEL I/O ROUTINE POINTER INX H MOV H,M MOV L,A PCHL ;EXECUTE THE LOW LEVEL I/O DRIVER ************************************************************************* * * * CONYTP: 6 NORTH STAR * * * * THE FOLLOWING CODE IMPLEMENTS THE NORTH STAR CONSOLE I/O SYSTEM. * * THIS SYSTEM IS FOR USERS WHO PURCHASE A MORROW DESIGNS DISK * * SYSTEM TO REPLACE THEIR NORTH STAR DISK SYSTEM. THE MAPPING OF * * THE LOGICAL TO PHYSICAL ENTRY POINTS IS PERFORMED AS FOLLOWS: * * * * DEVICE NAME LEFT RIGHT PARALLEL * * SERIAL SERIAL PORT * * * * CONSOLE CON: = TTY: CRT: UC1: * * READER RDR: = TTY: PTR: UR1: * * PUNCH PUN: = TTY: PTP: UP1: * * LIST LST: = TTY: CRT: UL1: * * * * FOR EXAMPLE, TO USE A PRINTER CONNECTED TO THE RIGHT SERIAL PORT, * * USE THE CP/M COMMAND: * * * * STAT LST:=CRT: * * * * LIKEWISE, THE CP/M COMMAND "STAT LST:=UL1:" IS USED IF YOU HAVE A * * PRINTER CONNECTED TO THE PARALLEL PORT. * * * ************************************************************************* NSLDAT EQU 2 ;LEFT SERIAL PORT DATA PORT NSLSTA EQU 3 ;LEFT SERIAL PORT STATUS PORT NSRDAT EQU 4 ;RIGHT SERIAL PORT DATA PORT NSRSTA EQU 5 ;RIGHT SERIAL PORT STATUS PORT NSSTBE EQU 1 ;TRANSMITTER BUFFER EMPTY STATUS BIT NSSRBR EQU 2 ;RECIEVER BUFFER READY STATUS BIT ;SEE THE 8251 DATA SHEETS FOR MORE ; CONFIGURATION INFORMATION. NSLIN1 EQU 0CEH ;LEFT SERIAL PORT INITIALIZATION # 1 NSRIN1 EQU 0CEH ;RIGHT SERIAL PORT INITIALIZATION # 1 ;76543210 BIT DEFINATIONS ;11001110 DEFAULT CONFIGURATION ;XXXXXX00 SYNCHRONOUS MODE ;XXXXXX01 1X CLOCK RATE ;XXXXXX10 16X CLOCK RATE ;XXXXXX11 64X CLOCK RATE ;XXXX00XX 5 BIT CHARACTERS ;XXXX01XX 6 BIT CHARACTERS ;XXXX10XX 7 BIT CHARACTERS ;XXXX11XX 8 BIT CHARACTERS ;XXX0XXXX PARITY DISBABLE ;XXX1XXXX PARITY ENABLE ;XX0XXXXX ODD PARITY GENERATION/CHECK ;XX1XXXXX EVEN PARITY GENERATION/CHECK ;00XXXXXX INVALID ;01XXXXXX 1 STOP BIT ;10XXXXXX 1.5 STOP BITS ;11XXXXXX 2 STOP BITS NSLIN2 EQU 37H ;LEFT SERIAL PORT INITIALIZATION # 2 NSRIN2 EQU 37H ;RIGHT SERIAL PORT INITIALIZATION # 2 ;76543210 BIT DEFINATIONS ;00110111 DEFAULT CONFIGURATION ;XXXXXXX1 ENABLE TRANSMITTER ;XXXXXX1X ASSERT DTR* ;XXXXX1XX ENABLE RECIEVER ;XXXX1XXX SEND BREAK CHARACTER, TXD LOW ;XXX1XXXX RESET PE, OE, FE ERROR FLAGS ;XX1XXXXX ASSERT RTS* ;X1XXXXXX INTERNAL RESET ;1XXXXXXX ENTER HUNT MODE (FOR SYNC) NSPDAT EQU 0 ;PARALLEL DATA PORT NSPSTA EQU 6 ;PARALLEL STATUS PORT NSPRBR EQU 1 ;RECIEVER BUFFER READY STATUS BIT NSPTBE EQU 2 ;TRANSMITTER BUFFER EMPTY STATUS BIT NSRAM EQU 0C0H ;NORTH STAR MEMORY PARITY PORT, ; SET TO 0 FOR NO NORTH STAR RAM ************************************************************************* * * * LEFT SERIAL PORT ROUTINES. USE TTY: DEVICE. * * * ************************************************************************* TTYIN: ;READ A CHARACTER IN NSLSTA ANI NSSRBR JZ TTYIN ;WAIT TILL A CHARACTER IS READY IN NSLDAT ;GET THE CHARACTER ANI 7FH ;STRIP PARITY RET TTYOUT: ;WRITE A CHARACTER IN NSLSTA ANI NSSTBE JZ TTYOUT ;WAIT TILL THE BUFFER IS EMPTY MOV A,C ;WRITE THE CHARACTER OUT NSLDAT RET TTYIST: ;RETURN INPUT BUFFER STATUS IN NSLSTA ANI NSSRBR RZ ;RETURN NOT READY MVI A,0FFH RET ;THERE IS A CHARACTER READY TTYOST: ;RETURN OUTPUT BUFFER STATUS IN NSLSTA ANI NSSTBE RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ************************************************************************* * * * RIGHT SERIAL PORT ROUTINES. USE CRT:, PTR:, AND PTP: DEVICES. * * * ************************************************************************* CRTIN: ;READ A CHARACTER PTRIN: IN NSRSTA ANI NSSRBR JZ CRTIN ;WAIT TILL A CHARACTER IS READY IN NSRDAT ;GET THE CHARACTER ANI 7FH ;STRIP PARITY RET CRTOUT: ;WRITE A CHARACTER PTPOUT: IN NSRSTA ANI NSSTBE JZ CRTOUT ;WAIT TILL THE BUFFER IS EMPTY MOV A,C ;WRITE THE CHARACTER OUT NSRDAT RET CRTIST: ;RETURN INPUT BUFFER STATUS PTRIST: IN NSRSTA ANI NSSRBR RZ ;RETURN NOT READY MVI A,0FFH RET ;THERE IS A CHARACTER READY CRTOST: ;RETURN OUTPUT BUFFER STATUS IN NSRSTA ANI NSSTBE RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ************************************************************************* * * * PARALLEL PORT ROUTINES. USE UC1:, UR1:, UR2:, UP1:, UP2:, LPT:, * * AND UL1: DEVICES. * * * ************************************************************************* UC1IN: ;READ A CHARACTER UR1IN: UR2IN: IN NSPSTA ANI NSPRBR JZ UC1IN ;WAIT TILL A CHARACTER IS READY IN NSPDAT ;GET THE CHARACTER PUSH PSW MVI A,30H ;RESET THE PARALLEL INPUT FLAG OUT NSPSTA POP PSW ANI 7FH ;STRIP PARITY RET UC1OUT: ;WRITE A CHARACTER UP1OUT: UP2OUT: LPTOUT: UL1OUT: IN NSPSTA ANI NSPTBE JZ UC1OUT ;WAIT TILL THE BUFFER IS EMPTY MVI A,20H ;RESET THE PARALLEL OUTPUT FLAG OUT NSPSTA MOV A,C ;WRITE THE CHARACTER, STROBE BIT 7 NSPOUT: ORI 80H OUT NSPDAT ANI 7FH OUT NSPDAT ORI 80H OUT NSPDAT RET UC1IST: ;RETURN INPUT BUFFER STATUS UR1IST: UR2IST: IN NSPSTA ANI NSPRBR RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY LPTOST: ;RETURN OUTPUT BUFFER STATUS UL1OST: IN NSPSTA ANI NSPTBE RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ***************************************************************** * * * GOCPM IS THE ENTRY POINT FROM COLD BOOTS, AND WARM BOOTS. IT * * INITIALIZES SOME OF THE LOCATIONS IN PAGE 0, AND SETS UP THE * * INITIAL DMA ADDRESS (80H). * * * ***************************************************************** GOCPM: LXI H,BUFF ;SET UP INITIAL DMA ADDRESS CALL SETDMA MVI A,(JMP) ;INITIALIZE JUMP TO WARM BOOT STA WBOT STA ENTRY ;INITIALIZE JUMP TO BDOS LXI H,WBOOTE ;SET UP LOW MEMORY ENTRY TO CBIOS WARM BOOT SHLD WBOT+1 LXI H,BDOS+6 ;SET UP LOW MEMORY ENTRY TO BDOS SHLD ENTRY+1 XRA A ;A <- 0 STA BUFSEC ;SET BUFFER TO UNKNOWN STATE STA BUFWRTN ;SET BUFFER NOT DIRTY FLAG STA ERROR ;CLEAR BUFFER ERROR FLAG LDA CWFLG ;GET COLD/WARM BOOT FLAG ORA A LXI H,COLDMES ;POINTER TO INITIAL COLD COMMAND JZ CLDCMND LXI H,WARMES ;POINTER TO INITIAL WARM COMMAND CLDCMND:MOV E,M ;DO ONE LEVEL OF INDIRECTION INX H MOV D,M LDAX D ;GET COMMAND LENGTH INR A ;BUMP LENGTH TO INCLUDE LENGTH BYTE ITSELF LXI H,CCP+7 ;COMMAND BUFFER (INCLUDES LENGTH BYTE) MOV C,A ;SET UP FOR BLOCK MOVE MVI B,0 CALL MOVBYT ;MOVE COMMAND TO INTERNAL CCP BUFFER LDA CWFLG ;FIGURE OUT WHETHER OR NOT TO SEND MESSAGE ORA A LDA AUTOFLG JZ CLDBOT RAR CLDBOT: RAR LDA CDISK ;JUMP TO CP/M WITH CURRENTLY SELECTED DISK IN C MOV C,A JC CCP ;ENTER CP/M, SEND MESSAGE JMP CCP+3 ;ENTER CP/M, NO MESSAGE CWFLG: DB 0 ;COLD/WARM BOOT FLAG ***************************************************************** * * * WBOOT LOADS IN ALL OF CP/M EXCEPT THE CBIOS, THEN INITIALIZES * * SYSTEM PARAMETERS AS IN COLD BOOT. SEE THE COLD BOOT LOADER * * LISTING FOR EXACTLY WHAT HAPPENS DURING WARM AND COLD BOOTS. * * * ***************************************************************** WBOOT: LXI SP,TPA ;SET UP STACK POINTER MVI A,1 STA CWFLG ;SET COLD/WARM BOOT FLAG MVI H,WMDRIVE ;MOVE DRIVE TO WARM BOOT OFF OF INTO (H) MVI L,D$WBOOT ;PEFORM WARM BOOT OPERATION CALL JUMPER JNC GOCPM ;NO ERROR HLT ;HALT COMPUTER DB 0 JMP WBOOT ;IN CASE USER RESTARTS THE COMPUTER ***************************************************************** * * * SETSEC JUST SAVES THE DESIRED SECTOR TO SEEK TO UNTIL AN * * ACTUAL READ OR WRITE IS ATTEMPTED. * * * ***************************************************************** SETSEC: MOV H,B ;ENTER WITH SECTOR NUMBER IN (BC) MOV L,C SHLD CPMSEC DONOP: RET ***************************************************************** * * * SETDMA SAVES THE DMA ADDRESS FOR THE DATA TRANSFER. * * * ***************************************************************** SETDMA: MOV H,B ;ENTER WITH DMA ADDRESS IN (BC) MOV L,C SHLD CPMDMA ;CP/M DMA ADDRESS RET ***************************************************************** * * * HOME IS TRANSLATED INTO A SEEK TO TRACK ZERO. * * * ***************************************************************** HOME: LDA BUFWRTN ;TEST BUFFER DIRTY FLAG ORA A JNZ DOHOME ;SKIP BUFFER DISABLE IF BUFFER DIRTY XRA A ;INVALIDATE BUFFER ON HOME CALL STA BUFSEC DOHOME: LXI B,0 ;TRACK TO SEEK TO ***************************************************************** * * * SETTRK SAVES THE TRACK # TO SEEK TO. NOTHING IS DONE AT THIS * * POINT, EVERYTHING IS DEFFERED UNTIL A READ OR WRITE. * * * ***************************************************************** SETTRK: MOV H,B ;ENTER WITH TRACK NUMBER IN (BC) MOV L,C SHLD CPMTRK RET ***************************************************************** * * * SECTRAN TRANSLATES A LOGICAL SECTOR NUMBER INTO A PHYSICAL * * SECTOR NUMBER. * * * ***************************************************************** SECTRAN:LDA CPMDRV ;GET THE DRIVE NUMBER MOV H,A ;DRIVE IN (H) MVI L,D$STRAN JMP JUMPER ;SEE DEVICE LEVEL SECTOR TRANSLATION ROUTINES ***************************************************************** * * * SETDRV SELECTS THE NEXT DRIVE TO BE USED IN READ/WRITE * * OPERATIONS. IF THE DRIVE HAS NEVER BEEN SELECTED IT CALLS * * A LOW LEVEL DRIVE SELECT ROUTINE THAT SHOULD PERFORM SOME * * SORT OF CHECK IF THE DEVICE IS WORKING. IF NOT WORKING THEN * * IT SHOULD REPORT AN ERROR. IF THE LOGICAL DRIVE HAS BEEN * * SELECTED BEFORE THEN SETDRV JUST RETURNS THE DPH WITHOUT * * CHECKING THE DRIVE. * * * ***************************************************************** SETDRV: MOV A,C ;SAVE THE LOGICAL DRIVE NUMBER STA CPMDRV CPI MAXLOG ;CHECK FOR A VALID DRIVE NUMBER JNC ZRET ;ILLEGAL DRIVE MOV A,E ;CHECK IF BIT 0 OF (E) = 1 ANI 1 JNZ SETD3 ;DRIVE HAS ALLREADY BEEN ACCESSED MOV H,C ;MOVE LOGICAL DRIVE INTO (H) MVI L,D$SEL1 CALL JUMPER ;CALL LOW LEVEL DRIVE SELECT MOV A,H ;CHECK IF THE LOW LEVEL DRIVE SELECT RETURNED ORA L ; ZERO TO INDICATE AN ERROR JZ ZRET ;YES, AN ERROR SO REPORT TO CP/M PUSH H ;SAVE DPH ADDRESS CALL GDPH ;GET ENTRY IF DPH SAVE TABLE POP D ;DPH -> (DE) MOV M,E ;PUT ADDRESS OF DPH IN TABLE INX H MOV M,D INX H MOV M,C ;PUT SECTOR SIZE IN TABLE INX H MOV A,M ;CHECK IF BAD MAP HAS EVER BEEN READ FOR THIS ORA A ; DRIVE CZ GETBAD ;NEVER BEEN READ SO READ IN BAD MAP XCHG ;DPH -> (HL) SETD0: MOV A,C ;MOVE SECTOR SIZE CODE INTO (A) STA SECSIZ ;SAVE SECTOR SIZE XRA A SETD1: DCR C ;CREATE NUMBER OF (128 BYTES/PHYSICAL SECTOR)-1 JZ SETD2 RLC ORI 1 JMP SETD1 SETD2: STA SECPSEC ;SAVE FOR DEBLOCKING LDA CPMDRV ;SAVE CURRENT DRIVE AS OLD DRIVE STA LASTDRV ; IN CASE OF SELECT ERRORS RET SETD3: PUSH D ;SAVE DPH ADDRESS MOV H,C ;DRIVE IN (H) MVI L,D$SEL2 ;SELECT DRIVE CALL JUMPER CALL GDPH ;QUICK SELECT POP D MOV E,M ;DPH -> (DE) INX H MOV D,M INX H MOV C,M ;SECTOR SIZE -> (C) XCHG ;DPH -> (HL) JMP SETD0 GDPH: LDA CPMDRV ;RETURN POINTER TO DPH SAVE AREA RLC ;EACH ENTRY IS 4 BYTES LONG RLC MOV E,A MVI D,0 LXI H,DPHTAB ;DPH SAVE AREA TABLE DAD D ;ADD OFFSET RET ;(HL) = DPH SAVE AREA FOR CURRENT DRIVE ZRET: LXI H,0 ;SELDRV ERROR EXIT LDA LASTDRV ;GET LAST SELECTED DRIVE MOV C,A LDA CDISK ;PICK UP USER/DRIVE ANI 0F0H ;SAVE USER NUMBER ORA C ;PUT TOGETHER WITH OLD DRIVE STA CDISK RET ***************************************************************** * * * DPH SAVE AREA. EACH ENTRY IS 4 BYTES LONG: * * 0 - LSB OF DPH ADDRESS * * 1 - MSB OF DPH ADDRESS * * 2 - SECTOR SIZE CODE (1 = 128, 2 = 256, 3 = 512... * * 3 - BAD MAP HAS BEEN INITILIZED (0 = UNINITILIZED) * * * ***************************************************************** DPHTAB: REPT MAXLOG*4 DB 0 ENDM ***************************************************************** * * * GETBAD - CHECK IF A DEVICE HAS A BAD MAP. IF THE DEVICE HAS * * A BAD SECTOR MAP THEN APPEND BAD ENTRIES TO END OF BADMAP * * TABLE. * * * ***************************************************************** GETBAD: MVI M,1 ;SET DRIVE INITILIZED PUSH B PUSH D LDA CPMDRV ;PICK UP CURRENT DRIVE MOV H,A ;CALL DRIVE ROUTINE TO RETURN A POINTER TO MVI L,D$BAD ;THE TRACK AND SECTOR OF THE BAD MAP CALL JUMPER MOV A,H ;IF ROUTINE RETURNS 0 THEN THE DEVICE HAS ORA L ; NO BAD SECTOR MAP JZ BADRET MOV E,M ;PICK UP TRACK NUMBER OF BAD SECTOR MAP -> (DE) INX H MOV D,M INX H XCHG SHLD CPMTRK XCHG MOV A,M ;PICK UP SECTOR NUMBER OF OF BAD SECTOR MAP INX H MOV H,M MOV L,A SHLD TRUESEC CALL FILL ;READ IN BAD SECTOR MAP INTO THE BUFFER RC LHLD BADPTR ;PICK UP BAD MAP POINTER LXI D,BUFFER ;START AT BEGINNING OF BUFFER BADL: LDAX D ;PICK UP AN ENTRY FROM THE BUFFER ORA A JZ BADE ;ALL DONE MOV A,M ;PICK UP ENTRY FROM BAD MAP TABLE INR A JZ OVERFLO ;BAD MAP OVERFLOW LDA CPMDRV ;PUT DRIVE IN TABLE MOV M,A INX H LXI B,8 CALL MOVBYT ;MOVE THE REST OF INFORMATION INTO THE TABLE JMP BADL BADE: SHLD BADPTR ;RESTORE NEW BAD MAP POINTER BADRET: POP D POP B RET OVERFLO:LXI H,OMES CALL MESSAGE JMP BADRET OMES: DB 0DH, 0AH, 'BAD MAP OVERFLOW!', 0DH, 0AH, 0 NOBAD: LXI H,0 ;USED BY DEVICE DRIVES TO INDICATE NO BAD RET ; SECTOR MAP BADPTR: DW BADMAP ;POINTER TO NEXT AVAILABLE BAD MAP ENTRY ***************************************************************** * * * WRITE ROUTINE MOVES DATA FROM MEMORY INTO THE BUFFER. IF THE * * DESIRED CP/M SECTOR IS NOT CONTAINED IN THE DISK BUFFER, THE * * BUFFER IS FIRST FLUSHED TO THE DISK IF IT HAS EVER BEEN * * WRITTEN INTO, THEN A READ IS PERFORMED INTO THE BUFFER TO GET * * THE DESIRED SECTOR. ONCE THE CORRECT SECTOR IS IN MEMORY, THE * * BUFFER WRITTEN INDICATOR IS SET, SO THE BUFFER WILL BE * * FLUSHED, THEN THE DATA IS TRANSFERRED INTO THE BUFFER. * * * ***************************************************************** WRITE: MOV A,C ;SAVE WRITE COMMAND TYPE STA WRITTYP MVI A,1 ;SET WRITE COMMAND JMP RWENT ***************************************************************** * * * READ ROUTINE TO BUFFER DATA FROM THE DISK. IF THE SECTOR * * REQUESTED FROM CP/M IS IN THE BUFFER, THEN THE DATA IS SIMPLY * * TRANSFERRED FROM THE BUFFER TO THE DESIRED DMA ADDRESS. IF * * THE BUFFER DOES NOT CONTAIN THE DESIRED SECTOR, THE BUFFER IS * * FLUSHED TO THE DISK IF IT HAS EVER BEEN WRITTEN INTO, THEN * * FILLED WITH THE SECTOR FROM THE DISK THAT CONTAINS THE * * DESIRED CP/M SECTOR. * * * ***************************************************************** READ: XRA A ;SET THE COMMAND TYPE TO READ RWENT: STA RDWR ;SAVE COMMAND TYPE ***************************************************************** * * * REDWRT CALCULATES THE PHYSICAL SECTOR ON THE DISK THAT * * CONTAINS THE DESIRED CP/M SECTOR, THEN CHECKS IF IT IS THE * * SECTOR CURRENTLY IN THE BUFFER. IF NO MATCH IS MADE, THE * * BUFFER IS FLUSHED IF NECESSARY AND THE CORRECT SECTOR READ * * FROM THE DISK. * * * ***************************************************************** REDWRT: MVI B,0 ;THE 0 IS MODIFIED TO CONTAIN THE LOG2 SECSIZ EQU $-1 ; OF THE PHYSICAL SECTOR SIZE/128 ; ON THE CURRENTLY SELECTED DISK LHLD CPMSEC ;GET THE DESIRED CP/M SECTOR # MOV A,H ANI 80H ;SAVE ONLY THE SIDE BIT MOV C,A ;REMEMBER THE SIDE MOV A,H ANI 7FH ;FORGET THE SIDE BIT MOV H,A DCX H ;TEMPORARY ADJUSTMENT DIVLOOP:DCR B ;UPDATE REPEAT COUNT JZ DIVDONE ORA A MOV A,H RAR MOV H,A MOV A,L RAR ;DIVIDE THE CP/M SECTOR # BY THE SIZE ; OF THE PHYSICAL SECTORS MOV L,A JMP DIVLOOP ; DIVDONE:INX H MOV A,H ORA C ;RESTORE THE SIDE BIT MOV H,A SHLD TRUESEC ;SAVE THE PHYSICAL SECTOR NUMBER LXI H,CPMDRV ;POINTER TO DESIRED DRIVE,TRACK, AND SECTOR LXI D,BUFDRV ;POINTER TO BUFFER DRIVE,TRACK, AND SECTOR MVI B,6 ;COUNT LOOP DTSLOP: DCR B ;TEST IF DONE WITH COMPARE JZ MOVE ;YES, MATCH. GO MOVE THE DATA LDAX D ;GET A BYTE TO COMPARE CMP M ;TEST FOR MATCH INX H ;BUMP POINTERS TO NEXT DATA ITEM INX D JZ DTSLOP ;MATCH, CONTINUE TESTING ***************************************************************** * * * DRIVE, TRACK, AND SECTOR DON'T MATCH, FLUSH THE BUFFER IF * * NECESSARY AND THEN REFILL. * * * ***************************************************************** CALL FILL ;FILL THE BUFFER WITH CORRECT PHYSICAL SECTOR RC ;NO GOOD, RETURN WITH ERROR INDICATION ***************************************************************** * * * MOVE HAS BEEN MODIFIED TO CAUSE EITHER A TRANSFER INTO OR OUT * * THE BUFFER. * * * ***************************************************************** MOVE: LDA CPMSEC ;GET THE CP/M SECTOR TO TRANSFER DCR A ;ADJUST TO PROPER SECTOR IN BUFFER ANI 0 ;STRIP OFF HIGH ORDERED BITS SECPSEC EQU $-1 ;THE 0 IS MODIFIED TO REPRESENT THE # OF ; CP/M SECTORS PER PHYSICAL SECTORS MOV L,A ;PUT INTO HL MVI H,0 DAD H ;FORM OFFSET INTO BUFFER DAD H DAD H DAD H DAD H DAD H DAD H LXI D,BUFFER ;BEGINNING ADDRESS OF BUFFER DAD D ;FORM BEGINNING ADDRESS OF SECTGR TO TRANSFER XCHG ;DE = ADDRESS IN BUFFER LXI H,0 ;GET DMA ADDRESS, THE 0 IS MODIFIED T/ ; CONTAIN THE DMA ADDRESS CPMDMA EQU $-2 MVI A,0 ;THE ZERO GETS MODIFIED TO CONTAIN ; A ZERO IF A READ, OR A 1 IF WRITE RDWR EQU $-1 ANA A ;TEST WHICH KIND OF OPERATION JNZ INTO ;TRANSFER DATA INTO THE BUFFER OUTOF: CALL MOV128 LDA ERROR ;GET THE BUFFER ERROR FLAG RET INTO: XCHG ; CALL MOV128 ;MOVE THE DATA, HL = DESTINATION ; DE = SOURCE MVI A,1 STA BUFWRTN ;SET BUFFER WRITTEN INTO FLAG MVI A,0 ;CHECK FOR DIRECTORY WRITE WRITTYP EQU $-1 DCR A ;TEST FOR A DIRECTORY WRITE MVI A,0 RNZ ;NO ERROR EXIT ***************************************************************** * * * FLUSH WRITES THE CONTENTS OF THE BUFFER OUT TO THE DISK IF * * IT HAS EVER BEEN WRITTEN INTO. * * * ***************************************************************** FLUSH: MVI A,0 ;THE 0 IS MODIFIED TO REFLECT IF ; THE BUFFER HAS BEEN WRITTEN INTO BUFWRTN EQU $-1 ORA A ;TEST IF WRITTEN INTO RZ ;NOT WRITTEN, ALL DONE MVI A,D$WRITE STA RWOP+1 CALL PREP ;DO THE PHYSICAL WRITE STA ERROR ;SET UP THE ERROR FLAG RET ***************************************************************** * * * PREP PREPARES TO READ/WRITE THE DISK. RETRIES ARE ATTEMPTED. * * UPON ENTRY, H&L MUST CONTAIN THE READ OR WRITE OPERATION * * ADDRESS. * * * ***************************************************************** PREP: CALL ALT ;CHECK FOR ALTERNATE SECTORS DI ;RESET INTERRUPTS XRA A ;RESET BUFFER WRITTEN FLAG STA BUFWRTN MVI B,RETRIES ;MAXIMUM NUMBER OF RETRIES TO ATTEMPT RETRYLP:PUSH B ;SAVE THE RETRY COUNT MVI L,D$SEL2 ;SELECT DRIVE CALL JUMPBUF LHLD ALTTRK ;TRACK NUMBER -> (HL) MOV A,H ;TEST FOR TRACK ZERO ORA L PUSH H ;SAVE TRACK NUMBER MVI L,D$HOME CZ JUMPBUF POP B ;RESTORE TRACK # MVI L,D$STRK CALL JUMPBUF LHLD ALTSEC ;SECTOR -> (HL) MOV B,H MOV C,L MVI L,D$SSEC CALL JUMPBUF LXI B,BUFFER ;SET THE DMA ADDRESS MVI L,D$SDMA CALL JUMPBUF RWOP: MVI L,0 ;GET OPERATION ADDRESS CALL JUMPBUF POP B ;RESTORE THE RETRY COUNTER MVI A,0 ;NO ERROR EXIT STATUS RNC ;RETURN NO ERROR DCR B ;UPDATE THE RETRY COUNTER STC ;ASSUME RETRY COUNT EXPIRED MVI A,0FFH ;ERROR RETURN RZ ;RETURN SAD NEWS MOV A,B CPI RETRIES/2 JNZ RETRYLP ;TRY AGAIN PUSH B ;SAVE RETRY COUNT MVI L,D$HOME ;HOME DRIVE AFTER (RETRIES/2) ERRORS CALL JUMPBUF POP B JMP RETRYLP ;TRY AGAIN ***************************************************************** * * * FILL FILLS THE BUFFER WITH A NEW SECTOR FROM THE DISK. * * * ***************************************************************** FILL: CALL FLUSH ;FLUSH BUFFER FIRST RC ;CHECK FOR ERROR LXI D,CPMDRV ;UPDATE THE DRIVE, TRACK, AND SECTOR LXI H,BUFDRV LXI B,5 ;NUMBER OF BYTES TO MOVE CALL MOVBYT ;COPY THE DATA LDA RDWR ;TEST READ WRITE FLAG ORA A JZ FREAD ;SKIP WRITE TYPE CHECK IF READING LDA WRITTYP ;0 = ALLOC, 1 = DIR, 2 = UNALLOC SUI 2 ;TEST FOR AN UNALLOCATED WRITE RZ FWRITIN:LDA SECSIZ ;CHECK FOR 128 BYTE SECTORS DCR A RZ ;NO DEBLOCKING NEEDED FREAD: MVI A,D$READ STA RWOP+1 CALL PREP ;READ THE PHYSICAL SECTOR THE BUFFER STA ERROR ;SET THE ERROR STATUS RET ***************************************************************** * * * JUMPBUF, JUMPER ARE USED TO DISPATCH TO A LOW LEVEL DEVICE * * SUBROUTINE. JUMPER IS CALLED WITH THE DRIVE IN (H) AND THE * * ROUTINE NUMBER (SEE DESCRIPTION ABOVE) IN (L). IT PASSES * * ALONG THE (BC) AND (DE) REGISTERS UNALTERED. JUMPBUF IS * * A CALL TO JUMPER WITH THE DRIVE NUMBER FROM BUFDRV. * * * ***************************************************************** JUMPBUF:LDA BUFDRV ;DISPATCH WITH BUFDRV FOR DRIVE MOV H,A JUMPER: PUSH D PUSH B PUSH H MOV A,H ;LOGICAL DRIVE INTO (A) LXI D,DSTTAB ;DRIVE SPECIFICATION POINTER TABLE JUMPL: MOV C,A ;SAVE LOGICAL IN (C) LDAX D MOV L,A INX D LDAX D MOV H,A ;GET A DST POINTER IN (HL) INX D MOV A,C ;LOGICAL IN (A) SUB M ;SUBTRACT FROM FIRST ENTRY IN DST JNC JUMPL ;KEEP SCANNING TABLE TILL CORRECT DRIVER FOUND INX H ;BUMP (HL) TO POINT TO START OF DISPATCH TABLE POP D ;REAL (HL) -> (DE) MOV A,E ;MOVE OFFSET NUMBER INTO (A) RLC ;EACH ENTRY IS 2 BYTES MOV E,A ;MAKE AN OFFSET MVI D,0 DAD D ;(HL) = **ROUTINE MOV A,M ;PICK UP ADDRESS OF HANDLER FOR SELECTED INX H ; FUNCTION MOV H,M MOV L,A ;(HL) = *ROUTINE MOV A,C ;LOGICAL IN (A) POP B ;RESTORE SAVED REGISTERS POP D PCHL ***************************************************************** * * * CHECK FOR ALTERNATE SECTORS IN BAD SECTOR TABLE. IF AN * * ALTERNATE SECTOR IS FOUND REPLACE ALTTRK AND ALTSEC WITH * * NEW SECTOR NUMBER ELSE PASS ALONG UNALTERED. * * * ***************************************************************** ALT: LXI H,BADMAP ;ADDRESS OF BAD MAP -> (HL) LDA BUFDRV ;PICK UP DRIVE NUMBER CURRENTLY WORKING ON MOV C,A ;MOVE DRIVE INTO (C) FOR SPEED IN SEARCH ALL: XCHG LHLD BADPTR ;GET BAD MAP POINTER XCHG ; -> (DE) MOV A,D ;CHECK IF AT END OF BAD MAP TABLE CMP H JNZ ALT2 ;STILL MORE MOV A,E CMP L JNZ ALT2 ;STILL MORE LHLD BUFTRK ;NO ALTERNATE SECTOR SO USE SELECTED SECTOR SHLD ALTTRK LHLD BUFSEC SHLD ALTSEC RET ALT2: PUSH H ;SAVE CURRENT BAD MAP ENTRY ADDRESS MOV A,C ;MOVE DRIVE INTO (A) CMP M ;CHECK IF DRIVE IN TABLE MATCHES JNZ ALTMIS ;DOES NOT MATCH SKIP THIS ENTRY INX H ;POINT TO LSB OF ALTERNATE TRACK LDA BUFTRK ;PICK UP LSB OF BUFFER TRACK CMP M JNZ ALTMIS INX H ;POINT TO MSB ALTERNATE TRACK LDA BUFTRK+1 ;PICK UP MSB OF BUFFER TRACK CMP M JNZ ALTMIS INX H ;POINT TO LSB OF ALTERNATE SECTOR LDA BUFSEC ;PICK UP LSB OF BUFFER SECTOR CMP M JNZ ALTMIS INX H ;POINT TO MSB OF ALTERNATE SECTOR LDA BUFSEC+1 ;PICK UP MSB OF BUFFER SECTOR CMP M JNZ ALTMIS ;FOUND AN ALTERNATE SECTOR INX H ;POINT TO REAL INFO ON THE ALTERNATE SECTOR LXI D,ALTTRK XCHG ;MOVLOP (DE) = SOURCE, (HL) = DEST PUSH B LXI B,4 CALL MOVBYT ;MOVE ALTERNATE SECTOR INFO IN CORRECT PLACE POP B POP H RET ALTMIS: POP H ;CURRENT ALTERNATE DID NOT MATCH LXI D,9 ;BUMP POINTER BY THE LENGTH OF AN ENTRY DAD D JMP ALL ;LOOP FOR MORE ***************************************************************** * * * MOVER MOVES 128 BYTES OF DATA. SOURCE POINTER IN DE, DEST * * POINTER IN HL. * * * ***************************************************************** MOV128: LXI B,128 ;LENGTH OF TRANSFER MOVBYT: XRA A ;CHECK IF HOST PROCESSOR IS A Z80 ADI 3 JPO Z80MOV ;YES, ITS A Z80 SO USE BLOCK MOVE M8080: LDAX D ;GET A BYTE OF SOURCE MOV M,A ;MOVE IT INX D ;BUMP POINTERS INX H DCX B ;UPDATE COUNTER MOV A,B ;TEST FOR END ORA C JNZ M8080 RET Z80MOV: XCHG ;SOURCE IN (HL), DESTINATION IN (DE) DW 0B0EDH ;LDIR XCHG RET ***************************************************************** * * * RETURN DPH POINTER. ENTER WITH (DE) WITH DPH BASE ADDRESS * * AND (A) WITH LOGICAL DRIVE NUMBER. RETURNS WITH DPH ADDRESS * * IN (HL). * * * ***************************************************************** RETDPH MOV L,A ;MOVE LOGICAL DRIVE INTO (L) MVI H,0 DAD H ;MULTIPLY BY 16 (SIZE OF DPH) DAD H DAD H DAD H DAD D ;(HL) = POINTER TO DPH RET ***************************************************************** * * * UTILITY ROUTINE TO OUTPUT THE MESSAGE POINTED AT BY (HL) * * TERMINATED WITH A NULL. * * * ***************************************************************** MESSAGE:MOV A,M ;GET A CHARACTER OF THE MESSAGE INX H ;BUMP TEXT POINTER ORA A ;TEST FOR END RZ ;RETURN IF DONE PUSH H ;SAVE POINTER TO TEXT MOV C,A ;OUTPUT CHARACTER IN C CALL COUT ;OUTPUT THE CHARACTER POP H ;RESTORE THE POINTER JMP MESSAGE ;CONTINUE UNTIL NULL REACHED ***************************************************************** * * * THE FOLLOWING EQUATES RELATE THE MORROW DESIGNS 2D/B * * CONTROLLER. IF THE CONTROLLER IS NON STANDARD (0F800H) * * ONLY THE FDORIG EQUATE NEED BE CHANGED. * * * ***************************************************************** FDORIG EQU 0E000H ;ORIGIN OF DISK JOCKEY PROM FDBOOT EQU FDORIG+00H ;DISK JOCKEY 2D INITIALIZATION FDCIN EQU FDORIG+03H ;DISK JOCKEY 2D CHARACTER INPUT ROUTINE FDCOUT EQU FDORIG+06H ;DISK JOCKEY 2D CHARACTER OUTPUT ROUTINE FDHOME EQU FDORIG+09H ;DISK JOCKEY 2D TRACK ZERO SEEK FDSEEK EQU FDORIG+0CH ;DISK JOCKEY 2D TRACK SEEK ROUTINE FDSEC EQU FDORIG+0FH ;DISK JOCKEY 2D SET SECTOR ROUTINE FDDMA EQU FDORIG+12H ;DISK JOCKEY 2D SET DMA ADDRESS FDREAD EQU FDORIG+15H ;DISK JOCKEY 2D READ ROUTINE FDWRITE EQU FDORIG+18H ;DISK JOCKEY 2D WRITE ROUTINE FDSEL EQU FDORIG+1BH ;DISK JOCKEY 2D SELECT DRIVE ROUTINE FDTSTAT EQU FDORIG+21H ;DISK JOCKEY 2D TERMINAL STATUS ROUTINE FDSTAT EQU FDORIG+27H ;DISK JOCKEY 2D STATUS ROUTINE FDERR EQU FDORIG+2AH ;DISK JOCKEY 2D ERROR, FLASH LED FDDEN EQU FDORIG+2DH ;DISK JOCKEY 2D SET DENSITY ROUTINE FDSIDE EQU FDORIG+30H ;DISK JOCKEY 2D SET SIDE ROUTINE FDRAM EQU FDORIG+400H ;DISK JOCKEY 2D RAM ADDRESS DBLSID EQU 20H ;SIDE BIT FROM CONTROLLER IO EQU FDORIG+3F8H ;START OF I/O REGISTERS DREG EQU IO+1 CMDREG EQU IO+4 CLRCMD EQU 0D0H ***************************************************************** * * * DEVICE SPECIFICATION TABLE FOR THE DISK JOCKEY 2D/B * * * ***************************************************************** FDDST: DB MAXFD ;NUMBER OF LOGICAL DRIVES DW FDWARM ;WARM BOOT DW FDTRAN ;SECTOR TRANSLATION DW FDLDRV ;SELECT DRIVE 1 DW FDSEL2 ;SELECT DRIVE 2 DW FDLHOME ;HOME DRIVE DW FDSEEK ;SEEK TO SPECIFIED TRACK DW FDSSEC ;SET SECTOR DW FDDMA ;SET DMA ADDRESS DW FDREAD ;READ A SECTOR DW FDWRITE ;WRITE A SECTOR DW NOBAD ;NO BAD SECTOR MAP ***************************************************************** * * * FLOPPY DISK WARM BOOT LOADER * * * ***************************************************************** FDWARM: MOV C,A CALL FDSEL ;SELECT DRIVE A MVI C,0 ;SELECT SIDE 0 CALL FDSIDE WRMFAIL:CALL FDHOME ;TRACK 0, SINGLE DENSITY JC WRMFAIL ;LOOP IF ERROR ;THE NEXT BLOCK OF CODE RE-INITIALIZES ; THE WARM BOOT LOADER FOR TRACK 0 MVI A,5-2 ;INITIALIZE THE SECTOR TO READ - 2 STA NEWSEC LXI H,CCP-100H ;FIRST REVOLUTION DMA - 100H SHLD NEWDMA ;LOAD ALL OF TRACK 0 T0BOOT: MVI A,5-2 ;FIRST SECTOR - 2 NEWSEC EQU $-1 INR A ;UPDATE SECTOR # INR A CPI 27 ;SIZE OF TRACK IN SECTORS + 1 JC NOWRAP ;SKIP IF NOT AT END OF TRACK JNZ T1BOOT ;DONE WITH THIS TRACK SUI 27-6 ;BACK UP TO SECTOR 6 LXI H,CCP-80H ;MEMORY ADDRESS OF SECTOR - 100H SHLD NEWDMA NOWRAP: STA NEWSEC ;SAVE THE UPDATED SECTOR # MOV C,A CALL FDSEC ;SET UP THE SECTOR LXI H,CCP-100H ;MEMORY ADDRESS OF SECTOR - 100H NEWDMA EQU $-2 LXI D,100H ;UPDATE DMA ADDRESS DAD D NOWRP: SHLD NEWDMA ;SAVE THE UPDATED DMA ADDRESS MOV B,H MOV C,L CALL FDDMA ;SET UP THE NEW DMA ADDRESS LXI B,RETRIES*100H+0;MAXIMUM # OF ERRORS, TRACK # WRMFRED:PUSH B CALL FDSEEK ;SET UP THE PROPER TRACK CALL FDREAD ;READ THE SECTOR POP B JNC T0BOOT ;CONTINUE IF NO ERROR DCR B JNZ WRMFRED ;KEEP TRYING IF ERROR JMP FDERR ;TOO MANY ERRORS, FLASH THE LIGHT ;LOAD TRACK 1, SECTOR 1, SECTOR 3 (PARTIAL), SECTOR 2 (1024 BYTE SECTORS) T1BOOT: MVI C,1 ;TRACK 1 CALL FDSEEK LXI B,CCP+0B00H ;ADDRESS FOR SECTOR 1 LXI D,10*100H+1 ;RETRY COUNT + SECTOR 1 CALL WRMREAD LXI B,CCP+0F00H ;ADDRESS FOR SECTOR 2 LXI D,10*100H+3 ;RETRY COUNT + SECTOR 3 CALL WRMREAD LXI B,0300H ;SIZE OF PARTIAL SECTOR LXI D,CCP+1300H ;ADDRESS FOR SECTOR 3 LXI H,CCP+0F00H ;ADDRESS OF SECTOR 3 WRMCPY: MOV A,M ;GET A BYTE AND STAX D ; SAVE IT INX D ;BUMP POINTERS INX H DCX B ;BUMP COUNTER MOV A,B ;CHECK IF DONE ORA C JNZ WRMCPY ; IF NOT, LOOP LXI B,CCP+0F00H ;ADDRESS FOR SECTOR 2 LXI D,10*100H+2 ;RETRY COUNT + SECTOR 2 CALL WRMREAD XRA A ;CLEAR ERROR INDICATOR RET WRMREAD:PUSH D CALL FDDMA ;SET DMA ADDRESS POP B CALL FDSEC ;SET SECTOR WRMFRD: PUSH B ;SAVE ERROR COUNT CALL FDREAD ;READ A SECTOR JC WRMERR ;DO RETRY STUFF ON ERROR CALL FDSTAT ;SECTOR SIZE MUST BE 1024 BYTES ANI 0CH ;MASK LENGTH BITS SUI 0CH ;CARRY (ERROR) WILL BE SET IF < 0C0H WRMERR: POP B ;FETCH RETRY COUNT RNC ;RETURN IF NO ERROR DCR B ;BUMP ERROR COUNT JNZ WRMFRD JMP FDERR ;ERROR, FLASH THE LIGHT FDTRAN: INX B PUSH D ;SAVE TABLE ADDRESS PUSH B ;SAVE SECTOR # CALL FDGET ;GET DPH FOR CURRENT DRIVE LXI D,10 ;LOAD DPH POINTER DAD D MOV A,M INX H MOV H,M MOV L,A MOV A,M ;GET # OF CP/M SECTORS/TRACK ORA A ;CLEAR CARRY RAR ;DIVIDE BY TWO SUB C ;SUBTRACT SECTOR NUMBER PUSH PSW ;SAVE ADJUSTED SECTOR JM SIDETWO SIDEA: POP PSW ;DISCARD ADJUSTED SECTOR POP B ;RESTORE SECTOR REQUESTED POP D ;RESTORE ADDRESS OF XLT TABLE SIDEONE:XCHG ;HL <- &(TRANSLATION TABLE) DAD B ;BC = OFFSET INTO TABLE MOV L,M ;HL <- PHYSICAL SECTOR MVI H,0 RET SIDETWO:CALL FDGSID ;CHECK OUT NUMBER OF SIDES JZ SIDEA ;SINGLE SIDED POP PSW ;RETRIEVE ADJUSTED SECTOR POP B CMA ;MAKE SECTOR REQUEST POSITIVE INR A MOV C,A ;MAKE NEW SECTOR THE REQUESTED SECTOR POP D CALL SIDEONE MVI A,80H ;SIDE TWO BIT ORA H ; AND SECTOR MOV H,A RET FDLDRV: STA FDLOG ;SAVE LOGICAL DRIVE MOV C,A ;SAVE DRIVE # MVI A,0 ;HAVE THE FLOPPIES BEEN ACCESSED YET ? FLOPFLG EQU $-1 ANA A JNZ FLOPOK MVI B,17 ;FLOPPIES HAVN'T BEEN ACCESSED LXI H,FDBOOT ;CHECK IF 2D CONTROLLER IS INSTALLED MVI A,(JMP) CLOPP: CMP M ;MUST HAVE 17 JUMPS JNZ ZRET INX H INX H INX H DCR B JNZ CLOPP LXI D,FDINIT ;INITIALIZATION SEQUENCE LXI H,FDORIG+7E2H ;LOAD ADDRESS LXI B,30 ;BYTE COUNT CALL MOVBYT ;LOAD CONTROLLER RAM MVI A,0FFH ;START 1791 STA DREG MVI A,CLRCMD ;1791 RESET STA CMDREG MVI A,1 ;SET 2D INITIALIZED FLAG STA FLOPFLG FLOPOK: CALL FLUSH ;FLUSH BUFFER SINCE WE ARE USING IT LDA FDLOG ;SELECT NEW DRIVE MOV C,A CALL FDSEL CALL FDLHOME ;RECALIBRATE THE DRIVE LXI H,1 ;SELECT SECTOR 1 OF TRACK 2 SHLD TRUESEC INX H SHLD CPMTRK XRA A ;MAKE SURE WE ARE DOING A READ STA RDWR CALL FILL ;FILL IN BUFFER WITH SECTOR JC ZRET ;TEST FOR ERROR RETURN CALL FDSTAT ;GET STATUS ON CURRENT DRIVE STA FDLDST ;SAVE DRIVE STATUS ANI 0CH ;MASK IN SECTOR SIZE BITS PUSH PSW ;USED TO SELECT A DPB RAR LXI H,XLTS ;TABLE OF XLT ADDRESSES MOV E,A MVI D,0 DAD D PUSH H ;SAVE POINTER TO PROPER XLT CALL FDGET ;GET POINTER TO PROPER DPH POP D LXI B,2 ;COPY XLT POINTER INTO DPH CALL MOVBYT LXI D,8 ;OFFSET TO DPB POINTER IN DPH DAD D ;HL <- &DPH.DPB PUSH H CALL FDGSID ;GET POINTER TO SIDE FLAG TABLE ENTRY LDA FDLDST ;GET DRIVE STATUS ANI DBLSID ;CHECK DOUBLE SIDED BIT MOV M,A ;SAVE SIDES FLAG LXI D,DPB128S ;BASE FOR SINGLE SIDED DPB'S JZ SIDEOK LXI D,DPB128D ;BASE OF DOUBLE SIDED DPB'S SIDEOK: XCHG POP D ;(HL) -> DPB BASE, (DE) -> &DPH.DPB POP PSW ;OFFSET TO CORRECT DPB RAL RAL ;MAKE 0, 10, 20, 30 MOV C,A MVI B,0 ;MAKE OFFSET DAD B ;(HL) IS NOW A DPB POINTER XCHG ;PUT PROPER DPB ADDRESS IN DPH.DPB MOV M,E INX H MOV M,D LXI H,15 ;OFFSET TO DPB.SIZ DAD D MOV C,M ;FETCH SECTOR SIZE CODE FDGET: LDA FDLOG ;RETURN PROPER DPH LXI D,DPHFD0 JMP RETDPH FDSEL2: STA FDLOG MOV C,A JMP FDSEL FDLHOME:MVI C,0 ;SELECT SIDE 0 CALL FDSIDE JMP FDHOME ;DO ACTUAL HOME FDSSEC: PUSH B ;SAVE SECTOR NUMBER MOV A,B ;CHECK SIDE SELECT BIT RLC ;MOVE HIGH BIT TO BIT ZERO ANI 1 MOV C,A CALL FDSIDE ;CALL SELECT SIDE 0 = SIDE A, 1 = SIDE B POP B JMP FDSEC FDGSID: LXI H,FDLSID ;SIDE FLAG TABLE LDA FDLOG ;DRIVE NUMBER PUSH D MOV E,A ;MAKE OFFSET MVI D,0 DAD D ;OFFSET TO PROPER ENTRY POP D MOV A,M ;SET UP FLAGS ORA A RET FDINIT: DW 0 ;INITIALIZATION BYTES LOADED ONTO 2D/B DW 1800H ;HEAD LOADED TIMEOUT DW 0 ;DMA ADDRESS DB 0 ;DOUBLE SIDED FLAG DB 0 ;READ HEADER FLAG DB 07EH ;DRIVE SELECT CONSTANT DB 0 ;DRIVE NUMBER DB 8 ;CURRENT DISK DB 0 ;HEAD LOADED FLAG DB 9 ;DRIVE 0 PARAMETERS DB 0FFH ;DRIVE 0 TRACK ADDRESS DB 9 ;DRIVE 1 PARAMETERS DB 0FFH ;DRIVE 1 TRACK ADDRESS DB 9 ;DRIVE 2 PARAMETERS DB 0FFH ;DRIVE 2 TRACK ADDRESS DB 9 ;DRIVE 3 PARAMETERS DB 0FFH ;DRIVE 3 TRACK ADDRESS DB 9 ;CURRENT PARAMETERS DB 0 ;SIDE DESIRED DB 1 ;SECTOR DESIRED DB 0 ;TRACK DESIRED DB 0 ;HEADER IMAGE, TRACK DB 0 ;SECTOR DB 0 ;SIDE DB 0 ;SECTOR DW 0 ;CRC FDLOG: DB 0 FDLDST: DB 0 ;FLOPPY DRIVE STATUS BYTE FDLSID: REPT MAXFD DB 0FFH ;DOUBLE SIDED FLAG 0 = SINGLE, 1 = DOUBLE ENDM ***************************************************************** * * * XLTS IS A TABLE OF ADDRESS THAT POINT TO EACH OF THE XLT * * TABLES FOR EACH SECTOR SIZE. * * * ***************************************************************** XLTS: DW XLT128 ;XLT FOR 128 BYTE SECTORS DW XLT256 ;XLT FOR 256 BYTE SECTORS DW XLT512 ;XLT FOR 512 BYTE SECTORS DW XLT124 ;XLT FOR 1024 BYTE SECTORS ***************************************************************** * * * XLT TABLES (SECTOR SKEW TABLES) FOR CP/M 2.0. THESE TABLES * * DEFINE THE SECTOR TRANSLATION THAT OCCURS WHEN MAPPING CP/M * * SECTORS TO PHYSICAL SECTORS ON THE DISK. THERE IS ONE SKEW * * TABLE FOR EACH OF THE POSSIBLE SECTOR SIZES. CURRENTLY THE * * TABLES ARE LOCATED ON TRACK 0 SECTORS 6 AND 8. THEY ARE * * LOADED INTO MEMORY IN THE CBIOS RAM BY THE COLD BOOT ROUTINE. * * * ***************************************************************** XLT128: DB 0 DB 1,7,13,19,25 DB 5,11,17,23 DB 3,9,15,21 DB 2,8,14,20,26 DB 6,12,18,24 DB 4,10,16,22 XLT256: DB 0 DB 1,2,19,20,37,38 DB 3,4,21,22,39,40 DB 5,6,23,24,41,42 DB 7,8,25,26,43,44 DB 9,10,27,28,45,46 DB 11,12,29,30,47,48 DB 13,14,31,32,49,50 DB 15,16,33,34,51,52 DB 17,18,35,36 XLT512: DB 0 DB 1,2,3,4,17,18,19,20 DB 33,34,35,36,49,50,51,52 DB 5,6,7,8,21,22,23,24 DB 37,38,39,40,53,54,55,56 DB 9,10,11,12,25,26,27,28 DB 41,42,43,44,57,58,59,60 DB 13,14,15,16,29,30,31,32 DB 45,46,47,48 XLT124: DB 0 DB 1,2,3,4,5,6,7,8 DB 25,26,27,28,29,30,31,32 DB 49,50,51,52,53,54,55,56 DB 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 DB 57,58,59,60,61,62,63,64 DB 17,18,19,20,21,22,23,24 DB 41,42,43,44,45,46,47,48 ***************************************************************** * * * EACH OF THE FOLLOWING TABLES DESCRIBES A DISKETTE WITH THE * * SPECIFIED CHARACTERISTICS. * * * ***************************************************************** ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE FOR 128 BYTE SECTORS, * * SINGLE DENSITY, AND SINGLE SIDED. * * * ***************************************************************** DPB128S:DW 26 ;CP/M SECTORS/TRACK DB 3 ;BSH DB 7 ;BLM DB 0 ;EXM DW 242 ;DSM DW 63 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 16 ;CKS DW 2 ;OFF DB 1 ;128 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE FOR 256 BYTE SECTORS, * * DOUBLE DENSITY, AND SINGLE SIDED. * * * ***************************************************************** DPB256S:DW 52 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 1 ;EXM DW 242 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 2 ;256 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE AS 512 BYTE SECTORS, * * DOUBLE DENSITY, AND SINGLE SIDED. * * * ***************************************************************** DPB512S:DW 60 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 280 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 3 ;512 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE AS 1024 BYTE SECTORS, * * DOUBLE DENSITY, AND SINGLE SIDED. * * * ***************************************************************** DP1024S:DW 64 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 299 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 4 ;1024 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE FOR 128 BYTE SECTORS, * * SINGLE DENSITY, AND DOUBLE SIDED. * * * ***************************************************************** DPB128D:DW 52 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 1 ;EXM DW 242 ;DSM DW 127 ;DRM DB 0C0H ;AL0 DB 0 ;AL1 DW 32 ;CKS DW 2 ;OFF DB 1 ;128 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE AS 256 BYTE SECTORS, * * DOUBLE DENSITY, AND DOUBLE SIDED. * * * ***************************************************************** DPB256D:DW 104 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 486 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 2 ;256 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE AS 512 BYTE SECTORS, * * DOUBLE DENSITY, AND DOUBLE SIDED. * * * ***************************************************************** DPB512D:DW 120 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 561 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 3 ;512 BYTE SECTORS ***************************************************************** * * * THE FOLLOWING DPB DEFINES A DISKETTE AS 1024 BYTE SECTORS, * * DOUBLE DENSITY, AND DOUBLE SIDED. * * * ***************************************************************** DP1024D:DW 128 ;CP/M SECTORS/TRACK DB 4 ;BSH DB 15 ;BLM DB 0 ;EXM DW 599 ;DSM DW 255 ;DRM DB 0F0H ;AL0 DB 0 ;AL1 DW 64 ;CKS DW 2 ;OFF DB 4 ;1024 BYTE SECTORS ***************************************************************** * * * CBIOS RAM LOCATIONS THAT DON'T NEED INITIALIZATION. * * * ***************************************************************** CPMSEC: DW 0 ;CP/M SECTOR # CPMDRV: DB 0 ;CP/M DRIVE # CPMTRK: DW 0 ;CP/M TRACK # TRUESEC:DW 0 ;PHYSICAL SECTOR THAT CONTAINS CP/M SECTOR ERROR: DB 0 ;BUFFER'S ERROR STATUS FLAG BUFDRV: DB 0 ;DRIVE THAT BUFFER BELONGS TO BUFTRK: DW 0 ;TRACK THAT BUFFER BELONGS TO BUFSEC: DW 0 ;SECTOR THAT BUFFER BELONGS TO ALTTRK: DW 0 ;ALTERNATE TRACK ALTSEC: DW 0 ;ALTERANTE SECTOR LASTDRV:DB 0 ;LAST SELECTED DRIVE DN SET 0 REPT MAXFD DPHGEN FD,%DN,0,0 DN SET DN+1 ENDM BUFFER EQU $ ***************************************************************** * * * SIGNON MESSAGE OUTPUT DURING COLD BOOT. * * * ***************************************************************** PROMPT: DB 80H, CLEAR ;CLEAN BUFFER AND SCREEN DB ACR, ALF, ALF DB 'MORROW DESIGNS ' DB '0'+MSIZE/10 ;CP/M MEMORY SIZE DB '0'+(MSIZE MOD 10) DB 'K CP/M ' ;CP/M VERSION NUMBER DB CPMREV/10+'0' DB '.' DB (CPMREV MOD 10)+'0' DB ' ' DB (REVNUM/10)+'A'-1 DB (REVNUM MOD 10)+'0' DB ACR, ALF ; ; PRINT A MESSAGE LIKE: ; ; AB: DJDMA 8", CD: DJDMA 5 1/4", E: HDDMA M5 ; MSDRV SET 0 ;START WITH DRIVE A: MSBUMP MACRO NDRIVES ;PRINT A DRIVE NAME IF DN GT 1 DB ', ' ENDIF REPT NDRIVES DB MSDRV+'A' MSDRV SET MSDRV+1 ENDM DB ': ' ENDM PRHEX MACRO DIGIT ;WRITE A BYTE IN HEX PRNIB DIGIT/10H PRNIB DIGIT ENDM PRNIB MACRO DIGIT ;WRITE A DIGIT IN HEX TEMP SET DIGIT AND 0FH IF TEMP < 10 DB TEMP + '0' ELSE DB TEMP - 10 + 'A' ENDIF ENDM DN SET 1 ;GENERATE THE DRIVE MESSAGES REPT 16 ;RUN OFF AT LEAST 16 DRIVES IF DN EQ FDORDER ;GENERATE THE 2D/B MESSAGE MSBUMP MAXFD DB 'DJ2D/B @' PRHEX FDORIG/100H PRHEX FDORIG ENDIF DN SET DN+1 ENDM DB ACR,ALF DB 0 ;END OF MESSAGE ***************************************************************** * * * CBOOT IS THE COLD BOOT LOADER. ALL OF CP/M HAS BEEN LOADED IN * * WHEN CONTROL IS PASSED HERE. * * * ***************************************************************** CBOOT: LXI SP,TPA ;SET UP STACK XRA A ;CLEAR COLD BOOT FLAG STA CWFLG STA CPMDRV ;SELECT DISK A: STA CDISK LXI H,BIOS+3 ;PATCH COLD BOOT TO WARM CODE SHLD BIOS+1 LDA 00H ;INITIALIZE THE IOBYTE STA IOBYTE LXI D,BADMAP ;CLEAR OUT BAD MAP STAX D LXI H,BADMAP+1 LXI B,9*BADSIZ ;32 MAP ENTRIES CALL MOVBYT MVI M,0FFH ;END MARKER LXI H,DEVSET ;DEVICE SETUP ROUTINE POINTER TABLE CBOOT0: MOV E,M ;LOAD A ROUTINE ADDRESS INX H MOV D,M INX H MOV A,D ;TEST FOR THE END OF THE TABLE ORA E JZ CBOOT2 PUSH H ;SAVE THE TABLE POINTER LXI H,CBOOT1 ;RETURN ADDRESS PUSH H XCHG PCHL ;'CALL' A DEVICE SETUP ROUTINE CBOOT1: POP H ;RESTORE THE TABLE POINTER JMP CBOOT0 DEVSET: DW TTYSET, CRTSET, UC1SET ;DEVICE SETUP ROUTINE POINTERS DW PTRSET, UR1SET, UR2SET DW PTPSET, UP1SET, UP2SET DW LPTSET, UL1SET, 0 CBOOT2 EQU $ LXI H,PROMPT ;PREP FOR SENDING SIGNON MESSAGE CALL MESSAGE ;SEND THE PROMPT JMP GOCPM ************************************************************************* * * * INITIALIZE THE NORTH STAR MOTHER BOARD, LEFT SERIAL PORT, RIGHT * * SERIAL PORT, AND NORTH STAR RAM PARITY. * * * ************************************************************************* TTYSET: ;SET UP THE PARALLEL PORT + MOTHERBOARD XRA A ;INITIALIZE MOTHER BOARD OUT 6 OUT 6 OUT 6 OUT 6 MVI A,30H ;RESET THE PARALLEL PORT INPUT FLAG OUT NSPSTA MVI A,60H ;SET THE PARALLEL PORT OUTPUT FLAG OUT NSPSTA MVI A,ACR ;FORCE A CR OUT THE PARALLEL PORT CALL NSPOUT ;INITIALIZE THE LEFT SERIAL PORT MVI A,NSLIN1 ;SEE THE EQUATES FOR BIT DEFINATIONS OUT NSLSTA MVI A,NSLIN2 OUT NSLSTA XRA A ;CLEAR THE INPUT/OUTPUT BUFFERS OUT NSLDAT IN NSLDAT IN NSLDAT ;INITIALIZE THE RIGHT SERIAL PORT MVI A,NSRIN1 ;SEE THE EQUATES FOR BIT DEFINATIONS OUT NSRSTA MVI A,NSRIN2 OUT NSRSTA XRA A ;CLEAR THE INPUT/OUTPUT BUFFERS OUT NSRDAT IN NSRDAT IN NSRDAT ;RESET PARITY ON NORTH STAR RAMS MVI A,40H ;DISABLE PARITY LOGIC OUT NSRAM LXI H,0 ;STARTING ADDRESS NSET0: MOV A,M ;GET A BYTE MOV M,A ;REWRITE, SET PROPER PARITY INR L ;BUMP THE ADDRESS POINTER JNZ NSET0 NSET1: INR H ;SKIP TO THE NEXT MEMORY PAGE JZ NSET2 ;SKIP IF ALL DONE MVI A,(HIGH $) + 1 ;IS THE POINTER ABOVE US? CMP H ;SET CARRY IF POINTER IS <= OUR PAGE+1 JC NSET0 ;RESET THE NEXT PAGES PARITY MOV A,M ;TEST FOR A PROM OR NO MEMORY MOV B,A ;SAVE THE ORIGINAL BYTE CMA ;SEE IF THIS LOCATION WILL CHANGE MOV M,A CMP M ;TEST FOR A CHANGE MOV M,B ;RESTORE THE ORIGINAL VALUE JZ NSET0 ;VALUE COMPLEMENTED, MUST BE RAM ORA A ;TEST FOR NO MEMORY PRESENT JZ NSET1 ;SKIP TO THE NEXT PAGE IF NO MEMORY LXI D,700H ;SKIP 2K BYTES OF 'PROM' DAD D JNC NSET1 ;DO A PAGE CHECK IF NO OVERFLOW NSET2: MVI A,41H ;RE-ENABLE PARITY ON THE MEMORY BOARDS OUT NSRAM CRTSET: ;NULL ROUTINES PTRSET: PTPSET: UC1SET: UR1SET: UR2SET: UP1SET: UP2SET: LPTSET: UL1SET: RET DB 0,0FFH,0 CODELEN EQU ($-BIOS) ;LENGTH OF CBIOS CODE IF CODELEN GT 1000H ;TEST FOR SYSGEN PROBLEMS 'FATAL ERROR, SYSTEM IS TOO BIG FOR SYSGEN REV. 4.X' DBGTMP SET CODELEN ;CBIOS CODE LENGTH ! ENDIF IF DEBUG DBGTMP SET CODELEN ;CBIOS CODE LENGTH ! ENDIF DS 512-($-BUFFER) ;BUFFER FOR 512 BYTE SECTORS DS 512 ;ADDITIONAL SPACE FOR 1K SECTOR DEVICES ***************************************************************** * * * EACH BAD MAP ENTRY CONSISTS OF 9 BYTES: * * LOGICAL DRIVE NUMBER (1 BYTE) * * TRACK NUMBER OF BAD SECTOR (2 BYTES) * * SECTOR NUMBER OF BAD SECTOR (2 BYTES) * * TRACK NUMBER OF ALTERNATE SECTOR (2 BYTES) * * SECTOR NUMBER OF ALTERNATE SECTOR (2 BYTES) * * * ***************************************************************** BADMAP: DS BADSIZ*9+1 ;32 ENTRIES + END MARKER DIRBUF: DS 128 ;DIRECTORY BUFFER TEMPB: DS 16 ;A LITTLE TEMPORARY BUFFER ***************************************************************** * * * ALLOCATION AND CHECKED DIRECTORY TABLE AREA * * * ***************************************************************** DN SET 0 REPT MAXFD ALLOC FD,%DN,75,64 DN SET DN+1 ENDM END