Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D10/LBIOS.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1418 lines
39 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

title 'Concurrent CP/M Loader BIOS'
;*******************************************************
; Last Modification: 02/16/84
;
; L B I O S - 8 6
; ======================
;
; Concurrent CP/M Loader I/O System
; for
; CompuPro Computer System
;
; Separate Code and Data:
; -----------------------
; The code segment is separate from the data
; segment. The code is ORG'd at 0000h and the
; data is ORG'd at 0180h relative to the System
; Data Area.
;
; high +---------------------+
; | Ldr Program Data |
; + - - - - - - - - - - +
; | Ldr BIOS Data |
; +---------------------+ <- 0180h
; | Ldr BDOS Data |
; +---------------------+ <- 0000h
; +---------------------+
; | Ldr Program Code |
; + - - - - - - - - - - +
; | Ldr BIOS Code |
; +---------------------+ <- 0000h
; +---------------------+
; | Ldr BDOS Code |
; low +---------------------+ <- 0000h
;
;*******************************************************
;
; The following commands are used to generate CPMLDR.SYS
; RASM86 LBIOS
; RASM86 LPROG
; LINK86 LBIOS3.SYS = LBIOS,LPROG [DATA[ORIGIN[0180]]]
; GENLDR [nnnn]
;
; The following commands are used to generate the
; boot tracks image BOOTTRKS
; SID86
; #RDSKBOOT.SYS ;strips header and
; #WBOOT,180,37F ;default base page
; PIP BOOTTRKS = BOOT[O],CPMLDR.SYS[O]
;
;*******************************************************
;
; Register usage for BIOS interface routines:
;
; Entry: AL = function number (in entry)
; CX = first parameter
; DX = second parameter
; DS = ES = system data segment (in entry and init)
; Exit: AX = return or BIOS error code
; BX = AX (in exit)
; DS = ES = preserved through call
; SS,SP must also be preserved
; CX,DX,SI,DI,BP can be changed by the BIOS
;
;*******************************************************
;
; Loader IOS Coding Conventions
;
;*******************************************************
;
; @ as the first character of a symbol denotes
; a public variable
;
; ? as the first character of a symbol denotes
; a public label
;
; All labels, and code are in lower-case
; for easier reading.
;
; All immediate values (literals) are in uppercase.
;
; Fields within data structures have leading
; letters followed by an underbar and the field
; name. The data structures defined are:
;
; BH_ - BIOS Header
; DPB_ - Disk Parameter Block
; DPH_ - Disk Parameter Header
; IOPB_ - I/O Parameter Block
;
; Underscores are used for readiablity otherwise
; Symbols, code mnemonics, registers are in all upper-case
; within comments to distinquish them from the code.
;
;*******************************************************
;
; Character I/O Equates
;
;*******************************************************
; CompuPro System Support serial definitions
SS_BASE equ 050h ;base address
SS_MODE equ SS_BASE+0Eh ;CompuPro System Support mode
SS_COMMAND equ SS_BASE+0Fh ;CompuPro System Support command
SS_STATUS equ SS_BASE+0Dh ;CompuPro System Support status
SS_DATA equ SS_BASE+0Ch ;CompuPro System Support data
SS_TRANS_READY equ 00000001b ;System Support transmit buffer empty
SS_RECV_READY equ 00000010b ;System Support data available
SS_DSR equ 10000000b ;System Support data set ready
;*******************************************************
;
; Disk Parameter Header Equates
;
;*******************************************************
;
; +-----+-----+-----+-----+-----+------+-----+-----+
; 00h | XLT | | DOPEN| |
; +-----+-----+-----+-----+-----+------+-----+-----+
; 08h | DPB | CSV | ALV | DIRBCB |
; +-----+-----+-----+-----+-----+------+-----+-----+
; 10h | DATBCB | HSHTBL | INIT | LOGIN |
; +-----+-----+-----+-----+-----+------+-----+-----+
; 18h | READ | WRITE | UNIT| CHNNL| FCNT|
; +-----+-----+-----+-----+-----+------+-----+
DPH_XLT equ word ptr 0
DPH_DOPEN equ byte ptr 5
DPH_DPB equ word ptr 8
DPH_CSV equ word ptr 10
DPH_ALV equ word ptr 12
DPH_DIRBCB equ word ptr 14
DPH_DATBCB equ word ptr 16
DPH_HSHTBL equ word ptr 18
DPH_INIT equ word ptr 20
DPH_LOGIN equ word ptr 22
DPH_READ equ word ptr 24
DPH_WRITE equ word ptr 26
DPH_UNIT equ byte ptr 28
DPH_CHNNL equ byte ptr 29
DPH_FCNT equ byte ptr 30
;*******************************************************
;
; Disk Parameter Block Equates
;
;*******************************************************
;
; +-----+-----+-----+-----+-----+-----+-----+-----+
; 00h | SPT | BSH | BLM | EXM | DSM | DRM..
; +-----+-----+-----+-----+-----+-----+-----+-----+
; 08h ..DRM | AL0 | AL1 | CKS | OFF | PSH |
; +-----+-----+-----+-----+-----+-----+-----+-----+
; 10h | PHM |
; +-----+
DPB_SPT equ word ptr 0
DPB_BSH equ byte ptr 2
DPB_BLM equ byte ptr 3
DPB_EXM equ byte ptr 4
DPB_DSM equ word ptr 5
DPB_DRM equ word ptr 7
DPB_AL0 equ byte ptr 9
DPB_AL1 equ byte ptr 10
DPB_CKS equ word ptr 11
DPB_OFF equ word ptr 13
DPB_PSH equ byte ptr 15
DPB_PHM equ byte ptr 16
;*******************************************************
;
; Input/Output Parameter Block Definition
;
;*******************************************************
;
; Read and Write disk parameter equates
;
; At the disk read and write entries,
; all disk I/O parameters are on the stack
; and the stack at these entries 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
; +-------+-------+
; BP+0 | RET_ADR | Local ENTRY return address
; +-------+-------+ (assumes one level of call
; from ENTRY routine)
;
; These parameters may be indexed and modified
; directly on the stack and will be removed
; by the BDOS after the function is complete
iopb_mcnt equ byte ptr 15[bp]
iopb_drive equ byte ptr 14[bp]
iopb_track equ word ptr 12[bp]
iopb_sector equ word ptr 10[bp]
iopb_dmaseg equ word ptr 8[bp]
iopb_dmaoff equ word ptr 6[bp]
;*******************************************************
;
; Disk I/O Equates
;
;*******************************************************
DPH_FMB equ byte ptr 31 ;floppy mode byte used by driver
;*******************************************************
;
; Floppy Disk Drivers for Qume Drives
; and a DISK 1 Controller Board
;
;*******************************************************
; Floppy mode bits
FM_D_DENSITY equ 0000$0001b
FM_TWO_SIDED equ 0000$0010b
FM_N_MASK equ 0000$1100b
; read/write control string equates for the Intel 8272 FDC
D equ byte ptr 1 ;D stands for the drive and head
; to be used to perform a read/write
C equ byte ptr 2 ;C stands for the current Cylinder
; track number 0 - 76 of the medium
H equ byte ptr 3 ;H stands for head number 0 or 1, as
; specified in ID field
R equ byte ptr 4 ;R stands for the Sector number, which
; will be read or written
N equ byte ptr 5 ;N stands for the number of data bytes
; written in a Sector
EOT equ byte ptr 6 ;EOT stands for the final Sector number
; of a Cylinder
GPL equ byte ptr 7 ;GPL stands for the length of Gap 3
; (spacing between Sectors excluding
; VCO Sync Field)
DTL equ byte ptr 8 ;When N is defined as 00, DTL stands
; for the data length which is going to
; be read out or write into the sector
; Floppy controler port addresses
FD_PORT equ 0C0h ;base port address of DISK1 controller
FDC_S equ FD_PORT ;8272 status register
FDC_D equ FD_PORT + 1 ;8272 data register
D1_DMA equ FD_PORT + 2 ;DISK1 dma addr when write
D1_INTS equ FD_PORT + 2 ;DISK1 interrupt status when read
; Main status register bits
MSTR_RQM equ 1000$0000b ;master status request
MSTR_DIO equ 0100$0000b ;master status direction
MSTR_CB equ 0001$0000b ;command busy status
FDC_INT equ 1000$0000b ;FDC interrupt output is asserted
RQM_DELAY equ 5 ;12us delay count for master status
; Floppy controler function definitions
F_SPEC equ 03h ;specify
F_DSTS equ 04h ;sense drive status
F_RDAT equ 06h ;read data
F_RECA equ 07h ;recalibrate
F_RSTS equ 08h ;sense interrupt status
F_RDID equ 0Ah ;read id
F_SEEK equ 0Fh ;seek
F_MFM equ 0100$0000b ;double density, MFM mode bit
; Floppy retry equate
RETRY_COUNT equ 10
; Floppy disk status field equates
ST0 equ 0 ;status register 0
ST1 equ 1 ;status register 1
ST2 equ 2 ;status register 2
ST_N equ 6 ;result field N
PCN equ 1 ;present cylinder no. result
; Status field bit equates
ST0_INTCODE_MSK equ 1100$0000b
ST0_STRT_NO_END equ 0100$0000b
ST0_SE equ 0010$0000b ;seek end
ST0_NR equ 0000$1000b ;not ready
ST0_UNIT_MASK equ 0000$0011b ;unit mask
ST0_RECAL_MASK equ 1111$1100b
ST0_RECAL_TEST equ 0010$0000b ;seek complete signal
ST0_SEEK_MASK equ 1111$1100b
ST0_VALID_SEEK equ 0010$0000b ;seek complete signal
ST1_EOT_END equ 1000$0000b ;end of cylinder
ST3_READY equ 0010$0000b ;ready signal
ST3_TWO_SIDED equ 0000$1000b ;two sided disk
ST_N_MASK equ 0000$0011b ;N field mask
; Equates for the floppy disk code readability
OK equ 00h
ERROR equ 0FFh
HEAD_BIT equ 0000$0100b
RW_ERROR equ 01h
WR_PROT_ERROR equ 02h
RW_MEDIA_CHANGE equ 0FFh
SELDSK_ERROR equ 0
CYLINDER_2 equ 2
; CCP/M disk control block equates which define the
; disk types and maximum storage capability of each
; disk type.
; CCP/M to host disk constants
CPMSIB equ 1024/128 ;standard sectors in block
FPYSIB equ 2048/128 ;sectors in floppy disk block
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
;*******************************************************
;
; 8259A Programmable Interrupt Controller 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 transmit ready
; IRQ4 = DISK 1
; IRQ5 =
; IRQ6 =
; IRQ7 = Slave input
;
; SLAVE PIC: IRQ0 =
; IRQ1 = Timer 0 ( 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
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
;*******************************************************
;
; BIOS Kernel Code Publics and Externals
;
;*******************************************************
CSEG
public @sysdat ;force CS over-ride
public ?conout, ?pmsg
extrn ?start:near
;*******************************************************
;
; BIOS Code Header
;
;*******************************************************
org 0000h
jmp init ;I/O system initialization
jmp entry ;I/O system function entry
jmp ?start ;start of loader program
@sysdat rw 1 ;OS Data Segment
;*******************************************************
;
; BIOS Kernel Data Publics and Externals
;
;*******************************************************
DSEG
public @bh_dphtable, @dpha
;*******************************************************
;
; BIOS Data Header
;
;*******************************************************
org 0000h
;use the LINK-86 [data[origin[0180]]] option
;to set the origin of the data segment at 0180h
; disk parameter header offset table
@bh_dphtable dw offset @dpha ;drive A:
;*******************************************************
;
; BIOS Code Segment
;
;*******************************************************
CSEG
;====
init:
;====
; Entry: DS = ES = system data segment
; Exit: DS = ES = preserved through call
cli ;disable interrupts
cld ;set forward direction
; 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
sti
; initialize the console on the System Support board
mov al,0EEh ;AL = mode register 1 ,async 16x rate
out SS_MODE,al ;send mode register 1
mov al,07Eh ;AL = mode register 2, internal clock
out SS_MODE,al ;send mode register 2
mov al,00$1$0$0$1$1$1b ;trans. on,dtr low,rec. on,no break,
;...no reset,rts low
out SS_COMMAND,al ;set up command port
; Floppy disk controller initialization.
; 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 1 manual
mov bx,offset specify_cmd ;specify command
mov cl,length specify_cmd ;sets up initial fdc counter values
call send_command
mov si,offset signon ;signon message defined in INIT module
call ?pmsg ;print the BIOS signon message
retf
;*******************************************************
;
; BIOS Entry Function Dispatch
;
;*******************************************************
;=====
entry: ; BIOS Entry Point
;=====
; All calls to the BIOS after INIT, enter through this code
; with a CALLF and must return with a RETF.
; Entry: AL = function number
; CX = first parameter
; DX = second parameter
; DS = ES = system data segment
; Exit: AX = BX = return or BIOS error code
; DS = ES = preserved through call
; SS,SP must also be preserved
; CX,DX,SI,DI,BP can be changed by the BIOS
cld ;clear direction flag
xor ah,ah ! shl ax,1 ;index into BIOS function table
mov bx,ax
call functab[bx] ;call BIOS kernel routine
mov bx,ax ;BX = AX
retf
;*******************************************************
;
; BIOS Character Output Routines
;
;*******************************************************
?conout: ;BIOS function 2
;=======
; Entry: CL = character
; Exit: None
in al,SS_STATUS ;get uart status
test al,SS_TRANS_READY ;test if buffer empty
jz ?conout
mov al,cl
out SS_DATA,al
ret
?pmsg: ;Print String
;=====
; Entry: DS:SI = offset of string terminated by 0.
; Exit: None
mov cl,[si] ;get character from buffer
or cl,cl ! jz pmsg_exit ;check for 0 terminater
push si
call ?conout ;output character in CL
pop si
inc si
jmps ?pmsg ;get next character
pmsg_exit:
ret
;*******************************************************
;
; BIOS Disk I/O Routines
;
;*******************************************************
io_seldsk: ;BIOS function 9
;=========
; Entry: CL = disk to be selected
; DL = (Bit 0): 0 if first select
; Exit: AX = 0 if illegal select
; = offset of DPH relative to OS data segment
xor bx,bx
cmp cl,0 ! jne sel_ret ;if not valid drive exit
mov bx,@bh_dphtable ;get DPH from drive table
test dl,1 ! jnz sel_ret ;first time select?
call DPH_LOGIN[bx] ; yes
sel_ret:
mov ax,bx
ret
io_read: ;BIOS function 10
;=======
; Entry: IOPB filled in (on stack)
; Exit: AL = 0 if no error
; = 1 if physical error
; = 0FFH if media density has changed
mov bp,sp ;SS:BP points to IOPB
cmp iopb_drive,0 ! jne ret_error
mov bx,@bh_dphtable ;get DPH address
jmp DPH_READ[bx] ;jump to DPH read routine
ret_error:
mov al,1 ;return error if not valid
ret
io_notimp: ;BIOS function not implemented
;=========
xor ax,ax ;return success
ret
;*******************************************************
;
; Floppy Disk I/O Code Segment
;
;*******************************************************
fd_login: ;Login routine for the floppy disk drive
;========
; This routine figures out
; 1] what kind of floppy is in the drive
; 2] does a recal, homes the head
; 3] saves the floppy mode byte in the DPH.
; 4] sets up the current floppy mode byte.
; 5] sets up the dph's
; 6] 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.
;
; Entry: BX = DPH offset
; CL = selected disk
; Exit: BX = 0 if illegal select
; = offset of DPH relative to O.S. data segment
push bx
call get_media_type
pop bx ;BX = DPH offset
cmp al,ERROR ! jne fd_1
mov bx,SELDSK_ERROR ;set up the error code for CCP/M
jmps fd_login_exit
fd_1:
mov DPH_FMB[bx],al ;save the current floppy mode byte
; for this drive in the DPH
xor ah,ah ;set up the xlat table addr in DPH
mov di,ax ;save DI for index into DPB table
shr al,1 ! and al,0FEH
mov si,ax
mov ax,xtable[si] ;get the translation table
mov DPH_XLT[bx],ax ;put the xlat table addr in DPH
and di,0FFFEh ;get the proper dpb
mov ax,drv_tbl[di] ;index into the dpb table
mov DPH_DPB[bx],ax ;and put it in the dph
fd_login_exit:
ret ;BX = DPH offset
fd_read: ;Read routine for the floppy disk drive
;=======
; BX = DPH offset
; Exit: AL = 0 if no error
; = 1 if physical error
; = 0FFH if media density has changed
mov al,DPH_FMB[bx] ;get saved floppy mode
mov c_fmb,al ;set current floppy mode byte
mov ax,DPH_XLT[bx] ;get the xlat table
mov xltbl,ax ;save translation table address
mov bx,DPH_DPB[bx] ;get the DPB from the DPH
mov ax,DPB_SPT[bx]
mov maxsec,ax ;save maximum sector per track
mov cl,DPB_PSH[bx]
mov ax,128 ! shl ax,cl ;compute physical record size
mov secsiz,ax ; and save it
cmp iopb_mcnt,0 ! jne rw_1
mov al,1
ret
rw_1:
mov ax,iopb_sector ;is sector < max sector/track
cmp ax,maxsec ! jb same_trk
inc iopb_track ; next track
xor ax,ax
mov iopb_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:
mov isector,al ;store sector #
mov ax,iopb_track ;get track # from IOPB
mov itrack,ax
mov ax,iopb_dmaoff ;get dma offset from table
mov idmaoff,ax
mov ax,iopb_dmaseg ;get dma segment from IOPB
mov idmaseg,ax
call phys_rw ;call read routine
or al,al ! jnz err_ret ;if error occured return
mov ax,secsiz ;increment dma offset by the
add iopb_dmaoff,ax ; physical sector size
inc iopb_sector ;next sector
dec iopb_mcnt ;decrement multi sector count
jnz rw_1 ;if MCNT <> 0 store next sector dma
xor ax,ax
err_ret:
ret ;return with error code in AL
phys_rw: ;these are the physical drivers for the CompuPro
;-------
; physical read does the actual read from the floppy.
;
; Entry: itrack = the track to read from
; isector = the sector to read from
; idmaoff = the dma offset to read to or from
; idmaseg = the dma segment to read to or from
;
; Exit: AL = 0 if no error
; = 1 if physical error
; = 2 if Read/Only disk
; = 0FFH if media density has changed
mov rw_retries,RETRY_COUNT
rw_retry_lp:
; setup D, C, H, R, N, EOT, GPL, and DTL fields of RW_CMD
mov al,isector ;put sector in the control strings
inc al ;the bdos expects 0 relative sectors
mov (rw_cmd + R),al ;record
mov (rw_cmd + EOT),al ;and the end of track fields
mov al,F_RDAT ;setup for read command
test c_fmb,FM_D_DENSITY ;check if double density
jz rw_not_dd
or al,F_MFM ;yes - set MFM bit
rw_not_dd:
mov rw_cmd,al ;set r/w command in control string
mov al,c_fmb
and al,FM_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_cmd + N),al ; then stuff the control string
mov (rw_cmd + DTL),0FFh ;set dtl for all DD operations
cmp al,0 ! jne zero_dtl ;this checks for a SD floppy
mov (rw_cmd + DTL),128 ; set for SD operation
zero_dtl:
xor ah,ah ;get the gpl as per the
mov si,ax ! mov al,gpl_tbl[si] ;N value in the FMB
mov (rw_cmd + GPL),al
mov ax,itrack
test c_fmb,FM_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_cmd + C),al ;set up the seek control
mov (rw_cmd + C),al ;now the read control
; set the drive and head
xor al,al ;set the drive
mov (rw_cmd + H),0
test c_fmb,FM_TWO_SIDED
jz side0 ;if double sided
test itrack,1 ;and track is odd
jz side0 ;set the head bit
or al,HEAD_BIT ;set the head bit for the drive field
mov (rw_cmd + H),1 ;set the head field in the RW_CMD
side0:
mov (seek_cmd + D),al ;stuff the seek drive field
mov (rw_cmd + D),al ; and the RW_CMD drive field
call seek ;seek to the desired cylinder
cmp al,ERROR ! je phys_rw_3
; set up the floppy controllers dma address
mov ax,idmaseg ;get the segment
mov cl,4 ! rol ax,cl ;(para to bytes) shift add to offset
mov dx,ax ;save lower 16 bits of paragraph
and al,0Fh ;get upper nibble of paragraph
and dx,0FFF0h
add dx,idmaoff ;add in the offset
adc al,0 ;add carry into upper nibble
;send 24 bits to controler
out D1_DMA,al ;msb
mov al,dh ! out D1_DMA,al
mov al,dl ! out D1_DMA,al ;lsb
mov bx,offset rw_cmd ;send out the command string
mov cl,length rw_cmd
call send_command
call int_wait ;wait for the read
mov bx,offset rw_res ;get the results of the read
mov cl,length rw_res
call get_results
;check the interupt code
mov al,(rw_res + ST0) ;get the interupt code
and al,ST0_INTCODE_MSK ;check for start but no end
cmp al,ST0_STRT_NO_END
jne phys_rw_4 ;due to EOT
mov al,(rw_res + ST1)
cmp al,ST1_EOT_END
jne phys_rw_4
mov al,OK ;good read so exit
jmps p_read_exit
phys_rw_3:
call recalibrate ;recalibrate on seek errors
phys_rw_4:
dec rw_retries
jz phys_rw_err
jmp rw_retry_lp
phys_rw_err:
mov al,RW_ERROR
p_read_exit:
ret
get_media_type: ;determine media type for a disk select
;--------------
; figures out what kind of disk is in the drive specified
; Then it builds the Floppy mode byte(C_FMB)
; It sets the two sided bit, the density bit, and the sector
; size bits (2, 3) if the disk is DD
; Exit: AL = current floppy mode byte (C_FMB)
; AL = ERROR if there was an error
; C_FMB is set
call recalibrate ;recalibrate drive
cmp al,ERROR ;check for a error in recal
je media_type_exit ;return on error
; Put head 0 over cylinder 2 to sample the disk at the start
; of the directory. Track 0 is SD on the CompuPro DD disk.
mov (seek_cmd + D),0
mov (seek_cmd + C),CYLINDER_2
mov fc_retries,RETRY_COUNT ;initialize retry count
fc_retry_lp:
call seek ;seek to cylinder 2
cmp al,ERROR ! jne cylinder_2_now
dec fc_retries ! jnz fc_retry_lp
jmps media_type_exit ;return with error
cylinder_2_now:
mov c_fmb,0 ;set current floppy mode byte to 0
; get the number of sides from the FDD's status byte
test sdst_res,ST3_TWO_SIDED
jz single_sided
or c_fmb,FM_TWO_SIDED ;set two sided field
single_sided:
; resolve the density either SD or DD we should be over cylinder 2
; if the read id for a DD disk fails try a SD disk
mov rd_id_cmd,F_RDID + F_MFM ;set read id for DD
call read_id
jz sec_size
mov rd_id_cmd,F_RDID ;set read id for SD
call read_id
jz f_sel_com
dec fc_retries ! jnz single_sided
mov al,ERROR
jmps media_type_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 c_fmb,FM_D_DENSITY ;or in the DD bit in the FMB
mov al,(rd_id_res + ST_N) ;get the N field
and al,ST_N_MASK ;mask for validity
shl al,1 ! shl al,1 ;setup mask for C_FMB
or c_fmb,al ;or the mask into the current mode byte
f_sel_com:
mov al,c_fmb
media_type_exit:
ret
sense_drv_stat: ;sense drive status
;--------------
; Exit: AL = OK if drive is ready
; AL = ERROR if the drive is not ready
mov bx,offset sdst_cmd
mov D[bx],0 ;set the drive, head = 0
mov cl,length sdst_cmd
call send_command ;Sense drive status command
mov bx,offset sdst_res
mov cl,length sdst_res
call get_results
; 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.
xor al,al
test sdst_res,ST3_READY ;make sure the drive is ready
jnz sds_exit
mov al,ERROR
sds_exit:
ret
recalibrate: ;recalibrate drive
;-----------
; Exit: AL = OK if everthing went OK
; AL = ERROR if it could not find the track 0
; or the drive was off line
call sense_drv_stat ;Sense drive status
cmp al,ERROR ! je recal_exit
mov bx,offset recal_cmd
mov D[bx],0 ;stuff the control string
mov cl,length recal_cmd
call send_command ;send the recal command
call int_wait ;wait for the recal to happen
mov al,(sist_res + ST0)
and al,ST0_RECAL_MASK ;get status register 0
cmp al,ST0_RECAL_TEST ; and make sure recal was ok
mov al,OK
je recal_exit
mov al,ERROR
recal_exit:
ret
seek: ;seek sends the seek command to the fdc
;----
; Entry: SEEK_CMD must be set up on the way in
;
; Exit: AL = OK if everthing went OK
; AL = ERROR if it could not find the right track
; or the drive was off line
call sense_drv_stat ;sense drive status
cmp al,ERROR ! je sk_exit
mov bx,offset seek_cmd ;send the seek command
mov cl,length seek_cmd
call send_command
call int_wait ;wait for the seek
mov al,(sist_res + ST0) ;get status register 0
and al,ST0_SEEK_MASK ; and make sure its ok
cmp al,ST0_VALID_SEEK ! jne sk_err_exit
mov al,(seek_cmd + C) ;compare the cylinder we're over
cmp al,(sist_res + PCN) ;to the one we wanted
mov al,OK
je sk_exit
sk_err_exit:
mov al,ERROR
sk_exit:
ret
read_id:
;-------
; read ID expects the control byte set up before it is called.
; Entry: RD_ID_CMD (read ID control string set up)
; Exit: Z flag set if it could read an ID
; Z flag reset if the drive was not ready
mov bx,offset rd_id_cmd
mov D[bx],0 ;set the drive, head = 0
mov cl,length rd_id_cmd
call send_command ;send the read id command
call int_wait ;wait for the read
mov bx,offset rd_id_res ;get the results
mov cl,length rd_id_res
call get_results
mov al,rd_id_res + ST0 ;get the results
and al,ST0_INTCODE_MSK ;mask for the interupt code
cmp al,OK ;set Z flag if no error
ret
send_command: ;send command to 8272
;------------
; Entry: BX = address of the command string
; CL = the length of the command string
in al,FDC_S
test al,MSTR_CB ! jnz send_command
xor ch,ch
cli
snd_cmd1:
mov al,RQM_DELAY ;must delay 12us before polling
snd_cmd2: ;FDC status to insure valid results
dec al ! jnz snd_cmd2
snd_cmd3:
in al,FDC_S ;get master status from 8272
test al,MSTR_RQM ! jz snd_cmd3
test al,MSTR_DIO ! jnz snd_cmd3
mov al,[bx] ! out FDC_D,al ;send command string to 8272
inc bx
loop snd_cmd1 ;next byte of command string
sti
ret
get_results: ;get results form 8272
;-----------
; Entry: CL = number of bytes to expect from the fdc
; BX = addr of where to put the results
; Exit: the location starting where BX was pointing
; for a length of CX will have the results from the
; fdc result phase
in al,FDC_S
test al,MSTR_CB ! jz get_results
xor ch,ch
get_res1:
mov al,RQM_DELAY ;must delay 12us before polling
get_res2: ;FDC status to insure valid results
dec al ! jnz get_res2
get_res3:
in al,FDC_S ;get master status from 8272
test al,MSTR_RQM ! jz get_res3
test al,MSTR_DIO ! jz get_res3
in al,FDC_D ;get the result status
mov [bx],al ! inc bx
loop get_res1
ret
int_wait: ;interupt wait
;--------
; this routine does a flag wait on the fdc operation.
push bp
int_w1:
in al,D1_INTS ;wait for FDC interrupt to be asserted
test al,FDC_INT ! jz int_w1
; check the direction of data xfer from the FDC's main status port
flint_lp:
in al,FDC_S ;wait for the fdc to become ready
test al,MSTR_RQM ! jz flint_lp ; for data xfer
test al,MSTR_DIO ;if the fdc want to send us data,
jnz fdc_to_processor ; it must be our expected status
;the fdc is expecting a command,
; so query the interrupt status
; 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.
fdcsist:
in al,FDC_S
test al,MSTR_CB ! jnz fdcsist
fdcsist1:
in al,FDC_S ;poll the fdc to be ready for data com
test al,MSTR_RQM ! jz fdcsist1
test al,MSTR_DIO ! jnz fdcsist1
mov al,F_RSTS ! out FDC_D,al ;send sense interrupt status command
mov bx,offset sist_res
mov cl,length sist_res ;get the two byte result from the
call get_results ;fdc
fdc_to_processor:
pop bp
ret
;*******************************************************
;
; BIOS Data Segment
;
;*******************************************************
DSEG
; BIOS Function Table
functab dw io_notimp ; 0 - console status
dw io_notimp ; 1 - console input
dw io_notimp ; 2 - console output
dw io_notimp ; 3 - list output status
dw io_notimp ; 4 - list output
dw io_notimp ; 5 - aux input
dw io_notimp ; 6 - aux output
dw io_notimp ; 7 - CCP/M function
dw io_notimp ; 8 - CCP/M function
dw io_seldsk ; 9 - select disk
dw io_read ;10 - read sector
dw io_notimp ;11 - write sector
dw io_notimp ;12 - flush buffers
dw io_notimp ;13 - CCP/M function
dw io_notimp ;14 - char. device init
dw io_notimp ;15 - console output status
dw io_notimp ;16 - aux input status
dw io_notimp ;17 - aux output status
signon db 13,10
db 'Concurrent CP/M CompuPro Loader IOS',13,10,0
;*******************************************************
;
; Floppy Disk I/O Data Segment
;
;*******************************************************
imcnt db 0
itrack dw 0
isector db 0
idmaoff dw 0
idmaseg dw 0
; sides density bytes/sec
drv_tbl dw dpbs1 ;ss,sd, 128
dw dpbs2 ;ds,sd, 128
dw dpbd1 ;ss,dd, 256
dw dpbd2 ;ds,dd, 256
dw dpbd3 ;ss,dd, 512
dw dpbd4 ;ds,dd, 512
dw dpbd5 ;ss,dd, 1024
dw dpbd6 ;ds,dd, 1024
; GAP 3 Length, these values indicate spacing between
; sectors excluding VCO and Sync Field
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
; FLOPPY MODE BYTE AND TABLE
; B B B B B B B B
; 7 6 5 4 3 2 1 0
; \ / | + ------- set = double density, reset = single density
; | +---------- set = two sided, reset = single sided
; +------------- 0 = 128 byte sectors
; 1 = 256 byte sectors
; 2 = 512 byte sectors
; 3 = 1024 byte sectors
c_fmb db 0 ;the current floppy mode byte
;*******************************************************
;
; Intel 8272 FDC Command Set Data Strctures
;
;*******************************************************
; READ/WRITE DATA Command String
; D C H R N EOT GPL DTL
rw_cmd db 0, 0, 0, 0, 0, 0, 0, 0, 0
; r/w result string
; S S S
; T T T
; 0 1 2 C H R N
rw_res db 0, 0, 0, 0, 0, 0, 0
; READ ID Command String
;
rd_id_cmd db 0, 0
; | +--- head and drive
; +------ control byte
; S S S ;read ID result string
; T T T
; 0 1 2 C H R N
rd_id_res db 0, 0, 0, 0, 0, 0, 0
; RECALIBRATE Command and Result String
;
recal_cmd db F_RECA, 0 ;re-cal command string
; SENSE INTERRUPT STATUS Result String
;
sist_res db 0, 0 ; returned status from an interrupt
; | +--- present cylinder number
; +------ fdc status byte 0
; SPECIFY Command String
;SRT = 3ms, HUT = 240ms
;HLT = 112ms, DMA = on
specify_cmd db F_SPEC, 1101$1111b, 0111000$0b
; SENSE DRIVE STATUS Command/Result Strings
;
sdst_cmd db F_DSTS, 0 ;sense drive status control string
sdst_res db 0 ;sense drive status result byte ST3
; SEEK Command String
;
seek_cmd db F_SEEK, 0, 0
; | +--- new cylinder number
; +------ head and drive
; Retry counter variables
rw_retries db 0
fc_retries db 0 ;first call retries for first recal
;*******************************************************
;
; these are the disk parameters used by the disk routines
;
;*******************************************************
xltbl dw 0 ;translation table address
maxsec dw 0 ;max sectors per track
secsiz dw 0 ;sector size
; floppy disk 0
@dpha dw xltd3
db 0, 0, 0 ;scratch area
db 0 ;door open flag
db 0, 0 ;scratch area
dw dpbd6 ;disk paramater table
dw 0FFFFH, 0FFFFH ;checksum, allocation vector
dw 0FFFFH ;directory bcb
dw 0FFFFH ;data bcb
dw 0FFFFH ;hash table
dw 0 ;init routine
dw fd_login ;login routine
dw fd_read ;read routine
dw 0 ;write routine
db 0 ;unit
db 0 ;channel 0
db 1 ;one flag used
db 0 ;floppy mode byte used by driver
; 1944: 128 Byte Record Capacity
; 243: Kilobyte Drive Capacity
; 64: 32 Byte Directory Entries
; 64: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 8: 128 Byte Records / Block
; 8: 128 Byte Records / Track
; 2: Reserved Tracks
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 0C0h,000h ;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
; 3888: 128 Byte Record Capacity
; 486: Kilobyte Drive Capacity
; 128: 32 Byte Directory Entries
; 128: Checked Directory Entries
; 256: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 26: 128 Byte Records / Track
; 4: Reserved Tracks
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 0C0h,000h ;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
; 3888: 128 Byte Record Capacity
; 486: Kilobyte Drive Capacity
; 128: 32 Byte Directory Entries
; 128: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 52: 128 Byte Records / Track
; 2: Reserved Tracks
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 0C0h,000h ;2 blocks for directory
DW 8020h ;128/4 cks
DW 2 ;offset 2 tracks
db 1 ;physical sector shift
db 1 ;physical sector mask
; 7792: 128 Byte Record Capacity
; 974: Kilobyte Drive Capacity
; 256: 32 Byte Directory Entries
; 256: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 52: 128 Byte Records / Track
; 4: Reserved Tracks
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 0F0h,000h ;4 directory blocks
DW 8040h ;256/4 cks
DW 2*2 ;offset 4 tracks
db 1 ;physical sector shift
db 1 ;physical sector mask
; 4496: 128 Byte Record Capacity
; 562: Kilobyte Drive Capacity
; 128: 32 Byte Directory Entries
; 128: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 60: 128 Byte Records / Track
; 2: Reserved Tracks
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 0C0h,000h ;2 directory blocks
DW 8020h ;128/4 cks
DW 2 ;offset 2 tracks
db 2 ;physical sector shift
db 3 ;physical sector mask
; 8992: Byte Record Capacity
; 1124: Kilobyte Drive Capacity
; 256: 32 Byte Directory Entries
; 256: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 60: 128 Byte Records / Track
; 4: Reserved Tracks
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 0F0h,000h ;4 directory blocks
DW 8040h ;256/4 cks
DW 2*2 ;offset 4 tracks
db 2 ;physical sector shift
db 3 ;physical sector mask
; 4800: 128 Byte Record Capacity
; 600: Kilobyte Drive Capacity
; 128: 32 Byte Directory Entries
; 128: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 8: 128 Byte Records / Track
; 2: Reserved Tracks
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 0C0h,000h ;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
; 9600: 128 Byte Record Capacity
; 1200: Kilobyte Drive Capacity
; 256: 32 Byte Directory Entries
; 256: Checked Directory Entries
; 128: 128 Byte Records / Directory Entry
; 16: 128 Byte Records / Block
; 8: 128 Byte Records / Track
; 4: Reserved Tracks
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 0F0h,000h ;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
; THESE ARE THE SKEW TABLES
; sector translation tables (for floppy disks)
xtable dw xlts ;single 128
dw xltd1 ;double 256
dw xltd2 ;double 512
dw 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
END