************************************************************************* * * * 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: * * Disk Jockey 2D/B serial. * * Multi I/O serial. * * Decision I serial. * * * * Printer I/O: * * Multi I/O serial with handshaking. * * Multi I/O Diablo 1620 simulator for the Hytype II. * * * * 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 flags set a 'non-standard' system mode and an * * assembly time debugger. * * * * If this CBIOS is used with the CP/M 2.2 system that is shipped on * * a Morrow Designs diskette then NOSTAND can be set to 1. This * * will allow the CBIOS to use various data areas found inside of * * the CP/M 2.2 BDOS. If the CBIOS is used with a different * * operating system then NOSTAND should be set to 0. * * * * 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. * * * ************************************************************************* nostand equ 1 ;Set to 1 for non-standard mode 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 mwquiet equ 0 ;Set for no names printed on login wmdrive equ 0 ;Device to warm boot from. This is the ; CP/M logical drive number. ************************************************************************* * * * The following equates define the console and printer environments. * * * ************************************************************************* ************************************************************************* * * * Define the console driver to be used. * * * * CONTYP is: 0 Nothing, used for patching to PROM's. * * 3 2D/B driver. * * 6 North Star motherboard (2 serial + 1 parallel) * * * * Set CBAUD to the divisor latch value for the console. For an * * explanation of the values look at the DEFCON table. * * * ************************************************************************* contyp equ 3 cbaud equ 0 ************************************************************************* * * * Define the printer driver to be used. * * * * LSTTYP is: 0 Nothing, used for patching to PROM's. * * 1 Provide for 128 bytes of patch space. * * 2 Multio serial, no protocol. * * 3 Multio serial, Clear To Send protocol. * * 4 Multio serial, Data Set Ready protocol. * * 5 Multio serial, Xon/Xoff protocol. * * * * Note: The Decision board is functionally identical to the Multi * * I/O board for serial printer I/O. Selections 2 to 5 will * * work on the Wunderbuss i/o board. To use drivers 6 or 7 * * the MULTR3 equate will have to be set. * * * * Set pbaud to the divisor latch value for the printer. For an * * explanation of the values see the deflst table. * * * ************************************************************************* lsttyp equ 1 lbaud equ 0 ************************************************************************* * * * The next equate determines if you have a Multi I/O Rev 3 or a * * Decision I mother board for parallel i/o. If are not using * * either of these boards then you need not worry about this equate. * * If you are using a Multi I/O rev. other than 3.x or 4.x then you * * should set MULTR3 to 0. * * * ************************************************************************* multr3 equ 0 ;0 = Decision, 1 = Multi I/O rev. 3 or 4 congrp equ 1 ;Cosole port (1 = p1, 2 = p2, 3 = p3) lstgrp equ 3 ;Printer port (1 = p1, 2 = p2, 3 = p3) ************************************************************************* * * * 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 if nostand ne 0 cblock equ bios-19h ;Current actual block# * blkmsk ;Used for unallocated writting endif ************************************************************************* * * * 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 dw fddst 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 if contyp ne 0 const: jmp conist ;Console status routine cin: jmp conin ;Console input cout: jmp costrp ;Console output else const: jmp $ ;Console status routine PROM pointer cin: jmp $ ;Console input PROM pointer cout: jmp $ ;Console output PROM pointer endif if (lsttyp ne 0) or (contyp eq 6) pout: jmp lstout ;List device output else pout: jmp cout ;List device output endif if contyp eq 6 ;North Star drivers have punch entry points jmp punout ;Punch device output else jmp cout ;Use console I/O endif if contyp eq 6 ;North Star drivers have reader entry points jmp rdrin ;Reader device input else jmp cin ;Use console I/O endif 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 if lsttyp ne 0 jmp lstost ;List device status else jmp donop ;List device status endif jmp sectran ;Sector translation ; ; The following jumps are extended BIOS calls defined by Morrow Designs ; if maxfd ne 0 jmp fdsel ;Hookup for SINGLE.COM program else jmp donop endif 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 ************************************************************************* * * * I/O configuration table. * * * * At this CBIOS revision 11 bytes are defined for this table. * * Several extensive changes are planned for the table. Future * * revision of the IOCONF table will have independant entries for * * three serial ports and will be used by several character drivers. * * Also the IOBYTE will be implemented for all the character * * drivers. I might even write an external program to edit this * * table. * * * * The first two bytes show the I/O configuration that the CBIOS was * * assembled with. These bytes are used by external software to * * determine the configuration options that are available. * * * * The next byte is the initial IOBYTE value. This value is written * * to location 3 on cold boots. See the CP/M 2 alternation guide * * for a description of the IOBYTE. * * * * The next byte is to make sure that the group select byte on the * * Mult I/O or Decsion I stays consistant throughout the Cbios. * * Only the group bits themselves (bits 0 and 1) should be changed * * as you output to the group port. If you modify one of the other * * bits (such as driver-enable) then you should modify the same bit * * in this byte. For example: * * * * ;Select console group * * lda group ;Get group byte * * ori congrp ;Select the console port * * out grpsel ;Select the group * * * * ;Modify a bit in the group byte * * lda group ;Get group byte * * ori bank ;Set the bank bit * * sta group ;Save new group setting * * ori group2 ;Select second serial port * * out grpsel ;Select the desired group * * * * Note: You should not set the group bits themselves in the * * group byte. * * * * * * The following two words define the default baud rates for the * * console and the list devices. These words are provided so that * * the user can easily modify them and that they will also be used * * in the future by Morrow Designs software. * * * * The following is a list of possible baud rates and the decimal * * value needed for the defcon or deflst words. * * * * Baud rate defcon/deflst Baud rate defcon/deflst * * 50 2304 2000 58 * * 75 1536 2400 48 * * 110 1047 3600 32 * * 134.5 857 4800 24 * * 150 768 7200 16 * * 300 384 9600 12 * * 600 192 19200 6 * * 1200 96 38400 3 * * 1800 64 56000 2 * * * * * * The next two bytes are ued to configure the hardware handshaking * * protocall used by the serial list drivers with the Multio or * * Wunderbuss I/O boards. The first of these two bytes is a mask. * * This mask is ANDed with the 8250's MODEM Status Register to strip * * out the desired handshake lines. Next the result of the ANDing * * is XORed with the second of the two bytes. This XORing allows * * the handshake lines to be inverted. Common byte values are * * shown below. * * * * cts equ 10h ;Clear To Send status mask * * * * db cts ;Morrow Designs 'Clear To Send' * * db 0 * * * * db cts ;Inverted Clear To Send * * db cts * * * * db 0 ;No handshaking * * db 0ffh * * * * * * The last byte in the revision one structure is the last character * * that was recieved from the printer. This byte is used to * * implement Xon/Xoff software handshaking. This handshaking * * protocol should not bother printers that have not implemented * * Xon/Xoff protocol so this driver is enabled all the time. * * * ************************************************************************* ioconf: db 2 ;Revision 2 structure db 11 ;11 bytes long now db contyp ;Console device driver number db lsttyp ;List device drive number iobyt equ $ ;The initial IOBYTE is kept here db 00$00$00$00b ;All devices go to CON: group: db 0 ;Group byte defcon: dw cbaud ;Console baud rate divisor value deflst: dw lbaud ;Printer baud rate divisor value if (lsttyp ne 3) and (lsttyp ne 4) ;Xon/Xoff protocol lstand: db 0 ;Serial list handshake mask lstxor: db 0ffh ;Serial list inversion flag endif if lsttyp eq 3 ;Clear To Send protocol lstand: db cts ;Serial list handshake mask lstxor: db 0 ;Serial list inversion flag endif if lsttyp eq 4 ;Data Set Ready protocol lstand: db dsr ;Serial list handshake mask lstxor: db 0 ;Serial list inversion flag endif lastch: db xon ;Last character recieved from the printer ************************************************************************* * * * This routine is an experiment to reduce missed and garbled * * characters on console output. * * * ************************************************************************* if contyp ne 0 costrp: mov a,c ;Strip parity on conout ani 7fh mov c,a jmp conout endif ************************************************************************* * * * Due to its length, the TTYSET routine driver is below the CBOOT * * CBOOT routine. * * * ************************************************************************* ***************************************************************** * * * Read a character from the serial port. * * * ***************************************************************** conin: call selcon ;Select console conin1: in lsr ;Read status register ani dr ;Wait till character ready jz conin1 in rbr ;Read character ani 7fh ;Strip parity ret ***************************************************************** * * * Output a character to serial port. * * * ***************************************************************** ***************************************************************** * * * CONTYP: 3 2DB console driver * * * ***************************************************************** if contyp eq 3 conout: jmp fdcout ;Console output conin: jmp fdcin ;Console input conist: call fdtstat ;Console status mvi a,0ffh rz inr a ret endif ;2DB ***************************************************************** * * * 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 ioconf ;I/O 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. * * * ************************************************************************* if contyp eq 6 ;I/O byte implemented for North Star ; drivers. Other drivers to follow 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 endif ;IOBYTE redirector ************************************************************************* * * * CONTYP: 1 Blank space for console driver * * * * The driver entries CONOUT, CONIN, CONIST are defined in the CP/M * * alternation guide. Eg. Input parameters are in register C and * * results are returned in register A. The TTYSET routine is used * * for initialization code. It should execute a RET when complete. * * * * The TTYSET routine could be placed just below the CBOOT routine. * * This space (below CBOOT) is recyled for use as a disk buffer * * after CBOOT is done. * * * ************************************************************************* if contyp eq 1 ;User defined IO area ttyset equ $ ;Console initialization conout equ $ ;Console output conin equ $ ;Console input conist equ $ ;Console input status jmp $ ds 125 endif ;User IO ************************************************************************* * * * 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. * * * ************************************************************************* if contyp eq 6 ;Use North Star I/O? 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 endif ;North Star I/O configuration ************************************************************************* * * * LST: device driver routines. * * * * Routine used depends on the value of lsttyp. Possible LSTTYP * * values are listed as follows: * * * * LSTTYP is: 0 Nothing, used for patching to PROM's * * 1 Provide for 128 bytes of patch space * * 2 Multio serial, no protocol * * 3 Multio serial, Clear To Send protocol * * 4 Multio serial, Data Set Ready protocol * * 5 Multio serial, Xon/Xoff protocol * * * ************************************************************************* ************************************************************************* * * * lsttyp: 1 Blank space for printer driver * * * * The driver entries LSTOUT and LSTOST are defined in the CP/M * * alternation guide. Eg. Input parameters are in register C and * * results are returned in register A. The LSTSET routine is used * * for initialization code. It should execute a RET when complete. * * * * The LSTSET routine could be placed just below the CBOOT routine. * * This space (below CBOOT) is recyled for use as a disk buffer * * after CBOOT is done. * * * ************************************************************************* if lsttyp eq 1 lstset equ $ ;Printer initialization lstout equ $ ;Printer output lstost equ $ ;Printer output status ret ds 127 endif ;User IO ***************************************************************** * * * lsttyp: 2, 3, 4, or 5 Serial printer, multi protocol * * * ***************************************************************** if (lsttyp ge 2) and (lsttyp le 5) lstout: call lstost ;Check printer status ora a jz lstout ;Loop if not ready mov a,c ;Print the character out thr ret lstost: call sellst ;Printer status routine in lsr ;Check if transmitter buffer empty ani thre rz ;Return busy if buffer is not empty lhld lstand ;Fetch handshake mask bits in msr ;Get MODEM Status Register ana l ;Strip out hand-shake lines xra h ;Invert status rz ;Return busy if printer is busy lda lastch ;Get last character recieved from the printer mov b,a in lsr ;Check for a character from the printer ani dr jz xskip ;Skip if no character present in rbr ;Get the character ani 7fh ;Strip parity sta lastch ;Save last character recieved mov b,a xskip: mov a,b sui xoff ;Check for Xoff char (control S) jnz xsdone ;Printer ready ret ;Printer not ready (return zero) xsdone: mvi a,0ffh ;Printer ready for data ret endif ;Multi I/O serial driver ***************************************************************** * * * 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 if nostand ne 0 sta unaloc ;Clear unallocated write flag endif 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 if nostand ne 0 ;Do non standard (but quick and dirty) check ora a jnz fnaloc ;Skip if not an allocated write lda unaloc ;Check unallocated write in progress flag ora a jz fwritin ;We are doing an allocated write lhld cblock ;Get current block address xchg lhld oblock ; and old block address mov a,d ;Compare old versus new cmp h jnz awritin ;Different, clear unallocated writting mode mov a,e cmp l jnz awritin lxi h,cpmdrv ;Test for different drive lda unadrv cmp m jnz awritin ;Drive is different, clear unallocated mode ret ;Unallocated write, do nothing... fnaloc: dcr a jz awritin ;Do a directory write ;We are now doing an unallocated write lhld cblock ;Save current block number shld oblock lda cpmdrv ;Save drive that this block belongs to sta unadrv mvi a,1 ;Set unallocated write flag sta unaloc ret ; and we do nothing about the write awritin:xra a ;Clear unallocated writting mode sta unaloc else ;Do standard unallocated test sui 2 ;Test for an unallocated write rz endif 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. * * * ***************************************************************** if maxfd ne 0 ;Include Discus 2D ? 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 endif if (maxfd ne 0) or (maxdm ne 0) ***************************************************************** * * * 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 endif ***************************************************************** * * * Cbios ram locations that don't need initialization. * * * ***************************************************************** if nostand ne 0 ;Unallocated writting variables unaloc: db 0 ;Unallocated write in progress flag oblock: dw 0 ;Last unallocated block number written unadrv: db 0 ;Drive that the block belongs to endif 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 ***************************************************************** * * * DPB and DPH area. * * * ***************************************************************** if maxfd ne 0 dn set 0 rept maxfd dphgen fd,%dn,0,0 dn set dn+1 endm endif if maxdm ne 0 dn set 0 rept maxdm dphgen dm,%dn,0,0 dn set dn+1 endm endif 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 endif endif endif 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 group ;Clear group select byte sta cpmdrv ;Select disk A: sta cdisk lxi h,bios+3 ;Patch cold boot to warm code shld bios+1 lda iobyt ;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 if contyp ne 6 ;Non IOBYTE inits if contyp ne 0 ;Do not call TTYSET for PROM's call ttyset ;Initialize the terminal endif if lsttyp ne 0 ;Do not call LSTSET for PROM's call lstset ;Initialize the list device endif else ;Do IOBYTE inits 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 $ endif lxi h,prompt ;Prep for sending signon message call message ;Send the prompt jmp gocpm ***************************************************************** * * * Console and list device initialization routines follow. * * * ***************************************************************** if contyp eq 2 ;Multi I/O, Decision I ***************************************************************** * * * Terminal initilization routine. This routine reads the sense * * switch on the WB-14 and sets the speed accordingly. * * * ***************************************************************** ttyset: call selg0 ;Select group 0 in sensesw ;Get sense switch (ff on a Multio) push psw call selcon ;Select console pop psw push psw call tini0 ;Initialize the console pop psw push psw call selrdr ;Select the reader/punch pop psw call tini0 ;Initialize the reader/punch ret tini0: ani 0e0h ;Mask in upper three bits rlc ;Move into lower 3 bits rlc rlc cpi 7 ;check for sense = 7 (Default setting) jz dfbaud ;Use default baud rate lxi h,btab ;Pointer to baud rate table add a ;Table of words so double mov e,a ;Make a 16 bit number into (de) mvi d,0 dad d ;Get a pointer into baud rate table mov e,m ;Get lower byte of word inx h ;Bump to high byte of word mov d,m ;Get upper byte. (de) now has divisor jmp setit ;Set baud rate dfbaud: lhld defcon ;Use default baud rate xchg setit: mvi a,dlab+wls1+wls0+stb ;Enable divisor access latch out lcr ;Set the baud rate in (de) mov a,d out dlm ;Set upper divisor mov a,e out dll ;Set lower divisor mvi a,wls1+wls0+stb ;Clear Divisor latch out lcr xra a out ier ;Set no interrupts out lsr ;Clear status mvi a,dtrenb+rtsenb ;Enable DTR and RTS outputs to terminal out mcr in msr ;Clear MODEM Status Register in lsr ;Clear Line Status Register in rbr ;Clear reciever buffers in rbr ret btab: dw 1047 ;110 Baud 000 dw 384 ;300 001 dw 96 ;1200 010 dw 48 ;2400 011 dw 24 ;4800 100 dw 12 ;9600 101 dw 6 ;19200 110 ;DEFCON 111 endif ;Multi I/O, Decision I if contyp eq 3 ;2D/B console initialization ttyset: call fdtstat ;Clean input buffer rnz ;All empty call fdcin jmp ttyset endif ;2D/B console if contyp eq 4 ttyset: call dminit ;See if controller present rc ;No controller, return lxi d,dmaci ;Console initialization sequence lxi h,dmchan lxi b,10 ;Command length call movbyt dcx h xra a ;Clear serial input status sta serin+1 jmp docmd2 ;Do stuff and return dmaci: db writem ;Zot monitor disable flag dw ttyset ;Any non-zero byte will do db 0 dw 1 ;One byte dw 13f5h ;Magical place in monitor db senabl ;Enable serial input db 1 endif ************************************************************************* * * * Initialize the North Star Mother board, left serial port, right * * serial port, and North Star RAM parity. * * * ************************************************************************* if contyp eq 6 ;North Star drivers 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 if nsram ne 0 ;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 endif crtset: ;Null routines ptrset: ptpset: uc1set: ur1set: ur2set: up1set: up2set: lptset: ul1set: ret endif ;North Star drivers if (lsttyp ge 2) and (lsttyp le 5) ;Serial Multi I/O list drivers lstset: call sellst ;Select printer group mvi a,dlab ;Access divisor latch out lcr lhld deflst ;Get LST: baud rate divisor mov a,h out dlm ;Set upper baud rate mov a,l out dll mvi a,stb+wls0+wls1 ;2 stop bits + 8 bit word out lcr mvi a,dtrenb+rtsenb ;DTR + RTS enabled out mcr in rbr ;Clear input buffer xra a out ier ;No interrupts ret endif 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 if (maxfd ne 0) or (maxdm ne 0) or (maxmw ne 0) ds 512 ;Additional space for 1k sector devices endif ***************************************************************** * * * 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 * * * ***************************************************************** if maxfd ne 0 dn set 0 rept maxfd alloc fd,%dn,75,64 dn set dn+1 endm endif if maxdm ne 0 dn set 0 rept maxdm alloc dm,%dn,75,64 dn set dn+1 endm endif if maxmf ne 0 dn set 0 rept maxmf alloc mf,%dn,22,16 dn set dn+1 endm endif bioslen equ (high ($-bios))+1 ;BIOS length in pages if bioslen gt biosln ;Test for overflow 'FATAL ERROR, system overflow. BIOSLN must be at least' dbgtmp set bioslen ;BIOSLN! endif if debug dbgtmp set biosln ;Current BIOSLN! if biosln gt bioslen dbgtmp set bioslen ;Optimal BIOSLN! endif endif end