home *** CD-ROM | disk | FTP | other *** search
- title 'Customized Basic I/O System'
-
- ;*********************************************
- ;* *
- ;* This Customized BIOS adapts CP/M-86 to *
- ;* the following hardware configuration *
- ;* Processor: 8085/8088 Dual Processor *
- ;* Brand: CompuPro (Godbout) *
- ;* Controller: iCom 3712 *
- ;* *
- ;* *
- ;* Programmer: Bruce R. Ratoff *
- ;* Revisions : 04/30/81 20:40 *
- ;* *
- ;*********************************************
-
- true equ -1
- false equ not true
- cr equ 0dh ;carriage return
- lf equ 0ah ;line feed
-
- ;*********************************************
- ;* *
- ;* Loader_bios is true if assembling the *
- ;* LOADER BIOS, otherwise BIOS is for the *
- ;* CPM.SYS file. *
- ;* *
- ;*********************************************
-
- loader_bios equ false
- bdos_int equ 224 ;reserved BDOS interrupt
-
- ;*********************************************
- ;* *
- ;* I/O Port Assignments *
- ;* *
- ;*********************************************
- ;
- ;Diskette interface (iCom 3712)
- ;Note: Port numbers are "doubled up" because iCom card
- ; counts on 8080 "address mirror" effect.
- datai equ 0c0c0h ;data/status input port
- datao equ 0c1c1h ;data output port
- cntrl equ 0c0c0h ;command output port
- ;
- ;Console interface (IMSAI SIO2-2 port 1)
- cstat equ 3 ;status
- cdata equ 2 ;data
- cimsk equ 2 ;input ready mask
- comsk equ 1 ;output ready mask
- ;
- ;Printer interface (IMSAI SIO2-2 port 2)
- lstat equ 5 ;status
- ldata equ 4 ;data
- lomsk equ 1 ;output ready mask
- limsk equ 2 ;input ready mask
-
-
- IF not loader_bios
- ;---------------------------------------------
- ;| |
- bios_code equ 2500h
- ccp_offset equ 0000h
- bdos_ofst equ 0B06h ;BDOS entry point
- ;| |
- ;---------------------------------------------
- ENDIF ;not loader_bios
-
- IF loader_bios
- ;---------------------------------------------
- ;| |
- bios_code equ 1200h ;start of LDBIOS
- ccp_offset equ 0003h ;base of CPMLOADER
- bdos_ofst equ 0406h ;stripped BDOS entry
- ;| |
- ;---------------------------------------------
- ENDIF ;loader_bios
-
- cseg
- org ccpoffset
- ccp:
- org bios_code
-
- ;*********************************************
- ;* *
- ;* BIOS Jump Vector for Individual Routines *
- ;* *
- ;*********************************************
-
- jmp INIT ;Enter from BOOT ROM or LOADER
- jmp WBOOT ;Arrive here from BDOS call 0
- jmp CONST ;return console keyboard status
- jmp CONIN ;return console keyboard char
- jmp CONOUT ;write char to console device
- jmp LISTOUT ;write character to list device
- jmp PUNCH ;write character to punch device
- jmp READER ;return char from reader device
- jmp HOME ;move to trk 00 on cur sel drive
- jmp SELDSK ;select disk for next rd/write
- jmp SETTRK ;set track for next rd/write
- jmp SETSEC ;set sector for next rd/write
- jmp SETDMA ;set offset for user buff (DMA)
- jmp READ ;read a 128 byte sector
- jmp WRITE ;write a 128 byte sector
- jmp LISTST ;return list status
- jmp SECTRAN ;xlate logical->physical sector
- jmp SETDMAB ;set seg base for buff (DMA)
- jmp GETSEGT ;return offset of Mem Desc Table
- jmp GETIOBF ;return I/O map byte (IOBYTE)
- jmp SETIOBF ;set I/O map byte (IOBYTE)
-
- ;*********************************************
- ;* *
- ;* INIT Entry Point, Differs for LDBIOS and *
- ;* BIOS, according to "Loader_Bios" value *
- ;* *
- ;*********************************************
-
- INIT: ;print signon message and initialize hardware
- mov ax,cs ;we entered with a JMPF so use
- mov ss,ax ;CS: as the initial value of SS:,
- mov ds,ax ;DS:,
- mov es,ax ;and ES:
- ;use local stack during initialization
- mov sp,offset stkbase
- cld ;set forward direction
-
- IF not loader_bios
- ;---------------------------------------------
- ;| |
- ; This is a BIOS for the CPM.SYS file.
- ; Setup all interrupt vectors in low
- ; memory to address trap
-
- push ds ;save the DS register
- mov IOBYTE,0 ;clear IOBYTE
- mov ax,0
- mov ds,ax
- mov es,ax ;set ES and DS to zero
- ;setup interrupt 0 to address trap routine
- mov int0_offset,offset int_trap
- mov int0_segment,CS
- mov di,4
- mov si,0 ;then propagate
- mov cx,510 ;trap vector to
- rep movs ax,ax ;all 256 interrupts
- ;BDOS offset to proper interrupt
- mov bdos_offset,bdos_ofst
- mov int0_offset,offset int0_trap
- mov int4_offset,offset int4_trap
- pop ds ;restore the DS register
-
- ; (additional CP/M-86 initialization)
- ;| |
- ;---------------------------------------------
- ENDIF ;not loader_bios
-
- IF loader_bios
- ;---------------------------------------------
- ;| |
- ;This is a BIOS for the LOADER
- push ds ;save data segment
- mov ax,0
- mov ds,ax ;point to segment zero
- ;BDOS interrupt offset
- mov bdos_offset,bdos_ofst
- mov bdos_segment,CS ;bdos interrupt segment
- ; (additional LOADER initialization)
- pop ds ;restore data segment
- ;| |
- ;---------------------------------------------
- ENDIF ;loader_bios
-
- mov bx,offset signon
- call pmsg ;print signon message
- mov cl,0 ;default to dr A: on coldstart
- jmp ccp ;jump to cold start entry of CCP
-
- WBOOT: jmp ccp+6 ;direct entry to CCP at command level
-
- IF not loader_bios
- ;---------------------------------------------
- ;| |
- int0_trap:
- cli
- mov bx,offset int0_trp
- jmps int_halt
- int4_trap:
- cli
- mov bx,offset int4_trp
- jmps int_halt
- int_trap:
- cli ;block interrupts
- mov bx,offset int_trp
- int_halt:
- mov ax,cs
- mov ds,ax ;get our data segment
- call pmsg
- pop bx ;get offset
- pop ax ;print segment
- push bx ;save offset
- call PHEX
- mov cl,':' ;colon
- call CONOUT
- pop ax ;print offset
- call PHEX
- hlt ;hardstop
-
- PHEX:
- push ax
- mov al,ah
- call PHXB ;print upper byte
- pop ax ;restore to print lower byte
- PHXB:
- push ax ;save byte
- mov cl,4 ;get high nibble
- shr al,cl ;into low bits
- call PHXD ;print digit
- pop ax ;restore byte
- and al,0fh ;isolate low nibble
- PHXD:
- add al,90h ;first half of conversion trick
- daa
- add al,40h ;second half of same
- daa
- mov cl,al ;now print digit
- jmps CONOUT
- ;| |
- ;---------------------------------------------
- ENDIF ;not loader_bios
-
- ;*********************************************
- ;* *
- ;* CP/M Character I/O Interface Routines *
- ;* *
- ;*********************************************
-
- CONST: ;console status
- in al,cstat ;get status byte
- and al,cimsk ;check input mask
- jz const1 ;not ready yet...return al=0, ZF=1
- or al,0ffh ;ready...return al=0FFh, ZF=0
- CONST1:
- ret
-
- CONIN: ;console input
- call CONST
- jz CONIN ;wait for RDA
- in al,cdata;get byte
- and al,7fh ;strip parity
- ret
-
- CONOUT: ;console output
- in al,cstat ;get status
- test al,comsk ;check output bits
- jz conout ;loop till ready
- mov al,cl ;setup
- out cdata,al ;send character
- ret ;then return data
-
- LISTOUT: ;list device output
- call LISTST ;get output status
- jz LISTOUT ;wait for TBE
- mov al,cl ;setup
- out ldata,al ;send char
- in al,lstat ;check for handshake received
- and al,limsk
- jz LISTOUT2 ;no handshake...exit
- in al,ldata ;get handshake char
- and al,7fh ;strip parity
- cmp al,'S'-40h ;XOFF?
- jnz LISTOUT2 ;nope
- mov lstactive,0ffh ;set list active flag
- LISTOUT2:
- ret
-
- LISTST: ;poll list status
- in al,lstat ;get status byte
- and al,lomsk ;test output bits
- jz LISTST1 ;not ready...exit with al=0, zf=1
- mov al,lstactive ;line ready...waiting for XON?
- not al
- test al,al
- jnz LISTST1 ;not waiting...say ready
- in al,lstat ;check for handshake
- and al,limsk
- jz LISTST1 ;not yet...say still busy
- in al,ldata ;got something...
- and al,7fh ;strip parity
- cmp al,'Q'-40h ;is it XON?
- mov al,0
- jnz LISTST1 ;no, return false
- not al ;ready...exit with al=0ffh, zf=0
- mov lstactive,0 ;clear list active flag
- LISTST1:
- test al,al ;make sure flags are set
- ret
-
- PUNCH: ;write punch device
- ret ;is a "bit bucket"
-
- READER:
- mov al,1ah ;is an EOF source
- ret
-
- GETIOBF:
- mov al,IOBYTE
- ret
-
- SETIOBF:
- mov IOBYTE,cl ;set iobyte
- ret ;iobyte not implemented
-
- pmsg:
- mov al,[BX] ;get next char from message
- test al,al
- jz return ;if zero return
- mov CL,AL
- call CONOUT ;print it
- inc BX
- jmps pmsg ;next character and loop
-
- ;*********************************************
- ;* *
- ;* Disk Input/Output Routines *
- ;* *
- ;*********************************************
-
- SELDSK: ;select disk given by register CL
- ndisks equ 2 ;number of disks (up to 16)
- mov seekfg,0ffh ;set seek flag
- mov disk,cl ;save disk number
- mov bx,0000h ;ready for error return
- cmp cl,ndisks ;n beyond max disks?
- jnb return ;return if so
- mov ch,0 ;double(n)
- mov bx,cx ;bx = n
- mov cl,4 ;ready for *16
- shl bx,cl ;n = n * 16
- mov cx,offset dpbase
- add bx,cx ;dpbase + n * 16
- return: ret ;bx = .dph
-
- HOME: ;move selected disk to home position (Track 0)
- mov cx,0 ;set disk i/o to track zero
- ;**** fall through ****
- SETTRK: ;set track address given by CX
- mov trk,CX
- mov seekfg,0ffh ;set seek flag
- ret
-
- SETSEC: ;set sector number given by cx
- mov sect,CX
- ret
-
- SECTRAN: ;translate sector CX using table at [DX]
- mov bx,cx
- add bx,dx ;add sector to tran table address
- mov bl,[bx] ;get logical sector
- ret
-
- SETDMA: ;set DMA offset given by CX
- mov dma_adr,CX
- ret
-
- SETDMAB: ;set DMA segment given by CX
- mov dma_seg,CX
- ret
- ;
- GETSEGT: ;return address of physical memory table
- mov bx,offset seg_table
- ret
-
- ;*********************************************
- ;* *
- ;* All disk I/O parameters are setup: *
- ;* DISK is disk number (SELDSK) *
- ;* TRK is track number (SETTRK) *
- ;* SECT is sector number (SETSEC) *
- ;* DMA_ADR is the DMA offset (SETDMA) *
- ;* DMA_SEG is the DMA segment (SETDMAB)*
- ;* READ reads the selected sector to the DMA*
- ;* address, and WRITE writes the data from *
- ;* the DMA address to the selected sector *
- ;* (return 00 if successful, 01 if perm err)*
- ;* *
- ;*********************************************
-
- READ:
- mov cl,10 ;set retry count
- READ1:
- call STUP ;set up unit/track/sector
- mov al,3 ;send read command
- call DLOOP
- mov dx,datai ;set port number
- in al,dx ;get back status
- test al,8 ;check CRC flag
- jz RDOK ;no error...go get data
- dec cl ;got an error...count retrys
- jnz READ2 ;some retrys left...continue
- mov al,1 ;bad news....return error
- ret
- READ2:
- test cl,3 ;time for a re-seek?
- jpo READ1 ;no, just reread
- mov seekfg,0ffh ;yes, set seek flag
- call RESET ;clear errors, home drive
- jmps READ1 ;try read again
- RDOK:
- mov cx,128 ;set byte counter
- cld ;set forward direction
- push es ;save extra segment
- les di,dword ptr dma_adr ;set dest index and segment
- mov dx,cntrl
- RDLUP:
- mov ax,40h ;send "examine read buffer" command
- out dx,al ;to disk control port
- in al,dx ;get data byte
- stos al ;store it, bump pointer and count
- mov al,41h ;send "step read buffer" command
- out dx,al ;to controller
- loop RDLUP ;repeat 128 times
- pop es ;restore extra segment
- mov al,0 ;return good status
- out dx,al ;also put controller in status mode
- ret
-
- WRITE:
- mov cx,128 ;set 128 byte counter
- cld ;set forward direction
- push ds ;save current data segment
- lds si,dword ptr dma_adr ;set source index
- WRLUP:
- lods al ;get next byte
- mov dx,datao
- out dx,al ;send to controller
- mov al,31h ;send "shift write buffer" command
- mov dx,cntrl
- out dx,al ;to controller
- mov al,0 ;remove command
- out dx,al ;(bit 0 must toggle to be seen)
- loop WRLUP ;repeat for sector length times
- pop ds
- RTRYP:
- call STUP ;setup for write
- in al,dx ;check controller status
- test al,10h ;write protected?
- jz TRYWR ;no, continue
- mov bx,offset prtmsg ;say "protected"
- call ERROR ;and wait for user action
- jmps RTRYP ;retry if user hits return key
- TRYWR:
- mov al,5 ;send write command
- call DLOOP ;to controller with wait
- WROK:
- mov al,0 ;return good status
- ret
-
- ;*********************************************
- ;* *
- ;* Disk Utility Routines *
- ;* *
- ;*********************************************
- ;
- ;print an error message and wait for user response
- ;if control-c, then abort to cp/m, else return
- ;to caller and (usually) retry operation
- ERROR:
- call PMSG ;print an error message
- call CONIN ;wait for user response
- push ax ;save character
- mov bx,offset crlf ;echo cr, lf
- call PMSG
- pop ax ;now look at char
- cmp al,3 ;control-c?
- jz ERR1 ;yes, return to cp/m
- ret ;else retry error'd operation
- ERR1:
- mov cl,0 ;tell cp/m user 0, drive A
- jmp ccp ;bye-bye
-
- ;Perform select and possibly seek logic for either a
- ;read or write operation.
- STUP:
- mov al,0bh ;issue "reset errors" command
- call DLOOP ;to controller with wait
- mov al,disk ;get drive number
- mov cl,6 ;prepare to shift into
- shl ax,cl ;high 2 bits of cmd byte
- or ax,sect ;put sector number in low bits
- mov dx,datao
- out dx,al ;send to controller
- mov al,21h ;issue "set unit/sector" command
- call DLOOP
- mov dx,datai
- mov cx,100 ;set up delay loop
- STUP0:
- mov bx,8000 ;inner delay loop
- STUP1:
- in al,dx ;get controller status
- test al,20h ;check "drive fail" (ready) flag
- jz STUP2 ;no problem...continue
- dec bx ;count down inner delay loop
- jnz STUP1
- loop STUP0 ;count down outer delay loop
- mov bx,offset rdymsg ;timed out...complain
- call error ;and wait for response
- jmps STUP ;retry the whole mess
- STUP2:
- mov al,0 ;clear seek flag
- xchg al,seekfg ;and fetch previous value
- test al,al ;was it set?
- jnz stup3 ;yes, go do seek or home
- ret ;no seek needed...exit
- STUP3:
- mov ax,trk ;look at track number
- test al,al ;is it 0?
- jz RESET ;yes, do a home
- mov dx,datao
- out dx,al ;otherwise, set new track
- mov al,11h ;give "set track" command
- call DLOOP
- mov al,9 ;then give "seek" command
- ;**** fall through ****
- ;
- ;This routine issues a controller command and waits for completion
- DLOOP:
- mov dx,cntrl
- out dx,al ;send command
- mov al,0 ;strobe it off
- out dx,al
- LOOP1:
- in al,dx ;get controller status
- test al,1 ;check ready bit
- jnz LOOP1 ;loop till ready
- ret ;then exit
- ;
- ;This routine issues a "clear" command followed by a "home" command
- RESET:
- mov al,81h ;send "clear"
- call DLOOP
- mov al,0dh ;send "home"
- jmps DLOOP
-
-
- ;*********************************************
- ;* *
- ;* Data Areas *
- ;* *
- ;*********************************************
- data_offset equ offset $
-
- dseg
- org data_offset ;contiguous with code segment
- lstactive db 0 ;set if list handshake active
- IOBYTE db 0 ;i/o assignments (unused at present)
- seekfg db 0 ;set to 0ffh if next access requires seek
- disk db 0 ;disk number
- trk dw 0 ;track number
- sect dw 0 ;sector number
- dma_adr dw 0 ;DMA offset from DS
- dma_seg dw 0 ;DMA Base Segment
-
- signon db cr,lf,cr,lf
- db 'CP/M-86 Version 1.0 for iCom 3712',cr,lf
- db 'System Generated 04/30/81'
- db cr,lf,0
-
- int_trp db cr,lf
- db 'Interrupt Trap Halt at ',0
-
- int0_trp db cr,lf
- db 'Divide Trap Halt at ',0
-
- int4_trp db cr,lf
- db 'Overflow Trap Halt at ',0
-
- rdymsg db cr,lf
- db 'Drive not ready',0
-
- prtmsg db cr,lf
- db 'Drive write protected',0
-
- crlf db cr,lf,0
-
- ; System Memory Segment Table
-
- segtable db 1 ;1 segment
- dw tpa_seg ;1st seg starts after BIOS
- dw tpa_len ;and extends to 0ffff
-
- include singles.lib ;read in disk definitions
-
- loc_stk rw 32 ;local stack for initialization
- stkbase equ offset $
-
- lastoff equ offset $
- tpa_seg equ (lastoff+0400h+15) / 16
- tpa_len equ 0fffh - tpa_seg ; 64K less 16 byte reset vector less cp/m size
-
- db 0 ;fill last address for GENCMD
-
- ;*********************************************
- ;* *
- ;* Dummy Data Section *
- ;* *
- ;*********************************************
- dseg 0 ;absolute low memory
- org 0 ;(interrupt vectors)
- int0_offset rw 1
- int0_segment rw 1
- ; pad to overflow trap vector
- rw 6
- int4_offset rw 1
- int4_segment rw 1
- ; pad to system call vector
- rw 2*(bdos_int-5)
-
- bdos_offset rw 1
- bdos_segment rw 1
- END
-