Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM-86/MPM-86 2.0 SOURCES/04/XIOS.A86
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1579 lines
34 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 '8086 Hardware Interface'
;*****************************************************
;*
;* X I O S - 8 6
;* ===================
;*
;* MP/M-86 eXtended I/O System
;* for
;* Intel SBC 204 Floppy Diskette Interface
;*
;* Copyright (C) 1980, 1981
;* Digital Research, Inc.
;* Box 579, Pacific Grove
;* California, 93950
;*
;* 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.
;*
;* (Permission is hereby granted to use or
;* abstract the following program in the
;* implementation of CP/M, MP/M or CP/NET
;* for the 8086 or 8088 Micro-processor.)
;*
;*****************************************************
;*
;* 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
;
debug equ false
;*****MDISK SUPPORT*****
memdisk equ false
;***********************
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;*****************************************************
;*
;* CHARACTER I/O EQUATES
;*
;*****************************************************
;
;
;base address of serial board
serbase equ 040h
;
nconsoles equ 4
nlists equ 1
;
;
; using Intel SBC 534 serial board
;
;port address to reset entire board
sereset equ serbase+0fh
;
;port address to set test mode
setestmode equ serbase+0eh
;
;port address to enable counter/timer
ctcenable equ serbase+0ch
;
;port address to enable uarts
uartenable equ serbase+0dh
;
;counter/timer mode addresses
ctc0to2md equ serbase+03h
ctc3to5md equ serbase+07h
ctc0mode equ 036h
ctc1mode equ 076h
ctc2mode equ 0b6h
ctc3mode equ 036h
;
;counter/timer load addresses
; and count values
ctc0ld equ serbase+00h
ctc1ld equ serbase+01h
ctc2ld equ serbase+02h
ctc3ld equ serbase+04h
cnt0vall equ 008h
cnt0valh equ 000h
cnt1vall equ 008h
cnt1valh equ 000h
cnt2vall equ 008h
cnt2valh equ 000h
cnt3vall equ 008h
cnt3valh equ 000h
;
;uart mode and command
;
u0mode equ 04eh
u1mode equ 04eh
u2mode equ 04eh
u3mode equ 04eh
u0cmd equ 037h
u1cmd equ 037h
u2cmd equ 037h
u3cmd equ 037h
;
; console i/o and status ports
; in and out status masks
;
;
; console 0
;
c0ioport equ 0d8h
c0stport equ 0dah
c0inmsk equ 02h
c0outmsk equ 01h
;
; console 1
;
c1ioport equ serbase+02h
c1stport equ serbase+03h
c1inmsk equ 002h
c1outmsk equ 001h
;
; console 2
;
c2ioport equ serbase+04h
c2stport equ serbase+05h
c2inmsk equ 002h
c2outmsk equ 001h
;
; console 3
;
c3ioport equ serbase+06h
c3stport equ serbase+07h
c3inmsk equ 002h
c3outmsk equ 001h
;
; list 0
;
l0ioport equ serbase+00h
l0stport equ serbase+01h
l0inmsk equ 002h
l0outmsk equ 081h
;
;
;
;*****************************************************
;*
;* DISK I/O EQUATES
;*
;* Intel iSBC 204 Disk Controller Ports
;*
;*****************************************************
base204 equ 0a0h ;SBC204 assigned addr
fdc_com equ base204+0 ;8271 FDC out command
fdc_stat equ base204+0 ;8271 in status
fdc_parm equ base204+1 ;8271 out parameter
fdc_rslt equ base204+1 ;8271 in result
fdc_rst equ base204+2 ;8271 out reset
dmac_adr equ base204+4 ;8257 DMA base adr out
dmac_cont equ base204+5 ;8257 out control
dmac_scan equ base204+6 ;8257 out scan control
dmac_sadr equ base204+7 ;8257 out scan address
dmac_mode equ base204+8 ;8257 out mode
dmac_stat equ base204+8 ;8257 in status
fdc_sel equ base204+9 ;FDC select port
fdc_segment equ base204+10 ;segment addr register
reset_204 equ base204+15 ;reset interface
max_retries equ 10 ;retries on disk i/o
;before perm error
;*****MDISK SUPPORT*****
mdiskbase equ 2000h ;base address of mdisk
;***********************
;*****************************************************
;*
;* 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_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_cns equ byte ptr 020H ; PD console field
pf_keep equ 02H ; KEEP bit in p_flag
;flag assignments
tick_flag equ 1
sec_flag equ 2
;device # assignments for POLL DEV
c0indev equ 00h ;console 0 input device
c1indev equ 01h ;console 1 input device
c2indev equ 02h ;console 2 input device
c3indev equ 03h ;console 3 input device
c0outdev equ 04h ;console 0 output device
c1outdev equ 05h ;console 1 output device
c2outdev equ 06h ;console 2 output device
c3outdev equ 07h ;console 3 output device
l0outdev equ 08h ;list 0 output device
flpy_poll_dev equ 09h ;floppy disk poll device
;
; system data area must preceed code
; area for 8080 model of the XIOS
;
include sysdat.lib
endsysdat equ ((offset $)+0fh) AND 0fff0h
CSEG
org offset endsysdat
;*****************************************************
;*
;* SYSTEM CODE AREA
;*
;* XIOS JUMP TABLE
;*
;*****************************************************
jmp init ;system initialization
jmp entry ;xios entry point
sysdat dw 0 ;Sysdat Segment
supervisor equ offset $
rw 2
;*****************************************************
;*
;* UTILITY SUBROUTINES
;*
;*****************************************************
;====
pmsg:
;====
; print message on current console until null (char 0)
; input: BX = address of message
;put running processes console
;number in DL
pushf ! cli
push stoppoll
mov stoppoll,true
push ds ! mov ds,sysdat ;DS = system data area
mov si,rlr ;SI -> current pd
mov dl,p_cns[si] ;DL = def console #
pop ds
ploop:
mov al,[bx] ; get next char
cmp al,0 ! jz pmsg_ret ; return if zero
mov cl,al ; CL = character
push dx ! push bx ; save console,posit.
call conout ; print it
pop bx ! pop dx ; restore posit.,cons.
inc bx ! jmps ploop ; inc and loop
pmsg_ret:
pop stoppoll
popf ! ret ; end of message
;*****************************************************
;*
;* INTERRUPT ROUTINES
;*
;*****************************************************
;these variables must be in code segment
tickint_ss dw 0
tickint_sp dw 0
ax_save dw 0
zero dw 0
;=======
tickint:
;=======
; Interrupt handler for tick interrupts
;save context
push ds ! mov ds,sysdat
mov tickint_ss,ss
mov tickint_sp,sp
mov ax_save,ax
mov ax,cs
mov ss,ax
mov sp,offset tickint_tos
push ax_save
push bx ! push cx ! push dx
push bp ! push si ! push di ! push es
mov ds,ax
; 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:
; check to set tick flag
cmp clockon,true ! jne tick_done
mov dx,tick_flag
mov cl,f_flagset ! call supif
tick_done: ;restore context
pop es ! pop di ! pop si ! pop bp
pop dx ! pop cx ! pop bx ! pop ax
mov ss,tickint_ss
mov sp,tickint_sp
;force dispatch
pop ds
; jmp intdisp
;=======
intdisp:
;=======
jmpf cs:dword ptr .dispatcher
;========
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 ax,cs
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],0
call pmsg
; print Illegal Interrupt message
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 ;hard stop
;the terminate returned !!!!
;*****************************************************
;*
;* INITIALIZATION CODE AREA
;*
;* Inter-Module Interface Routines
;*
;*****************************************************
;====
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
;-----------------------------------------------------
;Save sysdat seg addr in case we need
;to see system data area. Set DS=CS
push ds ;save DS on stack for
;exit
;initialize segment registers
mov sysdat,ds ; save sysdat for
; sysdat access
;place copy of SUPMOD in data segment
;into Code Segment (supervisor)
mov bx,offset supmod
mov si,supervisor
mov ax,[bx] ! mov cs:[si],ax
mov ax,2[bx] ! mov cs:2[si],ax
;Make copy of Interrupt Routines
;access point to dispatcher in
;Code Segment
push cs ! pop ds ; DS = CS
cld ;set forward direction
;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 initss,ss
mov initsp,sp
mov ax,cs ! mov ss,ax
mov sp,offset initstack
; Setup all interrupt vectors in low
; memory to address trap
if not debug
push ds
push es ;ES must be saved
mov ax,0
mov ds,ax
mov es,ax ;set ES and DS to zero
;setup interrupt 0 to trap routine
mov .0,offset int_trap
mov .2,CS
mov di,4
mov si,0 ;then propagate
mov cx,510 ;trap vector to
rep movsw ;int 255
pop es
pop ds ;restore DS,ES
endif
;-----------------------------------------------------
; CHARACTER I/O INITIALIZATION
;-----------------------------------------------------
;
;
;*********************************************
;*
;* sbc 534 serial board initialization
;*
;*********************************************
;
mov al,0
out sereset,al ;reset serial board
out setestmode,al ;set test mode to off
out ctcenable,al ;enable ctc addressing
;
;start clock for port 0
mov al,ctc0mode ! out ctc0to2md,al
mov al,cnt0vall ! out ctc0ld,al
mov al,cnt0valh ! out ctc0ld,al
;
;start clock for port 1
mov al,ctc1mode ! out ctc0to2md,al
mov al,cnt1vall ! out ctc1ld,al
mov al,cnt1valh ! out ctc1ld,al
;
;start clock for port 2
mov al,ctc2mode ! out ctc0to2md,al
mov al,cnt2vall ! out ctc2ld,al
mov al,cnt2valh ! out ctc2ld,al
;
;start clock for port 3
mov al,ctc3mode ! out ctc3to5md,al
mov al,cnt3vall ! out ctc3ld,al
mov al,cnt3valh ! out ctc3ld,al
;
out uartenable,al ;enable uart addressing
;
;initialize port 0
mov al,u0mode ! out l0stport,al
mov al,u0cmd ! out l0stport,al
;
;initialize port 1
mov al,u1mode ! out c1stport,al
mov al,u1cmd ! out c1stport,al
;
;initialize port 2
mov al,u2mode ! out c2stport,al
mov al,u2cmd ! out c2stport,al
;
;initialize port 3
mov al,u3mode ! out c3stport,al
mov al,u3cmd ! out c3stport,al
;
;
;-----------------------------------------------------
; DISK I/O INITIALIZATION
;-----------------------------------------------------
;***** MDISK SUPPORT *****
if memdisk
;initialize MDISK
mov cx,mdiskbase
push es ! mov es,cx
mov di,0 ! mov ax,0e5e5h
cmp es:[di],ax ! je mdisk_end
mov cx,2000h
rep stos ax
mdisk_end:
pop es
;
endif
;*************************
;-----------------------------------------------------
; SUP/RTM INITIALIZATION
;-----------------------------------------------------
;Initialize Clock Tick
if not debug
;set up tick interrupt vector
;tick causes interrupt 22
sub ax,ax ! push ds ! mov ds,ax
mov word ptr .088h,offset tick_int
mov word ptr .08ah,cs
pop ds
;setup ticks to occur every
; 1/60th of a second
mov tick_count,60
mov al,034h ! out 0d6h,al ;PIT ch.0=mode 2
;set # of 1/1.2288e6 seconds
;20480=5000h=1/60th second
mov al,000h ! out 0d0h,al ;low count
mov al,050h ! out 0d0h,al ;high count
;set up interrupt controller
mov al,013h ! out 0c0h,al ;ICW1
mov al,020h ! out 0c2h,al ;ICW2
; = base interrupt
mov al,00fh ! out 0c2h,al ;ICW4,
; auto EOI,
; 8086 mode
mov al,0fbh ! out 0c2h,al ;OCW2,
; interrupt mask,
; only 2
endif
;-----------------------------------------------------
; INITIALIZATION EXIT
;-----------------------------------------------------
;allow poll_device mechanism to work
mov stoppoll,false
;print optional message on Console 0
mov bx,offset signon
call pmsg
;restore stack
; all stack switches must be in
; critical areas (interrupts off).
pushf ! pop ax
cli
mov ss,initss
mov sp,initsp
push ax
popf
;return back to BDOS
pop ds
retf
;*****************************************************
;*
;* 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
; output: AX = BX = return
cld ;clear D flag
mov bx,cs ! mov ds,bx ; (only 8080 model)
mov ah,0 ! 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
mov ch,0
callf cs:dword ptr .supervisor ! ret
;*****************************************************
;*
;* MP/M XIOS functions
;*
;*****************************************************
;*****************************************************
;*
;* CHARACTER I/O CODE AREA
;*
;*****************************************************
;=====
const: ; Function 0: Console Status
;=====
; input: CL = console device number
; output: AL = 0ffh if ready
; = 000h if not ready
mov ch,0 ! shl cx,1
mov bx,cx
mov dx,consttbl[bx]
mov bl,dh ;BL = status mask
mov dh,0 ;DX = status port address
; find input status for console device
in al,dx
and al,bl
mov al,0
jz badstatus
mov al,0ffh
badstatus:
ret
;=====
conin: ; Function 1: Console Input
;=====
; input: CL = console device number
; output: AL = character
mov ch,0 ! shl cx,1
mov bx,cx
mov dx,conintbl[bx]
mov bl,dh ;BL = poll device no.
mov dh,0 ;DX = i/o port address
; input routine for console device
mov bh,0 ! push dx
call rtm_poll ! pop dx
in al,dx
;and al,07fh ;CP/NET uses parity bit
ret
;======
conout: ; Function 2: Console Output
;======
; input: CL = character
; DL = console device #
; output: None
mov dh,0 ! shl dx,1
mov bx,dx
mov dx,conouttbl[bx]
mov bl,dh ;BL = poll device no.
mov dh,0 ;DX = i/o port address
; output routine for console device
push cx ! push dx
mov bh,0 ! call rtm_poll
pop dx ! pop ax
out dx,al ! ret
;=====
plist: ; Function 3: List Output
;=====
; input: CL = character
; DL = list device #
; output: None
mov dh,0 ! shl dx,1
mov bx,dx
mov dx,louttbl[bx]
mov bl,dh ;BL = poll device no.
mov dh,0 ;DX = list port address
; output routine for list device
push cx ! push dx
mov bh,0 ! call rtm_poll
pop dx ! pop ax
out dx,al ! ret
;=====
punch: ; Function 4: Punch Output
reader: ; Function 5: Reader Output
;======
; PUNCH and READER devices are not supported
; under MP/M-86
; input: CL = character
; output: AL = character (control Z)
mov al,1ah ! ret ; return EOF
;------
plstst: ; convert poll device no.
;------ ; to list device no.
sub cl,nconsoles * 2
; fall into list status
;======
listst: ; Function 13: List Status
;======
; input: CL = list device number
; output: AL = 0ffh if ready
; = 000h if not ready
mov ch,0 ! shl cx,1
mov bx,cx
mov dx,loutsttbl[bx]
mov bl,dh ;BL = status mask
mov dh,0 ;DX = output port address
; find output status of List device
in al,dx
and al,bl
cmp al,bl
mov al,0ffh
jz gstat
mov al,0
gstat: ret
;==========
maxconsole: ; Function 20: Maximum Consoles
;==========
; input: None
; output: AL = number of consoles
mov ax,nconsoles ! ret
;=======
maxlist: ; Function 21: Maximum List Devices
;=======
; input: None
; output: AL = number of consoles
mov ax,nlists ! ret
;*****************************************************
;*
;* DISK I/O CODE AREA
;*
;*****************************************************
;====
HOME: ; Function 6: Home
;====
; move selected disk to home position (Track 0)
; If there is Hardware home function, it should
; be done here otherwise, do a settrk to 0
; input: None
; output: None
mov trk,0 ;set disk i/o to track zero
xor bx,bx
mov bl,disk ;index into disk home routine
shl bx,1
jmp dskhomtbl[bx]
flpy_home:
mov bx,offset hom_com
call execute ;home drive
hom_ret:
ret ; and return
;======
SELDSK: ; Function 7: Select Disk
;======
; input: CL = disk to be selected
; output: AX = 0 if illegal disk
; = offset of DPH relative from
; XIOS Data Segment
xor ax,ax ;zero registers ax and bx
mov bx,ax
mov ch,0 ;translate logical disk
mov si,cx ;to physical disk device
mov al,dtrntbl[si]
cmp al,0ffh ;valid disk select?
jz sel_ret ;if not valid return
;else compute the
; disk parameter address
mov disk,al ;save physical drive no.
mov cl,4
shl al,cl ;multiply by 16
add ax,offset dp_base
mov bx,ax
sel_ret:
mov ax,bx
ret
;======
SETTRK: ; Function 8: Set Track
;======
; input: CX = Track Number
; output: None
mov trk,cl ;we only use 8 bits of
; track address
ret
;======
SETSEC: ; Function 9: Set Sector
;======
; input: CX = Sector Number
; output: None
mov sect,cl ;we only use 8 bits of
; sector address
ret
;======
SETDMA: ; Function 10: Set DMA Offset
;======
; input: CX = Offset of DMA buffer
; output: None
mov dma_adr,CX
ret
;*********************************************
;* *
;* All disk I/O parameters are setup: the *
;* Read and Write entry points transfer one *
;* sector of 128 bytes to/from the current *
;* DMA address using the current disk drive *
;* *
;*********************************************
;====
READ: ; Function 11: Read
;====
; input: None
; output: AL = 00h if no error occured
; = 01h if error occured
xor bx,bx
mov bl,disk ;index into disk read routine
shl bx,1
jmp dskrdtbl[bx]
;***** MDISK SUPPORT *****
if memdisk
;
mdsk_read:
call mdisk_calc
mov di,dma_adr ! mov si,0
push es ! mov es,dma_seg
push ds ! mov ds,ax
mov cx,64 ! rep movs ax,ax
pop ds ! pop es
mov ax,0 ! ret
;
endif
;*************************
flpy_read:
mov al,12h ;basic read sector command
jmps r_w_common
;***** MDISK SUPPORT *****
if memdisk
;
mdisk_calc:
mov bh,0 ! mov bl,trk
mov ax,26 ! mul bx
mov bh,0 ! mov bl,sect
add ax,bx ! mov cl,3
shl ax,cl ! add ax,mdiskbase+1
ret
;
endif
;*************************
;=====
WRITE: ; Function 12: Write
;=====
; input: CL = 0 - deferred write
; 1 - non-deferred write
; 2 - def wrt 1st sect unalloc blk
; 3 - non-def 1st sect unalloc blk
; output: AL = 00h if no error occured
; = 01h if error occured
; = 02h if read/only disk
xor bx,bx
mov bl,disk ;index into disk write routine
shl bx,1
jmp dskwrttbl[bx]
;***** MDISK SUPPORT *****
if memdisk
;
mdsk_write:
call mdisk_calc
mov di,0 ! mov si,dma_adr
push es ! mov es,ax
push ds ! mov ds,dma_seg
mov cx,64 ! rep movs ax,ax
pop ds ! pop es
mov ax,0 ! ret
;
endif
;*************************
flpy_write:
mov al,0ah ;basic write sector command
r_w_common:
mov bx,offset io_com ;point to command string
mov byte ptr 1[BX],al ;put command into string
; fall into execute and return
execute: ;execute command string.
;[BX] points to length,
; followed by Command byte,
; followed by length-1 parameter bytes
mov al,80h
test disk,1 ;A drive is even phys. drive
jnz exec1 ;B drive is odd phys. drive
mov al,40h
exec1: mov sel_mask,al
mov last_com,BX ;save command address
;for retries
outer_retry:
;allow some retrying
mov rtry_cnt,max_retries
retry:
mov BX,last_com
call send_com ;transmit command to i8271
; check status poll
mov BX,last_com
mov al,1[bx] ;get command op code
mov cx,0800h ;mask if it will be "int req"
cmp al,2ch
jb flpy_poll ;ok if it is an interrupt type
mov cx,8080h ;else use "not command busy"
and al,0fh
cmp al,0ch ; unless there isn't
mov al,0
ja exec_exit ; any result
;poll for bits in CH,
flpy_poll: ; toggled with bits in CL
mov status_mask,cx
mov bx,flpy_poll_dev ! call rtm_poll
;Operation complete,
in al,fdc_rslt ; see if result indicates
and al,1eh ; an error
jz exec_exit ;no error, then exit
;some type of error occurred
cmp al,10h
jne dr_rdy ;was it a not ready drive ?
;yes, here to wait for drive ready
call test_ready
jnz dr_rdy ;if ready try again
call test_ready
;if not ready twice in row,
dr_rdy: ; then we just retry read or write
dec rtry_cnt
jnz retry ; up to 10 times
; retries do not recover from the
; hard error
cmp al,012h ; check if r/o disk
jne err_exit
mov al,02h ; return r/o error code
ret
err_exit:
mov ah,0 ;setup error table index
mov bx,ax ;make error code 16 bits
mov bx,errtbl[BX]
call pmsg ;print appropriate message
mov al,01h ;set code for permanent error
exec_exit:
ret
;*********************************************
;* *
;* The i8271 requires a read status command *
;* to reset a drive-not-ready after the *
;* drive becomes ready *
;* *
;*********************************************
test_ready:
mov dh, 40h ;proper mask if dr 1
test sel_mask,80h
jnz nrdy2
mov dh, 04h ;mask for dr 0 status bit
nrdy2:
mov bx,offset rds_com
call send_com
dr_poll:
in al,fdc_stat ;get status word
test al,80h
jnz dr_poll ;wait for not command busy
in al,fdc_rslt ;get "special result"
test al,dh ;look at bit for this drive
and al,01eh
ret ;return status of ready
;*********************************************
;* *
;* Send_com sends a command and parameters *
;* to the i8271: BX addresses parameters. *
;* The DMA controller is also initialized *
;* if this is a read or write *
;* *
;*********************************************
send_com:
in al,fdc_stat
test al,80h ;insure command not busy
jnz send_com ;loop until ready
;check to initialize for a DMA operation
mov al,1[bx] ;get command byte
cmp al,12h
jne write_maybe ;if not read it maybe write
mov cl,40h ;is a read command, go set DMA
jmps init_dma
write_maybe:
cmp al,0ah
jne dma_exit ;leave DMA if not read/write
mov cl,80h ;we have write, not read
init_dma:
; read or write operation, setup DMA controller
; (CL contains proper direction bit)
mov al,04h
out dmac_mode,al ;enable dmac
mov al,00
out dmac_cont,al ;1st byte to ctrl port
mov al,cl
out dmac_cont,al ;load direction register
mov ax,dma_adr
out dmac_adr,al ;send low byte of DMA
mov al,ah
out dmac_adr,al ;send high byte
mov ax,dma_seg
out fdc_segment,al ;send low byte of seg addr
mov al,ah
out fdc_segment,al ;then high segment address
dma_exit:
mov cl,[BX] ;get count
inc BX
mov al,[BX] ;get command
or al,sel_mask ;merge command and drive code
out fdc_com,al ;send command byte
parm_loop:
dec cl
jz exec_exit ;no (more) parameters, return
inc BX ;point to (next) parameter
parm_poll:
in al,fdc_stat
test al,20h ;"parameter register full" bit
jnz parm_poll ;idle until parm reg not full
mov al,[BX]
out fdc_parm,al ;send next parameter
jmps parm_loop ;see if more parameters
flpy_poll_stat:
;--------------
; See if current operation complete
mov cx,cs:status_mask
in al,fdc_stat ;read status
and al,ch
xor al,cl ;isolate what we want to poll
mov al,0
jz flpy_poll_nrdy
mov al,0ffh
flpy_poll_nrdy:
ret
;=======
SECTRAN: ; Function 14: Sector Translate
;=======
; Translate sector number given a translate table
; If the translate table address is 0, don't translate
; input: CX = Sector Number
; DX = Offset of Translate Table
; output: AX = Translated Sector Number
cmp dx,0 ! jne sectran1
mov ax,cx ! ret
sectran1:
mov bx,cx
add bx,dx ;add sector to tran table addr
mov bl,[bx] ;get logical sector
xor bh,bh
mov ax,bx
ret
;=======
SETDMAB: ; Function 15: Set DMA Base
;=======
; set DMA segment
; input: CX = Segment of DMA buffer
; output: None
mov dma_seg,CX
ret
;========
flushbuf: ; Function 24: 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
ret ;with no blocking/deblocking
;*****************************************************
;*
;* 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: BX = device #
push bx ! mov cx,bx
call polldev ! pop bx
cmp al,0ffh ! je pllret
cmp stoppoll,true ! je rtm_poll
;---------
rtm_poll1: ; do poll_dev with no pretest
;---------
mov dx,bx ! mov cl,f_polldev
jmp supif
pllret: ret
;=======
polldev: ; Function 17: Poll Device
;=======
; input: CL = device number
; output: AL = 000h if not ready
; = 0ffh if ready
mov bh,0 ! mov bl,cl
shl bx,1
jmp polltbl[bx]
;=======
strtclk: ; Function 18: Start Clock
;=======
; Enable Flagsets on Tick Interrupts
; input: None
; output: None
mov clockon,true
ret
;=======
stopclk: ; Function 19: Stop Clock
;=======
; Disable Flagsets on Tick Interrupts
; input: None
; output: None
mov clockon,false
ret
;=======
getsegt: ; Function 16: Get Segment Table
;=======
; Not supported by MP/M-86
; input: None
; output: AX = 0ffffh
mov ax,0ffffh ! ret
;=========
selmemory: ; Function 22: Select Memory
;=========
; input: None
; output: None
ret
;====
idle: ; Function 23: Idle
;====
; input: None
; output: None
;
; The Idle routine is called by the Idle Process.
; Since the Idle routine has the worst priority (255)
; in the system, It will run only when nothing else
; can run. This routine cannot use any resources that
; may take it off the Ready List. This includes any
; kind of I/O that uses Poll Device or System Flags.
mov cl,f_dispatch
call supif
jmp idle
; If all devices are Interrupt Driven then the Idle
; Routine can be the following instead:
; halt ! jmp idle
; This cannot be used if any I/O uses POLL DEVICE
; since polling is only done during dispatches.
;=====
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
nop ! nop
;*****************************************************
;*
;* 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 const ; 0-console status
dw conin ; 1-console input
dw conout ; 2-console output
dw plist ; 3-list output
dw punch ; 4-punch output
dw reader ; 5-reader input
dw HOME ; 6-home
dw SELDSK ; 7-select disk
dw SETTRK ; 8-set track
dw SETSEC ; 9-set sector
dw SETDMA ;10-set DMA offset
dw READ ;11-read
dw WRITE ;12-write
dw listst ;13-list status
dw sectran ;14-sector translate
dw setdmab ;15-set DMA base
dw getsegt ;16-get segment table
dw polldev ;17-poll device
dw strtclk ;18-start clock
dw stopclk ;19-stop clock
dw maxconsole ;20-maximum consoles
dw maxlist ;21-max list devices
dw selmemory ;22-select memory
dw idle ;23-idle
dw flushbuf ;24-flush buffer
;-----------------------------------------------------
;
; routines to find device status
; on poll device calls
;
polltbl dw const ;00-con 0 in
dw const ;01-con 1 in
dw const ;02-con 2 in
dw const ;03-con 3 in
dw const ;04-con 0 out
dw const ;05-con 1 out
dw const ;06-con 2 out
dw const ;07-con 3 out
dw plstst ;08-list 0 out
dw flpy_poll_stat ;09-dsk status
signon db cr,lf
db 'MP/M-86 V2.0 for SBC 8612',cr,lf,0
int_trp db ' Uninitialized Interrupt',cr,lf,0
loc_stk rw 32 ;local stack for initialization
stkbase equ offset $
tickint_tos rw 0
initss rw 1
initsp rw 1
rw 32
initstack rw 0
;*****************************************************
;*
;* CHARACTER I/O DATA AREA
;*
;*****************************************************
;
org ((offset $) + 1) and 0fffeh
;
; console i/o table for
; status mask and port address
;
consttbl dw (c0inmsk shl 8) or c0stport
dw (c1inmsk shl 8) or c1stport
dw (c2inmsk shl 8) or c2stport
dw (c3inmsk shl 8) or c3stport
dw (c0outmsk shl 8) or c0stport
dw (c1outmsk shl 8) or c1stport
dw (c2outmsk shl 8) or c2stport
dw (c3outmsk shl 8) or c3stport
;
; console input table for
; poll device no. and port address
;
conintbl dw (c0indev shl 8) or c0ioport
dw (c1indev shl 8) or c1ioport
dw (c2indev shl 8) or c2ioport
dw (c3indev shl 8) or c3ioport
;
; console output table for
; poll device no. and port address
;
conouttbl dw (c0outdev shl 8) or c0ioport
dw (c1outdev shl 8) or c1ioport
dw (c2outdev shl 8) or c2ioport
dw (c3outdev shl 8) or c3ioport
;
; list i/o table for
; status mask and port address
;
loutsttbl dw (l0outmsk shl 8) or l0stport
;
; list output for
; poll device no. and port address
;
louttbl dw (l0outdev shl 8) or l0ioport
;*****************************************************
;*
;* DISK DATA AREA
;*
;*****************************************************
errtbl dw er0,er1,er2,er3
dw er4,er5,er6,er7
dw er8,er9,erA,erB
dw erC,erD,erE,erF
er0 db cr,lf,'Null Error ??',0
er1 equ er0
er2 equ er0
er3 equ er0
er4 db cr,lf,'Clock Error :',0
er5 db cr,lf,'Late DMA :',0
er6 db cr,lf,'ID CRC Error :',0
er7 db cr,lf,'Data CRC Error :',0
er8 db cr,lf,'Drive Not Ready :',0
er9 db cr,lf,'Write Protect :',0
erA db cr,lf,'Trk 00 Not Found :',0
erB db cr,lf,'Write Fault :',0
erC db cr,lf,'Sector Not Found :',0
erD equ er0
erE equ er0
erF equ er0
nrdymsg equ er8
rtry_cnt db 0 ;disk error retry counter
last_com dw 0 ;address of last command string
dma_adr dw 0 ;dma offset stored here
dma_seg dw 0 ;dma segment stored here
sel_mask db 40h ;select mask, 40h or 80h
; Various command strings for i8271
io_com db 3 ;length
rd_wr db 0 ;read/write function code
trk db 0 ;track #
sect db 0 ;sector #
hom_com db 2,29h,0 ;home drive command
rds_com db 1,2ch ;read status command
status_mask dw 0 ;mask for flpy_poll
disk db 0 ;physical disk selected
; logical to physical disk
; translation table
; A B C D
dtrntbl db 000h,001h,0ffh,0ffh
; E F G H
db 0ffh,0ffh,0ffh,0ffh
; I J K L
db 0ffh,0ffh,0ffh,0ffh
; M N O P
;*****MDISK SUPPORT*****
if memdisk
db 002h,0ffh,0ffh,0ffh
endif
;***********************
if not memdisk
db 0ffh,0ffh,0ffh,0ffh
endif
; disk home routine table
dskhomtbl dw flpy_home ;A drive
dw flpy_home ;B drive
;*****MDISK SUPPORT*****
if memdisk
dw hom_ret ;M drive
endif
;***********************
; disk read routine table
dskrdtbl dw flpy_read ;A drive
dw flpy_read ;B drive
;*****MDISK SUPPORT*****
if memdisk
dw mdsk_read ;M drive
endif
;***********************
; disk write routine table
dskwrttbl dw flpy_write ;A drive
dw flpy_write ;B drive
;*****MDISK SUPPORT*****
if memdisk
dw mdsk_write ;M drive
endif
;***********************
include singles.lib ;read in disk definitions
;*****************************************************
;*
;* SUP/RTM DATA AREA
;*
;*****************************************************
stoppoll dw false ;disallows poll_device
;for internal printing
;of strings when true
clockon db false ;if true, Tick flag is
;set on Tick interrupts
tick_count db 60
;
; 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
db 0 ;fill last address for GENCMD