;************************************************************* ;* 1-11-83 ;* 3-20-83 ;* ;* X I O S - 8 6 ;* =================== ;* ;* CCP/M-86 eXtended I/O System ;* for ;* CompuPro Computer System ;* ;* by Ray Pedrizetti ;* and Jeff Newman (12/16/82) ;* ;* The XIOS can be assembled in two forms ;* that are acceptable to GENSYS in building ;* an MP/M-86 II system. ;* ;* 8080 model: ;* ----------- ;* Mixed code and data. The Code and Data ;* segments are the same. The code segment ;* is ORG'd at 1000h relative to the System ;* Data Area ;* ;* high +-----------------+\ ;* | System Tables | | ;* +-----------------+ | ;* | XIOS (C and D) | > System Data ;* +-----------------+ | ;* | Sysdat | | ;* +-----------------+X ;* | System Code | > System Code ;* low +-----------------+/ ;* ;* Separate Code and Data: ;* ---------------------- ;* ;* The Code segment is separate from the ;* Data. The Code is ORG'd at 0000h and the ;* Data is ORG'd at 1000h. ;* ;* high +-----------------+\ ;* | System Tables | | ;* +-----------------+ | ;* | XIOS Data | > System Data ;* +-----------------+ | Area ;* | Sysdat | | ;* +-----------------+X ;* | XIOS Code | | ;* +-----------------+ > System Code ;* | System Code | | Modules ;* low +-----------------+/ ;* ;* This XIOS is presented as an example ;* hardware interface to an MP/M-86 system. ;* In many places in the code, more efficient ;* methods can be used. ;* ;* ;***************************************************** ;* ;* REGISTER USAGE FOR XIOS INTERFACE ROUTINES: ;* ;* input: AL = function # (in entry) ;* CX = parameter ;* DX = second parameter ;* DS = sysdat (in entry and init) ;* = CS elsewhere ;* ES = User's Data Area ;* ;* output: AX = return ;* BX = AX (in exit) ;* ES,DS must be preserved though call ;* ;* NOTE: Some changes have been made in the ;* argument/return register usage from ;* the CP/M-86 BIOS. ;* ;***************************************************** ;* ;* SYSTEM EQUATES ;* ;***************************************************** ; include system.lib ; ; conditional assembly switches ; bios equ false xios equ not bios debug equ 003h ; - see debugflag - ; 001h = clock tick not enabled ; 002h = interrupt vector not initializied cr equ 0dh ;carriage return lf equ 0ah ;line feed esc equ 01bh ;escape ;----------------------------------------------------- eject ;***************************************************** ;* ;* DISK I/O EQUATES ;* ;***************************************************** ; max_retries equ 02 ;retries on disk i/o ;before perm error ;*****MDISK SUPPORT***** mdiskbase equ 6000h ;base address of mdisk ;*********************** ; Read and Write disk parameter equates ; ; At the disk read and write function entrys ; all disk I/O parameters are on the stack ; and the stack at these entrys appears as ; follows: ; ; +-------+-------+ ; +14 | DRV | MCNT | Drive and Multi sector count ; +-------+-------+ ; +12 | TRACK | Track number ; +-------+-------+ ; +10 | SECTOR | Physical sector number ; +-------+-------+ ; +8 | DMA_SEG | DMA segment ; +-------+-------+ ; +6 | DMA_OFF | DMA offset ; +-------+-------+ ; +4 | RET_SEG | BDOS return segment ; +-------+-------+ ; +2 | RET_OFF | BDOS return offset ; +-------+-------+ ; SP+0 | RET_ADR | Local entry return address ; +-------+-------+ ; ; These parameters may be indexed and modifide ; directly on the stack and will be removed ; by the BDOS after the function is complete drive equ byte ptr 14[bp] mcnt equ byte ptr 15[bp] track equ word ptr 12[bp] sector equ word ptr 10[bp] dmaseg equ word ptr 8[bp] dmaoff equ word ptr 6[bp] xlt equ 0 ;tranalation table offset in dph dpb equ 8 ;disk parameter block offset in dph spt equ 0 ;sectors per track offset in dpb psh equ 15 ;physical shift factor offset in dpb mf equ byte ptr 5 ;***************************************************** ;* ;* SUP/RTM EQUATES ;* ;***************************************************** tracebit equ 0100H f_dispatch equ 142 ; MPM dispatch func # f_terminate equ 143 ; MPM terminate func # f_polldev equ 131 ; MPM polldevice func # f_flagwait equ 132 ; MPM flagwait func # f_flagset equ 133 ; MPM flagset func # p_flag equ word ptr 06H ; PD flag field p_name equ byte ptr 08H ; PD Name field p_uda equ word ptr 010H ; PD UDA Segment Addr p_cns equ byte ptr 020H ; PD console field pf_keep equ 02H ; KEEP bit in p_flag DELAY_F EQU 08DH DELAY_16_MS EQU 1 ; number of ticks to wait ;flag assignments TICK_FLAG EQU 1 SEC_FLAG EQU 2 C0IN_FLAG EQU 4 C0OUT_FLAG EQU 5 NMI_FLAG EQU 6 FDC_FLAG EQU 7 H_DISK_FLAG EQU 8 C1_IN_FLAG EQU 9 C1_OUT_FLAG EQU 10 C2_IN_FLAG EQU 11 C2_OUT_FLAG EQU 12 C3_IN_FLAG EQU 13 C3_OUT_FLAG EQU 14 C4_IN_FLAG EQU 15 C4_OUT_FLAG EQU 16 C5_IN_FLAG EQU 17 C5_OUT_FLAG EQU 18 C6_IN_FLAG EQU 19 C6_OUT_FLAG EQU 20 C7_IN_FLAG EQU 21 C7_OUT_FLAG EQU 22 C8_IN_FLAG EQU 23 C8_OUT_FLAG EQU 24 ;device # assignments for POLL DEV c0indev equ 0 ;console 0 input device c0outdev equ 1 ;console 0 output device l0outdev equ 2 ;list 0 output device eject ; FLOPPY MODE BITS two_sided equ 01b d_density equ 10b ; READ WRITE CONTROL STRING EQUATES D equ 1 C equ 2 H equ 3 R equ 4 N equ 5 EOT equ 6 GPL equ 7 DTL equ 8 ; FLOPPY DISK STATUS FILED EQUATES st0 equ 0 st1 equ 1 st2 equ 3 ; FLOPPY CONTROLER ADDRESSES fd_port equ 0c0h ; floppy base port fdcs equ fd_port ; status register fdcd equ fd_port + 1 ; data register fdma equ fd_port + 2 ; dma addr when write ints equ fd_port + 2 ; status register when read ser equ fd_port + 3 ; serial port ; FLOPPY CONTROLER FUNCTION DEFINITIONS f_s_rtk equ 02 ; single density read track f_d_rtk equ 42H ; double density read track f_spec equ 03 ; specify f_dsts equ 04 ; drive status f_rdat equ 06 ; read sector fm f_drdt equ 46H ; read sector mfm f_wrat equ 05 ; write sector fm f_wrdt equ 45H ; write sector mfm f_reca equ 07 ; recalibrate f_rsts equ 08 ; read status f_seek equ 0fh ; seek f_s_read_id equ 0ah ; single density read ID f_d_read_id equ 04ah ; double density read ID ; FLOPPY DRIVE CONTROL EQUATES spt1 equ 16 - 8 ; shugart 800s (8 ms) ; equ 16 - 3 ; shugart 850s (3 ms) ; equ 16 - 3 ; remex (3 ms) ; DPB EQUATES dspt equ 0 bsh equ 2 blm equ 3 exm equ 4 dsm equ 5 drm equ 7 al0 equ 9 al1 equ 10 cks equ 11 off equ 13 ; FLOPPY RETRY EQUATES RW_RECAL_COUNT EQU 5 RETRY_COUNT EQU 10 ; ERROR SYSTEM EQUATES PATH_ENTRY EQU word ptr 0 PATH_EXIT EQU word ptr 2 LAST_RETRY EQU word ptr 4 LAST_RETURN EQU word ptr 6 USE EQU word ptr 8 RETRY_SUM EQU word ptr 10 RETRY1_SUM EQU word ptr 12 RECAL_SUM EQU word ptr 14 PATH_ONLY EQU 4 ; STRUCTURES SIZES PATH_RETRY EQU 8 PATH_RETRY_HIST EQU 16 ; the extra bytes are for sid's display ; THIS IS FOR THE COMMAND AND STATUS CIRCULAR BUFFER RET_ADDR equ 4 ; bp and di ; THESE ARE FOR STATUS REGISTER 0 STR0_NR equ 08H ; not ready STR0_SE equ 20H ; seek end STR0_UNIT_MASK equ 03H ; unit mask ; THESE ARE FOR STATUS REGISTER 3 STR3_UNIT_SEL_0 EQU 1H STR3_UNITSEL_1 EQU 2H STR3_HEAD_ADDR EQU 4H STR3_TWO_SIDED EQU 8H STR3_TRACK_0 EQU 10H STR3_READY EQU 20H STR3_WRT_PROT EQU 40H STR3_FAULT EQU 80H FLOPPY_INT_DRIVEN EQU TRUE FLOPPY_POLE_DRIVEN EQU not FLOPPY_INT_DRIVEN ; THESE ARE FOR THE DISK ERRORS DRV_NOT_READY EQU 0 DRV_FAULT EQU 1 DRV_RECAL EQU 2 ERROR_MESSAGE_LENGTH EQU 25 MAIN_CONSOLE_INPUT EQU 0 eject ; READABILTY EQUATES ; PIC EQUATES: see pages 7-120 -> ... in the 1982 INTEL DATA CATALOG ; ; interupt structure ; ; MASTER PIC : ; IRQ0 = ; IRQ1 = DISK 2 ; IRQ2 = interfacer 3 receive ready ; IRQ3 = interfacer 3 transmite ready ; IRQ4 = DISK 1 ; IRQ5 = ; IRQ6 = ; IRQ7 = Slave input ; ; SLAVE PIC : ; IRQ0 = ; IRQ1 = Timer 0 ( mpm's tick ) ; IRQ2 = Timer 1 ( free ) ; IRQ3 = Timer 2 ( free ) ; IRQ4 = 9511 svrq ; IRQ5 = 9511 end ; IRQ6 = SS Tx int ; IRQ7 = SS Rx int DISABLE_INTS EQU 0FFH ; mask to turn off all interrupts MASTER_INT_MASK EQU 061H ; floppies, hard disk, x-mite and ; receive for interfacer 3, ; and slave pic SLAVE_INT_MASK EQU 07CH ; receive interrupts ; and the timer tick NS_EOI EQU 20H ; Non specific end of interrupt MASTER_PIC_PORT EQU 50H SLAVE_PIC_PORT EQU 52H MASTER_ICW_1 EQU 15H ; basic operational mode of chip MASTER_ICW_2 EQU 40H ; base of chips interrupt vectors MASTER_ICW_3 EQU 80H ; master/slave map MASTER_ICW_4 EQU 01H ; interrupt response mode SLAVE_ICW_1 EQU MASTER_ICW_1 SLAVE_ICW_2 EQU MASTER_ICW_2 + 8 SLAVE_ICW_3 EQU 07H ; slave I.D. number SLAVE_ICW_4 EQU MASTER_ICW_4 CON_IN_OFF EQU 4EH * 4 CON_IN_SEG EQU CON_IN_OFF + 2 CON_OUT_OFF EQU 4FH * 4 CON_OUT_SEG EQU CON_OUT_OFF + 2 GBI3_IN_OFF EQU 42H * 4 GBI3_IN_SEG EQU GBI3_IN_OFF + 2 GBI3_OUT_OFF EQU 43H * 4 GBI3_OUT_SEG EQU GBI3_OUT_OFF + 2 FLPY_OFF EQU 44H * 4 FLPY_SEG EQU FLPY_OFF + 2 H_DISK_OFF EQU 41H * 4 H_DISK_SEG EQU H_DISK_OFF + 2 TICK_OFF EQU 49H * 4 TICK_SEG EQU TICK_OFF + 2 ; COUNTER TIMER EQUATES CTC_CONTROL_WORD EQU 36H ; timer 0, two byte rl, mode 3 CTC_COUNT_LB EQU 3CH CTC_COUNT_HB EQU 82H ; ; these are for the compupro ; see pages 7-120 -- 7-129 of the intel component data catalog 82 port_base equ 50h ; for the system support board Timer_control equ port_base + 7 Timer_0 equ port_base + 4 int_base equ 49h * 4 timer_int_off equ word ptr .int_base timer_int_seg equ word ptr .int_base + 2 eject ; EQUATES FOR THE FLOPPY DISK CODE READABILITY KOSHER EQU 0H ERROR EQU 0FFH FIRST_CALL_FLAG EQU 1 N_MASK EQU 00001100B FLPY_CNT_MASK EQU 03H TWO_SIDE_BIT EQU 08H FDC_INT_CODE_MASK EQU 0C0H FDC_SENSE_DRV_STAT_MSK EQU 07H STATUS_N_FIELD EQU 6 N_FIELD_MASK EQU 03 START_NO_END EQU 01000000B EOT_END EQU 80H RECAL_MASK EQU 11111100B RECAL_TEST EQU 20H MAX_FLPY_TRKS EQU 76 NEW_CYLINDER EQU 2 DRIVE_MASK EQU 00FFH MAX_DRIVES EQU 2 HEAD_BIT EQU 4 DRV_HD_OFFSET EQU 1 SEEK_MASK EQU 11111100B VALID_SEEK EQU 00100000B SIST_RESULT_LEN EQU 2 INT_WAIT_POLL_BIT EQU 80H FDC_CMD_OUT_TEST EQU 080H FDC_CMD_IN_TEST EQU 0C0H MSTR_RQM EQU 80H MSTR_IO_DIRECTION EQU 40H RW_ERROR EQU 01H RW_MEDIA_CHANGE EQU 0FFH NO_MEDIA_ERROR EQU 0FFH SELDSK_ERROR EQU 0 RETRY EQU 1 ACCEPT EQU 2 IGNORE EQU 3 NO_TRACK EQU 0FFH ASCII_UPPER_CASE_MASK EQU 11011111B FDC_READ EQU 1 FDC_WRITE EQU 2 TRACK_10 EQU 10 eject ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. ; CP/M to host disk constants hstsiz EQU 1024 ;blocking/deblocking buffer size cpmsib EQU 1024/128 ;standard sectors in block fpysib EQU 2048/128 ;sectors in floppy disk block hblksiz EQU 4*1024 ;M20 block size hhstsiz EQU 512 ;M20 bytes per sector hdspt EQU 21 ;M20 physical sectors per head/track hhstspt EQU hdspt*8 ;M20 physical sectors per track hhstblk EQU hhstsiz/128 ;M20 CP/M records per physical sector hcpmspt EQU hhstblk*hhstspt ;M20 CP/M records per track hardsib EQU hblksiz/128 ;standard records in hard disk data block dskhd EQU 8 ;hard drive, 512-byte sectors s1dsm EQU ((77-2)*26)/cpmsib s2dsm EQU ((77-2)*2*26)/fpysib d1dsm EQU ((77-2)*2*26)/fpysib d2dsm EQU ((77-2)*2*2*26)/fpysib d3dsm EQU ((77-2)*4*15)/fpysib d4dsm EQU ((77-2)*2*4*15)/fpysib d5dsm EQU ((77-2)*8*8)/fpysib d6dsm EQU ((77-2)*2*8*8)/fpysib h0dsm EQU 97*hcpmspt/hardsib ;1st 97 tracks of M20 h1dsm EQU h0dsm ;2nd 97 tracks of M20 h2dsm EQU 49*hcpmspt/hardsib ;last 49 tracks of M20 ndsk EQU 5 ;number of logical disk drives csvflen equ 256/4 ;csv length for floppies alvflen equ (d6dsm+7)/8 ;alloc vector length for floppies alvh0ln EQU (h0dsm+7)/8 ;alv length for logical hard drive 0 alvh1ln EQU (h1dsm+7)/8 ;alv length for logical hard drive 1 alvh2ln EQU (h2dsm+7)/8 ;alv length for logical hard drive 2 eject ;***************************************************** ;* ;* CHARACTER I/O EQUATES ;* ;***************************************************** nvcons equ 4 ; compupro system support serial definitions gbssdv EQU 00000010b ;system support data available gbssmt EQU 00000001b ;system support transmit buffer empty gbssds EQU 10000000b ;system support data set ready gbssm equ port_base + 0eh ; compupro system support mode gbssc equ port_base + 0fh ; compupro system support command gbsss equ port_base + 0dh ; compupro system support status gbssd equ port_base + 0ch ; compupro system support data ; interfacer 3 port difinitions gbi3_base equ 10h gbi3_uart_data equ gbi3_base gbi3_uart_status equ gbi3_base + 1 gbi3_uart_mode equ gbi3_base + 2 gbi3_uart_cmd equ gbi3_base + 3 gbi3_xmit_int_stat equ gbi3_base + 4 gbi3_xmit_int_mask equ gbi3_base + 4 gbi3_rcv_int_stat equ gbi3_base + 5 gbi3_rcv_int_mask equ gbi3_base + 5 gbi3_select_reg equ gbi3_base + 7 select_mask equ 0f0h ; mask off the upper nibble ; of the iflag field sys_support equ 0f0h ; if the nibble is 0fh ; it means it's the system ; support board GBI3_INT_ENABLE EQU 0FFH ; ; THESE EQUATES ARE THE THE UART NUMBERS ON THE INTERFACER 3 BAORD. ; THEY ARE USED IN THE BUFFER DISCRIPTORS FOR THE INTERRUPT ; ROUTINES. USART_0 EQU 00H USART_1 EQU 01H USART_2 EQU 02H USART_3 EQU 03H USART_4 EQU 04H USART_5 EQU 05H USART_6 EQU 06H USART_7 EQU 07H SYS_SUP_USART EQU 0FH ; ; console i/o and status ports ; in and out status masks ; ; ; console 0 ; c0ioport equ gbssd c0stport equ gbsss c0inmsk equ gbssdv c0outmsk equ gbssmt C1IOPORT EQU GBI3_UART_DATA C1STPORT EQU GBI3_UART_STATUS C2IOPORT EQU GBI3_UART_DATA C2STPORT EQU GBI3_UART_STATUS C3IOPORT EQU GBI3_UART_DATA C3STPORT EQU GBI3_UART_STATUS C4IOPORT EQU GBI3_UART_DATA C4STPORT EQU GBI3_UART_STATUS C5IOPORT EQU GBI3_UART_DATA C5STPORT EQU GBI3_UART_STATUS C6IOPORT EQU GBI3_UART_DATA C6STPORT EQU GBI3_UART_STATUS C7IOPORT EQU GBI3_UART_DATA C7STPORT EQU GBI3_UART_STATUS C8IOPORT EQU GBI3_UART_DATA C8STPORT EQU GBI3_UART_STATUS eject inmsgs equ 0100h iflagn equ byte ptr 0 iflag equ byte ptr 1 imsgcnt equ word ptr 2 imsgout equ word ptr 4 iioport equ byte ptr 6 istport equ byte ptr 7 iusart equ byte ptr 8 iesc_cnt equ byte ptr 9 i_bit_mask equ byte ptr 10 i_xmit_qctl equ word ptr 11 ibuffer equ byte ptr 16 onmsgs equ 0080h oflagn equ byte ptr 0 oflag equ byte ptr 1 omsgcnt equ word ptr 2 omsgout equ word ptr 4 oioport equ byte ptr 6 ostport equ byte ptr 7 ousart equ byte ptr 8 oesc_cnt equ byte ptr 9 o_bit_mask equ byte ptr 10 o_rcv_qctl equ word ptr 11 obuffer equ byte ptr 16 ctrlc equ 003h ctrld equ 004h ctrlq equ 011h ctrls equ 013h XOFF EQU CTRLS XON EQU CTRLQ XON_XOFF_MODE EQU 20H XOFF_PENDING EQU 10H XOFF_SENT EQU 40H eject ; THESE ARE FOR THE HARD DISK WITH A DISK 2 CONTROLLER H_READ_F EQU 1 H_WRITE_F EQU 2 ; ; disk 2 ports STAT_CONTROL equ 0C8H DISK_2_DATA equ STAT_CONTROL + 1 DISK_2_SELECT equ 0F0H ; ; error code equates. ; all the error codes should grouped here to keep track of them ROUTINE_USE equ 2 phys_drvs equ 1 ; number of physical hard drive(s) ; supported track_0 equ 0 ; this is track 0 drive_sel_op equ 0 ; disk 2 drive select op code drive_0 equ 10h ; this is the first and only drive ; in the system seek_outer equ false seek_inner equ true home_count equ 512 ; ; status equates ATTN_NOT equ 80h TIME_OUT equ 40h CRC_ERROR equ 20h OVER_RUN equ 10h READY_NOT equ 08h SEEK_COMPLETE_NOT equ 04h WRITE_FAULT_NOT equ 02h TRACK0_NOT equ 01h ; control equates ; ATTN_NOT EQU 80H RUN EQU 40H OP2 EQU 20H OP1 EQU 10H OP0 EQU 08H FAULT_CLR EQU 04H USR1 EQU 02H USR2 EQU 01H ; ; command equates NULL_F equ 0C0H READ_DATA_F equ 0C8H WRITE_DATA_F equ 0D0H WRITE_HEADER_F equ 091H READ_HEADER_F equ 0E0H ; ; seek direction, op2(bit 5) of the command word sets the direction ; signal to the disk drive. INNER EQU 20H OUTTER EQU 00H ; ; these are the offsets for the read header command buffer TEST_CYLINDER EQU 0H TEST_HEAD EQU 1H TEST_SECTOR EQU 2H eject ; ; these are for the disk2 selector card ; see page 28 of the disk 2 manual for details about the bits. ; the patterns given are for ; d7 = write/read ; d6 = memory (vs io port operations) ; d5 = increment the memory address ; d4 = no wait states ; d3 - d0 = compliment of the dma device the selector channel will work with DISK_2_INT_PRIORITY equ 10 DISK_2_DMA_PRIORITY equ not DISK_2_INT_PRIORITY WRITE_TO_DISK equ 00100000b or ( DISK_2_DMA_PRIORITY and 0fh ) READ_FROM_DISK equ 10100000b or ( DISK_2_DMA_PRIORITY and 0fh ) ; ; these are for the read/write routines TRACK_OFFSET EQU 0 HEAD_OFFSET EQU 2 SECTOR_OFFSET EQU 4 DMA_OFFSET equ 6 ; ; these are the op codes for the disk 2 OP_DRIVE equ 080H OP_TRACK equ 088H OP_HEAD equ 090h OP_SECTOR equ 098h ; these are for the select code FIRST_FLOPPY EQU 0 FIRST_H_DISK EQU 2 eject ; ; system data area must preceed code ; area for 8080 model of the XIOS ; include sysdat.lib CSEG org 0c00h ; offset endsysdat ;***************************************************** ;* ;* XIOS HEADER ;* ;***************************************************** jmp init ;system initialization jmp entry ;xios entry point sysdat dw 0 ;Sysdat Segment supervisor rw 2 DSEG org 0c0ch tick db false ;tick enable flag ticks_sec db 60 ;# of ticks per second doorop db 0 ;global door open interrupt flag db 0,0 ;reserved nvcns db nvcons ;number of virtual consoles nccb db 12 ;total number of ccbs nlcb db 1 ;number of list devices ccb dw offset ccb0 ;offset of the first ccb lcb dw offset lcb0 ;offset of first lcb ;disk parameter header offset table dph_tbl dw offset dph1 ;A: dw offset dph2 ;B: dw offset dph3 ;C: dw offset dph4 ;D: dw offset dph5 ;E: dw 0,0,0 ;F:,G:,H: dw 0,0,0 ;I:,J:,K: dw 0 ;L: dw offset dpe5 ;M: dw 0,0,0 ;N:,O:,P: mem_alloc dw 0 end_xios_hdr equ offset $ CSEG org end_xios_hdr dispatch rw 2 error_base dw offset path_counter debugflag db debug ; 001h = clock tick not enabled ; 002h = interrupt vector not initializied eject ;***************************************************** ;* ;* UTILITY SUBROUTINES ;* ;***************************************************** ;==== pmsg: ;==== ; print message on current console until 0ffh ; input: BX = address of message ;put running processes console ;number in DL push stoppoll mov stoppoll,true mov dl,cur_screen ;DL = def console # ploop: mov cl,[bx] ; get next char cmp cl,0ffh! je pmsgret ; return if 0ffh ; CL = character push dx ;save device number push bx ;save string ptr call io_conout ;display it pop bx ;regain pop dx ;console inc bx ;bump to next char jmps ploop ;loop till done pmsg_ret: pop stoppoll ret ; end of message eject ;***************************************************** ;* ;* INTERRUPT ROUTINES ;* ;***************************************************** ;======== int_trap: ;unknown interrupts go here ... ;======== ; We will terminate the process that caused this ; after writing a message to the process's default ; console. If the process is in KEEP mode, we will ; force it to terminate anyway... ; ; We don't need to save any registers since we are ; not going to return to the process. mov ds,sysdat ; print first 6 chars of PD Name mov bx,rlr add bx,p_name mov byte ptr 6[bx],':' mov byte ptr 7[bx],0ffh call pmsg ; print Illegal Interrupt message pop ax sub ax,offset int_work + 1 mov bx,offset int_trpcode ; call outbyte mov bx,offset int_trp call pmsg ; terminate process mov bx,rlr and p_flag[bx],not pf_keep mov cx,f_terminate mov dx,0ffffh int 224 hlt eject ;====== nmiint: ;nonmaskable interrupt handler ;====== push ds mov ds,sysdat mov nmi_ssreg,ss ;may need to check for mov nmi_spreg,sp ; reentrant interrupt since mov ss,sysdat ; nmi's can'nt be disabled mov sp,offset nmi_tos push ax ! push bx push cx ! push dx push di ! push si push bp ! push es mov es,sysdat mov dx,nmi_flag mov cl,f_flagset call supif pop es ! pop bp pop si ! pop di pop dx ! pop cx pop bx ! pop ax mov ss,nmi_ssreg mov sp,nmi_spreg pop ds jmp intdisp ;iret from dispatcher eject ;====== h_disk_int: ; hard disk interrupt handler ;====== push ds mov ds,sysdat mov h_disk_ssreg,ss ;may need to check for mov h_disk_spreg,sp ; reentrant interrupt since mov ss,sysdat ; nmi's can'nt be disabled mov sp,offset h_disk_tos push ax ! push bx push cx ! push dx push di ! push si push bp ! push es mov es,sysdat mov dx, H_DISK_FLAG mov cl,F_FLAGSET call supif mov al, NS_EOI ; just reset the PIC's out MASTER_PIC_PORT,al pop es ! pop bp pop si ! pop di pop dx ! pop cx pop bx ! pop ax mov ss, h_disk_ssreg mov sp, h_disk_spreg pop ds jmp intdisp ;iret from dispatcher eject ;===== flint: ;floppy disk interrupt routine ;===== push ds mov ds,sysdat mov flpy_int_ssreg,ss mov flpy_int_spreg,sp mov ss,sysdat mov sp,offset flpy_int_tos push ax ! push bx push cx ! push dx push di ! push si push bp ! push es mov es,sysdat mov bx, offset flint_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] ; check the direction of data xfer from the FDC's main status port flint_lp: ; wait for the fdc to become ready for data xfer in al, FDCS test al, MSTR_RQM ! jz flint_lp mov last_main_status, al ; if the fdc want to send us data, it must be our expected status test al, MSTR_IO_DIRECTION ! jnz fdc_to_processor ; the fdc is expecting a command, so query the interrupt status mov bx, offset fdc_interrupt_stat call fdcsist ; check the not ready flag test fdc_interrupt_stat, STR0_NR jz check_seek_complete ; the not ready bit was set, ; must have been a change in ready status, tell the BDOS mov doorop, TRUE ; set the media flag in the DPH xor ax, ax ; index into the dph's mov al, fdc_interrupt_stat ; from the drive that and al, STR0_UNIT_MASK ; interrupted us shl ax, 1 mov bx, offset dph_tbl add bx, ax mov ax, [bx] mov bx, ax mov MF[bx], TRUE ; set the MF true jmps flint_exit check_seek_complete: test fdc_interrupt_stat, STR0_SE jz flint_exit ; this should never execute ; the FDC says the seek is complete ; do the flag set so the seek or recal code can start again fdc_to_processor: ; just set the flag mov dl, fdc_flag mov cl, f_flagset call supif flint_exit: mov al, NS_EOI ; just reset the PIC's out MASTER_PIC_PORT,al mov bx, offset flint_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop es ! pop bp pop si ! pop di pop dx ! pop cx pop bx ! pop ax mov ss,flpy_int_ssreg mov sp,flpy_int_spreg pop ds jmpf cs:dword ptr dispatch iret eject ;======= tickint: ;======= ; Interrupt handler for tick interrupts push ds mov ds,sysdat test intick,0ffh ;if in tick handler jnz no_stk_sav ; dont switch stack mov tick_ssreg,ss mov tick_spreg,sp mov ss,sysdat mov sp,offset tick_tos no_stk_sav: inc intick push ax ! push bx push cx ! push dx push di ! push si push bp ! push es mov es,sysdat mov al,NS_EOI out MASTER_PIC_PORT,al ; reset the master out SLAVE_PIC_PORT,al ; reset the slave ; check to set tick flag cmp tick,true jne tick_done mov dx,tick_flag mov cl,f_flagset call supif tick_done: ; check to set second flag dec tick_count jnz do_tick_flag mov tick_count,60 mov dx,sec_flag mov cl,f_flagset call supif do_tick_flag: pop es ! pop bp ;restore context pop si ! pop di pop dx ! pop cx pop bx ! pop ax dec intick ;if in tick <> 0 jnz no_stk_rst ; dont restore stack mov ss,tick_ssreg mov sp,tick_spreg no_stk_rst: pop ds ;force dispatch ;jmps intdisp ;======= intdisp: ;======= jmpf cs:dword ptr dispatch eject update_stl: ;update status line ;---------- ; ; check for room in the con-out circular buffer ; if ( omsgs - omsgcnt > st_len ) display the status line ; also check for not being in the middle of an escape sequence mov bx, offset oq0desc mov ax, onmsgs sub ax, omsgcnt[bx] cmp ax, ST_LEN ! jb stl_ret cmp oesc_cnt[bx], 0 ! je status_line_now stl__ret: ret status_line_now: ;fill in status line info here !! push es mov ax,ds! mov es,ax ; fill in screen number mov al,cur_screen mov bl,al add al,'0' mov sc_num,al ;set screen # in stat_line ; fill in console owner xor bh,bh ;set up index into ccb_tbl shl bx,1 mov si,ccb_tbl[bx] ;get ccb address mov si,[si] ;get pd addr from ccb add si,p_name ;move console owners mov di,offset st_name ; name into status line mov cx,4 cld rep movsw ; fill in open file drive letters mov di,offset st_open mov cx,6 ;6 drives mov al,' ' ;clear open file string rep stosb mov dx,open_vector mov di,offset st_open update0: shr dx,1! jnc update1 mov al,cl add al,'A' stosb ;store drive letter update1: inc cx or dx,dx! jnz update0 ;any more drives? ; send the status line to the console mov bx, offset oq0desc ; base of con_out disciptor mov si, offset st_line ; addr of status line mov cx, ST_len ; length of status line cld ; put the status line in the conout buffer st_line_lp: push cx mov cl, [si] inc si push si call con1 pop si pop cx loop st_line_lp pop es ret eject ;***************************************************** ;* ;* CONSOLE I/O INTERUPT ROUTINES ;* ;***************************************************** ;======= ci0_int: ; console 0 input interupt entry ;======= push ds ! mov ds,sysdat mov conin_int_ss,ss mov conin_int_sp,sp mov ss,sysdat mov sp,offset conin_int_tos push ax ! push bx ! push dx mov bx,offset iq0desc call intci mov al,NS_EOI ; reset the PIC's out MASTER_PIC_PORT,al out SLAVE_PIC_PORT,al pop dx ! pop bx ! pop ax mov ss,conin_int_ss mov sp,conin_int_sp pop ds iret eject ;======= co0_int: ; console 0 output interupt entry ;======= ; push ds ! mov ds,sysdat mov conout_int_ss,ss mov conout_int_sp,sp mov ss,sysdat mov sp,offset conout_int_tos push ax ! push bx ! push dx mov bx,offset oq0desc call intco mov al,NS_EOI ; reset the PIC's out MASTER_PIC_PORT,al out SLAVE_PIC_PORT,al pop dx ! pop bx ! pop ax mov ss,conout_int_ss mov sp,conout_int_sp pop ds iret eject ;======= gbi3_ci_int: ; intrerfacer 3 input interupt entry ;======= push ds ! mov ds,sysdat mov gbi3_in_int_ss,ss mov gbi3_in_int_sp,sp mov ss,sysdat mov sp,offset gbi3_in_int_tos push ax ! push bx ! push cx ! push dx ci_test_lp: in al, GBI3_RCV_INT_MASK ; get the interrupt mask ; interrogate the interrupt mask register, for the uart ; that interrupted us. mov bx, offset bit_mask_tbl mov cx, length bit_mask_tbl ci_lp: test al, [bx] jnz ci_found_it inc bx loop ci_lp jmps ci_exit ci_found_it: mov bx, offset icdesctbl shl cx, 1 ; times 2 for word values add bx, cx ; index into the table mov bx, [bx] ; get the address of the Q descriptor call intci ; call the handler jmps ci_test_lp ci_exit: mov al,NS_EOI ; reset the PIC out MASTER_PIC_PORT,al pop dx ! pop cx ! pop bx ! pop ax mov ss, gbi3_in_int_ss mov sp, gbi3_in_int_sp pop ds iret eject ;======= gbi3_co_int: ;interfacer 3 output interupt entry ;======= ; push ds ! mov ds,sysdat mov gbi3_out_int_ss,ss mov gbi3_out_int_sp,sp mov ss,sysdat mov sp,offset gbi3_out_int_tos push ax ! push bx ! push cx ! push dx co_test_lp: mov ah, gbi3_xmit_int_vec ; get the interrupt mask ; check the interrupt vector for interrupts we have enabled ; when an enabled interrupt has been found ; interrogate the interrupt mask register, for the uart ; that interrupted us. mov bx, offset bit_mask_tbl mov cx, length bit_mask_tbl co_lp: test ah, [bx] ! jz co_lp_1 in al, GBI3_XMIT_INT_STAT test al, [bx] ! jnz co_found_it co_lp_1: inc bx loop co_lp jmp co_exit co_found_it: mov bx, offset ocdesctbl shl cx, 1 ; times 2 for word values add bx, cx ; index into the table mov bx, [bx] ; get the address of the Q descriptor call intco ; call the handler jmps co_test_lp co_exit: mov al,NS_EOI ; reset the PIC out MASTER_PIC_PORT,al pop dx ! pop cx ! pop bx ! pop ax mov ss, gbi3_out_int_ss mov sp, gbi3_out_int_sp pop ds iret eject ;===== intci: ;===== ; ; ENTRY: bx = &queue control block ; ; iflag: 01h - process flag waiting (buf empty) ; 02h - status ready ; 04h - network i/o ; 08h - raw character i/o ; 10h - Xoff pending ; 20H - Xon/Xoff mode ; 40H - Xoff sent ; if the USART is on the interfacer 3 send out the USART select ; command. xor dh,dh mov al, IUSART[bx] cmp al, SYS_SUP_USART ! je sys_support_in out GBI3_SELECT_REG, al sys_support_in: ; get the USART status mov dl,istport[bx] ! in al,dx test al,c0inmsk ! jnz xon_xoff_test ; if the usart had an error just exit jmp iciexit xon_xoff_test: ; we must have a valid character, so input it mov dl,iioport[bx] ! in al,dx ; check for XON_XOFF_MODE test IFLAG[bx], XON_XOFF_MODE ! jz not_xon_xoff ; must be Xon\Xoff test IFLAG[bx], XOFF_PENDING ! jz cmp_xoff ; there must be an Xoff pending, so check for an Xon cmp al, XON ! jne not_xon_xoff ; must be the Xon, so clear the Xoff pending and start xmiter ; first in the receive control structure mov al, not XOFF_PENDING and IFLAG[bx], al ; then in the transmite control sturcture mov bx, I_XMIT_QCTL[bx] and OFLAG[bx], al ; turn off the pending flag ; start the xmiter mov al, O_BIT_MASK[bx] or gbi3_xmit_int_vec, al mov al, gbi3_xmit_int_vec out GBI3_XMIT_INT_MASK, al jmp iciexit cmp_xoff: cmp al, XOFF ! jne not_xon_xoff ; must be an Xoff, so post an Xoff pending, and stop the xmiter ; first the receive control structure mov al, XOFF_PENDING or IFLAG[bx], al ; then in the transmite control sturcture mov bx, I_XMIT_QCTL[bx] or OFLAG[bx], al ; turn on the pending flag ; stop the xmiter mov ah, O_BIT_MASK[bx] not ah mov al, gbi3_xmit_int_vec and al,ah out GBI3_XMIT_INT_MASK, al mov gbi3_xmit_int_vec, al jmp iciexit not_xon_xoff: ; get the count of the number of characters push cx ! mov cx,imsgcnt[bx] ; get the current position of the characters being read ; from the buffer push si mov si,imsgout[bx] ici4: ; set the ready status flag or iflag[bx],02h ici2: ; if we're not in Xon/Xoff mode ; and we're at the end of the buffer, bit buckett the character test IFLAG[bx], XON_XOFF_MODE ! jz ici5 ; must be in Xon/Xoff mode test IFLAG[bx], XOFF_SENT ! jnz ici5 ; there has not been an Xoff sent, so check the upper limit cmp cx, ( onmsgs - 20 ) ! jb ici5 ; we need to send an Xoff call intci_X_handler ici5: cmp cx,inmsgs ! jae ici3 ; there must be room in the buffer, so put the char in the buffer ; put the character at the current reading position + the number ; of characters put in the buffer but not yet read MOD the ; buffer size. add si,cx ! and si,inmsgs-1 mov ibuffer[bx+si],al ; bump the number of characters counter inc cx ! mov imsgcnt[bx],cx ; check if there is proccess waiting on this buffer test iflag[bx],01h ! jz icidone ici3: ; there must be a proccess waiting on this buffer, so do a flag set. push bp ! push di ! push es mov dl,iflagn[bx] mov cl,f_flagset call supif pop es ! pop di ! pop bp icidone: pop si ! pop cx iciexit: ret eject intci_X_handler: ; ; This handles sending an Xoff to what ever is sending data ; to this Usart buffer. It post the flags and shuts down ; the transmite side of the usart as long the Xoff is pending. ; It is the responsibility of the io_conin routine to start the ; interrupts again. ; ; ENTRY: bx = &input Q discriptor ; ; EXIT: none ; ; PRESERVED : ax, bx push ax ! push bx ; post the Xoff Sent flag in the input control sturcture ; before we point bx to the output Q control or IFLAG[bx], XOFF_SENT ; get the addr of the output Q descriptor mov bx, I_XMIT_QCTL[bx] ; put an XOFF into the output buffer push cx ; save the regs were going to use push si mov cx, OMSGCNT[bx] ; number of chars in the buffer mov si, OMSGOUT[bx] ; current output pointer add si,cx ; add um up and si, ONMSGS - 1 ; mod the buffer size mov byte ptr OBUFFER[bx+si],XOFF ; stuff in the Xoff inc cx ; bump the chars in buffer counter mov OMSGCNT[bx], cx ; put it back call intco pop si ; restore the invironment pop cx pop bx ! pop ax ret eject ;===== intco: ;===== ; ; ENTRY: bx = &queue control block ; ; oflag: 01h - process flag waiting (buffer full) ; 10h - Xoff pending ; 20h - Xon/Xoff mode xor dh,dh mov al, OUSART[bx] cmp al,SYS_SUP_USART ! je sys_support_out out GBI3_SELECT_REG, al sys_support_out: test OFLAG[bx], XON_XOFF_MODE ! jz sys_sup_out_1 test OFLAG[bx], XOFF_PENDING ! jz sys_sup_out_1 ; we must be in Xon/Xoff mode with an Xoff pending ; so don't send the character jmp icoexit sys_sup_out_1: ; check the usart status mov dl,ostport[bx] ! in al,dx test al,c0outmsk ! jz icoexit ; must be OK push cx ! mov cx,omsgcnt[bx] push si cmp cx,0 ! je icodone ; check for an empty buffer ; must have something to send mov si,omsgout[bx] ; get offset of char mov al,obuffer[bx+si] ; get the character mov dl,oioport[bx] ! out dx,al ; send char out inc si ! and si,onmsgs-1 ; point to next char mov omsgout[bx],si ; and stash it away dec cx ! mov omsgcnt[bx],cx ; decrement the the char count ; if there is a proccess waiting for this buffer ; do a flag set for it when the buffer is half empty cmp cx,(onmsgs/2) ! ja icodone test oflag[bx],01h ! jz icodone push bx ! push bp ! push di ! push es mov dl,oflagn[bx] mov cl,f_flagset call supif pop es ! pop di ! pop bp ! pop bx icodone: pop si ! pop cx ; check the transmite buffer for being empty cmp OMSGCNT[bx], 0 ! jne intco1 ; the transmite buffer is empty, so turn off the ; usarts interrupt system. ; the system support board must have the PIC transmite ; interrupt turned off. cmp OUSART[bx], SYS_SUP_USART jne turn_gbi3_xmit_off in al, SLAVE_PIC_PORT + 1 or al, 40h out SLAVE_PIC_PORT + 1, al jmps intco1 turn_gbi3_xmit_off: ; this code block is for the interfacer 3. ; It turns the interrupt mask off. mov ah, O_BIT_MASK[bx] not ah ; get ready to and off usart mov al, gbi3_xmit_int_vec ; get the current board mask and al,ah ; and out our usart out GBI3_XMIT_INT_MASK, al mov gbi3_xmit_int_vec, al ; put back into the vector intco1: icoexit: ret eject ;***************************************************** ;* ;* INITIALIZATION CODE AREA ;* ;***************************************************** ;==== init: ; XIOS system initialization routine. ;==== ; The INIT routine initializes all necessary ; hardware ; ; -called from SUP init. routine with CALLF ; ; -Interrupt 224 is reinitialized by SUP later ; -It is okay to turn on interrupts at any time ; a STI is performed immediately after RETF ; ; -Current Stack has about 10 levels here. Must do a ; local stack switch if more is needed. ; ; -If assembled (GENCMD'd) with 8080 model, ; CS=DS=Sysdat ; -If assembled with separate Code and Data, ; CS=Code (ORGed at 0) DS=Sysdat ; ; -This example shows 8080 model ; ; input: DS = sysdat segment address ; ;----------------------------------------------------- ; SYSTEM INITIALIZATION AREA ;----------------------------------------------------- cli ;disable interrupts mov sysdat,ds ; save sysdat for sysdat access ;place copy of SUPMOD in data segment ;into Code Segment (supervisor) mov ax,supmod mov supervisor,ax mov ax,supmod+2 mov supervisor+2,ax ;Make copy of Interrupt Routines ;access point to dispatcher in ;Code Segment mov ax,dispatcher mov dispatch,ax mov ax,dispatcher+2 mov dispatch+2,ax ;stack switch since we are doing ; i/o with polled devices when ; printing login message ; interrupts are known to be off ; here so no need to save flags, ; disable, and restore flags mov int_ssreg,ss mov int_spreg,sp cld ;set forward direction push ds! pop es push ds! pop ss mov sp,offset int_tos ; setup a vector routine for each possible interrupt mov cx,256 ;256 interrupt vectors mov di,offset int_work mov al,0cch ;opcode for INT 3 rep stosb ;store INT 3 in interrupt table ; Setup all interrupt vectors in low ; memory to address trap push ds xor ax,ax ! mov ds,ax ;set DS to zero test debugflag,002h ! jnz no_int_trap xor di,di ;low memory mov bx,offset int_work ;start of interrupt vector pointers mov cx,256 ;loop control setint: mov word ptr [di],bx mov word ptr 2[di],cs add di,004H ;next vector inc bx ;next routine loop setint ;... mov word ptr .0ch,offset int_trap ; setup INT 3 no_int_trap: eject ; setup character i/o interrupt addr ; console input slave irq 6 ( int 4eh ) mov word ptr .CON_IN_OFF, offset co0_int mov word ptr .CON_IN_SEG, cs ; console output slave irq 7 ( int 4fh ) mov word ptr .CON_OUT_OFF, offset ci0_int mov word ptr .CON_OUT_SEG, cs ; interfacer 3 input master irq 2 ( int 42h ) mov word ptr .GBI3_IN_OFF, offset gbi3_ci_int mov word ptr .GBI3_IN_SEG, cs ; interfacer 3 output master irq 3 ( int 43h ) mov word ptr .GBI3_OUT_OFF, offset gbi3_co_int mov word ptr .GBI3_OUT_SEG, cs ; setup hard disk i/o interrupt addr mov word ptr .H_DISK_OFF, offset h_disk_int mov word ptr .H_DISK_SEG, cs ; setup floppy disk i/o interrupt addr (VI5) mov word ptr .FLPY_OFF, offset flint mov word ptr .FLPY_SEG, cs ; setup clock timer interrupt addr mov word ptr .TICK_OFF, offset tickint mov word ptr .TICK_SEG, cs ; setup nonmaskable interrupt addr ; mov word ptr .0008h,offset nmiint ; mov word ptr .000ah,cs pop ds ;restore DS eject ;----------------------------------------------------- ; CHARACTER I/O INITIALIZATION ;----------------------------------------------------- ; initialize the console on the system support board MOV AL,01101110b ;async, 16x, 8 bits, no parity, even, 1 stop OUT gbssm,AL ;set up mode register 1 MOV AL,01111110b ;9600 baud OUT gbssm,AL ;set up mode register 2 MOV AL,00100111b ;trans. on, dtr low, rec. on, no break, ;...no reset, rts low OUT gbssc,AL ;set up command port ; initialize the interfacer three board mov dl, 0 mov cx, 8 gbi3_init_lp: mov al, dl inc dl call gbi3_init loop gbi3_init_lp ; turn on all the interfacer 3 receive interrupts mov al, GBI3_INT_ENABLE out GBI3_RCV_INT_MASK, al ; and turn off all the interfacer 3 transmite interrupts not al out GBI3_XMIT_INT_MASK, al ; initialize the bit vector mov gbi3_xmit_int_vec, al eject ;----------------------------------------------------- ; SUP/RTM INITIALIZATION ;----------------------------------------------------- ; ; interupt structure ; ; MASTER PIC : ; IRQ0 = ; IRQ1 = DISK 2 ; IRQ2 = interfacer 3 receive ready ; IRQ3 = interfacer 3 transmite ready ; IRQ4 = DISK 1 ; IRQ5 = ; IRQ6 = ; IRQ7 = Slave input ; ; SLAVE PIC : ; IRQ0 = ; IRQ1 = Timer 0 ( mpm's tick ) ; IRQ2 = Timer 1 ( free ) ; IRQ3 = Timer 2 ( free ) ; IRQ4 = 9511 svrq ; IRQ5 = 9511 end ; IRQ6 = SS Tx int ; IRQ7 = SS Rx int mov tick_count,60 ; ; set up the master PIC mov al,MASTER_ICW_1 out MASTER_PIC_PORT, al mov al,MASTER_ICW_2 ; interupts start at interupt 40h out MASTER_PIC_PORT + 1,al mov al,MASTER_ICW_3 ; only IRQ 7 has a slave attached out MASTER_PIC_PORT + 1, al mov al,MASTER_ICW_4 ; Set for 8088 mode out MASTER_PIC_PORT + 1, al mov al,DISABLE_INTS ; turn off all interupts for now out MASTER_PIC_PORT + 1, al ; ; set up the slave PIC mov al,SLAVE_ICW_1 out SLAVE_PIC_PORT, al mov al,SLAVE_ICW_2 ; base of the slave vectors AT 48H out SLAVE_PIC_PORT + 1,al mov al,SLAVE_ICW_3 ; slave ID number = 7 out SLAVE_PIC_PORT + 1, al mov al,SLAVE_ICW_4 ; 8088 mode out SLAVE_PIC_PORT + 1, al mov al, DISABLE_INTS ; turn off the ints for now out SLAVE_PIC_PORT + 1, al ; ; now set up the timer for 16.67 milliseconds ; timer 0, two byte rl, mode 3 mov al,CTC_CONTROL_WORD out timer_control, al ; timer 0's count mov al,CTC_COUNT_LB out timer_0, al mov al, CTC_COUNT_HB out timer_0, al ; ; now turn on the interupts ; ; system support usart receive only, ; interfacer three usarts, floppies, and hard disk mov al, MASTER_INT_MASK out MASTER_PIC_PORT + 1, al mov al,SLAVE_INT_MASK out SLAVE_PIC_PORT + 1, al sti ; ----------------------------------------------------- ; DISK I/O INITIALIZATION ;----------------------------------------------------- call fdc_init ; initialize the compupro disk system ; call h_init ;initialize MDISK mov cx,mdiskbase push es ! mov es,cx xor di,di mov ax,0e5e5h cmp es:[di],ax ! je mdisk_end mov cx,2000h rep stos ax mdisk_end: pop es ;----------------------------------------------------- ; INITIALIZATION EXIT ;----------------------------------------------------- ;print optional message on Console 0 mov bx,offset signon call pmsg ;restore stack mov ss,int_ssreg mov sp,int_spreg ;return back to BDOS retf gbi3_init: ; ; ENTRY: al = uart on interfacer 3 to initialize ; ; async, 16x, 8 bits, no parity, even, 1 stop ; 9600 baud ; ; EXIT: none out gbi3_select_reg, al MOV AL,01101110b OUT gbi3_uart_mode,AL ;set up mode register 1 MOV AL,01111110b ;9600 baud OUT gbi3_uart_mode,AL ;set up mode register 2 MOV AL,00100111b ;trans. on, dtr low, rec. on, no break, ;...no reset, rts low OUT gbi3_uart_cmd,AL ;set up command port ret eject ;***************************************************** ;* ;* ENTRY POINT CODE AREA ;* ;***************************************************** ;===== ================== entry: ; XIOS Entry Point ;===== ================== ; All calls to the XIOS routines enter through here ; with a CALLF. Must return with a RETF ; input: AL = function number ; CX = parameter ; DX = 2nd parameter ; DS = system data ; ES = user data area ; output: AX = BX = return cld ;clear D flag xor ah,ah shl ax,1 ;call routine mov bx,ax call functab[bx] mov bx,ax ;BX=AX retf ;All Done ;===== ====================== supif: ; Supervisor Interface ;===== ====================== ; ; input: CX = function # ; DX = parameter ; DS = parameter segment if address ; ES = user data area ; output: BX = AX = return ; CX = error code for RTM functions ; ES = return segment if address push es mov bx,rlr mov es,p_uda[bx] xor ch,ch callf cs:dword ptr supervisor pop es ret eject ;***************************************************** ;* ;* CHARACTER I/O CODE AREA ;* ;***************************************************** ;----------------------------------------------------- ; INTERUPT DRIVE CONSOLE STATUS ROUTINE ;----------------------------------------------------- ;======== io_const: ; Function 0: Console Status ;======== ; input: DL = device number ; output: AL = 0FFh if ready ; = 000h if not ready cmp dl, NVCONS ! jb v_icon_now xor dh, dh sub dl, NVCONS - 1 shl dx, 1 mov bx, offset icdesctbl add bx, dx mov bx, [bx] jmps io_con_st_1 v_icon_now: mov bx, offset iq0desc io_con_st_1: xor al, al test IFLAG[bx], 02h ! jz cst1 dec al cst1: ret conoutst: ; ; input ? called from rtm_poll ; ; output 00h if not ready ; 0ffh if ready ret eject ;======== io_conin: ; Function 1: Console Input ;======== ; input: DL = console device number ; output: AL = character or screen number ; AH = 000h if character returned ; = 0ffh if switch screen # returned call conin1 ;get character cmp al,ESC ;is char = escape code je conin01 ; yes xor ah,ah ;set character code ret conin01: ; determine if this is an escape char or escape sequence mov cx,200h ;loop count for second char conin02: push cx call io_const pop cx or al,al! jnz conin03 loop conin02 ;if no second char with in mov ax,esc ; required time ret ; return escape char conin03: call conin1 ;get second character sub al,'S' ;normalize function number cmp al,nvcons ;is screens number enabled jnb io_conin ; no mov ah,0ffh ;set switch screen code ret conin1: ;------ ; ; ENTRY: dl = concurrents console number call io_const cin1: pushf ! cli cmp imsgcnt[bx],0 ! jne cin2 or iflag[bx],01h popf ! push bx mov dl,iflagn[bx] mov cl,f_flagwait call supif ! pop bx jmps cin1 cin2: mov si,imsgout[bx] mov al,ibuffer[bx+si] inc si ! and si,inmsgs-1 mov imsgout[bx],si dec imsgcnt[bx] ! jz cin4 and i_flag[bx],0feh ; check for Xon/Xoff mode test IFLAG[bx], XON_XOFF_MODE ! jz cin5 ; must in Xon/Xoff mode test IFLAG[bx], XOFF_SENT ! jz cin5 ; An Xoff has been sent call cin_X_handler jmps cin5 cin4: and iflag[bx],0fdh cin5: popf ret eject cin_X_handler: ; ; This routine handles the process side of the Xon Xoff protocol ; ; ENTRY: bx = addr of Input Q control structure ; ; EXIT: none ; ; PRESERVED: bx ; check for at least half of the Q empty cmp IMSGCNT[bx], ( ONMSGS / 2 ) ! ja not_half_empty ; there must be some room in the Q, tell it to start sending again push bx ; clear the Xoff sent flag in the input Q control and IFLAG[bx], not XOFF_SENT ; get the output Q addr mov bx, I_XMIT_QCTL[bx] ; send the Xon mov cl, XON call con1 pop bx not_half_empty: ret eject ;========= io_conout: ; Function 2: Console Output ;========= ; input: CL = character ; DL = device # ; output: None ; ; if the console is 0 - 3 it means we're refering to a pontential ; virtual console. If the console is 4 - 11 it means we're refering ; to a physical uart on the interfacer three board. cmp dl, NVCONS ! jb v_con_now ; now get the buffer discriptor mov dh, 0 sub dl, NVCONS - 1 ; normailze for the sys sup board shl dx, 1 ; index into desc table mov bx, offset ocdesctbl add bx, dx mov bx, [bx] ; get the Q desc jmps conout01 v_con_now: cmp curscreen,dl ! jne v_con_exit mov bx, offset oq0desc jmps conout01 v_con_exit: ret conout01: cmp cl,esc ;does char = escape? jne conout1 mov oesc_cnt[bx],4 ; yes - setup escape counter conout1: con1: pushf ! cli ; check for room in the buffer push cx ! mov cx,omsgcnt[bx] cmp cx,onmsgs ! jb conout ; buffer must be full or oflag[bx],01h ; set proccess waiting flag pop cx ! popf push cx ! push bx mov dl,oflagn[bx] ; and wait for the buffer mov cl,f_flagwait call supif pop bx ! pop cx and oflag[bx],0feh jmps con1 conout: ;send character cmp oesc_cnt[bx],0 ! je conout11 dec oesc_cnt[bx] conout11: con2: ; put the character in the output buffer mov si,omsgout[bx] add si,cx ! and si,onmsgs-1 pop ax ! mov obuffer[bx+si],al inc cx ! mov omsgcnt[bx],cx dec cx ! jnz con3 ; check for the main system console cmp OUSART[bx], SYS_SUP_USART ! je sys_support_usart ; must be on the interfacer 3, so check the Xon/Xoff mode test OFLAG[bx], XON_XOFF_MODE ! jz not_xon_xoff_1 ; must be in Xon/Xoff mode, check for an Xoff pending test OFLAG[bx], XOFF_PENDING ! jz not_xon_xoff_1 ; there must be an Xoff pending, so exit jmp con3 not_xon_xoff_1: call intco ; call to interupt routine ; turn on the usart's interrupt mov al, O_BIT_MASK[bx] or gbi3_xmit_int_vec, al ; set our bit vector mov al, gbi3_xmit_int_vec out GBI3_XMIT_INT_MASK, al ; turn on the usarts interrupt jmps con3 sys_support_usart: call intco ; enable the system support usart transmite interrupt in al, SLAVE_PIC_PORT + 1 and al, 0bfh out SLAVE_PIC_PORT + 1, al con3: popf ret ;back to caller eject ;========= io_listst: ; Function 3: List Status ;========= ; input: DL = list device number ; output: AL = 0ffh if ready ; = 000h if not ready xor al,al ret ;back to caller ;======= io_list: ; Function 4: List Output ;======= ; input: CL = character ; dl = list device number ; output: None mov dl, 11 call io_conout ret ;back to caller ;======== io_auxin: ; Function 5: Auxilary Input Device ;======== ; input: None ; output: AL = character nop ! nop ! nop mov al,01ah eject ARG1 EQU BYTE PTR 1 GTYPE EQU BYTE PTR 2 ARG2 EQU BYTE PTR 3 ARG3 EQU BYTE PTR 4 ;========= io_auxout: ; Function 6: Auxilary Output Device ;========= ; ; This is now a general purpose function ; It is designed to be entered via function 50 ( S_BIOS ) ; by setting the function number to 6 ; ; ENTRY: dx = bios descriptor offset ; ds = bios descriptor segment ; ; EXIT: routine dependent ; ; bios discriptor: page 245 of the CCP/M programers guide ; +-------+---------------+---------------+ ; |FUNC 6 | CX | DX | ; +-------+---------------+---------------+ ; ; ch is used as an index into a table of 256 routines. ; ; G & G argument convention: ; ; CL CH DL DH ; +------+------+------+------+------+ ; | FUNC | arg1 | type | arg2 | arg3 | ; +------+------+------+------+------+ ; 0 1 2 3 4 xor ax,ax ; get the routine number mov al, ch shl ax, 1 mov bx, offset func_6_tbl ; index into the proper routine add bx,ax mov bx, [bx] call bx ret func_6_tbl: dw f6_dummy dw f6_setup dw f6_output dw f6_input dw f6_status eject f6_setup: ; ; this is a functional copy of the G & G function 6 implementation ; see page 67 of the G & G mpm 8/16 manual ; ; ENTRY: TYPE = 1 ; arg1 = console number ; arg2 = bits 0 - 3: select baud rate ; 0 = 9600 ; 1 = 110 ; 2 = 300 ; 3 = 600 ; 4 = 1200 ; 5 = 1800 ; 6 = 2400 ; 7 = 4800 ; 8 = 9600 ; 9 = 19.2 K ; bits 4 - 5: select parity ; 0 = none ; 1 = add parity ; 2 = even parity ; bit 6: selects number of stop bits ; 0 = 1 stop bit ; 1 = 2 stop bits ; bit 7: selects number of data bits ; 0 = 7 data bits ; 1 = 8 data bits ; arg3 = handshaking ; 0 = no handshaking ; 1 = DTR protocol ; 2 = Xon/Xoff protocol NO_PROTOCOL EQU 0 DTR_PROTOCOL EQU 1 XON_XOFF EQU 2 ; Handshaking cmp dh, NO_PROTOCOL ! jne check_xon_xoff_p ; Get the input Q descriptor xor ax,ax mov al, cl shl ax, 1 mov bx, offset icdesctbl add bx,ax mov bx, [bx] and IFLAG[bx], not XON_XOFF_MODE ; get the output Q descriptor xor ax,ax mov al, cl shl ax, 1 mov bx, offset ocdesctbl add bx,ax mov bx, [bx] and IFLAG[BX], not XON_XOFF_MODE jmp f6_setup_exit check_xon_xoff_p: cmp dh, XON_XOFF ! jne f6_setup_exit ; Get the input Q descriptor xor ax,ax mov al, cl shl ax, 1 mov bx, offset icdesctbl add bx,ax mov bx, [bx] or IFLAG[bx], XON_XOFF_MODE ; get the output Q descriptor xor ax,ax mov al, cl shl ax, 1 mov bx, offset ocdesctbl add bx,ax mov bx, [bx] or IFLAG[BX], XON_XOFF_MODE jmp f6_setup_exit f6_setup_exit: ret eject f6_output: cmp dl, 0 ! je no_bias1 add dl, NVCONS - 1 no_bias1: call io_conout ret f6_input: mov dl, cl cmp dl, 0 ! je no_bias2 add dl, NVCONS - 1 no_bias2: call conin1 ret f6_status: mov dl,cl cmp dl, 0 ! je no_bias3 add dl, NVCONS - 1 no_bias3: call io_const ret f6_dummy: ret ;========= io_switch: ; Function 7: Switch Screen ;========= ; input: DL = screen to switch to ; output: None mov curscreen,dl ;save screen number jmp update_stl ;update status line ;=========== io_statline: ; Function 8: Display Status Line ;=========== ; input: DX = 0 ; output: None jmp update_stl eject ;***************************************************** ;* ;* DISK IO CODE AREA ;* ;***************************************************** ;========= io_seldsk: ; Function 9: Select Disk ;========= ; input: CL = disk to be selected ; DL = 00h if disk has not been previously selected ; = 01h if disk has been previously selected ; output: AX = 0 if illegal disk ; = offset of DPH relative from ; XIOS Data Segment mov bx, offset io_seldsk_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov io_sd_drv, cl xor bx, bx mov bl,cl shl bx, 1 call select_tbl[bx] io_sd_exit: pushf! push ax! push bx mov bx, offset io_seldsk_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop bx! pop ax! popf ret eject f_dsk_sel: ; ; this routine translates the floppy cpm number to a controller ; number. Then calls the floppy disk select routine. ; ; ENTRY: cl = cpm logical drive ; dl[bit 0] = select code ; ; EXIT: ax = bx = &dph if every thing went ok ; ax = bx = 0 if there is no DPH for this drive sub cl, FIRST_FLOPPY call disk_sel ; select disk routine for the compupro ret h_dsk_sel: ; ; this cpm logical drive to a controller specific drive ; ; ENTRY: cl = cpm logical drive ; bx = offset into a dph table ; dl[bit 0] = select code ; ; EXIT: ax = bx = &dph if every thing went ok ; ax = bx = 0 if there is no DPH for this drive ; ; NOTE: this routine just indexes into the dph table ; and returns what ever is there. There is no protection mov ax, dph_tbl[bx] mov bx, ax mov current_reskew, 0 ret eject ;***************************************************** ; At the disk Read and Write function entrys ; all disk I/O parameters are on the stack ; and the stack at these entrys appears as ; follows: ; ; +-------+-------+ ; +14 | DRV | MCNT | Drive and Multi sector count ; +-------+-------+ ; +12 | TRACK | Track number ; +-------+-------+ ; +10 | SECTOR | Physical sector number ; +-------+-------+ ; +8 | DMA_SEG | DMA segment ; +-------+-------+ ; +6 | DMA_OFF | DMA offset ; +-------+-------+ ; +4 | RET_SEG | BDOS return segment ; +-------+-------+ ; +2 | RET_OFF | BDOS return offset ; +-------+-------+ ; SP+0 | RET_ADR | Local entry return address ; +-------+-------+ ; ; These parameters may be indexed and modifide ; directly on the stack and will be removed ; by the BDOS after the function is complete. ;***************************************************** eject ;======= io_read: ; Function 10: Read sector ;======= ; Reads the sector on the current disk, track and ; sector into the current dma buffer. ; input: parameters on stack ; output: AL = 000h if no error occured ; AL = 001h if an error occured ; = 0ffh if media density has changed mov bx, offset io_read_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov bp,sp mov al,drive cmp al,16! jb rdsk_ok ;check for valid drive mov al,1 ;return error if not ret rdsk_ok: mov idrive,al ;save DPH index in local variable xor ah,ah ;Index into the physical driver mov si,ax shl si,1 jmp read_tbl[si] ;jump to physical driver read routine read_m_dsk: ;---------- call mdisk_calc ;calculate byte address push es ;save UDA les di,dword ptr dmaoff ;load destination DMA address xor si,si ;setup source DMA address push ds ;save current DS mov ds,bx ;load pointer to sector in memory rep movsw ;execute move of 128 bytes.... pop ds ;then restore user DS register pop es ;restore UDA xor ax,ax ;return with good return code ret eject ;======== io_write: ; Function 11: Write disk ;======== ; Write the sector in the current Dma buffer ; to the current disk on the current ; track in the current sector. ; input: CL = 0 - Defered Writes ; 1 - non-defered writes ; 2 - def-wrt 1st sect unalloc blk ; output: AL = 000h if no error occured ; = 001h if error occured ; = 002h if read only disk ; = 0ffh if media density has changed mov bx, offset io_write_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov bp,sp ;set BP for indexing into IOPB mov al,drive cmp al,16! jb wdsk_ok ;check if valid drive mov al,1 ;return error if not ret wdsk_ok: mov idrive,al ;save DPH index in local variable xor ah,ah ;Index into the physical driver mov si,ax shl si,1 jmp write_tbl[si] ;jump to physical driver write routine write_m_dsk: ;----------- call mdisk_calc ;calculate byte address push es ;save UDA mov es,bx ;setup destination DMA address xor di,di push ds ;save user segment register lds si,dword ptr dmaoff ;load source DMA address rep movsw ;move from user to disk in memory pop ds ;restore user segment pointer pop es ;restore UDA xor ax,ax ;return no error ret mdisk_calc: ;---------- ; output: BX = sector paragraph address ; CX = length in words to transfer mov bx,track ;pickup track number mov cl,3 ;times eight for relative sector number shl bx,cl mov cx,sector ;plus sector add bx,cx ;gives relative sector number mov cl,3 ;times eight for paragraph of sector start shl bx,cl add bx,mdiskbase+1 ;plus base address of disk in memory mov cx,64 ;length for move of 1 sector mov al,mcnt xor ah,ah mul cx ;length * multi sector count mov cx,ax cld ret eject ; ; the compupro routines leap here after they set up si ; to point to the acctual read or write routine ; read_write: ;unskews and reads or writes multi sectors ;---------- ; input: SI = read or write routine address ; output: AX = return code mov bx, offset read_write_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov cl, idrive mov dl, FIRST_CALL_FLAG ; this is not the first select call io_seldsk ;get DPH address or bx,bx! jnz dsk_ok ;check if valid ret_error: mov al,1 ; return error if not ret dsk_ok: mov ax,xlt[bx] mov xltbl,ax ;save translation table address mov bx,dpb[bx] mov ax,spt[bx] mov maxsec,ax ;save maximum sector per track mov cl,psh[bx] mov ax,128 shl ax,cl ;compute physical record size mov secsiz,ax ; and save it call initdmatbl ;initialize dma offset table cmp mcnt,0 je rw_sects rw_1: mov ax,sector ;is sector < max sector/track cmp ax,maxsec! jb same_trk call rw_sects ; no - read/write sectors on track call initdmatbl ; reinitialize dma offset table inc track ; next track xor ax,ax mov sector,ax ; initialize sector to 0 same_trk: mov bx,xltbl ;get translation table address or bx,bx! jz no_trans ;if xlt <> 0 xlat al ; translate sector number no_trans: xor bh,bh mov bl,al ;sector # is used as the index shl bx,1 ; into the dma offset table mov ax,dmaoff mov dmatbl[bx],ax ;save dma offset in table add ax,secsiz ;increment dma offset by the mov dmaoff,ax ; physical sector size inc sector ;next sector dec mcnt ;decrement multi sector count jnz rw_1 ;if mcnt <> 0 store next sector dma rw_sects: ;read/write sectors in dma table mov al,1 ;preset error code xor bx,bx ;initialize sector index rw_s1: cmp current_reskew, 0 je no_reskew push bx! push ax mov ax, bx mov bx, current_reskew mov ah, 0 xlat al mov di, ax pop ax! pop bx jmps re_skew_1 no_reskew: mov di,bx re_skew_1: shl di,1 ;compute index into dma table cmp word ptr dmatbl[di],0ffffh je no_rw ;nop if invalid entry push bx! push si ;save index and routine address mov ax,track ;get track # from IOPB mov itrack,ax mov ax,di ;sector # is index value shr ax, 1 mov isector,al mov ax,dmatbl[di] ;get dma offset from table mov idmaoff,ax mov ax,dmaseg ;get dma segment from IOPB mov idmaseg,ax call si ;call read/write routine pop si! pop bx ;restore routine address and index or al,al! jnz err_ret ;if error occured return no_rw: inc bx ;next sector index cmp bx,maxsec ;if not end of table jb rw_s1 ; go read/write next sector err_ret: pushf! push ax! push bx push ax mov bx, offset read_write_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx! pop ax! popf ret ;return with error code in AL eject initdmatbl: ;initialize DMA offset table ;---------- mov di,offset dmatbl mov cx,maxsec ;length = maxsec + 1 sectors may inc cx ; index relative to 0 or 1 mov ax,0ffffh push es ;save UDA push ds! pop es rep stosw ;initialize table to 0ffffh pop es ;restore UDA ret ;=========== io_flushbuf: ; Function 12: Flush Buffer ;=========== ; input: None ; output: AL = 00h if no error occurs ; = 01h if error occurs ; = 02h if read/only disk xor al,al ;no need to flush buffer with ret ; no blocking/deblocking in XIOS eject ;***************************************************** ;* ;* SUP/RTM CODE AREA ;* ;***************************************************** ;-------- rtm_poll: ;check dev, if not ready, do rtm poll ;-------- ; Check poll condition. ; If not ready,Call MPM Poll Device Routine ; input: DL = device # push dx call io_polldev pop dx cmp al,0ffh je pllret cmp stoppoll,true je rtm_poll ;--------- rtm_poll1: ; do poll_dev with no pretest ;--------- mov cl,f_polldev jmp supif pllret: ret ;========== io_polldev: ; Function 13: Poll Device ;========== ; input: DL = device number ; output: AL = 000h if not ready ; = 0ffh if ready xor bh,bh! mov bl,dl shl bx,1 jmp polltbl[bx] ;ret patch: ;----- nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop patch1: ;----- nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop patch2: ;----- nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop patch3: ;----- nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop nop ! nop ! nop ! nop ! nop ! nop eject ;***************************************************** ;* ;* these are the physical drivers for the compupro ;* ;* pushed into an 8080 model ;* ;***************************************************** fdc_init: ; ; Floppy disk controller initialization. ; drive specify. ; Set up the values for the fdc's three internal timers. ; HUT (head unload time) = (0fh * 16ms) [240ms] ; SRT (step rate) = (0fh - 0dh * 1ms increments) [3ms] ; HLT (head load time) = (31H * 2ms) [98ms] ; and it sets up the DMA mode ; ND ( non-dma bit ) = DMA mode [0] ; ; see pages 41 and 38 of the compupro disk one manual ; ; input none ; output see above specs ; ; reg usage flags, ax, bx, cx ; ; Init the fdc mov bx, offset spec_str mov cx,length spec_str call send_cmd ; ; clear the FMT push es mov ax,ds mov es,ax xor ax,ax mov cx, length fmt mov di, offset fmt rep stosb pop es ; ; reset the path counter mov path_counter, 0 ; ; with gen ccpm there is no need for a dirbuf, check sum vec ; or the alloc vectors to be declared in the bios. ret eject disk_sel: ; ; disk select ; input cl = drive ; dl(0) = first select status ; output Ax = Bx = addr of dph, or 0 on error ; ; on first select as indicated by dl(0) = 0 from the bdos ; this routine figures out ; 1] what kind of floppy is in the drive ; 2] does a recal, homes the head ; 3] sets up the floppy mode table byte for this disk. ; on all calls it ; 1] sets up the current floppy mode byte. ; 2] sets up the select specific bytes in the r/w control string ; N, GPL, and DTL ; 3] sets up the dph's ; 3] returns the addr of the DPH ; NOTES: ; there is a DPB for each of the possible disk configurations. ; 1] SD 128 ; 2] DD 256 ; 3] DD 512 ; 4] DD 1024 ; 5-8] same as 1 - 4 with double sided disks. mov bx, offset disk_sel_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov c_drive,cl ; stash the drive were selecting test dl, FIRST_CALL_FLAG! jnz not_first_call ; first call ? call first_call cmp al, ERROR! jne ds_1 ; set up the error code for CCP/M mov ax, SELDSK_ERROR mov bx, ax jmp disk_sel_exit ds_1: ; put the current floppy mode byte in the floppy mode table xor ax,ax ; point to the fmbt table entry mov al, c_drive mov bx, offset fmt add bx, ax mov al, c_fmb ; put the byte in place mov [bx], al not_first_call: mov bx, offset fmt ; set up the current floppy mode byte xor ax, ax mov al, c_drive add bx,ax mov al, [bx] mov c_fmb, al ; ; set up the select specific physical read/write bytes and al, N_MASK ; get the N value from the mode byte shr al,1! shr al,1 ; and shift the N bit field to the lsbs mov ( rw_cs + N ), al ; then stuff the control string cmp al, 0! jne zero_dtl ; this checks for a SD floppy mov byte ptr rw_cs + DTL, 128 ; set for sd floppy jmps skip_zero_dtl zero_dtl: mov byte ptr rw_cs + DTL, 0 ; sts dtl for all DD operations skip_zero_dtl: ; ; set up the gpl mov ah, 0 ; get the gpl as per the mov bx, offset gpl_tbl ; N value in the FMB add bx,ax mov al,[bx] mov ( rw_cs + GPL ), al ; ; set up the re_skew vector mov bx, offset re_skew_tbl xor ax,ax mov al, c_fmb shr ax, 1 and ax, 0FEH add bx, ax mov ax, [bx] mov current_reskew, ax ; ; set up the dph mov bx, offset dph_tbl ; get the addr of the first dph xor ax,ax mov al, c_drive shl ax,1 add bx,ax ; point to the dph mov ax, [bx] mov dx,ax ; save the addr(dph) in dx mov bx, offset xtable ; get the translation table xor ax,ax ; from the fmb bytes/sec field mov al, c_fmb shr al,1! and al, 0FEH ; N value * 2 add bx,ax mov ax, [bx] mov bx,dx ; put the xlat table addr in dph mov xlt[bx],ax xor ax,ax ; get the proper dpb mov al, c_fmb shl ax, 1 ; index into the dpb table mov bx, offset drv_tbl add bx,ax mov ax,[bx] mov bx,dx ; and put it in the dph mov dpb[bx],ax ; ; get the offset to the proper DBH in ax and bx for ; return to the bdos. It returns 0 if there is no dph mov bx,dx mov ax,dx disk_sel_exit: pushf! push bx push ax mov bx, offset disk_sel_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx! popf ret eject read: ; ; calls the de-skewing routine mov bx, offset read_es mov ax,path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov si, offset read1 jmp read_write read1: ; ; get a local copy of the current floppy mode byte mov bx, offset read1_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov fdc_op, FDC_READ call phys_rw pushf! push ax! push bx push ax mov bx, offset read1_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx! pop ax! popf ret eject write: ; ; calls the de-skewing routine mov bx, offset write_es mov ax,path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov si, offset write1 jmp read_write write1: mov bx, offset write1_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] ; ; get a local copy of the current floppy mode byte mov fdc_op, FDC_WRITE call phys_rw pushf! push ax! push bx push ax mov bx, offset write1_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx! pop ax! popf ret eject phys_rw: ; ; physical read/write does the actual read or write from the floppy. ; ; ENTRY: fdc_op = FDC_READ if it's a read / FDC_WRITE if its write ; idrive = the drive to read or write ; itrack = the track to read or write from ; isector = the sector to read or write from ; idmaoff = the dma offset to read or write to or from ; idmaseg = the dma segment to read or write to or from ; ; N, GTL, and DTL in rw_cs are expected to be set up by disk_sel ; ; EXIT: al = KOSHER if everthing went OK ; al = RW_MEDIA_CHANGE if the media was changed ; al = RW_ERROR if an error other than a detectable ; media change occured. ; mov bx, offset phys_rw_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] ; this was added because Dave Brown said to. ; It just returns KOSHER if the BDOS calls a second time ; for a given drive after RW has returned a MEDIA ERROR cmp media_error, NO_MEDIA_ERROR je real_rw mov al, idrive cmp al, media_error jne real_rw mov al, RW_MEDIA_CHANGE jmp p_read_exit real_rw: mov rw_recals, RW_RECAL_COUNT mov rw_retries, RETRY_COUNT mov rw_retries_1, RETRY_COUNT ; make shure the drive is on line mov cl, idrive call check_drive_status cmp al, KOSHER! je phys_rw_1 jmp p_rw_err_exit phys_rw_1: rw_recal_lp: call rw_preamble cmp al, KOSHER ! je phys_rw_retries dec rw_retries_1 jnz rw_recal_lp mov al, RW_ERROR jmp p_read_exit phys_rw_retries: mov bx, offset rw_cs ; send out the command string mov cx, length rw_cs call send_cmd call int_wait ; wait for the read or write mov bx, offset rw_ss ; get the results of the read or write mov cx, length rw_ss call stat_ret ; ; check the interupt code mov al, rw_ss ; get the interupt code and al, FDC_INT_CODE_MASK ; check for start but no end cmp al, START_NO_END ! je end_cyl ; due to EOT jmps p_read_er end_cyl: cmp byte ptr (1 + rw_ss), EOT_END jne p_read_er mov al, KOSHER jmps p_read_exit p_read_er: dec rw_retries ; bump the retry counter jnz phys_rw_retries cmp rw_recals, RW_RECAL_COUNT jne skip_media_test mov al, c_fmb mov last_fmb, al mov cl, rw_cs + D call first_call cmp al, last_fmb! jne media_change skip_media_test: dec rw_recals ; bump the recal counter jz p_rw_err_exit mov cl, ( rw_cs + D ) ; get the drive call recal ; do a recal jmps rw_recal_lp p_rw_err_exit: mov al, RW_ERROR ! jmps p_read_exit media_change: mov al, ( D + rw_cs ) and al, FLPY_CNT_MASK mov media_error, al mov media_change_detected, RW_MEDIA_CHANGE mov al, RW_MEDIA_CHANGE p_read_exit: or al,al pushf! push ax! push bx push ax mov bx, offset phys_rw_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax xor ax,ax mov al, rw_retries mov LAST_RETRY[bx], ax mov ax, RETRY_COUNT sub al, rw_retries add RETRY_SUM[bx], ax mov ax, RW_RECAL_COUNT sub al, rw_recals add RECAL_SUM[bx], ax mov ax, RETRY_COUNT sub al, rw_retries_1 add RETRY1_SUM[bx], ax pop bx! pop ax! popf ret eject rw_preamble: ; ; Read/write pre-amble ; Sets up the current floppy mode byte from the floppy mode ; byte table. ; sets up D, C, H, R, and EOT fields of rw_cs ; sets up the 24 bit DMA address for the Disk1 ; Seeks to the proper track ; ; ENTRY: fdc_op = read or write opertion ; idrive = drive to prepare for the read or write ; itrack = cylinder to seek to ; isector = sector to read/write ; idmaoff = where to get or put it ; idmaseg = " " " " " " ; ; EXIT: the D,C, and H fields of the R/W control string are ; set up ; al = ERROR if there was a seek error ; al = KOSHER if everthing went OK mov bx, offset rw_preamble_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov al, isector ; put sector in the control strings inc al ; the bdos expects 0 relative sectors mov (R + rw_cs),al ; record mov (EOT + rw_cs),al ; and the end of track fields xor ax,ax mov al, idrive ; from the floppy mode table mov bx, offset fmt ; indexed off the drive numb add bx,ax ; A = 0 , B = 1, ... P = 15 mov al,[bx] mov c_fmb,al ; set up the read or write control byte cmp fdc_op, FDC_READ jne write_now test al, D_DENSITY ! jz read_sd mov rw_cs, F_DRDT jmps dma_now read_sd: mov rw_cs, F_RDAT jmps dma_now write_now: test al, D_DENSITY ! jz write_sd mov rw_cs, F_WRDT jmps dma_now write_sd: mov rw_cs, F_WRAT dma_now: lea bx, idmaoff ; set up the dma addr call d_dma call seek_trk ; do the seek pushf! push ax! push bx mov bx, offset rw_preamble_es mov LAST_RETURN[bx], ax mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop bx! pop ax! popf ret eject d_dma: ; ; DMA address load routine ; set up the floppy controllers dma address ; ; ENTRY: bx = dword of the dma address ( offset, segment ) ; ; EXIT: with the floppy controller's dma set up ; ; reg usage flags, ax, cx, and dx mov dx,2[bx]! mov ax,dx ; get the segment mov cl,4! shl ax,cl ; (para to bytes) shift add to offset mov cl,4! shr dh,cl ; save ms nibble add ax,[bx] ; add the bytes adc dh,0 ; carry into msn mov dl,al ; send 24 bits to controler mov al,dh! out F_DMA,al ; msb - lsb mov al,ah! out F_DMA,al mov al,dl! out F_DMA,al ret eject first_call: ; ; first call for a disk select. ; figures out what kind of disk is in the drive specified. ; Then it builds the Floppy mode byte(FMB). ; It sets the two sided bit, the density bit, and the sector ; size bits (2,3) if the disk is DD. ; then it puts the FMB in the floppy mode table (FMT). ; ; ENTRY: cl = drive to seek ; the drives are 0 relative. ; the head bit must set also ; ; EXIT: al = current floppy mode byte ( c_FMB ) ; al = ERROR if there was an error ; c_fmb is set mov bx, offset first_call_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] ; set up the retry counter mov fc_retries, RETRY_COUNT mov fc_retries_1, RETRY_COUNT ; reset the media error flag only when the drive it was set for ; get a new first call on it cmp media_error, NO_MEDIA_ERROR je fc_0 cmp cl, media_error jne fc_0 mov media_error, NO_MEDIA_ERROR fc_0: mov fc_c_drv, cl call recal ; home the head... cmp al, ERROR! jne fc_1 jmp first_call_exit fc_1: ; put head 0 over track 10 to sample the disk ; when I sampled the compupro DD 1024bytes/sector disk ; over track 0 it said it was a SD disk. mov al, fc_c_drv and al, FLPY_CNT_MASK mov ( seek_f_s + D ), al mov ( seek_f_s + C ), TRACK_10 fc_retry_lp: call p_seek cmp al, KOSHER ! je track_10_now dec fc_retries_1 jnz fc_retry_lp mov al, ERROR jmp first_call_exit track_10_now: mov c_fmb, 0 ; set entire current floppy mode byte to 0 ; get the number of sides from the FDD's status byte xor ax,ax ; get the address into the table mov bx, offset stat_reg_3_tbl mov al, fc_c_drv and al, FLPY_CNT_MASK add bx, ax test byte ptr [bx], TWO_SIDE_BIT jz single_sided or c_fmb, TWO_SIDED ; set two sided field single_sided: ; ; resolve the density either SD or DD ; we should be over track 0 due to the recal ; first call sd ; if the read id for an SD disk fails go into the ; DD routine. mov rdidcs, FS_READ_ID ; set read_id for sd mov al, fc__c_drv ; set the drive, head = 0 mov ( rdidcs + D ), al call read_id mov al, ST0[bx] ; get the results and al, FDC_INT_CODE_MASK ; mask for the interupt code cmp al, KOSHER ! jne try_dd jmps f_sel_com try_dd: mov rdidcs, FD_READ_ID mov al, fc_c_drv ; set the drive, head = 0 mov rdidcs + D, al call read_id mov al, ST0[bx] ; get the results and al, FDC_INT_CODE_MASK ; mask for the interupt code cmp al, KOSHER ! je sec_size dec fc_retries jnz single_sided mov al, ERROR! jmps first_call_exit sec_size: ; ; first set the d_density bit in the c_fmb ; get the sector size from the N field returned by the FDC or byte ptr c_fmb, D_DENSITY ; or in the DD bit in the FMB xor ax, ax ; get the end field mov al, rdidss + STATUS_N_FIELD and al, N_FIELD_MASK ; mask for validity mov bx, offset den_tbl ; index into the table add bx,ax mov al,[bx] ; the the mask or c_fmb,al ; or the mask into the current mode byte f_sel_com: mov al, c_fmb first_call_exit: pushf! push bx! push ax mov bx, offset first_call_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter mov ax, RETRY_COUNT sub al, fc_retries add RETRY_SUM[bx], ax mov ax, RETRY_COUNT sub al, fc_retries_1 add RETRY1_SUM[bx], ax pop ax mov LAST_RETURN[bx], ax pop bx! popf ret eject recal: ; ; this issues the recalibrate command to the drive ; specified in cl ; ; ENTRY: cl = drive to recal. Always head 0 ; ; EXIT: al = ERROR if there was an error ; al = KOSHER if everything went OK mov bx, offset recal_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov recal_er_cnt, RETRY_COUNT and cl, FLPY_CNT_MASK ; mask out the head bit (drive only) mov (rccs + D), cl ; stuff the control string mov recal_drive, cl ; stash the drive recal_er_lp: mov cl, recal_drive call check_drive_status cmp al, KOSHER! je recal_2 jmp recal_exit recal_2: ; to get here the drive must be on line ( READY and not FAULT ) mov bx, offset rccs ; send the recal command mov cx, length rccs call send_cmd call int_wait ; wait for the recal to happen mov al, fdc_interrupt_stat ; check for a kosher recal and al, RECAL_MASK cmp al, RECAL_TEST je recal_kosher_end ; exit if recal ok dec recal_er_cnt! jz recal_1 jmp recal_er_lp ; else loop up to the error recal_1: mov type_disk_error, DRV_RECAL mov al, ERROR! jmps recal_exit recal_kosher_end: mov al, KOSHER recal_exit: or al,al pushf! push ax! push bx push ax mov bx, offset recal_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax xor ax, ax mov al, recal_er_cnt mov LAST_RETRY[bx], ax mov ax, RETRY_COUNT sub al, recal_er_cnt add RETRY_SUM[bx], ax pop bx! pop ax! popf ret eject read_id: ; ; read ID expects the control byte and the drive/head byte ; set up before it is called. ; It returns with bx pointing to the returned status. ; ; ENTRY: al = drive and head code, same a rdidcs + D ; rdidcs ( read ID control string set up ) ; ; EXIT: bx = addr(rdidss) ( read ID status string ) ; al = KOSHER if it could read an ID ; al = ERROR if the drive was not ready mov bx, offset read_id_es mov ax,path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov cl, (rdidcs + D) call check_drive_status cmp al, ERROR! je read_id_exit mov bx, offset rdidcs ; send the read id command mov cx, length rdidcs call send_cmd call int_wait ; wait for the read mov bx, offset rdidss ; get the results mov cx, length rdidss call stat_ret mov al, KOSHER read_id_exit: mov bx, offset rdidss push bx! push ax mov bx, offset read_id_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx ret eject seek_trk: ; ; ; ENTRY: itrack = track to seek to ; c_fmb = should contain an accurate ; current floppy mode byte ; idrive = the drive we're supposed to do the seek on ; ; EXIT: al = KOSHER if everything went OK ; al = ERROR if the drive was off line or we didn't ; finish the seek over the track we wanted ; the D, C, and H fields of rw_cs are filled in by this routine mov bx, offset seek_trk_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] ; ; set up the retry count mov seek_retries, RETRY_COUNT seek_retry_lp: ; ; seek the track ; get the number of sides ; from the current floppy mode byte mov ax, itrack test c_fmb,two_sided jz ssided shr ax,1 ; two sided drive ; so seek trk/2 + bit(0) ; ssided: ; set the cylinder number for the seek and control string mov ( seek_f_s + C ), al ; set up the seek control mov ( C + rw_cs ), al ; now the read/write control ; ; get the drive and head from idrive mov al, idrive ; get the drive test c_fmb, TWO_SIDED jz side0 test itrack, 1 jz side0 ; set the head bit or al,HEAD_BIT ; set the head bit for the drive field mov byte ptr (H + rw_cs), 1 ; set the head field in the wr_cs jmps side1 side0: mov byte ptr (H + rw_cs), 0 side1: mov ( seek_f_s + D ), al ; stuff the seek drive field mov ( D + rw_cs ), al ; and the rw_cs drive field call p_seek ; call the seek primitive cmp al, KOSHER ! je seek_trk_exit dec seek_retries jnz sk_rt_1 jmps seek_trk_exit sk_rt_1: jmp seek_retry_lp seek_trk_exit: or al,al pushf! push ax! push bx push ax mov bx, offset seek_trk_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax xor ax, ax mov al, seek_retries mov LAST_RETRY[bx], ax mov ax, RETRY_COUNT sub al, seek_retries add RETRY_SUM[bx],ax pop bx! pop ax! popf ret eject p_seek: ; ; primitive seek sends the seek command to the fdc ; ; ENTRY: seek_f_s must be set up on the way in ; ; EXIT: al = KOSHER if everthing went OK ; al = ERROR if it could not find the right track ; or the drive was off line mov bx, offset p_seek_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] mov cl, ( seek_f_s + D ) call check_drive_status cmp al, KOSHER! je p_seek_1 jmps sk_exit p_seek_1: mov bx, offset seek_f_s ; send the seek command mov cx, length seek_f_s call send_cmd call int_wait ; wait for the seek mov al, fdc_interrupt_stat ; get status word 0 and al, SEEK_MASK ; and make shure its ok cmp al, VALID_SEEK ! je skst0_ok mov al, ERROR! jmps sk_exit skst0_ok: mov al, ( seek_f_s + C ) ; compare the cylinder we're over cmp al, ( fdc_interrupt_stat + 1) ; to the one we wanted mov al, KOSHER je sk_exit mov al, ERROR sk_exit: or al,al pushf! push ax! push bx push ax mov bx, offset p_seek_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx! pop ax! popf ret eject check_drive_status: ; ; Check drive status checks status of the drive passed in cl ; It returns cl untouched, the stat_reg_3_tbl[cl] is updated ; ; Entry: cl = drive to check the status of ; ; Exit: al = KOSHER if the drive is ready and on line ; al = ERROR if the drive is either not ready or ; is sending back a fault signal. ; cl = preserved push ax! push bx mov bx, offset check_drive_status_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] pop bx! pop ax push cx call sense_drive_stat ; make shure the drive is ready test al, STR3_READY jnz drv_rdy_recal_0 mov type_disk_error, DRV_NOT_READY mov al, ERROR! jmps cds_exit drv_rdy_recal_0: ; check for any fault status test al, STR3_FAULT mov al, KOSHER ; the move does not affect the flags jz cds_exit mov type_disk_error, DRV_FAULT mov al, ERROR cds_exit: or al,al pop cx push bx! push ax mov bx, offset check_drive_status_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx ret eject sense_drive_stat: ; ; Sense drive status ; This routine issues the sense drive status to the FDC for ; the FDD indicated in cl ; ; ENTRY: cl = the drive we want to query. ; ; EXIT: al = will contain status register 3 ; the stat_reg_3_tbl[cl] will contain al mov bx, offset sense_drive_stat_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] push cx ; query the FDC for the FDD's current status and cl, FDC_SENSE_DRV_STAT_MSK mov ( sdscs + D ), cl mov bx, offset sdscs mov cx, length sdscs call send_cmd mov bx,offset sdsst mov cx, length sdsst call stat_ret ; NOTE ; the status byte returned by this call has the fdd's ; ready line status bit in it (bit(3)) ; if the upper nibble = 2 the door is closed. ; else if the upper nibble = 4 the is open. ; stash the byte in the status register 3 table pop cx xor ax,ax ; get the address into the table mov bx, offset stat_reg_3_tbl mov al, cl and al, FLPY_CNT_MASK add bx, ax mov al, sdsst ; get the fdd's status mov [bx], al ; stash the status push bx! push ax mov bx, offset sense_drive_stat_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx], ax pop bx ret eject fdcsist: ; ; floppy disk controler sense interupt status. ; ; input bx pointing to a two byte area ; to return the status in. ; output the two bytes pointed to by bx will contain the ; results of the interupt status querry. ; NOTE: ; neither the recalibrate or the seek commands have ; a result phase. Therefore it is mandatory to issue the ; rdcsist command to properly terminate these commands. ; See the 8272 spec sheet for the details. pushf! push ax! push bx mov bx, offset fdcsist_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] pop bx! pop ax! popf ; poll on the fdc to be ready for data com fdcsist1: in al, FDCS test al, MSTR_RQM ! jz fdcsist1 ; if the fdc does not want data just wait until it does test al, MSTR_IO_DIRECTION ! jnz fdcsist1 ; issue the one byte command mov al, f_rsts! out fdcd,al mov cx,SIST_RESULT_LEN ; get the two byte result from the call stat_ret ; fdc pushf! push ax! push bx mov bx, offset fdcsist_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop bx! pop ax! popf ret eject send_cmd: ; ; send command expects : ; bx pointing to the command string ; cx containing the length of the command string ; ; it stomps al, increments bx, and decrements cx pushf! push ax! push bx mov bx, offset send_cmd_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] pop bx! pop ax! popf push bp! push di ; stash the return addr of who called us ; send_cmd_addr_buff[ ++cp_scab ] = ret_addr mov di, offset send_cmd_addr_buff ; get the base of buffer mov ax, cp_scab ; get the current position inc ax! inc ax ; bump to next postion mov cp_scab, ax ; stash new current position and ax, length send_cmd_addr_buff - 1 ; mod buffer size add di, ax ; add index to base mov bp, sp ; get the return addr mov ax, RET_ADDR[bp] ; off the stack mov [di],ax ; into the buffer ; poll on the fdc to be ready sc1: in al, FDCS test al, MSTR_RQM ! jz sc1 ; if the fdc does not want data just wait until it does test al, MSTR_IO_DIRECTION ! jnz sc1 ; stash the byte that we are sending out ; send_cmd_data_buff[ ++cp_scdb ] = command_string[bx] mov di, offset send_cmd_data_buff mov ax, cp_scdb inc ax mov cp_scdb, ax and ax, length send_cmd_data_buff - 1 add di, ax mov al, [bx] out fdcd, al mov [di], al inc bx loop sc1 pop di ! pop bp pushf! push bx! push ax mov bx, offset send_cmd_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx! popf ret eject stat_ret: ; ; status return ; input cx number of bytes to expect from the fdc ; bx addr of where to put the results ; ; output the location starting where bx was pointing ; for a length of cx will have the results from the ; fdc result phase pushf! push ax! push bx mov bx, offset stat_ret_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] pop bx! pop ax! popf push bp! push di ; stash the return addr of who called us ; stat_ret_addr_buff[ ++cp_srab ] = ret_addr mov di, offset stat_ret_addr_buff ; get the base of buffer mov ax, cp_srab ; get the current position inc ax! inc ax ; bump to next postion mov cp_srab, ax ; stash new current position and ax, length stat_ret_addr_buff - 1 ; mod buffer size add di, ax ; add index to base mov bp, sp ; get the return addr mov ax, RET_ADDR[bp] ; off the stack mov [di],ax ; into the buffer ; poll the fdc for the results str1: in al, FDCS test al, MSTR_RQM ! jz str1 ; does not want to send us data just keep on polling it. test al, MSTR_IO_DIRECTION ! jz str1 ; stash the byte that we are reading in ; stat_ret_data_buff[ ++cp_srdb ] = in (FDCD) mov di, offset stat_ret_data_buff mov ax, cp_srdb inc ax mov cp_srdb, ax and ax, length stat_ret_data_buff - 1 add di, ax in al, fdcd ; get the result status mov [di], al mov [bx], al inc bx loop str1 pop di! pop bp pushf! push bx! push ax mov bx, offset stat_ret_es mov ax, path_counter mov PATH_EXIT[bx], ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx! popf ret eject int_wait: ; ; interupt wait ; ; this routine does a flag wait on the fdc operation. cmp int_drv_flpy, TRUE! je real_int iw1: in al, ints ; poll the interupt status test al, INT_WAIT_POLL_BIT jz iw1 ret real_int: push ax! push bx! push cx! push dx push di! push si! push bp push es! push ds! mov bx, offset int_wait_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter mov dl, fdc_flag mov cl, f_flagwait call supif mov bx, offset int_wait_es mov ax, path_counter mov PATH_EXIT[bx], ax inc PATH_COUNTER pop ds! pop es pop bp! pop si! pop di pop dx! pop cx! pop bx! pop ax ret eject ;==== h_init: ;==== ; This routine is responsible for the initialzation of the ; hard disk sub-system. ; It initializes the memory structures, homes the head, ; and puts the disk2 and it's selector in a safe state. ; ; see page 4-11 of "M2301B/M2302B ; microdisk drives ; C/E Manual ; (lsi version) ; by FUJITSU ; and ; page 6 of the disk 2 manual mov bx, offset h_init_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter inc USE[bx] ; init the last physical sector to 0 mov last_cyl,track_0 ; do the initial read of the selector channel ; pages 27 and 28 of the disk 2 guide in al, DISK_2_SELECT ; init the header buffer d word mov header_buffer_addr, ds ; we only are supporting one drive ; wait for the drive to be come ready mov al, OP_DRIVE ; select drive command call send_command mov al, DRIVE_0 ; for this drive call send_data init_drv_rdy_lp: ; wait for the drive mov al, NULL_F call send_command call stat_return test al, READY_NOT jnz init_drv_rdy_lp call h_home jz init_exit or al, ERROR init_exit: mov bx, offset h_init_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter ret eject ;====== h_read: ;====== ; this routine is called by the bdos ; ; ENTRY: bp = &(IOPB on the stack) ; ; EXIT: OK if the read happened ok ; RW_ERROR if there was a read error ; mov bx, offset h_read_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] mov hard_op, H_READ_F mov si, offset h_rd_wt jmp read_write ;====== h_write: ;====== ; this routine is called by the bdos ; ; ENTRY: bp = &(IOPB on the stack) ; ; EXIT: OK if the read happened ok ; RW_ERROR if there was a read error ; mov bx, offset h_write_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] mov hard_op, H_WRITE_F mov si, offset h_rd_wt jmp read_write eject ;==== h_rd_wt: ;==== ; ; This is the main sector read routine for concurrent ; It does everything possible to make the read. ; The drive is assumed to be 0 and selected befor this operation. ; ; ENTRY: hd_op = READ if we want a read, WRITE if we want a write ; itrack = the track we want to read ; isector = the sector we want to read ; idmaoff = where to get or put the data ; idmaseg = where to get or put the data ; ; EXIT: al = OK if every thing went OK ; al = RW_ERROR (01) if there was a fatal error ; ; NOTE: ; when I implement the bad sector translation stuff ; it will translate the itrack and isector near the beginning ; of this routine. mov bx, offset h_rd_wt_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] mov bx, offset rw_track mov h_rd_wt_param_add, bx ; save the param pointer ; translate the track from concurrent to the track and ; sector for the hard disk ; this assumes 8 heads [ 0 - 7 ] mov ax, itrack and ax, 07 mov HEAD_OFFSET[bx], al mov ax, itrack mov cl, 3 shr ax, cl mov TRACK_OFFSET[bx], ax ; move the remaining params passed in from read_write to ; our local copies xor ax, ax mov al, isector mov SECTOR_OFFSET[bx], ax mov ax, idmaoff mov DMA_OFFSET[bx], ax mov ax, idmaseg mov DMA_OFFSET + 2 [bx], ax ; select the drive and ; check for the drive being ready. mov al, OP_DRIVE call send_command mov al, DRIVE_0 call send_data call stat_return and al, READY_NOT! jz rd_drv_rdy ; return fatal error if drive not ready or al, RW_ERROR ret rd_drv_rdy: mov re_homes, RETRY_COUNT / 2 re_home_lp: mov h_rd_wt_retries, RETRY_COUNT h_rd_wt_retry_lp: mov bx, h_rd_wt_param_add ; set up the parameter pointer ; seek to the proper track mov ax, TRACK_OFFSET[bx] mov cyl,ax call seek mov bx, h_rd_wt_param_add ; set up the parameter pointer ; set up the drive register mov al, OP_DRIVE ; select the drive/head register for call send_command ; for the subsequent out instruction xor ax,ax ; only drive 0 is valid mov ax, HEAD_OFFSET[bx] and ax, 0fH ; THE lower nibble in al is head or al, DRIVE_0 ; the upper nibble is the drive call send_data ; set up the track register mov al, OP_TRACK call send_command mov ax, TRACK_OFFSET[bx] ; select the track call send_data ; set up the head register mov al, OP_HEAD call send_command mov ax, HEAD_OFFSET[bx] ; select the head and ax,0fh call send_data ; set up the sector register mov al, OP_SECTOR call send_command mov ax, SECTOR_OFFSET[bx] ;select the sector and al, 0ffh call send_data ; set up the dma base and direction lea bx, DMA_OFFSET[bx] cmp hard_op, H_READ_F jne h_wrt_now mov al, READ_FROM_DISK jmps set_h_dma h_wrt_now: mov al, WRITE_TO_DISK set_h_dma: call set_disk_2_dma ; do the read or write cmp hard_op, H_READ_F jne h_wrt_now_1 mov al, READ_DATA_F jmps h_do_rd_wt h_wrt_now_1: mov al, WRITE_DATA_F h_do_rd_wt: call send_command ; get the status byte and deal with any errors call h_int_wait call stat_return test al, TIME_OUT or CRC_ERROR or OVER_RUN jnz h_rd_wt_err_1 and al, KOSHER jmp h_rd_wt_exit h_rd_wt_err_1: ; stash the last return error code from the controller mov h_rd_wt_error_type, al ; check the number of retries dec h_rd_wt_retries ! jnz rd_wt_retry_1 ; re-home the head after 5 retries dec re_homes ! jz re_home_1 call h_home jmp re_home_lp re_home_1: mov al, RW_ERROR jmp h_rd_wt_exit rd_wt_retry_1: ; if it's a crc_error or a data_over_run error just retry it test al, TIME_OUT! jnz rd_wt_retry_2 jmp h_rd_wt_retry_lp rd_wt_retry_2: ; must be a time out error, so check for the proper track mov bx, offset header_buffer_addr call read_header cmp al, KOSHER! je check_track or al, RW_ERROR jmps h_rd_wt_exit check_track: ; we h_rd_wt the header so check the track mov bx, h_rd_wt_param_add mov ax, TRACK_OFFSET[bx] mov bx, offset header_buffer ; if the head is over the proper cyinder/track just retry cmp ax, TEST_CYLINDER[bx]! jne wrong_track jmp h_rd_wt_retry_lp wrong_track: ; must have been over a wrong track. so update last track and re-seek mov ax, TEST_CYLINDER[bx] mov last_cyl,ax mov bx, h_rd_wt_param_add mov ax, TRACK_OFFSET[bx] mov cyl,ax call seek jmp h_rd_wt_retry_lp h_rd_wt_exit: pushf ! push bx ! push ax mov bx, offset h_rd_wt_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter mov ax, RETRY_COUNT sub al, h_rd_wt_retries add RETRY_SUM[bx],ax mov ax, RETRY_COUNT / 2 sub al, re_homes add RECAL_SUM[bx],ax pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject ;===== h_home: ;===== ; ; this routine will home the drive. ; If the track 0 not signal is true we do nothing. ; If it's false we try to home the heads. ; ; ENTRY: none ; ; EXIT: al = 0ffh on error ; al = 000h if things went OK. ; the zero flag refects al push bx mov bx, offset h_home_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop bx ; if were on track 0 we don't have to home mov al, OP_DRIVE call send_command mov al, DRIVE_0 call send_data call stat_return test al, TRACK_0_NOT jz home_exit ; we have do the home mov home_retries,RETRY_COUNT home_retry_lp: ; first find out what track we're over mov bx, offset header_buffer_addr call read_header cmp al, KOSHER ! je h_home_1 dec home_retries jnz home_retry_lp or al, ERROR jmp home_exit h_home_1: ; get the current cylinder xor ax,ax mov bx, offset header_buffer mov al, TEST_CYLINDER[bx] mov last_cyl, ax ; seek to cylinder 0 mov cyl, 0 call seek call stat_return test al, TRACK0_NOT ! jz end_home_lp ; try to issue the home command pushf! cli mov al, SEEK_OUTER ; set direction call send_command mov cx, HOME_COUNT ; and bang the port home_lp: in al, DISK_2_DATA ; over 256 reads from the data port loop home_lp ; at a rate between 3K and 3 Meg popf mov dl, ( 15 * DELAY_16_MS ) ; wait for the hard disk to recover mov cl, DELAY_F ; about 250 ms call supif call stat_return test al,TRACK0_NOT ! jz end_home_lp ; if we're still not over track 0 ; get away from the stop and try again mov cyl, 30 call seek dec home_retries jnz home_retry_lp or al, ERROR end_home_lp: mov last_cyl, TRACK_0 home_exit: pushf ! push bx ! push ax mov bx, offset h_home_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter mov ax, RETRY_COUNT sub al, home_retries add RETRY_SUM[bx],ax pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject ;=========== read_header: ;=========== ; ; This routine reads the three header bytes from the first sector ; encountered on the track the head is over. In essence it just ; drops the head and tells you the current cylinder, head, and sector. ; ; ENTRY: bx = &dma_add (dword) ; ; EXIT: ; al = ERROR if the drive was not ready. ; or if the header couldn't be ready with in ; RETRY_COUNT attempts. ; al = OK if every thing worked OK, ; the address pointed to by bx on the way in ; will contain the cylinder, head, and sector ; for the currently selected drive. push bx mov bx, offset read_header_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop bx mov rd_hdr_retries, RETRY_COUNT rd_hdr_retry_lp: ; set up the dma base and direction mov al, READ_FROM_DISK call set_disk_2_dma rd_hdr_drv_rdy: mov al, READ_HEADER_F call send_command call h_int_wait call stat_return ; check for no errors and al, TIME_OUT or CRC_ERROR or OVER_RUN test al,KOSHER! jz exit_read_header ; must have some sort of error dec rd_hdr_retries! jnz rd_hdr_retry_lp or al, ERROR exit_read_header: pushf ! push bx ! push ax mov bx, offset read_header_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter mov ax, RETRY_COUNT sub al, rd_hdr_retries add RETRY_SUM[bx],ax pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject ;==== seek: ;==== ; ; This routine seeks to the track passed in. ; It does no error recovery. It expects the READ or Write routine ; to take care of errors. ; ; ENTRY: cyl the cylinder we want to seek to. ; last_cyl the last cylinder we were on. ; The one the head should be over when we ; enter this routine. ; EXIT: there is no error code returned. ; if there is an error in the seek operation, the corresponing ; read or write will fail. When the corresponding read or write ; tries to recover it will do the seeks again. push bx ! push ax mov bx, offset seek_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop ax ! pop bx ; Is the current cylinder the one we want. mov ax, cyl cmp ax, last_cyl! je exit_seek jg requested_cyl_greater sub last_cyl,ax ; the last cylinder was greater mov al, OUTTER ; set the direction twords the edge call send_command jmps seek_1 requested_cyl_greater: xchg ax, last_cyl ; the cylinder we want is greater sub last_cyl,ax mov al, inner ; set the direction twords the spindle call send_command seek_1: mov cx, last_cyl ; last_cyl = abs( cyl - last_cyl ) pushf! cli ; critical region seek_2: in al, DISK_2_DATA ; bang the step port loop seek_2 popf ; set the null command and do a flag wait mov al, NULL_F call send_command call h_int_wait call stat_return mov ax,cyl ; update the cylinder register mov last_cyl,ax ; just to get back to here the seek must have happened. ; the only action I can take at this time would be a sample ; of the track field on the disk. This has to be done ; by the read or write any way. So return. exit_seek: pushf ! push bx ! push ax mov bx, offset seek_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject set_disk_2_dma: ; ; This routine sets the 24 bit dma from the dword ; pointed to by Bx. ; ; ENTRY: al = mode byte for the selector channel ; bx = &dma_add (dword) ; ; EXIT: the selector channel will have it's dma ; set to the value passed in. push bx ! push ax mov bx, offset set_disk_2_dma_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop ax ! pop bx push ax ; just do a read of the selector channel to make it ; ready for the subsequent writes in al, DISK_2_SELECT ; calculate the segment and offset into a 20 bit dma value mov dx, 2[bx]! mov ax,dx mov cl,4! shl ax,cl shr dh,cl add ax,[bx] adc dh,0 ; send this three (3) byte dma value to the disk 2 selector channel mov dl, al in al, DISK_2_SELECT mov al,dh! out DISK_2_SELECT,al mov al,ah! out DISK_2_SELECT,al mov al,dl! out DISK_2_SELECT,al ; send the mode control byte to the selector channel pop ax out DISK_2_SELECT,al pushf ! push bx ! push ax mov bx, offset set_disk_2_dma_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject ;======== h_int_wait: ;======== ; ; This routine waits for the interrupt ; ; ENTRY: none ; ; EXIT: none jmps real_h_int int_wait_lp: call stat_return test al, ATTN_NOT jnz int_wait_lp jmp h_int_wait_exit real_h_int: push ax! push bx! push cx! push dx push di! push si! push bp push es! push ds! mov bx, offset h_int_wait_es mov ax, path_counter mov PATH_ENTRY[bx], ax inc path_counter mov dl, H_DISK_FLAG mov cl, F_FLAGWAIT call supif mov bx, offset h_int_wait_es mov ax, path_counter mov PATH_EXIT[bx], ax inc PATH_COUNTER pop ds! pop es pop bp! pop si! pop di pop dx! pop cx! pop bx! pop ax h_int_wait_exit: ret eject send_command: ; ; this routine sends a command to the DISK2 controller ; ; ENTRY: al = command ; ; EXIT: none ; ; bx must be preserved push ax ! push bx mov bx, offset send_command_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop bx ! pop ax push bp! push di push ax ; stash the return addr of who called us ; send_cmd_addr_buff[ ++cp_scab ] = ret_addr mov di, offset hsend_cmd_addr_buff ; get the base of buffer mov ax, hcp_scab ; get the current position inc ax! inc ax ; bump to next postion mov hcp_scab, ax ; stash new current position and ax, length hsend_cmd_addr_buff - 1 ; mod buffer size add di, ax ; add index to base mov bp, sp ; get the return addr mov ax, RET_ADDR+2[bp] ; off the stack mov [di],ax ; into the buffer ; stash the byte that we are sending out ; send_cmd_data_buff[ ++cp_scdb ] = command_string[bx] mov di, offset hsend_cmd_data_buff mov ax, hcp_scdb inc ax mov hcp_scdb, ax and ax, length hsend_cmd_data_buff - 1 add di, ax pop ax out STAT_CONTROL, al mov [di], al pop di! pop bp pushf ! push bx ! push ax mov bx, offset send_command_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject send_data: ; ; this routine sends a data byte to the DISK2 controller ; ; ENTRY: al = data byte ; ; EXIT: none ; ; NOTE: bx must be preserved push ax ! push bx mov bx, offset send_data_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop bx ! pop ax push bp! push di push ax ; stash the return addr of who called us ; send_cmd_addr_buff[ ++cp_scab ] = ret_addr mov di, offset send_data_addr_buff ; get the base of buffer mov ax, cp_sdab ; get the current position inc ax! inc ax ; bump to next postion mov cp_sdab, ax ; stash new current position and ax, length send_data_addr_buff - 1 ; mod buffer size add di, ax ; add index to base mov bp, sp ; get the return addr mov ax, RET_ADDR+2[bp] ; off the stack mov [di],ax ; into the buffer ; stash the byte that we are sending out ; send_cmd_data_buff[ ++cp_sddb ] = command_string[bx] mov di, offset send_data_data_buff mov ax, cp_sddb inc ax mov cp_sddb, ax and ax, length send_data_data_buff - 1 add di, ax pop ax out DISK_2_DATA, al mov [di], al pop di! pop bp pushf ! push bx ! push ax mov bx, offset send_data_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject stat_return: ; ; this routine just returns the status from the disk controler ; ; ENTRY: none ; ; EXIT: al = current status from the disk controller push bx ! push ax mov bx, offset stat_return_es mov ax, path_counter mov PATH_ENTRY[bx],ax inc path_counter inc USE[bx] pop ax ! pop bx push bp! push di ; stash the return addr of who called us ; stat_ret_addr_buff[ ++cp_srab ] = ret_addr mov di, offset hstat_ret_addr_buff ; get the base of buffer mov ax, hcp_srab ; get the current position inc ax! inc ax ; bump to next postion mov hcp_srab, ax ; stash new current position and ax, length hstat_ret_addr_buff - 1 ; mod buffer size add di, ax ; add index to base mov bp, sp ; get the return addr mov ax, RET_ADDR[bp] ; off the stack mov [di],ax ; into the buffer ; stash the byte that we are sending out ; stat_ret_data_buff[ ++cp_srdb ] = in (FDCD) mov di, offset hstat_ret_data_buff mov ax, hcp_srdb inc ax mov hcp_srdb, ax and ax, length hstat_ret_data_buff - 1 add di, ax in al, STAT_CONTROL ; get the result status mov [di], al pop di! pop bp pushf ! push bx ! push ax mov bx, offset stat_return_es mov ax, path_counter mov PATH_EXIT[bx],ax inc path_counter pop ax mov LAST_RETURN[bx],ax pop bx ! popf ret eject ;***************************************************** ;* ;* SYSTEM DATA AREA ;* ;***************************************************** endcode rw 0 DSEG $ org (offset endcode + 1) and 0fffeh ;org to an even word offset ;current UDA for MPM calls udaseg rw 1 ;----------------------------------------------------- ; XIOS FUNCTION TABLE ;----------------------------------------------------- functab dw io_const ; 0-console status dw io_conin ; 1-console input dw io_conout ; 2-console output dw io_listst ; 3-list status dw io_list ; 4-list output dw io_auxin ; 5-aux in dw io_auxout ; 6-aux out dw io_switch ; 7-switch screen dw io_statline ; 8-display status line dw io_seldsk ; 9-select disk dw io_read ;10-read dw io_write ;11-write dw io_flushbuf ;12-flush buffer dw io_polldev ;13-poll device signon db cr,lf db 'CCP/M-86 V2.0 for CompuPro (12/16/82)',cr,lf db '=====================================',cr,lf,0ffh nmi_tos rw 0 ;use signon message area for nmi_ssreg rw 1 ; nonmaskable interrupt stack nmi_spreg rw 1 nmi_instk rb 1 rw 48 tick_tos rw 0 tick_ssreg rw 1 tick_spreg rw 1 tick_count db 60 intick db 0 rw 48 int_tos rw 0 int_ssreg rw 1 int_spreg rw 1 rw 48 flpy_int_tos rw 0 flpy_int_ssreg rw 1 flpy_int_spreg rw 1 rw 48 h_disk_tos rw 0 h_disk_ssreg rw 1 h_disk_spreg rw 1 ; ; console input interupt stack area rw 32 conin_int_tos rw 0 conin_int_ss rw 1 conin_int_sp rw 1 ; ; console output interupt stack area rw 32 conout_int_tos rw 0 conout_int_ss rw 1 conout_int_sp rw 1 ; ; interfacer 3 input interrupt stack area rw 32 gbi3_in_int_tos rw 0 gbi3_in_int_ss rw 1 gbi3_in_int_sp rw 1 ; ;interfacer 3 output interupt stack area rw 32 gbi3_out_int_tos rw 0 gbi3_out_int_ss rw 1 gbi3_out_int_sp rw 1 int_trp db ' Uninitialized interrupt, code = 0' int_trpcode db 'xxH',cr,lf,0ffh eject ;***************************************************** ;* ;* CHARACTER DATA AREA ;* ;***************************************************** org ((offset $) +1) and 0FFFEH ccb_tbl dw offset ccb0 ;ccb offset table dw offset ccb1 dw offset ccb2 dw offset ccb3 dw offset ccb4 ccb0 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 10 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb1 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 1 ;virtual console number dw 0 ;reserved dw 0002h ;state flags dw 10 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb2 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 2 ;virtual console number dw 0 ;reserved dw 0003h ;state flags dw 10 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb3 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 3 ;virtual console number dw 0 ;reserved dw 0003h ;state flags dw 10 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb4 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb5 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb6 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb7 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb8 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb9 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb10 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved ccb11 dw 0 ;owner dw 0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource db 0 ;reserved db 0 ;virtual console number dw 0 ;reserved dw 0000h ;state flags dw 0 ;max buffer size K bytes dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0,0,0 ;reserved dw 0 ;reserved eject lcb0 dw 0,0,0,0 ;reserved db 0ffh,0ffh ;mimic, msource cur_screen db 0 ;current screen number esc_cnt db 0 ;count of chars following escape st_line db esc,'j' ;save cursor position db 0,0,0,0 db esc,'x1' ;enable status line db esc,'Y' ;direct cursor address db 31+25,31+1 ; line 25, column 1 db 'Console=' sc_num db '0 ' ;ascii screen number st_name db ' ' ;console owner process name db ' ' st_open db 'xxxxxx' ;drives with open files ; db ;additional bytes for status line db esc,'k' ;restore cursor position db 0,0,0,0 db 0ffh st_len equ (offset $-1) - (offset st_line) local_drv_trk dw 0 type_disk_error db 0 drive_to_ascii_tbl db 'ABCDEFGHIJKLMNOP' binary_to_hex_ascii db '0123456789ABCDEF' error_message_tbl dw offset drv_not_ready_m dw offset drv_fault_m dw offset recal_err_m ; 1 2 ; 1234567890123456789012345 drv_not_ready_m db 'DRIVE NOT READY ' drv_fault_m db 'DRIVE FAULT ' recal_err_m db 'DURING RECAL ATTEMPT ' eject ; interupt driven console input data gbi3_xmit_int_vec db 0 icdesctbl dw offset iq0desc ; system support dw offset iq1desc ; interfacer 3 from here on down dw offset iq2desc dw offset iq3desc dw offset iq4desc dw offset iq5desc dw offset iq6desc dw offset iq7desc dw offset iq8desc ocdesctbl dw offset oq0desc ; system support dw offset oq1desc ; interfacer 3 from here on down dw offset oq2desc dw offset oq3desc dw offset oq4desc dw offset oq5desc dw offset oq6desc dw offset oq7desc dw offset oq8desc org ((offset $) + 0fh) and 0fff0h iq0desc db c0in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c0ioport ; int out data port db c0stport ; int out stat port db SYS_SUP_USART db 0 ; escape count db 0 ; interrupt control mask dw offset oq0desc ; complimentery Q control rb 3 rb inmsgs oq0desc db c0out_flag db 0 rb 4 db c0ioport db c0stport db SYS_SUP_USART db 0 ; escape count db 0 dw offset iq0desc rb 3 rb onmsgs iq1desc db c1in_flag ; int flag number db 0 rb 4 ; int message count db c1ioport ; int out data port db c1stport ; int out stat port db USART_0 db 0 db 01 dw oq1desc rb 3 rb inmsgs oq1desc db c1out_flag db 0 rb 4 db c1ioport db c1stport db USART_0 db 0 db 01 dw offset iq1desc rb 3 rb onmsgs iq2desc db c2in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c2ioport ; int out data port db c2stport ; int out stat port db USART_1 db 0 db 02 dw offset oq2desc rb 3 rb inmsgs oq2desc db c2out_flag db 0 rb 4 db c2ioport db c2stport db USART_1 db 0 db 02 dw offset iq2desc rb 3 rb onmsgs iq3desc db c3in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c3ioport ; int out data port db c3stport ; int out stat port db USART_2 db 0 db 04 dw offset oq3desc rb 3 rb inmsgs oq3desc db c3out_flag db 0 rb 4 db c3ioport db c3stport db USART_2 db 0 db 04 dw offset iq3desc rb 3 rb onmsgs iq4desc db c4in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c4ioport ; int out data port db c4stport ; int out stat port db USART_3 db 0 db 08 dw offset oq4desc rb 3 rb inmsgs oq4desc db c4out_flag db 0 rb 4 db c4ioport db c4stport db USART_3 db 0 db 08 dw offset iq4desc rb 3 rb onmsgs iq5desc db c5in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c5ioport ; int out data port db c5stport ; int out stat port db USART_4 db 0 db 10h dw offset oq5desc rb 3 rb inmsgs oq5desc db c5out_flag db 0 rb 4 db c5ioport db c5stport db USART_4 db 0 db 10h dw offset iq5desc rb 3 rb onmsgs iq6desc db c6in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c6ioport ; int out data port db c6stport ; int out stat port db USART_5 db 0 db 20h dw offset oq6desc rb 3 rb inmsgs oq6desc db c6out_flag db 0 rb 4 db c6ioport db c6stport db USART_5 db 0 db 20h dw offset iq6desc rb 3 rb onmsgs iq7desc db c7in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c7ioport ; int out data port db c7stport ; int out stat port db USART_6 db 0 db 40h dw offset oq7desc rb 3 rb inmsgs oq7desc db c7out_flag db 0 rb 4 db c7ioport db c7stport db USART_6 db 0 db 40h dw offset iq7desc rb 3 rb onmsgs iq8desc db c8in_flag ; int flag number db 0 ; int flag rb 4 ; int message count db c8ioport ; int out data port db c8stport ; int out stat port db USART_7 db 0 db 80h dw offset oq8desc rb 3 rb inmsgs oq8desc db c8out_flag db 0 rb 4 db c8ioport db c8stport db USART_7 db 0 db 80h dw offset iq8desc rb 3 rb onmsgs bit_mask_tbl db 80h, 40h, 20h, 10h, 08h, 04h, 02h, 01h ; bit_mask_tbl_1 db 01h, 02h, 04h, 08h, 10h, 20h, 40h, 80h eject ;***************************************************** ;* ;* SUP/RTM DATA AREA ;* ;***************************************************** stoppoll dw false ;disallows poll_device ;for internal printing ;of strings when true polltbl dw offset io_const dw offset conoutst dw 0 dw 0 ; ; scratch area ; dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch eject ;***************************************************** ;* ;* Compupro disk driver data area ;***************************************************** spec_str db fspec, 0dfh, 70 fc_c_drv db 0 ; local drive code for first call c_drive db 0 ; current drive were selecting ; sides density bytes/sec drv_tbl dw dpbs1 ; ss, sd, 128 dw dpbs2 ; ds, sd, 128 dw 0 dw 0 dw 0 dw 0 dw dpbd1 ; ss, dd, 256 dw dpbd2 ; ds, dd, 256 dw 0 dw 0 dw dpbd3 ; ss, dd, 512 dw dpbd4 ; ds, dd, 512 dw 0 dw 0 dw dpbd5 ; ss, dd, 1024 dw dpbd6 ; ds, dd, 1024 gpl_tbl db 7 ; SD 128 byte sectors db 1ah ; DD 256 byte sectors db 0fh ; DD 512 byte sectors db 08 ; DD 1024 byte sectors sdscs db f_dsts, 0 ; sense drive status control string sdsst db 0 ; sense drive status status word three ; STATUS REGISTER 3 TABLE, these reflect the most current ; status of the floppy drives. stat_reg_3_tbl db 0 ; floppy 0, ( A ) db 0 ; floppy 1, ( B ) db 0 ; floppy 2, ( C ) db 0 ; floppy 3, ( D ) rb 12 ; for more floppies latter... eject ; ; FLOPPY MODE BYTE AND TABLE ; B B B B B B B B ; 7 6 5 4 3 2 1 0 ; \/ + ------- set = two sided, reset = single sided ; | +---------- set = double density, reset = single density ; +------------- 0 = 128 byte sectors ; 1 = 256 byte sectors ; 2 = 512 byte sectors ; 3 = 1024 byte sectors last_fmb db 0 c_fmb db 0 ; the current floppy mode byte fmt rb 16 ; floppy mode table den_tbl db 0000b ; 128 bytes/sector db 0100b ; 256 bytes/sector db 1000b ; 512 bytes/sector db 1100b ; 1024 bytes/sector fdc_op db 0 rdid_cs db 0, 0 ; ^ ^ ; | +--- head and drive ; +------ control byte ; S S S ; r/w status return string ; T T T ; 0 1 2 C H R N rdid_ss db 0, 0, 0, 0, 0, 0, 0 rccs db freca, 0 ; re-cal control string rcst db 0, 0 ; re_cal return status recal_drive db 0 ; the drive recal is working with eject ; D C H R N EOT GPL DTL rw_cs db 0, 0, 0, 0, 0, 0, 0, 0, 0 ; read_write_control_string ; S S S ; r/w status return string ; T T T ; 0 1 2 C H R N rw_ss db 0, 0, 0, 0, 0, 0, 0 seek_f_s db f_seek, 0, 0 ; ^ ^ ; | +--- new cylinder number ; +------ head and drive seek_st db 0, 0 ; returned status of the seek ; ^ ^ ; | +--- present cylinder number ; +------ fdc status byte 0 fdc_interrupt_stat db 0, 0 ; returned status from an interrupt ; ^ ^ ; | +--- present cylinder number ; +------ fdc status byte 0 last_main_status db 0 ; last read from fdc's main ; status port when the FDC had ; a request for the master media_error db 0 ; used by phys_rw and first select media_change_detected db 0 ; used by phys_rw io_sd_drv db 0 ; io seldsk drive eject ; ERROR STRUCTURES int_drv_flpy db TRUE ; this byte turns on the interrupt ; drive for the floppies return_error db TRUE ; this byte tells the bios to return ; any errors to the BDOS, instead of ; going through the operator re-try ; query stuff. ; ; THESE COUNTERS ARE USED BY THE INTERFACER 3 INTERRUPT HANDLER ci_never db 0 ; these are counter to reflect co_never db 0 ; takeing a path we shouldn't recal_er_cnt db 0 rw_recals db 0 rw_retries db 0 rw_retries_1 db 0 seek_retries db 0 fc_retries db 0 ; first call retries for first recal fc_retries_1 db 0 path_counter dw 0 io_seldsk_es rs PATH_RETRY_HIST io_read_es rs PATH_RETRY_HIST io_write_es rs PATH_RETRY_HIST read_write_es rs PATH_RETRY_HIST disk_sel_es rs PATH_RETRY_HIST first_call_es rs PATH_RETRY_HIST read_id_es rs PATH_RETRY_HIST read_es rs PATH_RETRY_HIST read1_es rs PATH_RETRY_HIST write_es rs PATH_RETRY_HIST write1_es rs PATH_RETRY_HIST phys_rw_es rs PATH_RETRY_HIST rw_preamble_es rs PATH_RETRY_HIST recal_es rs PATH_RETRY_HIST seek_trk_es rs PATH_RETRY_HIST p_seek_es rs PATH_RETRY_HIST fdcsist_es rs PATH_RETRY_HIST int_wait_es rs PATH_RETRY_HIST flint_es rs PATH_RETRY_HIST check_drive_status_es rs PATH_RETRY_HIST sense_drive_stat_es rs PATH_RETRY_HIST send_cmd_es rs PATH_RETRY_HIST stat_ret_es rs PATH_RETRY_HIST ; these are for the hard disk h_init_es rs PATH_RETRY_HIST h_home_es rs PATH_RETRY_HIST h_read_es rs PATH_RETRY_HIST h_write_es rs PATH_RETRY_HIST h_rd_wt_es rs PATH_RETRY_HIST read_header_es rs PATH_RETRY_HIST seek_es rs PATH_RETRY_HIST set_disk_2_dma_es rs PATH_RETRY_HIST h_int_wait_es rs PATH_RETRY_HIST send_command_es rs PATH_RETRY_HIST send_data_es rs PATH_RETRY_HIST stat_return_es rs PATH_RETRY_HIST eject send_cmd_addr_buff rw 100h cp_scab dw 0 ; current position send_cmd_data_buff rb 400h cp_scdb dw 0 ; current position stat_ret_addr_buff rw 100h cp_srab dw 0 ; current position stat_ret_data_buff rb 400h cp_srdb dw 0 ; current position read_error_type db 0 write_error_type db 0 h_send_cmd_addr_buff rw 100h hcp_scab dw 0 ; current position h_send_cmd_data_buff rb 400h hcp_scdb dw 0 ; current position send_data_addr_buff rw 100h cp_sdab dw 0 ; current position send_data_data_buff rb 400h cp_sddb dw 0 ; current position hstat_ret_addr_buff rw 100h hcp_srab dw 0 ; current position hstat_ret_data_buff rb 400h hcp_srdb dw 0 ; current position h_rd_wt_error_type db 0 header_buffer_addr dw offset header_buffer dw 0 header_buffer db 0,0,0,0,0 ; should only need three eject ;***************************************************** ;* ;* IOPB for disk I/O ;* ;***************************************************** iopb dd loczero ;pointer for 8089 opcode db 0 ;operation code idrive db 0 ;disk drive id itrack dw 0 ;track for I/O head db 0 ;head for I/O isector db 0 ;sector for I/O count db 0 ;number of sectors for I/O retcode db 0 ;return code from operation retmask db 0 ;return code mask retries db 0 ;number of error retries idmaoff dw 0 ;DMA offset address idmaseg dw 0 ;DMA segment address seclen dw 0 ;sector length dw 0,0,0 ;work area ;***************************************************** ;* ;* DISK DATA AREA ;* ;***************************************************** xltbl dw 0 ;translation table address maxsec dw 0 ;max sectors per track secsiz dw 0 ;sector size dmatbl rw 50 ;dma address table eject ; ; Disk Parameter block header table ; Currently set up for ; A floppy ; B floppy ; C hard disk ; D hard disk ; E hard disk ; M Memory disk ; N - P Not Avail select_tbl: dw offset f_dsk_sel ; first floppy dw offset f_dsk_sel dw offset h_dsk_sel ; first hard disk dw offset h_dsk_sel dw offset h_dsk_sel read_tbl dw offset read dw offset read dw offset h_read dw offset h_read dw offset h_read dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset read_m_dsk dw offset ret_error dw offset ret_error dw offset ret_error write_tbl dw offset write dw offset write dw offset h_write dw offset h_write dw offset h_write dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset ret_error dw offset write_m_dsk dw offset ret_error dw offset ret_error dw offset ret_error ; ; these are used by the compupro routines ; floppy disk 0 dph1 dw xltd3, 0000h ; translate table dw 0000h, 0000h ; scratch area dw dpbd6 ; disk paramater table dw 0ffffh, 0ffffh ; check, alloc vectors dw 0ffffh ; dir buf control block dw 0ffffh ; data buff cntrl block dw 0ffffh ; hash table segment ; floppy disk 1 dph2 dw xltd3, 0000h ; translate table dw 0000h, 0000h ; scratch area dw dpbd6 ; disk paramater table dw offset dph1_csv ; check sum vector dw 0ffffh ; alloc vectors dw 0ffffh ; dir buf control block dw 0ffffh ; data buff cntrl block dw 0ffffh ; hash table segment ; hard disk outter edge dph3 dw 0000h, 0000h ; translate table dw 0000h, 0000h ; scratch area dw dpbh1 ; disk paramater table dw 0ffffh ; check sum vector dw 0ffffh ; alloc vectors dw 0ffffh ; dir buf control block dw 0ffffh ; data buff cntrl block dw 0ffffh ; hash table segment ; hard disk middle dph4 dw 0000h, 0000h ; translate table dw 0000h, 0000h ; scratch area dw dpbh2 ; disk paramater table dw 0ffffh ; check sum vector dw 0ffffh ; alloc vectors dw 0ffffh ; dir buf control block dw 0ffffh ; data buff cntrl block dw 0ffffh ; hash table segment ; hard disk near spindle dph5 dw 0000h, 0000h ; translate table dw 0000h, 0000h ; scratch area dw dpbh3 ; disk paramater table dw 0ffffh ; check sum vector dw 0ffffh ; alloc vectors dw 0ffffh ; dir buf control block dw 0ffffh ; data buff cntrl block dw 0ffffh ; hash table segment ; mdisk dpe5 dw xlt5,0000h ;Translate Table dw 0000h,0000h ;Scratch Area dw dpb5 ;Dsk Parm Block dw offset dph2_csv ; check sum vector dw 0ffffh ; Alloc Vectors dw 0ffffh ;Dir Buff Cntrl Blk dw 0 ;Data Buff Cntrl Blk dw 0 ;Hash Table Segment dph1_csv rb 256 / 4 + 1 ; ( drm/4 ) + 2 dph2_csv rb 256 / 4 + 1 ; ( drm/4 ) + 2 ; DISKDEF 5,0,7,,1024,127,32,0,0 ; ; 1016: 128 Byte Record Capacity ; 127: Kilobyte Drive Capacity ; 32: 32 Byte Directory Entries ; 0: Checked Directory Entries ; 128: Records / Extent ; 8: Records / Block ; 8: Sectors / Track ; 0: Reserved Tracks ; dpb5 equ offset $ ;Disk Parameter Block dw 8 ;Sectors Per Track db 3 ;Block Shift db 7 ;Block Mask db 0 ;Extnt Mask dw 126 ;Disk Size - 1 dw 31 ;Directory Max db 128 ;Alloc0 db 0 ;Alloc1 dw 0 ;Check Size dw 0 ;Offset db 0 ;Phys Sec Shift db 0 ;Phys Sec Mask xlt5 equ 0 ;No Translate Table eject ; THESE ARE THE SKEW TABLES ; sector translation tables (for floppy disks) xtable DW (Offset xlts) ;single 128 DW (Offset xltd1) ;double 256 DW (Offset xltd2) ;double 512 DW (Offset xltd3) ;double 1024 xlts DB 0,6,12,18,24,4,10,16,22,2,8,14,20 ; physical skew = 6 DB 1,7,13,19,25,5,11,17,23,3,9,15,21 ; 26 sectors/track ; 128 byte sectors xltd1 db 0,9,18,1,10,19,2,11,20,3,12,21 ; physical skew = 9 db 4,13,22,5,14,23,6,15,24,7,16,25 ; 26 sectors/track db 8,17 ; 256 byte sectors xltd2 db 0,4,8,12,1,5,9,13 ; physical skew = 4 db 2,6,10,14,3,7,11 ; 15 sectors/track ; 512 byte sectors xltd3 DB 0,3,6,1,4,7,2,5 ; physical skew = 3 ; 8 sectors per track ; 1024 byte sectors ; THESE ARE THE RE-SKEW TABLES current_reskew dw 0 re_skew_tbl dw offset re_skew_26_2 ; S.D. 128 bytes/sec dw offset re_skew_26_2 ; D.D. 256 bytes/sec dw offset re_skew_15_2 ; D.D. 512 bytes/sec dw offset re_skew_8_2 ; D.D. 1024 bytes/sec re_skew_26_3 db 0,3,6,9,12,15,18,21,24,1,4,7,10 db 13,16,19,22,25,2,5,8,11,14,17,20,23 re_skew_26_2 db 0,2,4,6,8,10,12,14,16,18,20,22,24 db 1,3,5,7,9,11,13,15,17,19,21,23,25 re_skew_15_2 db 0,2,4,6,8,10,12,14 db 1,3,5,7,9,11,13 re_skew_8_2 db 0,2,4,6 db 1,3,5,7 eject ; ; params for h_rd_wt hard_op db 0 rw_track dw 0 rw_head dw 0 rw_sector dw 0 rw_dma_off dw 0 rw_dma_seg dw 0 ; ; these are the current retry counters h_rd_wt_retries db 0 re_homes db 0 write_retries db 0 rd_hdr_retries db 0 home_retries db 0 ; ; The disk 2 controler wants a control word and delivers a status ; word for each operation disk2_control db 0 disk2_status db 0 ; BIT CTL STATUS ; (write) (read) ;-------------------------------------------------------- ; 7 attn_not attn_not ; 6 run time out ; 5 op2 crc error ; 4 op1 over run ; 3 op0 ready_not ; 2 fault clr seek complete_not ; 1 usr1 write fault_not ; 0 usr0 track0_not ; ; where: _not indicates an active low signal ; ; used by init and seek last_cyl dw 0 ; the last cylinder we were on cyl dw 0 ; the current cylinder we want h_rd_wt_param_add dw 0 eject ; disk type definition blocks for each particular mode. dpbs1: ;single density, single sided. DW 26 ;sectors per track DB 3,7,0 ;block size=1k, exm=0 DW s1dsm-1,64-1 ;dsm,drm DB 11000000b,00000000b ;2 blocks for directory DW 8010H ;64/4 cks DW 2 ;offset by 2 tracks db 0 ; physical sector shift db 0 ; physical sector mask dpbs2: ;single density, double sided. DW 26 ;sectors per track DB 4,15,1 ;block size=2k, exm=1 DW s2dsm-1,128-1 ;dsm, drm DB 11000000b,00000000b ;2 blocks for directory DW 8020H ;128/4 cks DW 2*2 ;offset by 4 tracks db 0 ; physical sector shift db 0 ; physical sector mask dpbd1: ;double density, single sided. (256 byte sectors) DW 26 ;physical sectors per track DB 4,15,0 ;block size = 2k, exm=0 (should be 1) DW d1dsm-1,128-1 ;dsm, drm DB 11000000b,00000000b ;2 blocks for directory DW 8020H ;128/4 cks DW 2 ;offset 2 tracks db 1 ; physical sector shift db 1 ; physical sector mask dpbd2: ;double density, double sided. (256 byte sectors) DW 26 ; physical sectors per track DB 4,15,0 ;2k block size, exm=0 DW d2dsm-1,256-1 ;dsm, drm DB 11110000b,00000000b ;4 directory blocks DW 8040H ;256/4 cks DW 2*2 ;offset 4 tracks db 1 ; physical sector shift db 1 ; physical sector mask dpbd3: ;double density, single sided. (512 byte sectors) DW 15 ;physical sectors per track DB 4,15,0 ;2k block size, exm=0 DW d3dsm-1,128-1 ;dsm, drm DB 11000000b,00000000b ;2 directory blocks DW 8020H ;128/4 cks DW 2 ;offset 2 tracks db 2 ; physical sector shift db 3 ; physical sector mask dpbd4: ;double density, double sided. (512-byte sectors) DW 15 ;physical sectors per track DB 4,15,0 ;2k block size, exm=0 DW d4dsm-1,256-1 ;dsm, drm DB 11110000b,00000000b ;4 directory blocks DW 8040 ;256/4 cks DW 2*2 ;offset 4 tracks db 2 ; physical sector shift db 3 ; physical sector mask dpbd5: ;double density, single sided. (1024-byte sectors) DW 8 ;physical sectors per track DB 4,15,0 ;2k block size, exm=0 DW d5dsm-1,128-1 ;dsm, drm DB 11000000b,00000000b ;2 directory blocks DW 8020H ;128/4 cks, semi-permanent DW 2 ;offset 2 tracks db 3 ; physical sector shift db 7 ; physical sector mask dpbd6: ;double density, double sided. (1024-byte sectors) DW 8 ;physical sectors per track DB 4,15,0 ;2k block size, exm=0 DW d6dsm-1,256-1 ;dsm, drm DB 11110000b,00000000b ;4 directory blocks DW 8040H ; 256/4 cks, semi-permanent DW 2*2 ;offset 4 tracks db 3 ; physical sector shift db 7 ; physical sector mask dpbh1: ; hard disk near outtter edge DW 11 ;physical sectors per track DB 5,31,1 ; 4k block size, exm=1 DW 7FDh,1FFH ;dsm, drm DB 0ffh,0ffh ; 16 directory blocks DW 8000h ; 0 cks, semi-permanent DW 8 ;offset 8 tracks db 3 ; physical sector shift db 7 ; physical sector mask dpbh2: ; hard disk near middle DW 11 ;physical sectors per track DB 5,31,1 ; 4k block size, exm=1 DW 7FDh,1FFH ;dsm, drm DB 0ffh,0ffh ; 16 directory blocks DW 8000h ; 0 cks, semi-permanent DW 2F0h ;offset 2F0h tracks db 3 ; physical sector shift db 7 ; physical sector mask dpbh3: ; hard disk near spindle DW 11 ;physical sectors per track DB 5,31,1 ; 4k block size, exm=1 DW 4E5h,0FFH ;dsm, drm DB 0ffh,0ffh ; 16 directory blocks DW 8000h ; 0 cks, semi-permanent DW 5D8h ;offset 5D8h tracks db 3 ; physical sector shift db 7 ; physical sector mask eject ;***************************************************** ;* ;* RAM areas for uninitialized iznterrupt trap ;* ;***************************************************** ; int_work rb 256 ;interrupt vector routines db 0 ;fill last address for GENCMD ;***************************************************** ;* ;* Dummy Data Section ;* ;***************************************************** dseg 0 ;absolute low memory org 0 ;(interrupt vectors) loczero rw 2*(mpmint) ;save space for nothing END