IMD 1.16: 13/08/2007 18:24:13 bios osborne source files *master* 10/9/81  ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċOCCBIO2AH OCCBIOS1H `OCCBIO82HA € OCCBIO82HA OCCBIO63ASM OCCBIO1AH OCCBIO4AH OCCBIO6AH OCCBIO7AH OCCBIO8AH OCCBIO11HA OCCBIO41HA OCCBIO61HA !OCCBIO71HA "OCCBIO81HA #$%&'()*OCCBIO5AH +,OCCBIO3AH -OCCBIO43ASM./OCCBIO0AH 0OCCBIO42HA 12OCCBIO62HA 34OCCBIO02HA 5OCCBIO83ASM€6789:;<=OCCBIO83ASM>?OCCBIO33ASM @OCCBIO53ASMABOCCBIO03ASM COCCBIO21HA DOCCBIO23ASMEOCCBIO51HA FGOCCBIO01HA HOCCBIO31HA Iċ; MDS-800 I/O Drivers for CP/M 2.2 ; (four drive single density version) ; ; Version 2.2 February, 1980 ; vers equ 22 ;version 2.2 ; ; Copyright (c) 1980 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 ; ; true equ 0ffffh ;value of "true" false equ not true ;"false" test equ false ;true if test bios ; if test bias equ 03400h ;base of CCP in test system endif if not test bias equ 0000h ;generate relocatable cp/m system endif ; patch equ 1600h ; org patch cpmb equ $-patch ;base of cpm console processor bdos equ 806h+cpmb ;basic dos (resident portion) cpml equ $-cpmb ;length (in bytes) of cpm system nsects equ cpml/128 ;number of sectors to load offset equ 2 ;number of disk tracks used by cp/m cdisk equ 0004h ;address of last logged disk on warm start buff equ 0080h ;default buffer address retry equ 10 ;max retries on disk i/o before error ; ; perform following functions ; boot cold start ; wboot warm start (save i/o byte) ; (boot and wboot are the sameOCCBIO22HA JOCCBIO72HA KOCCBIO12HA LMOCCBIO32HA NOCCBIO52HA OPOCCBIO73ASMQOCCBIO13ASMRSċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ page ; Sector Translation Tables. XLTS: ;Translation table 2 to 1 DB 0, 1, 4, 5, 8, 9, 12,13, 16,17 DB 2, 3, 6, 7, 10,11, 14,15, 18,19 ; Translation 3 to 1 ; DB 0, 1, 6, 7, 12,13, 18,19 ; DB 2, 3, 8, 9, 14,15 ; DB 4, 5, 10,11, 16,17 ; Translation 4 to 1 ; DB 0, 1, 8, 9, 16,17 ; DB 2, 3, 10, 11, 18,19 ; DB 4, 5, 12, 13 ; DB 6, 7, 14, 15 IF (*-XLTS) <> (MSEC*2) MSG 'Translation table error',ERROR ENDIF space 4,10 ; Control Blocks for disk drives DPBASE: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive A: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive B: space 4,10 ; Disk type definition blocks for each particular mode. DPBS1: ;Single density, single sided. DPBGEN DSKS1,2*MSEC,4,15,1,S1DSM,64,1000000000000000b,3 .AL IF ALVSZ <> ALVS MSG 'Allocation problems ALVS<> ALVSZ, ALVSZ= ',ALVSZ .9 ERROR .AL ENDIF ; endx OSBBIOS2  for mds) ; const console status ; reg-a = 00 if no character ready ; reg-a = ff if character ready ; conin console character in (result in reg-a) ; conout console character out (char in reg-c) ; list list out (char in reg-c) ; punch punch out (char in reg-c) ; reader paper tape reader in (result to reg-a) ; home move to track 00 ; ; (the following calls set-up the io parameter block for the ; mds, which is used to perform subsequent reads and writes) ; seldsk select disk given by reg-c (0,1,2...) ; settrk set track address (0,...76) for subsequent read/write ; setsec set sector address (1,...,26) for subsequent read/write ; setdma set subsequent dma address (initially 80h) ; ; (read and write assume previous calls to set up the io parameters) ; read read track/sector to preset dma address ; write write track/sector from preset dma address ; ; jump vector for indiviual routines jmp boot wboote: jmp wboot jmp const jmp conin jmp conout jmp list jmp punch jmp reader jmp ċċhome jmp seldsk jmp settrk jmp setsec jmp setdma jmp read jmp write jmp listst ;list status jmp sectran ; maclib diskdef ;load the disk definition library disks 4 ;four disks diskdef 0,1,26,6,1024,243,64,64,offset diskdef 1,0 diskdef 2,0 diskdef 3,0 ; endef occurs at end of assembly ; ; end of controller - independent code, the remaining subroutines ; are tailored to the particular operating environment, and must ; be altered for any system which differs from the intel mds. ; ; the following code assumes the mds monitor exists at 0f800h ; and uses the i/o subroutines within the monitor ; ; we also assume the mds system has four disk drives revrt equ 0fdh ;interrupt revert port intc equ 0fch ;interrupt mask port icon equ 0f3h ;interrupt control port inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor) ; ; mds monitor equates mon80 equ 0f800h ;mds monitor rmon80 equ 0ff0fh ;restart mon80 (boot error) ci equ 0f803h ;console character to reg-a ri equ 0f8066 ;read last sector? jc rd1 ; must be sector 26, zero and go to next track lda iot ;get track to register a inr a mov c,a ;ready for call call settrk xra a ;clear sector number rd1: inr a ;to next sector mov c,a ;ready for call call setsec pop b ;recall sector count dcr b ;done? jnz rdsec ; ; done with the load, reset default buffer address gocpm: ;(enter here from cold start boot) ; enable rst0 and rst7 di mvi a,12h ;initialize command out revrt xra a out intc ;cleared mvi a,inte ;rst0 and rst7 bits on out intc xra a out icon ;interrupt control ; ; set default buffer address to 80h lxi b,buff call setdma ; ; reset monitor entry points mvi a,jmp sta 0 lxi h,wboote shld 1 ;jmp wboot at location 00 sta 5 lxi h,bdos shld 6 ;jmp bdos at location 5 if not test sta 7*8 ;jmp to mon80 (may have been changed by ddt) lxi h,mon80 shld 7*8+1 endif ; leave iobyte set ; previously selected disk was b, send parameter to cpm lda cdisk ;last logL ret ; setdma: ;set dma address given by regs b,c mov l,c mov h,b shld iod ret ; read: ;read next disk record (assuming disk/trk/sec/dma set) mvi c,readf ;set to read function call setfunc call waitio ;perform read function ret ;may have error set in reg-a ; ; write: ;disk write function mvi c,writf call setfunc ;set to write function call waitio ret ;may have error set ; ; ; utility subroutines prmsg: ;print message at h,l to 0 mov a,m ora a ;zero? rz ; more to print push h mov c,a call conout pop h inx h jmp prmsg ; setfunc: ; set function for next i/o (command in reg-c) lxi h,iof ;io function address mov a,m ;get it to accumulator for masking ani 11111000b ;remove previous command ora c ;set to new command mov m,a ;replaced in iopb ; the mds-800 controller requires disk bank bit in sector byte ; mask the bit from the current i/o function ani 00100000b ;mask the disk select bit lxi h,ios ;address the sector select byte ora m ;h ;reader in to reg-a co equ 0f809h ;console char from c to console out po equ 0f80ch ;punch char from c to punch device lo equ 0f80fh ;list from c to list device csts equ 0f812h ;console status 00/ff to register a ; ; disk ports and commands base equ 78h ;base of disk command io ports dstat equ base ;disk status (input) rtype equ base+1 ;result type (input) rbyte equ base+3 ;result byte (input) ; ilow equ base+1 ;iopb low address (output) ihigh equ base+2 ;iopb high address (output) ; readf equ 4h ;read function writf equ 6h ;write function recal equ 3h ;recalibrate drive iordy equ 4h ;i/o finished mask cr equ 0dh ;carriage return lf equ 0ah ;line feed ; signon: ;signon message: xxk cp/m vers y.y db cr,lf,lf if test db '32' ;32k example bios endif if not test db '00' ;memory size filled by relocator endif db 'k CP/M vers ' db vers/10+'0','.',vers mod 10+'0' db cr,lf,0 ; boot: ;print signon message and go to ccp ; (note: mds boot initialized iobyte at 0003h) lxi ged disk number mov c,a ;send to ccp to log it in ei jmp cpmb ; ; error condition occurred, print message and retry booterr: pop b ;recall counts dcr c jz booter0 ; try again push b jmp wboot0 ; booter0: ; otherwise too many retries lxi h,bootmsg call prmsg jmp rmon80 ;mds hardware monitor ; bootmsg: db '?boot',0 ; ; const: ;console status to reg-a ; (exactly the same as mds call) jmp csts ; conin: ;console character to reg-a call ci ani 7fh ;remove parity bit ret ; conout: ;console character from c to console out jmp co ; list: ;list device out ; (exactly the same as mds call) jmp lo ; listst: ;return list status xra a ret ;always not ready ; punch: ;punch device out ; (exactly the same as mds call) jmp po ; reader: ;reader character in to reg-a ; (exactly the same as mds call) jmp ri ; home: ;move to home position ; treat as track 00 seek mvi c,0 jmp settrk ; seldsk: ;select disk given by register c lxi h,0000h ;return 000select proper disk bank mov m,a ;set disk select bit on/off ret ; waitio: mvi c,retry ;max retries before perm error rewait: ; start the i/o function and wait for completion call intype ;in rtype call inbyte ;clears the controller ; lda dbank ;set bank flags ora a ;zero if drive 0,1 and nz if 2,3 mvi a,iopb and 0ffh ;low address for iopb mvi b,iopb shr 8 ;high address for iopb jnz iodr1 ;drive bank 1? out ilow ;low address to controller mov a,b out ihigh ;high address jmp wait0 ;to wait for complete ; iodr1: ;drive bank 1 out ilow+10h ;88 for drive bank 10 mov a,b out ihigh+10h ; wait0: call instat ;wait for completion ani iordy ;ready? jz wait0 ; ; check io completion ok call intype ;must be io complete (00) unlinked ; 00 unlinked i/o complete, 01 linked i/o complete (not used) ; 10 disk status changed 11 (not used) cpi 10b ;ready status change? jz wready ; ; must be 00 in the accumulator ora a jnz werror ;some other condition,sp,buff+80h lxi h,signon call prmsg ;print message xra a ;clear accumulator sta cdisk ;set initially to disk a jmp gocpm ;go to cp/m ; ; wboot:; loader on track 0, sector 1, which will be skipped for warm ; read cp/m from disk - assuming there is a 128 byte cold start ; start. ; lxi sp,buff ;using dma - thus 80 thru ff available for stack ; mvi c,retry ;max retries push b wboot0: ;enter here on error retries lxi b,cpmb ;set dma address to start of disk system call setdma mvi c,0 ;boot from drive 0 call seldsk mvi c,0 call settrk ;start with track 0 mvi c,2 ;start reading sector 2 call setsec ; ; read sectors, count nsects to zero pop b ;10-error count mvi b,nsects rdsec: ;read next sector push b ;save sector count call read jnz booterr ;retry if errors occur lhld iod ;increment dma address lxi d,128 ;sector size dad d ;incremented dma address in hl mov b,h mov c,l ;ready for call to set dma call setdma lda ios ;sector number just read cpi 20 if error mov a,c cpi ndisks ;too large? rnc ;leave HL = 0000 ; ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3 sta dbank ;to select drive bank mov a,c ;00, 01, 10, 11 ani 1b ;mds has 0,1 at 78, 2,3 at 88 ora a ;result 00? jz setdrive mvi a,00110000b ;selects drive 1 in bank setdrive: mov b,a ;save the function lxi h,iof ;io function mov a,m ani 11001111b ;mask out disk number ora b ;mask in new disk number mov m,a ;save it in iopb mov l,c mvi h,0 ;HL=disk number dad h ;*2 dad h ;*4 dad h ;*8 dad h ;*16 lxi d,dpbase dad d ;HL=disk header table address ret ; ; settrk: ;set track address given by c lxi h,iot mov m,c ret ; setsec: ;set sector number given by c lxi h,ios mov m,c ret sectran: ;translate sector bc using table at de mvi b,0 ;double precision sector number in BC xchg ;translate table address to HL dad b ;translate(sector) address mov a,m ;translated sector number to A sta ios mov l,a ;return sector number in  retry ; ; check i/o error bits call inbyte ral jc wready ;unit not ready rar ani 11111110b ;any other errors? (deleted data ok) jnz werror ; ; read or write is ok, accumulator contains zero ret ; wready: ;not ready, treat as error for now call inbyte ;clear result byte jmp trycount ; werror: ;return hardware malfunction (crc, track, seek, etc.) ; the mds controller has returned a bit in each position ; of the accumulator, corresponding to the conditions: ; 0 - deleted data (accepted as ok above) ; 1 - crc error ; 2 - seek error ; 3 - address error (hardware malfunction) ; 4 - data over/under flow (hardware malfunction) ; 5 - write protect (treated as not ready) ; 6 - write error (hardware malfunction) ; 7 - not ready ; (accumulator bits are numbered 7 6 5 4 3 2 1 0) ; ; it may be useful to filter out the various conditions, ; but we will get a permanent error message if it is not ; recoverable. in any case, the not ready condition is ; treated as a separate condihl,p_cout ; table of output rtns godispch: mvi b,1 ;number of shifts required to align ;CONSOLE field jmp dispch ;--------------- ; list device character output ; LST: mvi b,4 ldk hl,p_list ;table of list routines jmp dispch ;--------------- ; output to punch ; PNCH: mvi b,6 ldk hl,p_pnch ; punch routines jmp dispch ;---------------- ; reader input ; RDR: mvi b,8 ldk hl,p_rdr ; reader routines jmp dispch space 4,10 ; L i s t S t a t u s. ; ; Return the ready status for the list device. ; ; EXIT A = 0 (zero), list device is not ready to ; accept another character. ; A = FFh (255), list device is ready to accept ; a character. ; The list status is returned depending upon the iobyte fields ; LIST field (bits 6,7) ; =0: status of crt. (always ready) ; =1: status of parallel port printer ; =2: status of serial printer ; =3: complete status of serial port ; LSTST: mvi b,4 ;number of left shifts thru carry ;to align LIST field of IOBY: ; check if any translated keys are pending ld a,xltkey ora a jrnz const5 ; if no xlated keys pending, check keyhit flag LD A,LKEY ;Get Key hit flag xri nokey RZ ;If data not available const5: ORI 0FFh RET page ;** ; Routine name: KEYINP - gets keystroke from rom kbd driver. Translates ; the codes 80h to 8fh as per table. ; ; Outputs: A = translated code in ASCII ; All registers are destroyed ; ; Translation scheme: ; the translation table has a two byte entry for each code between ; 80h and 8fh. The incoming keystroke from the keyboard is translated ; to one, two or three character sequence as follows: ; if byte 0 is all zeros, the translated value is byte 1. ; if byte 0 is less than 80h, the key is translated to a ; 2 byte sequence: byte0 byte1 ; if byte 0 is 80h to ffh, the key is translated to a 3 byte ; sequence: Escape byte0-80h byte1 basvl0 equ 80h ;lowest code of the codes that ;are translated. KEYINP: ; if there are no xlated keystion for later improvement trycount: ; register c contains retry count, decrement 'til zero dcr c jnz rewait ;for another try ; ; cannot recover from error mvi a,1 ;error code ret ; ; intype, inbyte, instat read drive bank 00 or 10 intype: lda dbank ora a jnz intyp1 ;skip to bank 10 in rtype ret intyp1: in rtype+10h ;78 for 0,1 88 for 2,3 ret ; inbyte: lda dbank ora a jnz inbyt1 in rbyte ret inbyt1: in rbyte+10h ret ; instat: lda dbank ora a jnz insta1 in dstat ret insta1: in dstat+10h ret ; ; ; ; data areas (must be in ram) dbank: db 0 ;disk bank 00 if drive 0,1 ; 10 if drive 2,3 iopb: ;io parameter block db 80h ;normal i/o operation iof: db readf ;io function, initial read ion: db 1 ;number of sectors to read iot: db offset ;track number ios: db 1 ;sector number iod: dw buff ;io address ; ; ; define ram areas for bdos operation endef end TE ldk hl,p_lstat ;list status routines jmp dispch page dispch: ; on entry here reg B contains the left shift count ; required to align the iobyte field to bit 1 position. ; and reg HL contains address of select table lda iobyte dspch1: ral djnz dspch1 ani 6 ;get select field*2 mov e,a ldk d,0 ; de = iobyte field * 2 dad de mov e,m inx hl mov d,m ; get the routine address lxi h,0 dad sp ;get callers stack adrs lxi sp,lclstk ;switch to local stack push hl ex de,hl call dspch2 ;call routine pointed to by hl pop hl sphl ;restore callers stack ret dspch2: pchl ds 32 lclstk: ;32 byte local stack ; ; addresses of routines ; p_cstat: dw const ; keyboard status dw pistat ; parallel input stat dw sistat ; serial port input status dw ieinstat ; status of input device on IEEE port p_cinp: dw keyinp ; get input from keyboard dw parinp ; parallel input dw spinp ; serial port input dw ieinp ; ieee port input p_cout waiting then ; call the keyboard driver in rom ldk hl,xltkey ld a,[hl] ;get number of xlated keys ora a jrz kin30 ;if keys pending then dec [hl] ;reduce pending count cpi 1 jrnz kin20 ;if only one key then ld a,xltvl1 ;get translated value mov c,a ret ;return kin20: ;else if two keys are waiting then ld a,xltvl2 ;get first val mov c,a ret ;return ;endif kin30: ;else ; get next key from keyboard driver and translate if reqd. ldk e,low(conin) call romcd1 ; ; when control is returned here, A has the input code for ; console character. If code is between 80h and 8fh, it is ; translated. ; cpi basvl0 rc ;return when code is not tobe xlated cpi basvl0+tbllen rnc sui basvl0 ;subtract base val ral ;mult remainder by 2 mov e,a ;build ptr to table entry mvi d,0 ldk hl,xltbl dad de ld a,[hl] ;get byte 0 inx hl ;point to byte 1 ora a jrnz kin40 ;if f page ;***** ; file: OSBbios9.asm ; This file contains CP/M extensions to the OSBORNE CBIOS ; added by MICOROCDE CORPORATION. ; ; Revisions: ; YNS 20AUG81 Initial release ; YNS 29AUG81 Expanded trans. table to include ctl/numerics ; Translate keys to 1/2 or three char seq. ; Iobyte assignements redone. ; YNS 01SEP81 Added parallel port support ; YNS 05SEP81 Invert data to/from parallel port ; Added local stack. ; YNS 06SEP81 Return character in C as well as A from ; all input routines. ; YNS 08SEP81 Fixed "some" ieee bugs ; ;***** ; ; the following routines will use the IOBYTE to transfer ; control to the appropriate device driver ; ;-------------- ; return console status ; CNSTA: ldk hl,p_cstat ; status table jr godispch ; call appropriate rtn ;------------ ; read input character from device ; CNIN: ldk hl,p_cinp ; table of input rtns jr godispch ;------------- ; put output character to device ; c contains output character ; CNOUT: ldk : dw crtout ; output character to crt dw parout ; parallel output dw spout ; serial port output dw ieout ; ieee port output p_list: dw crtout ; list assigned to crt dw parout ; parallel port output dw spout ; serial port dw ACICTL ; serial port usart ctl p_pnch: dw crtout ; punch assigned to crt dw ieout ; ieee port dw spout ; serial port dw parout ; parallel port out p_rdr: dw keyinp ; reader assigned to keyboard dw ieinp ; ieee port dw spinp ; serial port dw parinp ; parallel port input p_lstat: dw crstat dw postat ;parallel port output stat dw sostat ;serial port output stat dw acistat ;serial port usart status page ; C O N S O L S T A T U S ; ; This routine samples the Console status and returns the ; following values in the A register. ; ; EXIT A = 0 (zero), means no character ; currently ready to read. ; ; A = FFh (255), means character ; currently ready to read. nokey equ 00h ;indicates key not present CONSTirst byte is 0 then ld a,[hl] mov c,a ret ;return with byte1 as xlated val. kin40: ; if msb of byte 0 is 0 then the xlated val is byte0 and byte 1 bit 7,a jrnz kin50 ;elseif bit7 is 0 then push af ;save byte 0 ld a,[hl] ;get byte1 from table sto a,xltvl1 ;save translated value lk a,1 sto a,xltkey ;set xlated keys to 1 pop af mov c,a ret ;return with the first char of the ;sequence kin50: ;else ; the key is translated to a three char seq. esc byte0-80h byte1 ani 07fh ;get lower seven bits sto a,xltvl2 ;save byte0-80h ld a,[hl] sto a,xltvl1 ;save byte1 lk a,2 sto a,xltkey lk a,1bh ;a = esc code mov c,a ret xltvl1: db 0 xltvl2: db 0 xltkey: db 0 xltbl: ;default table ; ctl numerics produce and escape seq. Esc n ; cursor keys produce ctl/l, ctl/h, ctl/k and ctl/j db 1bh,'0' db 1bh,'1' db 1bh,'2' db 1bh,'3' db 1bh,'4' db 1bh,'5' db 1bh,'6' db 1bh,'7' db 1bh,'8' db 1bh,'9' dbnc hl ;increment table ptr for next byte shld tblptr ldk a,3 jr crt25 ; ; Illegal sequence. Char following dc4 is not valid. This ; outputs a dc4 and the invalid char to the crt. crt40: push bc ;save current char ldk c,dc4cod call crt10 ;***note*** pop bc jr crt10 ; dc4flg db 0 tblptr dw 0 dc4cod equ 14h page ;** ; routine: SOSTAT ; gets status of output device attached to serial port SOSTAT: call acistat ;get 6850 status ani si.trdy rz ;return with not ready status ori true ret ;** ; routine: SISTAT ; gets status of input device attached to serial port SISTAT: call acistat ani si.rrdy rz ;return with not ready status ori true ret ;** ; routine: SPINP ; Inputs a character from the serial port ; Uses the reader (sp) driver in ROM ; SPINP: ldk e,low(reader) jmp romcd1 ;** ; routine: SPOUT ; Outputs character in reg c to the serial port (list device) ; calls the list (sp) driver in ROM ; SPOUT: ldk e,low(li*secondary address output may be added here*** ; lk hl,ie_mode sbit ie_lstn,[hl] ;set mode to listener ieo20: ; pop b ieo22: push b ;save char again in case of retry ldk e,low(ieb6c) call romcd1 pop b ora a jrnz ieo22 ;try again if error ret page ;** The Parallel port is actually the IEEE port driven with the centronix ; protocol. The bit assignements of the PIA and PIB are as follows: ; PIA0-7 = data bus ; PIB0 = 0, data bus is output. 1, data bus is input ; PIB1 = set to 1. ; PIB2 = set to 0. ; PIB3 = 0 output, 1 Input ; PIB4 = not used ; PIB5 = output strobe. Active = 1. ; PIB6 = 0, printer busy. 1, printer is ready. ; PIB7 = not used. ; ; CA2 = going low indicates to device that we are busy. ; CA1 = low to high transition gates input data to port a. ; ; The port is bidirectional but only one direction ; can be active at any time. The direction of port is determined ; by which routines are called. If postat or parout are ; called, it is made an o 0,'K'-40h db 0,'L'-40h db 0,'J'-40h db 0,'H'-40h tbllen equ (*-xltbl)/2 page ;** ; routine: CRSTAT ; returns status of crt. ; crt is always ready CRSTAT: ori 0FFh ret ;** ; routine name: CRTOUT ; ; inputs: C: output character ; outputs: update translate table when the dc4 sequence found provided ; we are not in an escape seq. or in graphic mode. ; otherwise outputs the character to console ; all registers destroyed ; The dc4 sequence is as follows: ; dc4 k b0 b1 ; where: ; dc4 is the ascii device control char code 14h ; k is the table entry number + 30h. ; b0 is byte 0 of the table. ; b1 is byte 1 of the table. ; esch flag bit definitions (also check in file bmkey.asm) ef_esc: equ 8 ef_gr: equ 1 CRTOUT: lda esch and ef_esc+ef_gr jnz crt10 ;check for dc4 seq only when neither esc seq ; nor graphic lda dc4flg ; ora a ; jnz crt20 ; if not in dc4 sequence then mov a,c cpi dc4cod jst) jmp romcd1 ;** ; routine: ACICTL ; outputs character in c to the ACIA CTL port. ; ACICTL: call sw2rom mov a,c sta h.sctrl jmp sw2ram ;** ; routine: acistat ; returns usart status in A ; The ringin signal is read from the pia at address 2c00 ; and merged in at the overrun error bit of the acia status riport equ h.vio+1 ribit equ 040h ormask equ 020h acistat: call sw2rom lda riport ;read in ringin signal rrc ;shift ring in to overrun err ;position ani ormask ;get ring in mov c,a lda h.ssts ani 0ffh-ormask ;remove overrun error bit ora c ;merge ring in bit jmp sw2ram page ; ie device mod values ie_talk equ 0 ;device is a talker ie_lstn equ 1 ;device is a listener ie_ad0 db 0 ;device address iemode db 0 ;mode of IEEE device ;** ; routine: IEINSTAT ; gets status of the input device attached to ieee port ; Uses ROM resident primitives IEINSTAT: ori 0ffh ;indicate ready for now.*** ret ;** ; routput port and an input port if ; pistat or parinp are called. ; port registers pa.dta equ h.ieee+0 pa.dir equ pa.dta pa.ctl equ h.ieee+1 pb.dta equ h.ieee+2 pb.dir equ pb.dta pb.ctl equ h.ieee+3 ; port ctl register constants. pa.cdr equ 00101010b ;to address port a direction pa.cdt equ 00101110b ;to address port a data and set ;port a in input program handshake mode. pb.cdr equ 00000000b ;to address port b direction pb.cdt equ 00000100b ;to address port b data ; direction register constants pa.dro equ 0ffh ;port a output mode pa.dri equ 00h ;port a input mode pb.dr equ 0bfh ;port b direction pb.dto equ 00000010b ;port b data for output pb.dti equ 00001011b ;port b data for input pp_ordy equ 01000000b ;output rdy bit in pib pp_irdy equ 10000000b ;input rdy bit in pia ctl reg strb equ 00100000b ;strobe bit in port b ; port modes pp_undef equ 0 pp_out equ 1 pp_in equ 2 pp_mode db pp_undef ;*** ; sbrt: CV2OP. initializes the port to a parallel output ; nz crt10 ;if start of dc seq then ldk a,1 ;set dc4 flag sto a,dc4flg ret crt10: ;else (*this is called as a sbrt*) xra a sto a,dc4flg ;reset dc4 found flag ldk e,low(conout) ;output to crt jmp romcd1 ; ; following ensures that the character following the dc4 ; is between 30h and 30h+tbllen. In case of error the characters ; are displayed. crt20: cpi 1 jnz crt30 ;exit when it is not second char after dc4 mov a,c sui '0' ; do a range check on code jc crt40 ;exit when char .lt. '0' cpi tbllen jnc crt40 ;or .gt. entries in table rlc ; multiply index by 2 mov c,a ldk b,0 ; set up bc for a dbl add ldk hl,xltbl dad bc ; add bc to hl shld tblptr ; save the ptr ldk a,2 ; set dc4 flg to indicate crt25: sto a,dc4flg ;next state ret ; ; store input character in xlate table crt30: lhld tblptr mov m,c sui 3 jrz crt25 ;clear dc4 flag and return when last ;char of dc4 seq received. iutine: IEINP ; Reads a character from IEEE port ; Uses ROM resident primitives. IEINP: lda ie_mode bit ie_talk,a jrnz iei20 ;if device is not a talker then ;make talker iei05: lda ie_ad0 adi 40h ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz iei05 ;try again if error ; ; ***secondary address output may be added here*** lk hl,ie_mode sbit ie_talk,[hl] ;set mode to talker iei20: ; ldk e,low(ieb7c) call romcd1 bit 7,l jrnz iei20 ;try again if error mov c,a ret ;** ; routine: IEOUT ; Outputs the character in reg C to IEEE port ; Uses ROM resident primitives. ; IEOUT: push b ;save character lda ie_mode bit ie_lstn,a jrnz ieo20 ;if device is not a listener then ;make listener ieo05: lda ie_ad0 adi 20h ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz ieo05 ;try again if error ; ; ** port. cv2op: lda pp_mode cpi pp_out rz ;return when in output mode ; set port a to output on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dro sta pa.dir ;output constant to dir. reg to put ; a port in output mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dto sta pb.dta ;initialize port b data lk a,pp_out sta pp_mode ret ;*** ; sbrt: CV2IP. initializes the port to a parallel input ; port. cv2ip: lda pp_mode cpi pp_in rz ;return when in input mode ; set port a to input on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dri sta pa.dir ;output constant to dir. reg to put ; a port in input mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b dċ FILL: STO A,RDFLAG ;Save read flag LDK DE,HSTBUF ;initial offset LDK HL,128 ;128 byte records LD A,SEKSEC ;Get logical sector EX DE,HL RRC JRNC FILL3 ;If low bit not set ADD HL,DE ;Add bias to offset FILL3: EX DE,HL ADD HL,HL ANI 07Fh ;Mask sector STO A,SEKSEC LD HL,DMAADR XTHL ;Set return parameters PUSH DE PUSH HL ;Set return address LDK HL,HSTACT ;host active flag LD A,[hl] STO 1,[hl] ;always becomes 1 ORA A JRZ FILL6 ;If host buffer inactive LDK HL,HSTSEC LDK DE,SEKSEC LDK B,SEKDSK-SEKSEC+1 FILL4: LD A,[de] CMP [hl] JRNZ FILL5 ;If mis-match INC HL INC DE DJNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LD A,SEKDSK ;Move disk and type STO A,HSTDSK STO A,ACTDSK LD HL,SEKTRK STO HL,HSTTRK STO HL,ACTTRK LD A,SEKSEC STO A,HSTSEC STO A,ACTSEC LD A,RDFLAG ORA A RNZ ;If no read required LDK A,0 ;Read JR FINAL space 4,10 ; FLUSH - Write out active host buffer onto disirection lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dti sta pb.dta ;initialize port b data lk a,pp_in sta pp_mode ret ;** ; routine: POSTAT ; gets status of the parallel (centronix) printer ; attached to the ieee port ; POSTAT: call sw2rom call cv2op ;convert to output lda pb.dta ;get port b data ani pp_ordy jrz pos10 ori true pos10: jmp sw2ram ;** ; routine: PISTAT ; gets status of the input device attached to the ; parallel port ; piactl db 0 PISTAT: call sw2rom call cv2ip lda piactl ani pp_irdy jrnz pis20 ;if saved status indicates there is a char ;in the PIA lda pa.ctl sta piactl ;this is saved as reading the ;pia clears the status ani pp_irdy jrz pis30 pis20: ori true pis30: jmp sw2ram ;** ; routine: PARINP ; inputs a character from parallel port. PARINP: call pistat jrz parinp ;wait t page READ: ;a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. CALL MVINFO ;Move information for transfer XRA A ;Set flag to force a read STO A,UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP HL POP DE LDK BC,128 ;Move 128 bytes LDIR LD A,ERFLAG ORA A RZ ;If no error XRA A STO A,HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 WRITE: ;the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. CALL MVINFO ;Move information for transfer MOV A,C ;Write type in c STO A,WRTYPE CPI WRUAL JRNZ WRIT2 ;Ik. FLUSH: LDK HL,HSTWRT LD A,[hl] ORA A RZ ;If host buffer already on disk STO 0,[hl] LD A,HSTDSK ;Move disk and type STO A,ACTDSK LD HL,HSTTRK STO HL,ACTTRK LD A,HSTSEC STO A,ACTSEC LDK A,3 ;Write flag ; JMP FINAL space 4,10 FINAL: ;Preform final transfer processing. ; ; ENTRY A = 0 .. read disk. ; = 3 .. write disk. ; Calls: Rom resident routine to read/write ONE ; sector only. MOV E,A LDK D,0 LDK HL,ROMVEC+3*13 ADD HL,DE STO HL,SAVADR LDK HL,ACTSEC INC [hl] ;update sector+1 LDK A,MRTRY ;Set retry count FNL1: STO A,RTRY ;Clear retry count LD HL,SAVADR EX DE,HL LDK B,1 ;indicate one sector xfer CALL ROMJMP ;process read or write STO A,ERFLAG ;set possible error flag RZ ;If no errors LD A,RTRY ;Get retry counter DEC A JRNZ FNL1 ;If not permanent error ORI 01h STO A,ERFLAG ;Set error flag RET ; endx OSBBIOS6.asm ill char in pia call sw2rom xra a sta piactl ;clear saved status lda pa.dta cma ;invert data mov c,a ;also in c jmp sw2ram ;** ; routine: PAROUT ; outputs the character in c to the IEEE port treating the ; port as a parallel port. PAROUT: call postat jrz parout call sw2rom mov a,c cma ;invert data sta pa.dta lk a,pb.dto+strb sta pb.dta ;set strobe lk a,pb.dto sta pb.dta ;clear strobe jmp sw2ram page ;*** ; sbrt: SW2ROM ; switches to rom ; saves all registers SW2ROM: di push af enarom pop af ei ret ;*** ; sbrt: SW2RAM ; switches to ram ; preserves all registers SW2RAM: di push af disrom pop af ei ret yċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċf write to allocated LDK A,2048/128 STO A,UNACNT LD HL,SEKTRK STO HL,UNATRK ;UNATRK = SEKTRK LD A,LOGSEC INC A JR WRIT3 WRIT2: LDK HL,UNACNT LD A,[hl] ORA A JZ WRIT4 ;If no unallocated records DEC [hl] ;dec unalloc record count LD A,UNASEC ;Increment logical sector INC A CPI 2*10 JRNZ WRIT3 ;If not end of track LD HL,UNATRK INC HL STO HL,UNATRK XRA A WRIT3: STO A,UNASEC LDK A,0FFh WRIT4: CALL FILL POP DE POP HL LDK BC,128 LDIR LDK A,1 STO A,HSTWRT ;HSTWRT = 1 LD A,ERFLAG ORA A RNZ ;If any errors occurred LD A,WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LD A,ERFLAG ORA A RET page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address.  page MRTRY: = 5 ;Maximum number of retries. MSG 'Assemblying BIOS for LWA of ', LWAMEM,'h.' ; CP/M to host disk constants HSTSIZ: = 256 ;Blocking/Deblocking buffer size FPYSIB: = 2048/128 ;Sectors in floppy disk block ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. DSKS1: = 0 ;Single density, single sided. S1DSM: = ((40-3)*2*10)/FPYSIB ; BDOS constants on entry to write WRALL: = 0 ;write to allocated WRDIR: = 1 ;write to directory WRUAL: = 2 ;write to unallocated space 4,10 ; ROM equates. ENROM: = 0 ;Port to enable ROM DIROM: = 1 ;Port to disable ROM page ; Macro for generating Control Blocks for disk drives ; The format of these disk control blocks are as follows: ; 16 bits = -> translation table. ; 48 bits = Work area for CP/M. ; 16 bits = -> DIRBUF. ; 16 bits = -> Parameter block. ; 16 bits = -> check vector. ; 16 bits = -> allocation vector. NDSK: SET 0 ;Number of disk drivesus In CALL ROMCDE ;Go To Standby CALL ROMCDE ;Take Control CALL ROMCDE ;Output Interface Message CALL ROMCDE ;Output Device Message CALL ROMCDE ;Input Device Message CALL ROMCDE ;Parallel Poll . ORG BIOS CALL CBOOT ;Cold boot CALL WBOOT ;Warm boot JMP CONST ;Console status (input) CONIN: CALL ROMCDE ;Console input CONOUT: CALL ROMCDE ;Console output LIST: CALL ROMCDE ;List output PUNCH: CALL ROMCDE ;Punch output READER: CALL ROMCDE ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk CALL ROMCDE ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call SBAUD: CALL ROMCDE ; IEEE-488 vectors CALL ROMCDE ;Control Out CALL ROMCDE ;Statddress. ; BC = sector number to translate. ; ; EXIT HL = translated sector. SECTRN: LDA UNASEC CMP C CNZ CUNACT ;If sectors do not match MOV A,C STO A,LOGSEC MOV L,C MOV H,B ADD HL,DE MOV L,M MVI H,0 RET  ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a NOFDD: SET 0 ;Number of floppy disk drives ALVSZ: SET 0 ;Allocation vector size CSVSZ: SET 0 ;Check vector size LIST D,G,M DPHGEN MACRO TYPE,XLATE,DIRBUF,DPBADR NDSK: SET NDSK+1 DW %2 DW 0,0,0 DW %3 DW %4 DW CSV+CSVSZ DW ALV+ALVSZ NOFDD: SET NOFDD+1 CSVSZ: SET CSVSZ+(64/4) ALVSZ: SET ALVSZ+((S1DSM+7)/8) ENDM ; Make sure Systext agrees with assembled size space 4,10 ; Macro for generating the Disk Parameter Blocks. ; ; Disk type definition blocks for each particular mode. ; The format of these areas are as follow: ; 8 bit = disk type code ; 16 bit = Sectors per track ; 8 bit = Block shift ; 8 bit = BS mask ; 8 bit = Extent mask ; 16 bit = Disk size/1024 - 1. ; 16 bit = Directory size. ; 16 bit = Allocation for directory. ; 16 bit = check area size. ; 16 bit = offset to first track. DPBGEN MACRO TYPE,SPT,BSH,BSM,EXM,DSM,DIRSIZ,ALVMSK,OFFSET DB %1 DW %2 DB %3,%4,%5 DW %6-1,%7-1,REV (%8) DW (%7+3)/4 DW %9 ENDM page ; The following jump tabl page ; H O M E ; ; Return disk to home. This routine sets the track number ; to zero. The current host disk buffer is flushed to the ; disk. HOME: CALL FLUSH ;Flush host buffer XRA A STO A,HSTACT ;Clear host active flag STO A,UNACNT ;Clear sector count STO A,SEKTRK STO A,SEKTRK+1 RET space 4,10 SELDSK: ;Select disk drive for next transfer. ; ; ENTRY C = disk selection value (0..15). ; DE and 1 = 0, first call for this disk. ; ; EXIT HL = 0, if drive not selectable. ; HL = DPH address if drive is selected. MOV A,C CPI NDSK JNC SELD1 ;If invalid drive number STO A,SEKDSK MOV L,C MVI H,0 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 MOV B,E ;save initial bit LDK DE,DPBASE ADD HL,DE ;HL = DPH address PUSH HL LDK DE,100h + (low RSELDK) MOV A,B AND 1 CZ ROMJMP ;Select the disk in reg C POP HL RET SELD1: LDK HL,0 LDA CDISK SUB C RNZ ;If default drive not in error STO A,CDISK RET space 4,10 ; S E T ċe defines the entry points ; into the CBIOS for use by CP/M and other external ; routines; therfore the order of these jump cannot ; be modified. The location of these jumps can only ; be modified by 400h locations, which is a restriction ; of MOVCPM. ORG BIOS CALL CBOOT ;Cold boot CALL WBOOT ;Warm boot JMP CONST ;Console status (input) CONIN: CALL ROMCDE ;Console input CONOUT: CALL ROMCDE ;Console output LIST: CALL ROMCDE ;List output PUNCH: CALL ROMCDE ;Punch output READER: CALL ROMCDE ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk CALL ROMCDE ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call SBAUD: CALL ROMCDE ; IEEE-488 vectors CALL ROMCDE ;Control Out CALL ROMCDE ;Stat T R A C K. ; ; Set track number. The track number is saved for later ; use during a disk transfer operation. ; ; ENTRY BC = track number. SETTRK: STO BC,SEKTRK ;Set track LHLD UNATRK MOV A,L XRA C MOV C,A MOV A,H XRA B ORA C RZ ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a page READ: ;a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. CALL MVINFO ;Move information for transfer XRA A ;Set flag to force a read STO A,UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP HL POP DE LDK BC,128 ;Move 128 bytes LDIR LD A,ERFLAG ORA A RZ ;If no error XRA A STO A,HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 WRITE: ;the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. CALL MVINFO ;Move information for transfer MOV A,C ;Write type in c STO A,WRTYPE CPI WRUAL JRNZ WRIT2 ;Ik. FLUSH: LDK HL,HSTWRT LD A,[hl] ORA A RZ ;If host buffer already on disk STO 0,[hl] LD A,HSTDSK ;Move disk and type STO A,ACTDSK LD HL,HSTTRK STO HL,ACTTRK LD A,HSTSEC STO A,ACTSEC LDK A,3 ;Write flag ; JMP FINAL space 4,10 FINAL: ;Preform final transfer processing. ; ; ENTRY A = 0 .. read disk. ; = 3 .. write disk. ; Calls: Rom resident routine to read/write ONE ; sector only. MOV E,A LDK D,0 LDK HL,ROMVEC+3*13 ADD HL,DE STO HL,SAVADR LDK HL,ACTSEC INC [hl] ;update sector+1 LDK A,MRTRY ;Set retry count FNL1: STO A,RTRY ;Clear retry count LD HL,SAVADR EX DE,HL LDK B,1 ;indicate one sector xfer CALL ROMJMP ;process read or write STO A,ERFLAG ;set possible error flag RZ ;If no errors LD A,RTRY ;Get retry counter DEC A JRNZ FNL1 ;If not permanent error ORI 01h STO A,ERFLAG ;Set error flag RET ; endx OSBBIOS6.asm  page ; Physical data buffer address ((DMAADR) or HSTBUF) ; User data buffer address DMAADR: DW 0 ;Lower 16 bits (least, middle) space 4,10 ; BIOS blocking / deblocking flags. HSTACT: DB 0 ;host active flag HSTWRT: DB 0 ;host written flag UNACNT: DB 0 ;unalloc rec CNT UNATRK: DW 0 ;Track UNASEC: DB 255 ;Sector LOGSEC DB 0 ;Logical sector space 4,10 ; CP/M disk work space. ALV: DS ALVS CSV: DS CSVS page ; Disk access information. ; This area is organized into the following groups ; sector number ; track number ; disk drive ; Each of these groups has three cells for the ; current disk request, ACTual disk transfer, ; and active host disk. SEKSEC: DS 1 ;Current request's sector SEKTRK: DS 2 ;Current request's track SEKDSK: DS 1 ;Current request's disk ACTSEC: DS 1 ;Sector to use in transfer operation ACTTRK: DS 2 ;Track to use in transfer operation ACTDSK: DS 1 ;Disk to use in transfer operation HSTSEC: DS 1 ;Active host sector HSTTRK: DS 2 ;Actif write to allocated LDK A,2048/128 STO A,UNACNT LD HL,SEKTRK STO HL,UNATRK ;UNATRK = SEKTRK LD A,LOGSEC INC A JR WRIT3 WRIT2: LDK HL,UNACNT LD A,[hl] ORA A JZ WRIT4 ;If no unallocated records DEC [hl] ;dec unalloc record count LD A,UNASEC ;Increment logical sector INC A CPI 2*10 JRNZ WRIT3 ;If not end of track LD HL,UNATRK INC HL STO HL,UNATRK XRA A WRIT3: STO A,UNASEC LDK A,0FFh WRIT4: CALL FILL POP DE POP HL LDK BC,128 LDIR LDK A,1 STO A,HSTWRT ;HSTWRT = 1 LD A,ERFLAG ORA A RNZ ;If any errors occurred LD A,WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LD A,ERFLAG ORA A RET page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address.  page ; MVINFO Move information necessary for transfer. MVINFO: XRA A STO A,ERFLAG ;Clear error flag LD A,TEMSEC STO A,SEKSEC RET space 4,10 ; Print message terminated by zero byte. ; ; ENTRY HL -> message buffer, terminated by zero. ; ; EXIT HL -> zero byte + 1. ; A = 0. ; Z bit set. ; ; Destroys only HL, Flags, and A registers. PRINT: LD A,[hl] ;Get a character ORA A INC HL RZ ;If zero the terminate PUSH HL MOV C,A CALL CONOUT ;Output to the console POP HL JR PRINT SAVADR: DS 2 ;Disk transfer routine vector IF * > (MRAM-1) MSG 'CBIOS is too long, lwa= ',* .9 ERROR ENDIF ; Endx OSBBIOS8.asm ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċve host track HSTDSK: DS 1 ;Active host disk space 4,10 ; Disk transfer flags and counters. RTRY: DS 1 ;Retry counter RDFLAG: DS 1 ;Read flag ERFLAG: DS 1 ;Error reporting WRTYPE: DS 1 ;Write operation type SAVSEC: DS 1 ;Save sector ESPACE: ORG LWAMEM-HSTSIZ-128 BIOSTK: LKEY: DB 0 DIRBUF: DS 128 ;Directory buffer HSTBUF: DS HSTSIZ-1 ;Host buffer MSG 'Available exspansion = $',DIRBUF-ESPACE,' bytes.' TITLE 'Cross Reference Listing.'  groups ; sector number ; track number ; disk drive ; Each of these groups has three cells for the ; current disk request, ACTual disk transfer, ; and active host disk. SEKSEC: DS 1 ;Current request's sector SEKTRK: DS 2 ;Current request's track SEKDSK: DS 1 ;Current request's disk ACTSEC: DS 1 ;Sector to use in transfer operation ACTTRK: DS 2 ;Track to use in transfer operation ACTDSK: DS 1 ;Disk to use in transfer operation HSTSEC: DS 1 ;Active host sector HSTTRK: DS 2 ;Acti FILL: STO A,RDFLAG ;Save read flag LDK DE,HSTBUF ;initial offset LDK HL,128 ;128 byte records LD A,SEKSEC ;Get logical sector EX DE,HL RRC JRNC FILL3 ;If low bit not set ADD HL,DE ;Add bias to offset FILL3: EX DE,HL ADD HL,HL ANI 07Fh ;Mask sector STO A,SEKSEC LD HL,DMAADR XTHL ;Set return parameters PUSH DE PUSH HL ;Set return address LDK HL,HSTACT ;host active flag LD A,[hl] STO 1,[hl] ;always becomes 1 ORA A JRZ FILL6 ;If host buffer inactive LDK HL,HSTSEC LDK DE,SEKSEC LDK B,SEKDSK-SEKSEC+1 FILL4: LD A,[de] CMP [hl] JRNZ FILL5 ;If mis-match INC HL INC DE DJNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LD A,SEKDSK ;Move disk and type STO A,HSTDSK STO A,ACTDSK LD HL,SEKTRK STO HL,HSTTRK STO HL,ACTTRK LD A,SEKSEC STO A,HSTSEC STO A,ACTSEC LD A,RDFLAG ORA A RNZ ;If no read required LDK A,0 ;Read JR FINAL space 4,10 ; FLUSH - Write out active host buffer onto disċ  page ;***** ; Revisions: ; YNS 18AUG81 change bios jump vector to call new routines ; ; ;***** MRTRY: = 5 ;Maximum number of retries. MSG 'Assemblying BIOS for LWA of ', LWAMEM,'h.' ; CP/M to host disk constants HSTSIZ: = 256 ;Blocking/Deblocking buffer size FPYSIB: = 2048/128 ;Sectors in floppy disk block ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. DSKS1: = 0 ;Single density, single sided. S1DSM: = ((40-3)*2*10)/FPYSIB ; BDOS constants on entry to write WRALL: = 0 ;write to allocated WRDIR: = 1 ;write to directory WRUAL: = 2 ;write to unallocated space 4,10 ; ROM equates. ENROM: = 0 ;Port to enable ROM DIROM: = 1 ;Port to disable ROM page ; Macro for generating Control Blocks for disk drives ; The format of these disk control blocks are as follows: ; 16 bits = -> translation table. ; 48 bits = Work area for CP/M. ; 16 bits = -> DIRBUF. ; 16 bits = -> Parameter block. ; SBAUD: CALL ROMCDE ; IEEE-488 vectors ieb1c: CALL ROMCDE ;Control Out ieb2c: CALL ROMCDE ;Status In ieb3c: CALL ROMCDE ;Go To Standby ieb4c: CALL ROMCDE ;Take Control ieb5c: CALL ROMCDE ;Output Interface Message ieb6c: CALL ROMCDE ;Output Device Message ieb7c: CALL ROMCDE ;Input Device Message ieb8c: CALL ROMCDE ;Parallel Poll OT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident callddress. ; BC = sector number to translate. ; ; EXIT HL = translated sector. SECTRN: LDA UNASEC CMP C CNZ CUNACT ;If sectors do not match MOV A,C STO A,LOGSEC MOV L,C MOV H,B ADD HL,DE MOV L,M MVI H,0 RET  ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a 16 bits = -> check vector. ; 16 bits = -> allocation vector. NDSK: SET 0 ;Number of disk drives NOFDD: SET 0 ;Number of floppy disk drives ALVSZ: SET 0 ;Allocation vector size CSVSZ: SET 0 ;Check vector size LIST D,G,M DPHGEN MACRO TYPE,XLATE,DIRBUF,DPBADR NDSK: SET NDSK+1 DW %2 DW 0,0,0 DW %3 DW %4 DW CSV+CSVSZ DW ALV+ALVSZ NOFDD: SET NOFDD+1 CSVSZ: SET CSVSZ+(64/4) ALVSZ: SET ALVSZ+((S1DSM+7)/8) ENDM ; Make sure Systext agrees with assembled size space 4,10 ; Macro for generating the Disk Parameter Blocks. ; ; Disk type definition blocks for each particular mode. ; The format of these areas are as follow: ; 8 bit = disk type code ; 16 bit = Sectors per track ; 8 bit = Block shift ; 8 bit = BS mask ; 8 bit = Extent mask ; 16 bit = Disk size/1024 - 1. ; 16 bit = Directory size. ; 16 bit = Allocation for directory. ; 16 bit = check area size. ; 16 bit = offset to first track. DPBGEN MACRO TYPE,SPT,BSH,BSM,EXM,DSM,DIRSIZ,ALVMSK,OFFSET DB %1 DW %2 page ; H O M E ; ; Return disk to home. This routine sets the track number ; to zero. The current host disk buffer is flushed to the ; disk. HOME: CALL FLUSH ;Flush host buffer XRA A STO A,HSTACT ;Clear host active flag STO A,UNACNT ;Clear sector count STO A,SEKTRK STO A,SEKTRK+1 RET space 4,10 SELDSK: ;Select disk drive for next transfer. ; ; ENTRY C = disk selection value (0..15). ; DE and 1 = 0, first call for this disk. ; ; EXIT HL = 0, if drive not selectable. ; HL = DPH address if drive is selected. MOV A,C CPI NDSK JNC SELD1 ;If invalid drive number STO A,SEKDSK MOV L,C MVI H,0 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 MOV B,E ;save initial bit LDK DE,DPBASE ADD HL,DE ;HL = DPH address PUSH HL LDK DE,100h + (low RSELDK) MOV A,B AND 1 CZ ROMJMP ;Select the disk in reg C POP HL RET SELD1: LDK HL,0 LDA CDISK SUB C RNZ ;If default drive not in error STO A,CDISK RET space 4,10 ; S E T ċ DB %3,%4,%5 DW %6-1,%7-1,REV (%8) DW (%7+3)/4 DW %9 ENDM page ; The following jump table defines the entry points ; into the CBIOS for use by CP/M and other external ; routines; therfore the order of these jump cannot ; be modified. The location of these jumps can only ; be modified by 400h locations, which is a restriction ; of MOVCPM. ORG BIOS CALL CBOOT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call T R A C K. ; ; Set track number. The track number is saved for later ; use during a disk transfer operation. ; ; ENTRY BC = track number. SETTRK: STO BC,SEKTRK ;Set track LHLD UNATRK MOV A,L XRA C MOV C,A MOV A,H XRA B ORA C RZ ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a  page READ: ;a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. CALL MVINFO ;Move information for transfer XRA A ;Set flag to force a read STO A,UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP HL POP DE LDK BC,128 ;Move 128 bytes LDIR LD A,ERFLAG ORA A RZ ;If no error XRA A STO A,HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 WRITE: ;the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. CALL MVINFO ;Move information for transfer MOV A,C ;Write type in c STO A,WRTYPE CPI WRUAL JRNZ WRIT2 ;Ik. FLUSH: LDK HL,HSTWRT LD A,[hl] ORA A RZ ;If host buffer already on disk STO 0,[hl] LD A,HSTDSK ;Move disk and type STO A,ACTDSK LD HL,HSTTRK STO HL,ACTTRK LD A,HSTSEC STO A,ACTSEC LDK A,3 ;Write flag ; JMP FINAL space 4,10 FINAL: ;Preform final transfer processing. ; ; ENTRY A = 0 .. read disk. ; = 3 .. write disk. ; Calls: Rom resident routine to read/write ONE ; sector only. MOV E,A LDK D,0 LDK HL,ROMVEC+3*13 ADD HL,DE STO HL,SAVADR LDK HL,ACTSEC INC [hl] ;update sector+1 LDK A,MRTRY ;Set retry count FNL1: STO A,RTRY ;Clear retry count LD HL,SAVADR EX DE,HL LDK B,1 ;indicate one sector xfer CALL ROMJMP ;process read or write STO A,ERFLAG ;set possible error flag RZ ;If no errors LD A,RTRY ;Get retry counter DEC A JRNZ FNL1 ;If not permanent error ORI 01h STO A,ERFLAG ;Set error flag RET ; endx OSBBIOS6.asm  page ;***** ; file: OSBbios9.asm ; This file contains CP/M extensions to the OSBORNE CBIOS ; added by MICOROCDE CORPORATION. ; ; Revisions: ; YNS 20AUG81 Initial release ; YNS 29AUG81 Expanded trans. table to include ctl/numerics ; Translate keys to 1/2 or three char seq. ; Iobyte assignements redone. ; YNS 01SEP81 Added parallel port support ; ;***** ; ; the following routines will use the IOBYTE to transfer ; control to the appropriate device driver ; ;-------------- ; return console status ; CNSTA: ldk hl,ptr_cstat ; status table jr godispch ; call appropriate rtn ;------------ ; read input character from device ; CNIN: ldk hl,ptr_cinp ; table of input rtns jr godispch ;------------- ; put output character to device ; c contains output character ; CNOUT: ldk hl,ptr_cout ; table of output rtns godispch: mvi b,1 ;number of shifts required to align ;CONSOLE field jmp dispch ;--------------- ; list device character output ; LST: mvif write to allocated LDK A,2048/128 STO A,UNACNT LD HL,SEKTRK STO HL,UNATRK ;UNATRK = SEKTRK LD A,LOGSEC INC A JR WRIT3 WRIT2: LDK HL,UNACNT LD A,[hl] ORA A JZ WRIT4 ;If no unallocated records DEC [hl] ;dec unalloc record count LD A,UNASEC ;Increment logical sector INC A CPI 2*10 JRNZ WRIT3 ;If not end of track LD HL,UNATRK INC HL STO HL,UNATRK XRA A WRIT3: STO A,UNASEC LDK A,0FFh WRIT4: CALL FILL POP DE POP HL LDK BC,128 LDIR LDK A,1 STO A,HSTWRT ;HSTWRT = 1 LD A,ERFLAG ORA A RNZ ;If any errors occurred LD A,WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LD A,ERFLAG ORA A RET page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address.  page ; MVINFO Move information necessary for transfer. MVINFO: XRA A STO A,ERFLAG ;Clear error flag LD A,TEMSEC STO A,SEKSEC RET space 4,10 ; Print message terminated by zero byte. ; ; ENTRY HL -> message buffer, terminated by zero. ; ; EXIT HL -> zero byte + 1. ; A = 0. ; Z bit set. ; ; Destroys only HL, Flags, and A registers. PRINT: LD A,[hl] ;Get a character ORA A INC HL RZ ;If zero the terminate PUSH HL MOV C,A CALL CONOUT ;Output to the console POP HL JR PRINT SAVADR: DS 2 ;Disk transfer routine vector IF * > (MRAM-1) MSG 'CBIOS is too long, lwa= ',* .9 ERROR ENDIF ; Endx OSBBIOS8.asm ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ b,4 ldk hl,ptr_list ;table of list routines jmp dispch ;--------------- ; output to punch ; PNCH: mvi b,6 ldk hl,ptr_pnch ; punch routines jmp dispch ;---------------- ; reader input ; RDR: mvi b,8 ldk hl,ptr_rdr ; reader routines jmp dispch space 4,10 ; L i s t S t a t u s. ; ; Return the ready status for the list device. ; ; EXIT A = 0 (zero), list device is not ready to ; accept another character. ; A = FFh (255), list device is ready to accept ; a character. ; The list status is returned depending upon the iobyte fields ; LIST field (bits 6,7) ; =0: status of crt. (always ready) ; =1: status of parallel port printer ; =2: status of serial printer ; =3: complete status of serial port ; LSTST: mvi b,4 ;number of left shifts thru carry ;to align LIST field of IOBYTE ldk hl,ptr_lst ;list status routines jmp dispch page dispch: ; on entry here reg B contains the left shift count ; required to align the iobyte field to bit 1 positio FILL: STO A,RDFLAG ;Save read flag LDK DE,HSTBUF ;initial offset LDK HL,128 ;128 byte records LD A,SEKSEC ;Get logical sector EX DE,HL RRC JRNC FILL3 ;If low bit not set ADD HL,DE ;Add bias to offset FILL3: EX DE,HL ADD HL,HL ANI 07Fh ;Mask sector STO A,SEKSEC LD HL,DMAADR XTHL ;Set return parameters PUSH DE PUSH HL ;Set return address LDK HL,HSTACT ;host active flag LD A,[hl] STO 1,[hl] ;always becomes 1 ORA A JRZ FILL6 ;If host buffer inactive LDK HL,HSTSEC LDK DE,SEKSEC LDK B,SEKDSK-SEKSEC+1 FILL4: LD A,[de] CMP [hl] JRNZ FILL5 ;If mis-match INC HL INC DE DJNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LD A,SEKDSK ;Move disk and type STO A,HSTDSK STO A,ACTDSK LD HL,SEKTRK STO HL,HSTTRK STO HL,ACTTRK LD A,SEKSEC STO A,HSTSEC STO A,ACTSEC LD A,RDFLAG ORA A RNZ ;If no read required LDK A,0 ;Read JR FINAL space 4,10 ; FLUSH - Write out active host buffer onto disċ n. ; and reg HL contains address of select table lda iobyte dspch1: ral djnz dspch1 ani 6 ;get select field*2 mov e,a ldk d,0 ; de = iobyte field * 2 dad de mov e,m inx hl mov h,m ; get the routine address mov l,e ; into hl and xchange with pc pchl ; ; addresses of routines ; ptr_cstat: dw const ; keyboard status dw pistat ; parallel input stat dw sistat ; serial port input status dw ieinstat ; status of input device on IEEE port ptr_cinp: dw keyinp ; get input from keyboard dw parinp ; parallel input dw spinp ; serial port input dw ieinp ; ieee port input ptr_cout: dw crtout ; output character to crt dw parout ; parallel output dw spout ; serial port output dw ieout ; ieee port output ptr_list: dw crtout ; list assigned to crt dw parout ; parallel port output dw spout ; serial port dw ACICTL ; serial port usart ctl ptr_pnch: dw crtout ; punch assigned to crt dw ieout ; ieee port dw spout ; serial port dw part ;return ;endif kin30: ;else ; get next key from keyboard driver and translate if reqd. ldk e,low(conin) call romcd1 ; ; when control is returned here, A has the input code for ; console character. If code is between 80h and 8fh, it is ; translated. ; cpi basvl0 rc ;return when code is not tobe xlated cpi basvl0+tbllen rnc sui basvl0 ;subtract base val ral ;mult remainder by 2 mov e,a ;build ptr to table entry mvi d,0 ldk hl,xltbl dad de ld a,[hl] ;get byte 0 inx hl ;point to byte 1 ora a jrnz kin40 ;if first byte is 0 then ld a,[hl] ret ;return with byte1 as xlated val. kin40: ; if msb of byte 0 is 0 then the xlated val is byte0 and byte 1 bit 7,a jrnz kin50 ;elseif bit7 is 0 then push af ;save byte 0 ld a,[hl] ;get byte1 from table sto a,xltvl1 ;save translated value lk a,1 sto a,xltkey ;set xlated keys to 1 pop af ret ;return with the first char of t after dc4 mov a,c sui '0' ; do a range check on code jc crt40 ;exit when char .lt. '0' cpi tbllen jnc crt40 ;or .gt. entries in table rlc ; multiply index by 2 mov c,a ldk b,0 ; set up bc for a dbl add ldk hl,xltbl dad bc ; add bc to hl shld tblptr ; save the ptr ldk a,2 ; set dc4 flg to indicate crt25: sto a,dc4flg ;next state ret ; ; store input character in xlate table crt30: lhld tblptr mov m,c sui 3 jrz crt25 ;clear dc4 flag and return when last ;char of dc4 seq received. inc hl ;increment table ptr for next byte shld tblptr ldk a,3 jr crt25 ; ; Illegal sequence. Char following dc4 is not valid. This ; outputs a dc4 and the invalid char to the crt. crt40: push bc ;save current char ldk c,dc4cod call crt10 ;***note*** pop bc jr crt10 ; dc4flg db 0 tblptr dw 0 dc4cod equ 14h page ;** ; routine: SOSTAT ; gets status of output device attached to serial port out ; parallel port out ptr_rdr: dw keyinp ; reader assigned to keyboard dw ieinp ; ieee port dw spinp ; serial port dw parinp ; parallel port input ptr_lst: dw crstat dw postat ;parallel port output stat dw sostat ;serial port output stat dw acistat ;serial port usart status page ; C O N S O L S T A T U S ; ; This routine samples the Console status and returns the ; following values in the A register. ; ; EXIT A = 0 (zero), means no character ; currently ready to read. ; ; A = FFh (255), means character ; currently ready to read. nokey equ 00h ;indicates key not present CONST: ; check if any translated keys are pending ld a,xltkey ora a jrnz const5 ; if no xlated keys pending, check keyhit flag LD A,LKEY ;Get Key hit flag xri nokey RZ ;If data not available const5: ORI 0FFh RET page ;** ; Routine name: KEYINP - gets keystroke from rom kbd driver. Translates ; the codes 80h to 8fh as per table. ; ; Outputs: A = translhe ;sequence kin50: ;else ; the key is translated to a three char seq. esc byte0-80h byte1 ani 07fh ;get lower seven bits sto a,xltvl2 ;save byte0-80h ld a,[hl] sto a,xltvl1 ;save byte1 lk a,2 sto a,xltkey lk a,1bh ;a = esc code ret xltvl1: db 0 xltvl2: db 0 xltkey: db 0 xltbl: ;default table ; ctl numerics produce and escape seq. Esc n ; cursor keys produce ctl/l, ctl/h, ctl/k and ctl/j db 1bh,'0' db 1bh,'1' db 1bh,'2' db 1bh,'3' db 1bh,'4' db 1bh,'5' db 1bh,'6' db 1bh,'7' db 1bh,'8' db 1bh,'9' db 0,'K'-40h db 0,'L'-40h db 0,'J'-40h db 0,'H'-40h tbllen equ (*-xltbl)/2 page ;** ; routine: CRSTAT ; returns status of crt. ; crt is always ready CRSTAT: ori 0FFh ret ;** ; routine name: CRTOUT ; ; inputs: C: output character ; outputs: update translate table when the dc4 sequence found provided ; we are not in an escape seq. or in graphic mode. ; otherwise outputs the character to c SOSTAT: call acistat ;get 6850 status ani si.trdy rz ;return with not ready status ori true ret ;** ; routine: SISTAT ; gets status of input device attached to serial port SISTAT: call acistat ani si.rrdy rz ;return with not ready status ori true ret ;** ; routine: SPINP ; Inputs a character from the serial port ; Uses the reader (sp) driver in ROM ; SPINP: ldk e,low(reader) jmp romcd1 ret ;** ; routine: SPOUT ; Outputs character in reg c to the serial port (list device) ; calls the list (sp) driver in ROM ; SPOUT: ldk e,low(list) jmp romcd1 ;** ; routine: ACICTL ; outputs character in c to the ACIA CTL port. ; ACICTL: call sw2rom mov a,c sta h.sctrl jmp sw2ram ;** ; routine: acistat ; returns usart status in A acistat: call sw2rom lda h.ssts jmp sw2ram page ; ie device mod values ie_talk equ 0 ;device is a talker ie_lstn equ 1 ;device is a listener ie_ad0 db 0 ;device address ie_ad1 db 0 iated code in ASCII ; All registers are destroyed ; ; Translation scheme: ; the translation table has a two byte entry for each code between ; 80h and 8fh. The incoming keystroke from the keyboard is translated ; to one, two or three character sequence as follows: ; if byte 0 is all zeros, the translated value is byte 1. ; if byte 0 is less than 80h, the key is translated to a ; 2 byte sequence: byte0 byte1 ; if byte 0 is 80h to ffh, the key is translated to a 3 byte ; sequence: Escape byte0-80h byte1 basvl0 equ 80h ;lowest code of the codes that ;are translated. KEYINP: ; if there are no xlated keys waiting then ; call the keyboard driver in rom ldk hl,xltkey ld a,[hl] ;get number of xlated keys ora a jrz kin30 ;if keys pending then dec [hl] ;reduce pending count cpi 1 jrnz kin20 ;if only one key then ld a,xltvl1 ;get translated value ret ;return kin20: ;else if two keys are waiting then ld a,xltvl2 ;get first val reonsole ; all registers destroyed ; The dc4 sequence is as follows: ; dc4 k b0 b1 ; where: ; dc4 is the ascii device control char code 14h ; k is the table entry number + 30h. ; b0 is byte 0 of the table. ; b1 is byte 1 of the table. ; esch flag bit definitions (also check in file bmkey.asm) ef_esc: equ 8 ef_gr: equ 1 CRTOUT: lda esch and ef_esc+ef_gr jnz crt10 ;check for dc4 seq only when neither esc seq ; nor graphic lda dc4flg ; ora a ; jnz crt20 ; if not in dc4 sequence then mov a,c cpi dc4cod jnz crt10 ;if start of dc seq then ldk a,1 ;set dc4 flag sto a,dc4flg ret crt10: ;else (*this is called as a sbrt*) xra a sto a,dc4flg ;reset dc4 found flag ldk e,low(conout) ;output to crt jmp romcd1 ; ; following ensures that the character following the dc4 ; is between 30h and 30h+tbllen. In case of error the characters ; are displayed. crt20: cpi 1 jnz crt30 ;exit when it is not second char emode db 0 ;mode of IEEE device ;** ; routine: IEINSTAT ; gets status of the input device attached to ieee port ; Uses ROM resident primitives IEINSTAT: ;************* ret ;** ; routine: IEINP ; Reads a character from IEEE port ; Uses ROM resident primitives. IEINP: lda ie_mode bit ie_talk,a jrz iei20 ;if device is not a talker then ;make talker iei05: lda ie_ad0 adi 40h ;get primary address mov c,a ldk e,low(ieb5c) jmp romcd1 ;output interface message ora a jrnz iei05 ;try again if error iei10: lda ie_ad1 adi 60h mov c,a ldk e,low(ieb5c) jmp romcd1 ;output secondary address ora a jrnz iei10 lk hl,ie_mode sbit ie_talk,[hl] ;set mode to talker iei20: ; ldk e,low(ieb7c) jmp romcd1 bit 7,l jrnz iei20 ;try again if error ret ;** ; routine: IEOUT ; Outputs the character in reg C to IEEE port ; Uses ROM resident primitives. ; IEOUT: lda ie_mode bit ie_lstn,a jrz ieo20 ;if device is  rdy bit in pia ctl reg strb equ 00100000b ;strobe bit in port b ; port modes pp.undef equ 0 pp.out equ 1 pp.in equ 2 pp.mode db pp.undef ;*** ; sbrt: CV2OP. initializes the port to a parallel output ; port. cv2op: lda pp.mode cpi pp.out rz ;return when in output mode ; set port a to output on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dro sta pa.dir ;output constant to dir. reg to put ; a port in output mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dto sta pb.dta ;initialize port b data lk a,pp.out sta pp.mode ret ;*** ; sbrt: CV2IP. initializes the port to a parallel input ; port. cv2ip: lda pp.mode cpi pp.in rz ;return when in input mode ; set port a to input on all lines lk a,pa.cdr sta page ; B o o t C P / M f r o m d i s k. ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; 40-41: Points to where Date and Time are kept ; ; Register C must contain the selected drive, which is ; zero to select the A drive. The exit address is to ; the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selectionnot a listener then ;make listener ieo05: lda ie_ad0 adi 20h ;get primary address mov c,a ldk e,low(ieb5c) jmp romcd1 ;output interface message ora a jrnz ieo05 ;try again if error ieo10: lda ie_ad1 adi 60h mov c,a ldk e,low(ieb5c) jmp romcd1 ;output secondary address ora a jrnz ieo10 lk hl,ie_mode sbit ie_lstn,[hl] ;set mode to listener ieo20: ; ldk e,low(ieb6c) jmp romcd1 ora a jrnz ieo20 ;try again if error ret page ;** The Parallel port is actually the IEEE port driven with the centronix ; protocol. The bit assignements of the PIA and PIB are as follows: ; PIA0-7 = data bus ; PIB0 = 0, data bus is output. 1, data bus is input ; PIB1 = set to 1. ; PIB2 = set to 0. ; PIB3 = 0 output, 1 Input ; PIB4 = not used ; PIB5 = output strobe. Active = 1. ; PIB6 = 0, printer busy. 1, printer is ready. ; PIB7 = not used. ; ; CA2 = going low indicates to device that we are busy. ; CA1 = low to high transition gates input pa.ctl ;select direction reg lk a,pa.dri sta pa.dir ;output constant to dir. reg to put ; a port in input mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dti sta pb.dta ;initialize port b data lk a,pp.in sta pp.mode ret ;** ; routine: POSTAT ; gets status of the parallel (centronix) printer ; attached to the ieee port ; POSTAT: call sw2rom call cv2op ;convert to output lda pb.dta ;get port b data ani pp.ordy jrz pos10 ori true pos10: jmp sw2ram ;** ; routine: PISTAT ; gets status of the input device attached to the ; parallel port ; piactl db 0 PISTAT: call sw2rom call cv2ip lda piactl ani pp.irdy jrnz pis20 ;if saved status indicates there is a char ;in the PIA lda pa.ctl sta piactl ;this is saved as  value. The exit address ; is to the CCP routine. ; CBOOT: ;Entry A= drive to boot off of. MOV B,A ;save requested drive DISROM MOV A,B ;restore requested drive STO A,CDISK ;force requested drive LDK SP,CCP .autos IF ~ AUTOST LDK HL,SIGNON CALL PRINT ;Output Banner .autos ENDIF XRA A STO A,IOBYTE ;Clear I/O byte .autos IF AUTOST ORI 1 ;indicate cold boot .autos ENDIF JR BCCP ;Do CP/M WBOOT: ;Warm boot LDK SP,CCP CALL HOME ;flush any buffer BCPM: LDK DE,ROMVEC+3*1 ;Set ROM vector address LDK BC,CCP CALL ROMJMP ORA A JRNZ BCPM ;If error in read ORI 0FFh BCCP: ;Entry A = 01, if cold boot ; A = ff, if warm boot PUSH AF ;Save flags LDK BC,DBUF ;Set default data transfer address CALL SETDMA LDK HL,HSTBUF STO HL,DMADR ;set ROM DMA address ; Clear console control ESC cell XRA A STO A,ESCH ;clear ESC ; Set-up low core pointer cells LDK A,0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL data to port a. ; ; The port is bidirectional but only one direction ; can be active at any time. The direction of port is determined ; by which routines are called. If postat or parout are ; called, it is made an output port and an input port if ; pistat or parinp are called. ; port registers pa.dta equ h.ieee+0 pa.dir equ pa.dta pa.ctl equ h.ieee+1 pb.dta equ h.ieee+2 pb.dir equ pb.dta pb.ctl equ h.ieee+3 ; port ctl register constants. pa.cdr equ 00101010b ;to address port a direction pa.cdt equ 00101110b ;to address port a data and set ;port a in input program handshake mode. pb.cdr equ 00000000b ;to address port b direction pb.cdt equ 00000100b ;to address port b data ; direction register constants pa.dro equ 0ffh ;port a output mode pa.dri equ 00h ;port a input mode pb.dr equ 0bfh ;port b direction pb.dto equ 00000010b ;port b data for output pb.dti equ 00001011b ;port b data for input pp.ordy equ 01000000b ;output rdy bit in pib pp.irdy equ 10000000b ;inputreading the ;pia clears the status ani pp.irdy jrz pis30 pis20: ori true pis30: jmp sw2ram ;** ; routine: PARINP ; inputs a character from parallel port. PARINP: call pistat jrz parinp ;wait till char in pia call sw2rom xra a sta piactl ;clear saved status lda pa.dta jmp sw2ram ;** ; routine: PAROUT ; outputs the character in c to the IEEE port treating the ; port as a parallel port. PAROUT: call postat jrz parout call sw2rom mov a,c sta pa.dta lk a,pb.dto+strb sta pb.dta ;set strobe lk a,pb.dto sta pb.dta ;clear strobe jmp sw2ram page ;*** ; sbrt: SW2ROM ; switches to rom ; saves all registers SW2ROM: di push af enarom pop af ei ret ;*** ; sbrt: SW2RAM ; switches to ram ; preserves all registers SW2RAM: di push af disrom pop af ei ret pp.irdy jrnz pis20 ;if saved status indicates there is a char ;in the PIA lda pa.ctl sta piactl ;this is saved as  ,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDIF CAUTO: DB CAUTOL DB 'AUTOST ' CAUTOL = *-CAUTO-1 WAUTO: DB WAUTOL DB ' ' WAUTOL =pt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector POP DE ;Get calling address MOV A,E SUI 3 MOV E,A LDK D,high (ROMVEC) LD A,IOBYTE ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC = any parameters DI LDK HL,0 ADD HL,SP ;Old stack to HL LDK SP,BIOSTK PUSH HL ;Save old stack pointer ENAROM EX DE,HL ;ROM jump address to HL CALL GOROM DI PUSH AF ;save status returned DISROM POP AF POP HL ;Restore old stack pointer MOV SP,HL EI ! RET GOROM: EI JMP [hl] ,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interruddress. ; BC = sector number to translate. ; ; EXIT HL = translated sector. SECTRN: LDA UNASEC CMP C CNZ CUNACT ;If sectors do not match MOV A,C STO A,LOGSEC MOV L,C MOV H,B ADD HL,DE MOV L,M MVI H,0 RET  ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a *-WAUTO-2 ; Endx OSBBIOS5.asm at CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDIF CAUTO: DB CAUTOL DB 'AUTOST ' CAUTOL = *-CAUTO-1 WAUTO: DB WAUTOL DB ' ' WAUTOL = page ; H O M E ; ; Return disk to home. This routine sets the track number ; to zero. The current host disk buffer is flushed to the ; disk. HOME: CALL FLUSH ;Flush host buffer XRA A STO A,HSTACT ;Clear host active flag STO A,UNACNT ;Clear sector count STO A,SEKTRK STO A,SEKTRK+1 RET space 4,10 SELDSK: ;Select disk drive for next transfer. ; ; ENTRY C = disk selection value (0..15). ; DE and 1 = 0, first call for this disk. ; ; EXIT HL = 0, if drive not selectable. ; HL = DPH address if drive is selected. MOV A,C CPI NDSK JNC SELD1 ;If invalid drive number STO A,SEKDSK MOV L,C MVI H,0 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 MOV B,E ;save initial bit LDK DE,DPBASE ADD HL,DE ;HL = DPH address PUSH HL LDK DE,100h + (low RSELDK) MOV A,B AND 1 CZ ROMJMP ;Select the disk in reg C POP HL RET SELD1: LDK HL,0 LDA CDISK SUB C RNZ ;If default drive not in error STO A,CDISK RET space 4,10 ; S E T ċ page ; C O N S O L S T A T U S ; ; This routine samples the Console status and returns the ; following values in the A register. ; ; EXIT A = 0 (zero), means no character ; currently ready to read. ; ; A = FFh (255), means character ; currently ready to read. CONST: LD A,LKEY ;Get Key hit flag BIT 7,A RZ ;If data not available ORI 0FFh RET space 4,10 ; L i s t S t a t u s. ; ; Return the ready status for the list device. ; ; EXIT A = 0 (zero), list device is not ready to ; accept another character. ; A = FFh (255), list device is ready to accept ; a character. ; See rom code... page SETRRM: ;Set ROM-RAM flag ; Entry A= port to output (setting ROM or RAM enable) ; Exit none. ; Uses A DI PUSH BC MOV C,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interru T R A C K. ; ; Set track number. The track number is saved for later ; use during a disk transfer operation. ; ; ENTRY BC = track number. SETTRK: STO BC,SEKTRK ;Set track LHLD UNATRK MOV A,L XRA C MOV C,A MOV A,H XRA B ORA C RZ ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a;OCCBIO0A.ASM TITLE 'Osborne CP/M 2.2 CBIOS.' ;CBIOS - Osborne CP/M 2.2 CBIOS. * 4D2007-00 MASTER .ASM * 2D2007-00 ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ;REV = A ;DATE = 247 AUTOST = TRUE ;If autostart program VERS: EQU 22 space 4,10 ; Link files. link OCCbio1A ;Jump Table link OCCbio2A ;CP/M disk definitions link OCCbio3A ;Unit record I/O link OCCbio4A ;Non data transfer disk link OCCbio5A ;Cold and Warm boot link OCCbio6A ;Disk data transfer I/O link OCCbio7A ;Utility routines link bmram.asm ;Commom ram definitions ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ T R A C K. ; ; Set track number. The track number is saved for later ; use during a disk transfer operation. ; ; ENTRY BC = track number. SETTRK: STO BC,SEKTRK ;Set track LHLD UNATRK MOV A,L XRA C MOV C,A MOV A,H XRA B ORA C RZ ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table a page READ: ;a CP/M 128 byte sector. ; ; EXIT A = 0, successful read operation. ; A = 1, unsucessful read operation. ; Z bit = 1, successful read operation. ; Z bit = 0, unsuccessful read operation. CALL MVINFO ;Move information for transfer XRA A ;Set flag to force a read STO A,UNACNT ;Clear sector counter CALL FILL ;Fill buffer with data POP HL POP DE LDK BC,128 ;Move 128 bytes LDIR LD A,ERFLAG ORA A RZ ;If no error XRA A STO A,HSTACT ;Clear host active ORI 001h ;Set error flag RET space 4,20 WRITE: ;the selected 128 byte CP/M sector. ; ; ENTRY C = 0, write to a previously allocated block. ; C = 1, write to the directory. ; C = 2, write to the first sector of unallocated ; data block. ; ; EXIT A = 0, write was successful. ; A = 1, write was unsucessful. ; Z bit = 1, write was successful. ; Z bit = 0, write was unsucessful. CALL MVINFO ;Move information for transfer MOV A,C ;Write type in c STO A,WRTYPE CPI WRUAL JRNZ WRIT2 ;Iċddress. ; BC = sector number to translate. ; ; EXIT HL = translated sector. SECTRN: LDA UNASEC CMP C CNZ CUNACT ;If sectors do not match MOV A,C STO A,LOGSEC MOV L,C MOV H,B ADD HL,DE MOV L,M MVI H,0 RET  ;If same track ; JMP CUNACT space 4,10 ; Clear Unallocated block count (force pre-reads). CUNACT: XRA A ;A = 0 STO A,UNACNT ;Clear unallocated block count RET space 4,10 ; Set the sector for later use in the disk transfer. No ; actual disk operations are perfomed. ; ; Entry BC = sector number. SETSEC: MOV A,C STO A,TEMSEC ;sector to seek RET space 4,10 ; Set Disk memory address for subsequent disk read or ; write routines. This address is saved in DMAADR until ; the disk transfer is performed. ; ; ENTRY BC = Disk memory address. ; ; EXIT DMAADR = BC. SETDMA: STO BC,DMAADR RET space 4,15 ; Translate sector number from logical to physical. ; ; ENTRY DE = 0, no translation required. ; DE = translation table af write to allocated LDK A,2048/128 STO A,UNACNT LD HL,SEKTRK STO HL,UNATRK ;UNATRK = SEKTRK LD A,LOGSEC INC A JR WRIT3 WRIT2: LDK HL,UNACNT LD A,[hl] ORA A JZ WRIT4 ;If no unallocated records DEC [hl] ;dec unalloc record count LD A,UNASEC ;Increment logical sector INC A CPI 2*10 JRNZ WRIT3 ;If not end of track LD HL,UNATRK INC HL STO HL,UNATRK XRA A WRIT3: STO A,UNASEC LDK A,0FFh WRIT4: CALL FILL POP DE POP HL LDK BC,128 LDIR LDK A,1 STO A,HSTWRT ;HSTWRT = 1 LD A,ERFLAG ORA A RNZ ;If any errors occurred LD A,WRTYPE ;write type CPI WRDIR ;to directory? CZ FLUSH ;Force write of directory LD A,ERFLAG ORA A RET page ; FILL - fill host buffer with approprite host sector. ; ; ENTRY A = 0, Read required if not in buffer. ; 0therwise read not required. ; ; EXIT On exit the stack will contain the following ; values: ; POP x ;x = host record address. ; POP y ;y = caller's buffer address.  page ; H O M E ; ; Return disk to home. This routine sets the track number ; to zero. The current host disk buffer is flushed to the ; disk. HOME: CALL FLUSH ;Flush host buffer XRA A STO A,HSTACT ;Clear host active flag STO A,UNACNT ;Clear sector count STO A,SEKTRK STO A,SEKTRK+1 RET space 4,10 SELDSK: ;Select disk drive for next transfer. ; ; ENTRY C = disk selection value (0..15). ; DE and 1 = 0, first call for this disk. ; ; EXIT HL = 0, if drive not selectable. ; HL = DPH address if drive is selected. MOV A,C CPI NDSK JNC SELD1 ;If invalid drive number STO A,SEKDSK MOV L,C MVI H,0 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 MOV B,E ;save initial bit LDK DE,DPBASE ADD HL,DE ;HL = DPH address PUSH HL LDK DE,100h + (low RSELDK) MOV A,B AND 1 CZ ROMJMP ;Select the disk in reg C POP HL RET SELD1: LDK HL,0 LDA CDISK SUB C RNZ ;If default drive not in error STO A,CDISK RET space 4,10 ; S E T ċ FILL: STO A,RDFLAG ;Save read flag LDK DE,HSTBUF ;initial offset LDK HL,128 ;128 byte records LD A,SEKSEC ;Get logical sector EX DE,HL RRC JRNC FILL3 ;If low bit not set ADD HL,DE ;Add bias to offset FILL3: EX DE,HL ADD HL,HL ANI 07Fh ;Mask sector STO A,SEKSEC LD HL,DMAADR XTHL ;Set return parameters PUSH DE PUSH HL ;Set return address LDK HL,HSTACT ;host active flag LD A,[hl] STO 1,[hl] ;always becomes 1 ORA A JRZ FILL6 ;If host buffer inactive LDK HL,HSTSEC LDK DE,SEKSEC LDK B,SEKDSK-SEKSEC+1 FILL4: LD A,[de] CMP [hl] JRNZ FILL5 ;If mis-match INC HL INC DE DJNZ FILL4 ;If all bytes not checked RET FILL5: CALL FLUSH ;Flush host buffer FILL6: LD A,SEKDSK ;Move disk and type STO A,HSTDSK STO A,ACTDSK LD HL,SEKTRK STO HL,HSTTRK STO HL,ACTTRK LD A,SEKSEC STO A,HSTSEC STO A,ACTSEC LD A,RDFLAG ORA A RNZ ;If no read required LDK A,0 ;Read JR FINAL space 4,10 ; FLUSH - Write out active host buffer onto dis OCCBIO02.ASM ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = A2 ;DATE = 260 ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 AUTOST = TRUE ;If autostart program VERS: EQU 22 space 4,10 link OCCbio12.ASM ;Jump Table link OCCbio22.ASM ;CP/M disk definitions link OCCbio32.ASM ;Unit record I/O link OCCbio42.ASM ;Non data transfer disk link OCCbio52.ASM ;cold and warm boot link OCCbio62.ASM ;Disk data transfer I/O link OCCbio72.ASM ;Utility routines link OCCbio82.ASM ;Utility routines link OCCRAM1.asm ;Commom ram definitions ; END2: status of serial printer ; =3: complete status of serial port ; LSTST: proc mvi b,4 ;number of left shifts thru carry ;to align LIST field of IOBYTE ldk hl,ptr_lst ;list status routines jmp dispch page dispch: proc ; on entry here reg B contains the left shift count ; required to align the iobyte field to bit 1 position. ; and reg HL contains address of select table lda iobyte dspch1: ral djnz dspch1 ani 6 ;get select field*2 mov e,a ldk d,0 ; de = iobyte field * 2 dad de mov e,m inx hl mov h,m ; get the routine address mov l,e ; into hl and xchange with pc pchl ; ; addresses of routines ; ptr_cstat: dw const ; keyboard status dw pistat ; parallel input stat dw sistat ; serial port input status dw ieinstat ; status of input device on IEEE port ptr_cinp: dw keyinp ; get input from keyboard dw parinp ; parallel input dw spinp ; serial port input dw ieinp ; ieee port input ptr_cout: dw crtout ; output character to crtk. FLUSH: LDK HL,HSTWRT LD A,[hl] ORA A RZ ;If host buffer already on disk STO 0,[hl] LD A,HSTDSK ;Move disk and type STO A,ACTDSK LD HL,HSTTRK STO HL,ACTTRK LD A,HSTSEC STO A,ACTSEC LDK A,3 ;Write flag ; JMP FINAL space 4,10 FINAL: ;Preform final transfer processing. ; ; ENTRY A = 0 .. read disk. ; = 3 .. write disk. ; Calls: Rom resident routine to read/write ONE ; sector only. MOV E,A LDK D,0 LDK HL,ROMVEC+3*13 ADD HL,DE STO HL,SAVADR LDK HL,ACTSEC INC [hl] ;update sector+1 LDK A,MRTRY ;Set retry count FNL1: STO A,RTRY ;Clear retry count LD HL,SAVADR EX DE,HL LDK B,1 ;indicate one sector xfer CALL ROMJMP ;process read or write STO A,ERFLAG ;set possible error flag RZ ;If no errors LD A,RTRY ;Get retry counter DEC A JRNZ FNL1 ;If not permanent error ORI 01h STO A,ERFLAG ;Set error flag RET ; endx OSBBIOS6.asm  page ;***** ; file: OSBbios9.asm ; This file contains CP/M extensions to the OSBORNE CBIOS ; added by MICOROCDE CORPORATION. ; ; Revisions: ; YNS 20AUG81 Initial release ; YNS 29AUG81 Expanded trans. table to include ctl/numerics ; Translate keys to 1/2 or three char seq. ; Iobyte assignements redone. ; YNS 01SEP81 Added parallel port support ; YNS 05SEP81 Invert data to/from parallel port ; YNS 06SEP81 Return character in C as well as A from ; all input routines. ; YNS 08SEP81 Fixed "some" ieee bugs ; YNS 20SEP81 Recode ieee drivers to send untalk and ; unlisten commands after each char xfr. ; YNS 29SEP81 Add auto horiz. scroll ; ;***** ; ; the following routines will use the IOBYTE to transfer ; control to the appropriate device driver ; ;-------------- ; return console status ; CNSTA: proc ldk hl,ptr_cstat ; status table jr godispch ; call appropriate rtn ;------------ ; read input character from device ; CNIN: proc ldk hl,ptr_cinp ; tabl dw parout ; parallel output dw spout ; serial port output dw ieout ; ieee port output ptr_list: dw crtout ; list assigned to crt dw parout ; parallel port output dw spout ; serial port dw ACICTL ; serial port usart ctl ptr_pnch: dw crtout ; punch assigned to crt dw ieout ; ieee port dw spout ; serial port dw parout ; parallel port out ptr_rdr: dw keyinp ; reader assigned to keyboard dw ieinp ; ieee port dw spinp ; serial port dw parinp ; parallel port input ptr_lst: dw crstat dw postat ;parallel port output stat dw sostat ;serial port output stat dw acistat ;serial port usart status page ; C O N S O L S T A T U S ; ; This routine samples the Console status and returns the ; following values in the A register. ; ; EXIT A = 0 (zero), means no character ; currently ready to read. ; ; A = FFh (255), means character ; currently ready to read. nokey equ 00h ;indicates key not present CONST: proc ; check if any translated ;OCCBIO02.ASM TITLE 'Osborne CP/M 2.2 CBIOS.' ;CBIOS - Osborne CP/M 2.2 CBIOS. * 4D2007-00 MASTER .ASM * 2D2007-00 ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = A2 ;DATE = 260 ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 AUTOST = TRUE ;If autostart program VERS: EQU 22 space 4,10 link OCCbio12.ASM ;Jump Table link OCCbio22.ASM ;CP/M disk definitions link OCCbio32.ASM ;Unit record I/O link OCCbio42.ASM ;Non data transfer disk link OCCbio52.ASM ;cold and warm boot link OCCbio62.ASM ;Disk data transfer I/O link OCCbio72.ASM ;Utility routines link OCCbio82.ASM ;Utility routines link OCCRAM1.asm ;Commom ram definitions ; ENDe of input rtns jr godispch ;------------- ; put output character to device ; c contains output character ; CNOUT: proc ldk hl,ptr_cout ; table of output rtns godispch: mvi b,1 ;number of shifts required to align ;CONSOLE field jmp dispch ;--------------- ; list device character output ; LST: proc mvi b,4 ldk hl,ptr_list ;table of list routines jmp dispch ;--------------- ; output to punch ; PNCH: proc mvi b,6 ldk hl,ptr_pnch ; punch routines jmp dispch ;---------------- ; reader input ; RDR: proc mvi b,8 ldk hl,ptr_rdr ; reader routines jmp dispch space 4,10 ; L i s t S t a t u s. ; ; Return the ready status for the list device. ; ; EXIT A = 0 (zero), list device is not ready to ; accept another character. ; A = FFh (255), list device is ready to accept ; a character. ; The list status is returned depending upon the iobyte fields ; LIST field (bits 6,7) ; =0: status of crt. (always ready) ; =1: status of parallel port printer ; =keys are pending ld a,xltkey ora a jrnz const5 ; if no xlated keys pending, check keyhit flag LD A,LKEY ;Get Key hit flag xri nokey RZ ;If data not available const5: ORI 0FFh RET page ;** ; Routine name: KEYINP - gets keystroke from rom kbd driver. Translates ; the codes 80h to 8fh as per table. ; ; Outputs: A = translated code in ASCII ; All registers are destroyed ; ; Translation scheme: ; the translation table has a two byte entry for each code between ; 80h and 8fh. The incoming keystroke from the keyboard is translated ; to one, two or three character sequence as follows: ; if byte 0 is all zeros, the translated value is byte 1. ; if byte 0 is less than 80h, the key is translated to a ; 2 byte sequence: byte0 byte1 ; if byte 0 is 80h to ffh, the key is translated to a 3 byte ; sequence: Escape byte0-80h byte1 basvl0 equ 80h ;lowest code of the codes that ;are translated. KEYINP: proc ; if there are no xlated keys waiting then ; call the db 0,'J'-40h db 0,'H'-40h tbllen equ (*-xltbl)/2 page ;** ; routine: CRSTAT ; returns status of crt. ; crt is always ready CRSTAT: proc ori 0FFh ret ;** ; routine name: CRTOUT ; ; inputs: C: output character ; outputs: update translate table when the dc4 sequence found provided ; we are not in an escape seq. or in graphic mode. ; otherwise outputs the character to console ; all registers destroyed ; The dc4 sequence is as follows: ; dc4 k b0 b1 ; where: ; dc4 is the ascii device control char code 14h ; k is the table entry number + 30h. ; b0 is byte 0 of the table. ; b1 is byte 1 of the table. ; esch flag bit definitions (also check in file bmkey.asm) ef_esc: equ 8 ef_gr: equ 1 CRTOUT: proc lda esch and ef_esc+ef_gr jnz crt10 ;check for dc4 seq only when neither esc seq ; nor graphic lda dc4flg ; ora a ; jnz crt20 ; if not in dc4 sequence then mov a,c cpi dc4cod jnz crt10 ;if s call outch pop hl pop bc inc hl djnz :50 ret escsq db esc ;set screen coord escape sequence db 'S' db 0 ;** y coord db 0 ;** x coord ahsenb db 0ffh ;can be moved to BMRAM.ASM page ;** ; routine: SOSTAT ; gets status of output device attached to serial port SOSTAT: proc call acistat ;get 6850 status ani si.trdy rz ;return with not ready status ori true ret ;** ; routine: SISTAT ; gets status of input device attached to serial port SISTAT: proc call acistat ani si.rrdy rz ;return with not ready status ori true ret ;** ; routine: SPINP ; Inputs a character from the serial port ; Uses the reader (sp) driver in ROM ; SPINP: proc ldk e,low(reader) jmp romcd1 ;** ; routine: SPOUT ; Outputs character in reg c to the serial port (list device) ; calls the list (sp) driver in ROM ; SPOUT: proc ldk e,low(list) jmp romcd1 ;** ; routine: ACICTL ; outputs character in c to the ACIA CTL port. ; ACICTL: proc call keyboard driver in rom ldk hl,xltkey ld a,[hl] ;get number of xlated keys ora a jrz kin30 ;if keys pending then dec [hl] ;reduce pending count cpi 1 jrnz kin20 ;if only one key then ld a,xltvl1 ;get translated value mov c,a ret ;return kin20: ;else if two keys are waiting then ld a,xltvl2 ;get first val mov c,a ret ;return ;endif kin30: ;else ; get next key from keyboard driver and translate if reqd. ldk e,low(conin) call romcd1 ; ; when control is returned here, A has the input code for ; console character. If code is between 80h and 8fh, it is ; translated. ; cpi basvl0 rc ;return when code is not tobe xlated cpi basvl0+tbllen rnc sui basvl0 ;subtract base val ral ;mult remainder by 2 mov e,a ;build ptr to table entry mvi d,0 ldk hl,xltbl dad de ld a,[hl] ;get byte 0 inx hl ;point to byte 1 ora a jrnz kin40 ;if first byte is 0 then ld tart of dc seq then ldk a,1 ;set dc4 flag sto a,dc4flg ret crt10: ;else xra a sto a,dc4flg ;reset dc4 found flag call outch call ahscrl ret ; ; following ensures that the character following the dc4 ; is between 30h and 30h+tbllen. In case of error the characters ; are displayed. crt20: cpi 1 jnz crt30 ;exit when it is not second char after dc4 mov a,c sui '0' ; do a range check on code jc crt40 ;exit when char .lt. '0' cpi tbllen jnc crt40 ;or .gt. entries in table rlc ; multiply index by 2 mov c,a ldk b,0 ; set up bc for a dbl add ldk hl,xltbl dad bc ; add bc to hl shld tblptr ; save the ptr ldk a,2 ; set dc4 flg to indicate crt25: sto a,dc4flg ;next state ret ; ; store input character in xlate table crt30: lhld tblptr mov m,c sui 3 jrz crt25 ;clear dc4 flag and return when last ;char of dc4 seq received. inc hl ;increment table ptr for next byte shld tblptr  sw2rom mov a,c sta h.sctrl jmp sw2ram ;** ; routine: acistat ; returns usart status in A ; The ringin signal is read from the pia at address 2c00 ; and merged in at the overrun error bit of the acia status riport equ h.vio+1 ribit equ 040h ormask equ 020h acistat: proc call sw2rom lda riport ;read in ringin signal rrc ;shift ring in to overrun err ;position ani ormask ;get ring in mov c,a lda h.ssts ani 0ffh-ormask ;remove overrun error bit ora c ;merge ring in bit jmp sw2ram page ;*** ; IEEE drivers: ; ; The routines IEINSTAT, IEINP and IEOUT are used to ; transfer characters to and from an IEEE device attached to the ; OSBORNE IEEE port. The address of the device is specified in ; the cell IE_ADRS. No facility is provided at present to allow a ; transient programme to specify the device address. Thus the device ; attached must be addressable as 0 (zero). ; The function IEINSTAT returns the status of the input device. ; Unfoa,[hl] mov c,a ret ;return with byte1 as xlated val. kin40: ; if msb of byte 0 is 0 then the xlated val is byte0 and byte 1 bit 7,a jrnz kin50 ;elseif bit7 is 0 then push af ;save byte 0 ld a,[hl] ;get byte1 from table sto a,xltvl1 ;save translated value lk a,1 sto a,xltkey ;set xlated keys to 1 pop af mov c,a ret ;return with the first char of the ;sequence kin50: ;else ; the key is translated to a three char seq. esc byte0-80h byte1 ani 07fh ;get lower seven bits sto a,xltvl2 ;save byte0-80h ld a,[hl] sto a,xltvl1 ;save byte1 lk a,2 sto a,xltkey lk a,1bh ;a = esc code mov c,a ret xltvl1: db 0 xltvl2: db 0 xltkey: db 0 xltbl: ;default table ; ctl numerics produce and escape seq. Esc n ; cursor keys produce ctl/l, ctl/h, ctl/k and ctl/j db 1bh,'0' db 1bh,'1' db 1bh,'2' db 1bh,'3' db 1bh,'4' db 1bh,'5' db 1bh,'6' db 1bh,'7' db 1bh,'8' db 1bh,'9' db 0,'K'-40h db 0,'L'-40h ldk a,3 jr crt25 ; ; Illegal sequence. Char following dc4 is not valid. This ; outputs a dc4 and the invalid char to the crt. crt40: push bc ;save current char ldk c,dc4cod call outch pop bc jr crt10 ; dc4flg db 0 tblptr dw 0 dc4cod equ 14h ; sbrt: outch - calls rom cout routine outch: ldk e,low(conout) ;output to crt jmp romcd1 ; sbrt: ahscrl - does auto horizontal scroll if required. ; (** The flag ahsenb may be moved to BMRAM **) ahscrl: proc ld a,ahsenb or a rz ld hl,curs ;get cursor add hl,hl ld a,piaad ;a=horiz coord of screen sub vflo-96 ;-fuzz factor+48*2 cmp l jc :30 ;move screen when cursor about to go off ;the right margin sub 96 cmp l rz rc mov a,l jr :35 :30: mov a,l sub 96 :35: rar add a,' ' lk hl,escsq+3 sto a,[hl] ld a,piabd and 1fh add a,' ' dec hl sto a,[hl] ;escsq+2 = vert. coords dec hl dec hl ;point to start of esc seq lk b,4 :50: push bc push hl ld c,[hl]rtunately there is no standard way by which an IEEE device ; indicates that it has a character. In order to determine this, one ; has to read the character device. As a CP/M transient can call ; IEINSTAT many times before calling IEINP to read a char, and IEINSTAT ; has to read the char to determine the status, the character read has to ; be buffered till call to IEINP is made. IEINSTAT reads the device ; only when the buffer is empty. As zeros are used to indicate ; that the bfr is empty, a null character can not be read from the ; IEEE device. ; IEEE control codes ie_talk equ 40h ;make talker ie_utlk equ 5fh ;make untalk ie_lstn equ 20h ;make listener ie_ulstn equ 3fh ;make unlisten ie_adrs db 0 ;device address (can be moved to ;BMRAM) ie_char db 0 ;ie inp char buffer ;** ; routine: IEINSTAT ; gets status of the input device attached to ieee port ; ; if a char is present in ie_char then ; return with true status ; else ; make device talker ; rIB2 = set to 0. ; PIB3 = 0 output, 1 Input ; PIB4 = not used ; PIB5 = output strobe. Active = 1. ; PIB6 = 0, printer busy. 1, printer is ready. ; PIB7 = not used. ; ; CA2 = going low indicates to device that we are busy. ; CA1 = low to high transition gates input data to port a. ; ; The port is bidirectional but only one direction ; can be active at any time. The direction of port is determined ; by which routines are called. If postat or parout are ; called, it is made an output port and an input port if ; pistat or parinp are called. ; port registers pa.dta equ h.ieee+0 pa.dir equ pa.dta pa.ctl equ h.ieee+1 pb.dta equ h.ieee+2 pb.dir equ pb.dta pb.ctl equ h.ieee+3 ; port ctl register constants. pa.cdr equ 00101010b ;to address port a direction pa.cdt equ 00101110b ;to address port a data and set ;port a in input program handshake mode. pb.cdr equ 00000000b ;to address port b direction pb.cdt equ 00000100b ;to address port b data ; direction register constants pa.droroutine: PISTAT ; gets status of the input device attached to the ; parallel port ; piactl db 0 PISTAT: proc call sw2rom call cv2ip lda piactl ani pp.irdy jrnz pis20 ;if saved status indicates there is a char ;in the PIA lda pa.ctl sta piactl ;this is saved as reading the ;pia clears the status ani pp.irdy jrz pis30 pis20: ori true pis30: jmp sw2ram ;** ; routine: PARINP ; inputs a character from parallel port. PARINP: proc call pistat jrz parinp ;wait till char in pia call sw2rom xra a sta piactl ;clear saved status lda pa.dta cma ;invert data mov c,a ;also in c jmp sw2ram ;** ; routine: PAROUT ; outputs the character in c to the IEEE port treating the ; port as a parallel port. PAROUT: proc call postat jrz parout call sw2rom mov a,c cma ;invert data sta pa.dta lk a,pb.dto+strb sta pb.dta ;set strobe lk a,pb.dto sta pb.dta ;clear strobe jmp sw2ram page ;*** ; sbrt: SW2ROM ead the device ; if char read then ; store in bfr ; endif ; make untalk ; return with status of buffer ; endif IEINSTAT: proc lda ie_char ora a jz iei10 ;if char present then ori 0ffh ;return with true status ret iei10: ;endif ;make talker lda ie_adrs adi ie_talk ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz iei10 ;try again if error ; ; ***secondary address output may be added here*** iei20: ;read a char. ldk e,low(ieb7c) call romcd1 bit 7,l jrz iei30 ;if error then xra a ;inicate no char recvd iei30: sta ie_char ;stor the char ; ; iei40: ;make untalk mvi c,ie_utlk ldk e,low(ieb5c) call romcd1 ora a jrnz iei40 ; return with status of the char lda ie_char ora a rz ori 0ffh ret ;** ; routine: IEINP ; Reads a character from IEEE port IEINP: proc call ieinstat jrz ieinp ;wait till char avail ldk hl,ie_c equ 0ffh ;port a output mode pa.dri equ 00h ;port a input mode pb.dr equ 0bfh ;port b direction pb.dto equ 00000010b ;port b data for output pb.dti equ 00001011b ;port b data for input pp.ordy equ 01000000b ;output rdy bit in pib pp.irdy equ 10000000b ;input rdy bit in pia ctl reg strb equ 00100000b ;strobe bit in port b ; port modes pp.undef equ 0 pp.out equ 1 pp.in equ 2 pp.mode db pp.undef ;*** ; sbrt: CV2OP. initializes the port to a parallel output ; port. cv2op: proc lda pp.mode cpi pp.out rz ;return when in output mode ; set port a to output on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dro sta pa.dir ;output constant to dir. reg to put ; a port in output mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.d; switches to rom ; saves all registers SW2ROM: proc di push af enarom pop af ei ret ;*** ; sbrt: SW2RAM ; switches to ram ; preserves all registers SW2RAM: proc di push af disrom pop af ei ret ctl sta piactl ;this is saved as reading the ;pia clears the status ani pp.irdy jrz pis30 pis20: ori true pis30: jmp sw2ram ;** ; routine: PARINP ; inputs a character from parallel port. PARINP: proc call pistat jrz parinp ;wait till char in pia call sw2rom xra a sta piactl ;clear saved status lda pa.dta cma ;invert data mov c,a ;also in c jmp sw2ram ;** ; routine: PAROUT ; outputs the character in c to the IEEE port treating the ; port as a parallel port. PAROUT: proc call postat jrz parout call sw2rom mov a,c cma ;invert data sta pa.dta lk a,pb.dto+strb sta pb.dta ;set strobe lk a,pb.dto sta pb.dta ;clear strobe jmp sw2ram page ;*** ; sbrt: SW2ROM har ld a,[hl] sto 0,[hl] ;clear the buffer ret ;** ; routine: IEOUT ; Outputs the character in reg C to IEEE port ; Uses ROM resident primitives. ; IEOUT: proc push bc ;save the char ;make listener ieo05: lda ie_adrs adi ie_lstn ;get primary address mov c,a ldk e,low(ieb5c) call romcd1 ;output interface message ora a jrnz ieo05 ;try again if error ; ; ***secondary address output may be added here*** ; ieo20: ; mvi b,0 ;do not send eoi pop b ieo22: push b ;save char again in case of retry ldk e,low(ieb6c) call romcd1 pop b ora a jrnz ieo22 ;try again if error ; ; ;make unlisten ieo40: mvi c,ie_ulstn ldk e,low(ieb5c) call romcd1 ora a jrnz ieo40 ret page ;*** ; The Parallel port is actually the IEEE port driven with the centronix ; protocol. The bit assignements of the PIA and PIB are as follows: ; PIA0-7 = data bus ; PIB0 = 0, data bus is output. 1, data bus is input ; PIB1 = set to 1. ; Pto sta pb.dta ;initialize port b data lk a,pp.out sta pp.mode ret ;*** ; sbrt: CV2IP. initializes the port to a parallel input ; port. cv2ip: proc lda pp.mode cpi pp.in rz ;return when in input mode ; set port a to input on all lines lk a,pa.cdr sta pa.ctl ;select direction reg lk a,pa.dri sta pa.dir ;output constant to dir. reg to put ; a port in input mode lk a,pa.cdt sta pa.ctl ;select port a data reg. lk a,pb.cdr sta pb.ctì ;selecô porô b direction lk a,pb.dr sta pb.dir ;all lines are output except the output ;busy signal on bit 6 lk a,pb.cdt sta pb.ctl ;select data register lk a,pb.dti sta pb.dta ;initialize port b data lk a,pp.in sta pp.mode ret ;** ; routine: POSTAT ; gets status of the parallel (centronix) printer ; attached to the ieee port ; POSTAT: proc call sw2rom call cv2op ;convert to output lda pb.dta ;get port b data ani pp.ordy jrz pos10 ori true pos10: jmp sw2ram ;** ;  page ;***** ; Revisions: ; YNS 18AUG81 added iobyte function to listst ; modified romcde routine ; YNS 30AUG81 moved const and listst to osbbios9.asm ; YNS 23SEP81 saved hl in ROMCDE routine when returning ; to RAM as IEEE routines return status in ; HL ;***** SETRRM: ;Set ROM-RAM flag ; Entry A= port to output (setting ROM or RAM enable) ; Exit none. ; Uses A DI PUSH BC MOV C,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) ate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; CBOOT: ;Entry A= drive to boot off of. MOV B,A ;save requested drive DISROM MOV A,B ;restore requested drive STO A,CDISK ;force requested drive LDK SP,CCP ;********************** ; the following initializes the IEEE interface by issuing an ; IFC. (This code can be moved to ROM HINT routine.) YNS. mvi c,1 ldk e,low(ieb1c) ;call output control function call romcd1 ;********************** .autos IF ~ AUTOST LDK HL,SIGNON CALL PRINT ;Output Banner .autos ENDIF ldk a,iob_default STO A,IOBYTE ;Set I/O byte to default .autos IF AUTOST MVI a,1 ;indicate cold boot .autos ENDIF JR BCCP ;Do CP/M WBOOT: ;Warm boot LDK SP,CCP CALL HOME ;flush any buffer BCPM: LDK DE,ROMVEC+3*1 ;Set ROM vector address LDK BC,CCP CALL ROMJMP ORA A ;OCCBIO03.ASM TITLE 'Osborne CP/M 2.2 CBIOS.' *NOTE* FOR USE WITH OCCTXT6.AST ONLY * 4D2007-00 MASTER .ASM * 2D2007-00 ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = A3 ;DATE = 274 ;DEB ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 AUTOST = TRUE ;If autostart program VERS: = 22 space 4,10 LINK OCCBIO13.ASM ;Jump Table LINK OCCBIO23.ASM ;CP/M disk definitions LINK OCCBIO33.ASM ;Unit record I/O LINK OCCBIO43.ASM ;Non data transfer disk LINK OCCBIO53.ASM ;cold and warm boot LINK OCCBIO63.ASM ;Disk data transfer I/O LINK OCCBIO73.ASM ;Utility routines LINK OCCBIO83.ASM ;Utility routines LINK OCCRAM2.ASM ;Commom ram defini ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC = any parameters DI LDK HL,0 ADD HL,SP ;Old stack to HL LDK SP,BIOSTK PUSH HL ;Save old stack pointer ENAROM EX DE,HL ;ROM jump address to HL CALL GOROM DI PUSH AF ;save status returned DISROM POP AF ex de,hl ;save hl in de. IEEE routine returns status ;in HL POP HL ;Restore old stack pointer MOV SP,HL ex de,hl ;restore hl EI ! RET GOROM: EI JMP [hl] routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC)  JRNZ BCPM ;If error in read ORI 0FFh BCCP: ;Entry A = 01, if cold boot ; A = ff, if warm boot PUSH AF ;Save flags LDK BC,DBUF ;Set default data transfer address CALL SETDMA LDK HL,HSTBUF STO HL,DMADR ;set ROM DMA address ; Clear console control ESC cell XRA A STO A,ESCH ;clear ESC ; Set-up low core pointer cells LDK A,0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto tions ; END OCCBIO03.ASM ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = A3 ;DATE = 274 ;DEB ; Revisions: ; 1. Extensions to CBIOS added by: ; Microcode Corporation. ; Fremont, Ca ; Y. N. Sahae ; August 1981 AUTOST = TRUE ;If autostart program VERS: = 22 space 4,10 LINK OCCBIO13.ASM ;Jump Table LINK OCCBIO23.ASM ;CP/M disk definitions LINK OCCBIO33.ASM ;Unit record I/O LINK OCCBIO43.ASM ;Non data transfer disk LINK OCCBIO53.ASM ;cold and warm boot LINK OCCBIO63.ASM ;Disk data transfer I/O LINK OCCBIO73.ASM ;Utility routines LINK OCCBIO83.ASM ;Utility routines LINK OCCRAM2.ASM ;Commom ram defini page ;***** ; Revisions: ; YNS 20AUG81 change iobyte defaults ; YNS 23SEP81 added initializing of IEEE in CBOOT ; (can be moved to ROM HINT routine) ;***** ; B o o t C P / M f r o m d i s k. ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; 40-41: Points to where Date and Time are kept ; ; Register C must contain the selected drive, which is ; zero to select the A drive. The exit address is to ; the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropristart line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDIF CAUTO: DB CAUTOL DB 'AUTOST ' CAUTOL = *-CAUTO-1 WAUTO: DB WAUTOL DB ' ' WAUTOL = *-WAUTO-2 ; Endx OSBBIOS5.asm r LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto  page ; Sector Translation Tables. XLTS: ;Translation table 2 to 1 DB 0, 1, 4, 5, 8, 9, 12,13, 16,17 DB 2, 3, 6, 7, 10,11, 14,15, 18,19 ; Translation 3 to 1 ; DB 0, 1, 6, 7, 12,13, 18,19 ; DB 2, 3, 8, 9, 14,15 ; DB 4, 5, 10,11, 16,17 ; Translation 4 to 1 ; DB 0, 1, 8, 9, 16,17 ; DB 2, 3, 10, 11, 18,19 ; DB 4, 5, 12, 13 ; DB 6, 7, 14, 15 IF (*-XLTS) <> (MSEC*2) MSG 'Translation table error',ERROR ENDIF space 4,10 ; Control Blocks for disk drives DPBASE: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive A: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive B: space 4,10 ; Disk type definition blocks for each particular mode. DPBS1: ;Single density, single sided. DPBGEN DSKS1,2*MSEC,4,15,1,S1DSM,64,1000000000000000b,3 .AL IF ALVSZ <> ALVS MSG 'Allocation problems ALVS<> ALVSZ, ALVSZ= ',ALVSZ .9 ERROR .AL ENDIF ; endx OSBBIOS2 ċ0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDIF CAċ page ;***** ; Revisions: ; YNS 20AUG81 change iobyte defaults ; ;***** ; B o o t C P / M f r o m d i s k. ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; 40-41: Points to where Date and Time are kept ; ; Register C must contain the selected drive, which is ; zero to select the A drive. The exit address is to ; the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT UTO: DB CAUTOL DB 'AUTOST ' CAUTOL = *-CAUTO-1 WAUTO: DB WAUTOL DB ' ' WAUTOL = *-WAUTO-2 ; Endx OSBBIOS5.asm TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDIF CA page ; Sector Translation Tables. XLTS: ;Translation table 2 to 1 DB 0, 1, 4, 5, 8, 9, 12,13, 16,17 DB 2, 3, 6, 7, 10,11, 14,15, 18,19 ; Translation 3 to 1 ; DB 0, 1, 6, 7, 12,13, 18,19 ; DB 2, 3, 8, 9, 14,15 ; DB 4, 5, 10,11, 16,17 ; Translation 4 to 1 ; DB 0, 1, 8, 9, 16,17 ; DB 2, 3, 10, 11, 18,19 ; DB 4, 5, 12, 13 ; DB 6, 7, 14, 15 IF (*-XLTS) <> (MSEC*2) MSG 'Translation table error',ERROR ENDIF space 4,10 ; Control Blocks for disk drives DPBASE: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive A: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive B: space 4,10 ; Disk type definition blocks for each particular mode. DPBS1: ;Single density, single sided. DPBGEN DSKS1,2*MSEC,4,15,1,S1DSM,64,1000000000000000b,3 .AL IF ALVSZ <> ALVS MSG 'Allocation problems ALVS<> ALVSZ, ALVSZ= ',ALVSZ .9 ERROR .AL ENDIF ; endx OSBBIOS2 routines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; CBOOT: ;Entry A= drive to boot off of. MOV B,A ;save requested drive DISROM MOV A,B ;restore requested drive STO A,CDISK ;force requested drive LDK SP,CCP .autos IF ~ AUTOST LDK HL,SIGNON CALL PRINT ;Output Banner .autos ENDIF ldk a,iob_default STO A,IOBYTE ;Clear I/O byte .autos IF AUTOST ORI 1 ;indicate cold boot .autos ENDIF JR BCCP ;Do CP/M WBOOT: ;Warm boot LDK SP,CCP CALL HOME ;flush any buffer BCPM: LDK DE,ROMVEC+3*1 ;Set ROM vector address LDK BC,CCP CALL ROMJMP ORA A JRNZ BCPM ;If error in read ORI 0FFh BCCP: ;Entry A = 01, if cold boot ; A = ff, if warm boot PUSH AF ;Save flags LDK BC,DBUF ;Set default data transfer address CALL SETDMA LDK HL,HSTBUF STO HL,DMADR ;set ROM DMA address ; Clear console control ESC cell XRA A STO A,ESCH ;clear ESC ; Set-up low core pointer cells LDK A,;OCCBIO01.ASM TITLE 'Osborne CP/M 2.2 CBIOS.' ;CBIOS - Osborne CP/M 2.2 CBIOS. * 4D2007-00 MASTER .ASM * 2D2007-00 ASSY .ASM * 1D2007-00 LISTING .PRN * 4D1007-00 MASTER .COM * 2D1007-00 ASSY .C0M ; +-----------------------+ ; | | ; | C B I O S | ; | | ; +-----------------------+ ; Copyright 1981, Osborne. ; This product is a copyright program product of ; Osborne and is supplied for use with the Osborne. ;REV = A1 ;DATE = 247 AUTOST = TRUE ;If autostart program VERS: EQU 22 space 4,10 ; Link files. link OCCbio11 ;Jump Table link OCCbio21 ;CP/M disk definitions link OCCbio31 ;Unit record I/O link OCCbio41 ;Non data transfer disk link OCCbio51 ;Cold and Warm boot link OCCbio61 ;Disk data transfer I/O link OCCbio71 ;Utility routines link OCCbio81 ;Utility routines link bmram.asm ;Commom ram definitions OCCBIO23ASMEOCCBIO51HA FGOCCBIO01$$$ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċany parameters DI LDK HL,0 ADD HL,SP ;Old stack to HL LDK SP,BIOSTK PUSH HL ;Save old stack pointer ENAROM EX DE,HL ;ROM jump address to HL CALL GOROM DI PUSH AF ;save status returned DISROM POP AF POP HL ;Restore old stack pointer MOV SP,HL EI ! RET GOROM: EI JMP [hl] ent Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) LD A,IOBYTE ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC =  page ; MVINFO Move information necessary for transfer. MVINFO: XRA A STO A,ERFLAG ;Clear error flag LD A,TEMSEC STO A,SEKSEC RET space 4,10 ; Print message terminated by zero byte. ; ; ENTRY HL -> message buffer, terminated by zero. ; ; EXIT HL -> zero byte + 1. ; A = 0. ; Z bit set. ; ; Destroys only HL, Flags, and A registers. PRINT: LD A,[hl] ;Get a character ORA A INC HL RZ ;If zero the terminate PUSH HL MOV C,A CALL CONOUT ;Output to the console POP HL JR PRINT SAVADR: DS 2 ;Disk transfer routine vector IF * > (MRAM-1) MSG 'CBIOS is too long, lwa= ',* .9 ERROR ENDIF ; Endx OSBBIOS8.asm ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ page ; Sector Translation Tables. XLTS: ;Translation table 2 to 1 DB 0, 1, 4, 5, 8, 9, 12,13, 16,17 DB 2, 3, 6, 7, 10,11, 14,15, 18,19 ; Translation 3 to 1 ; DB 0, 1, 6, 7, 12,13, 18,19 ; DB 2, 3, 8, 9, 14,15 ; DB 4, 5, 10,11, 16,17 ; Translation 4 to 1 ; DB 0, 1, 8, 9, 16,17 ; DB 2, 3, 10, 11, 18,19 ; DB 4, 5, 12, 13 ; DB 6, 7, 14, 15 IF (*-XLTS) <> (MSEC*2) MSG 'Translation table error',ERROR ENDIF space 4,10 ; Control Blocks for disk drives DPBASE: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive A: DPHGEN DSKS1,XLTS,DIRBUF,DPBS1+1 ;Drive B: space 4,10 ; Disk type definition blocks for each particular mode. DPBS1: ;Single density, single sided. DPBGEN DSKS1,2*MSEC,4,15,1,S1DSM,64,1000000000000000b,3 .AL IF ALVSZ <> ALVS MSG 'Allocation problems ALVS<> ALVSZ, ALVSZ= ',ALVSZ .9 ERROR .AL ENDIF ; endx OSBBIOS2 ċ page ;***** ; Revisions: ; YNS 18AUG81 added iobyte function to listst ; modified romcde routine ; YNS 30AUG81 moved const and listst to osbbios9.asm ;***** SETRRM: ;Set ROM-RAM flag ; Entry A= port to output (setting ROM or RAM enable) ; Exit none. ; Uses A DI PUSH BC MOV C,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) LD A,IOBYTE ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC = ċ page ;***** ; Revisions: ; YNS 18AUG81 change bios jump vector to call new routines ; ; ;***** MRTRY: = 5 ;Maximum number of retries. MSG 'Assemblying BIOS for LWA of ', LWAMEM,'h.' ; CP/M to host disk constants HSTSIZ: = 256 ;Blocking/Deblocking buffer size FPYSIB: = 2048/128 ;Sectors in floppy disk block ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. DSKS1: = 0 ;Single density, single sided. S1DSM: = ((40-3)*2*10)/FPYSIB ; BDOS constants on entry to write WRALL: = 0 ;write to allocated WRDIR: = 1 ;write to directory WRUAL: = 2 ;write to unallocated space 4,10 ; ROM equates. ENROM: = 0 ;Port to enable ROM DIROM: = 1 ;Port to disable ROM page ; Macro for generating Control Blocks for disk drives ; The format of these disk control blocks are as follows: ; 16 bits = -> translation table. ; 48 bits = Work area for CP/M. ; 16 bits = -> DIRBUF. ; 16 bits = -> Parameter block. ; SBAUD: CALL ROMCDE ; IEEE-488 vectors ieb1c: CALL ROMCDE ;Control Out ieb2c: CALL ROMCDE ;Status In ieb3c: CALL ROMCDE ;Go To Standby ieb4c: CALL ROMCDE ;Take Control ieb5c: CALL ROMCDE ;Output Interface Message ieb6c: CALL ROMCDE ;Output Device Message ieb7c: CALL ROMCDE ;Input Device Message ieb8c: CALL ROMCDE ;Parallel Poll OT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call page ;***** ; Revisions: ; YNS 20AUG81 change iobyte defaults ;***** ; B o o t C P / M f r o m d i s k. ; ; The CBOOT entry point gets control from the cold start ; loader and is responsible for the basic system initial- ; ization. This includes outputting a sign-on message and ; initializing the following page zero locations: ; ; 0,1,2: Set to the warmstart jump vector. ; 3: Set to the initial IOBYTE value. ; 4: Default and logged on drive. ; 5,6,7: Set to a jump to BDOS. ; 40-41: Points to where Date and Time are kept ; ; Register C must contain the selected drive, which is ; zero to select the A drive. The exit address is to ; the CCP routine. ; ; ; The WBOOT entry point gets control when a warm start ; occurs, a ^C from the console, a jump to BDOS (function ; 0), or a jump to location zero. The WBOOT routine reads ; the CCP and BDOS from the appropriate disk sectors. ; WBOOT must also re-initialize locations 0,1,2 and 5,6,7. ; The WBOOT rou 16 bits = -> check vector. ; 16 bits = -> allocation vector. NDSK: SET 0 ;Number of disk drives NOFDD: SET 0 ;Number of floppy disk drives ALVSZ: SET 0 ;Allocation vector size CSVSZ: SET 0 ;Check vector size LIST D,G,M DPHGEN MACRO TYPE,XLATE,DIRBUF,DPBADR NDSK: SET NDSK+1 DW %2 DW 0,0,0 DW %3 DW %4 DW CSV+CSVSZ DW ALV+ALVSZ NOFDD: SET NOFDD+1 CSVSZ: SET CSVSZ+(64/4) ALVSZ: SET ALVSZ+((S1DSM+7)/8) ENDM ; Make sure Systext agrees with assembled size space 4,10 ; Macro for generating the Disk Parameter Blocks. ; ; Disk type definition blocks for each particular mode. ; The format of these areas are as follow: ; 8 bit = disk type code ; 16 bit = Sectors per track ; 8 bit = Block shift ; 8 bit = BS mask ; 8 bit = Extent mask ; 16 bit = Disk size/1024 - 1. ; 16 bit = Directory size. ; 16 bit = Allocation for directory. ; 16 bit = check area size. ; 16 bit = offset to first track. DPBGEN MACRO TYPE,SPT,BSH,BSM,EXM,DSM,DIRSIZ,ALVMSK,OFFSET DB %1 DW %2 page ;***** ; Revisions: ; YNS 18AUG81 added iobyte function to listst ; modified romcde routine ; YNS 30AUG81 moved const and listst to osbbios9.asm ;***** SETRRM: ;Set ROM-RAM flag ; Entry A= port to output (setting ROM or RAM enable) ; Exit none. ; Uses A DI PUSH BC MOV C,A OT,C A STO A,ROMRAM POP BC EI ! RET space 4,10 ROMRI: ;Exit ROM resident Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) LD A,IOBYTE ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC = tines exits with the C register set to the ; appropriate drive selection value. The exit address ; is to the CCP routine. ; CBOOT: ;Entry A= drive to boot off of. MOV B,A ;save requested drive DISROM MOV A,B ;restore requested drive STO A,CDISK ;force requested drive LDK SP,CCP .autos IF ~ AUTOST LDK HL,SIGNON CALL PRINT ;Output Banner .autos ENDIF ldk a,iob_default STO A,IOBYTE ;Set I/O byte to default .autos IF AUTOST MVI a,1 ;indicate cold boot .autos ENDIF JR BCCP ;Do CP/M WBOOT: ;Warm boot LDK SP,CCP CALL HOME ;flush any buffer BCPM: LDK DE,ROMVEC+3*1 ;Set ROM vector address LDK BC,CCP CALL ROMJMP ORA A JRNZ BCPM ;If error in read ORI 0FFh BCCP: ;Entry A = 01, if cold boot ; A = ff, if warm boot PUSH AF ;Save flags LDK BC,DBUF ;Set default data transfer address CALL SETDMA LDK HL,HSTBUF STO HL,DMADR ;set ROM DMA address ; Clear console control ESC cell XRA A STO A,ESCH ;clear ESC ; Set-up low core pointer cells  DB %3,%4,%5 DW %6-1,%7-1,REV (%8) DW (%7+3)/4 DW %9 ENDM page ; The following jump table defines the entry points ; into the CBIOS for use by CP/M and other external ; routines; therfore the order of these jump cannot ; be modified. The location of these jumps can only ; be modified by 400h locations, which is a restriction ; of MOVCPM. ORG BIOS CALL CBOOT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident callany parameters DI LDK HL,0 ADD HL,SP ;Old stack to HL LDK SP,BIOSTK PUSH HL ;Save old stack pointer ENAROM EX DE,HL ;ROM jump address to HL CALL GOROM DI PUSH AF ;save status returned DISROM POP AF POP HL ;Restore old stack pointer MOV SP,HL EI ! RET GOROM: EI JMP [hl] ent Interrupt routine. LD A,ROMRAM MOV C,A ;port OT,C A ;set ROM or RAM enabled POP IY POP IX POP HL POP DE POP BC POP AF LD SP,IESTK ;reset to interrupt entry stk EI ! RET space 4,10 ROMCDE: ;Call ROM resident processor ; Entry DE = resident processor to call biased ; by CBIOS jump vector. ; NOTE: ROM jump vector must match CBIOS vector ; ; Entry at ROMCD1 with low digit of CBIOS vector in reg E POP DE ;Get calling address MOV A,E SUI 3 MOV E,A ROMCD1: LDK D,high (ROMVEC) LD A,IOBYTE ROMJMP: ;Entry here to jump to ROM function code directly ; Entry DE = ROM jump address ; BC =  LDK A,0C3h ;Store jumps in low memory STO A,0 STO A,5 LDK HL,BIOS+3 STO HL,1 LDK HL,BDOS STO HL,6 LDK HL,IDAY STO HL,TIMPTR ;set date-time pointer LDK HL,CAUTO ;Digital Research has informed SORCIM that CP/M 2.2 ;CANNOT be booted off B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos ENDċ DB %3,%4,%5 DW %6-1,%7-1,REV (%8) DW (%7+3)/4 DW %9 ENDM page ; The following jump table defines the entry points ; into the CBIOS for use by CP/M and other external ; routines; therfore the order of these jump cannot ; be modified. The location of these jumps can only ; be modified by 400h locations, which is a restriction ; of MOVCPM. ORG BIOS CALL CBOOT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident callIF CAUTO: DB CAUTOL DB 'AUTOST ' CAUTOL = *-CAUTO-1 WAUTO: DB WAUTOL DB ' ' WAUTOL = *-WAUTO-2 ; Endx OSBBIOS5.asm ff B:. ;Manipulation of CDISK is kept here to avoid the bugs ;which would appear with its disappearance. ;Booting off B: is accomplished with the RAM cell DSKSWP. LD A,CDISK ;use requested drive ; AND 0Fh ;force user #0 ; STO A,BDOS+0336h ;set CP/M internal ; ;'CURDSK' static variable MOV C,A POP AF CMP 1 JRZ GCOLD ;If cold boot LDK HL,WAUTO GCOLD: LD A,[hl] ORA A JZ CCP+3 ;If no auto start line PUSH BC ;Save current drive LDK DE,CCP+7 LDK B,0 MOV C,A LDIR ;Move command line to buffer POP BC JMP CCP ;Go to CPM .autos IF ~ AUTOST SIGNON: DB 'Z'-40h DB 'Osborne Computer System' DB CR,LF,MSIZE/10+'0',MSIZE mod 10 + '0' DB 'K CP/M ',VERS/10+'0','.',VERS mod 10 + '0' DB CBIOSV+'@',CR,LF,0 .autos END page ;***** ; Revisions: ; YNS 18AUG81 change bios jump vector to call new routines ; ; ;***** MRTRY: = 5 ;Maximum number of retries. MSG 'Assemblying BIOS for LWA of ', LWAMEM,'h.' ; CP/M to host disk constants HSTSIZ: = 256 ;Blocking/Deblocking buffer size FPYSIB: = 2048/128 ;Sectors in floppy disk block ; CP/M disk control block equates which define the ; disk types and maximum storage capability of each ; disk type. DSKS1: = 0 ;Single density, single sided. S1DSM: = ((40-3)*2*10)/FPYSIB ; BDOS constants on entry to write WRALL: = 0 ;write to allocated WRDIR: = 1 ;write to directory WRUAL: = 2 ;write to unallocated space 4,10 ; ROM equates. ENROM: = 0 ;Port to enable ROM DIROM: = 1 ;Port to disable ROM page ; Macro for generating Control Blocks for disk drives ; The format of these disk control blocks are as follows: ; 16 bits = -> translation table. ; 48 bits = Work area for CP/M. ; 16 bits = -> DIRBUF. ; 16 bits = -> Parameter block. ; SBAUD: CALL ROMCDE ; IEEE-488 vectors ieb1c: CALL ROMCDE ;Control Out ieb2c: CALL ROMCDE ;Status In ieb3c: CALL ROMCDE ;Go To Standby ieb4c: CALL ROMCDE ;Take Control ieb5c: CALL ROMCDE ;Output Interface Message ieb6c: CALL ROMCDE ;Output Device Message ieb7c: CALL ROMCDE ;Input Device Message ieb8c: CALL ROMCDE ;Parallel Poll OT ;Cold boot CALL WBOOT ;Warm boot jmp cnsta ;Console status (input) CONIN: jmp cnin ;Console input CONOUT: jmp cnout ;Console output LIST: jmp lst ;List output PUNCH: jmp pnch ;Punch output READER: jmp rdr ;Reader input JMP HOME ;Set track to zero RSELDK: JMP SELDSK ;Select disk unit JMP SETTRK ;Set track JMP SETSEC ;Set sector JMP SETDMA ;Set Disk Memory Address RRDK: JMP READ ;Read from disk RWDK: JMP WRITE ;Write onto disk LISTST: jmp lstst ;Return LST: device status JMP SECTRN ;Sector translation routine ; Extensions RRI: JMP ROMRI JMP ROMJMP FMTJ: CALL ROMCDE ;Rom resident call page ; MVINFO Move information necessary for transfer. MVINFO: XRA A STO A,ERFLAG ;Clear error flag LD A,TEMSEC STO A,SEKSEC RET space 4,10 ; Print message terminated by zero byte. ; ; ENTRY HL -> message buffer, terminated by zero. ; ; EXIT HL -> zero byte + 1. ; A = 0. ; Z bit set. ; ; Destroys only HL, Flags, and A registers. PRINT: LD A,[hl] ;Get a character ORA A INC HL RZ ;If zero the terminate PUSH HL MOV C,A CALL CONOUT ;Output to the console POP HL JR PRINT SAVADR: DS 2 ;Disk transfer routine vector IF * > (MRAM-1) MSG 'CBIOS is too long, lwa= ',* .9 ERROR ENDIF ; Endx OSBBIOS8.asm ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ 16 bits = -> check vector. ; 16 bits = -> allocation vector. NDSK: SET 0 ;Number of disk drives NOFDD: SET 0 ;Number of floppy disk drives ALVSZ: SET 0 ;Allocation vector size CSVSZ: SET 0 ;Check vector size LIST D,G,M DPHGEN MACRO TYPE,XLATE,DIRBUF,DPBADR NDSK: SET NDSK+1 DW %2 DW 0,0,0 DW %3 DW %4 DW CSV+CSVSZ DW ALV+ALVSZ NOFDD: SET NOFDD+1 CSVSZ: SET CSVSZ+(64/4) ALVSZ: SET ALVSZ+((S1DSM+7)/8) ENDM ; Make sure Systext agrees with assembled size space 4,10 ; Macro for generating the Disk Parameter Blocks. ; ; Disk type definition blocks for each particular mode. ; The format of these areas are as follow: ; 8 bit = disk type code ; 16 bit = Sectors per track ; 8 bit = Block shift ; 8 bit = BS mask ; 8 bit = Extent mask ; 16 bit = Disk size/1024 - 1. ; 16 bit = Directory size. ; 16 bit = Allocation for directory. ; 16 bit = check area size. ; 16 bit = offset to first track. DPBGEN MACRO TYPE,SPT,BSH,BSM,EXM,DSM,DIRSIZ,ALVMSK,OFFSET DB %1 DW %2ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ ċċċċċċċċ!ċċċċċċċċ"ċċċċċċċċ#ċċċċċċċċ$ċċċċċċċċ%ċċċċċċċċ&ċċċċċċċċ'ċċċċċċċċ(ċċċċċċċċ)ċċċċċċċċ*ċċċċċċċċ+ċċċċċċċċ,ċċċċċċċċ-ċċċċċċċċ.ċċċċċċċċ/ċċċċċċċċ0ċċċċċċċċ1ċċċċċċċċ2ċċċċċċċċ3ċċċċċċċċ4ċċċċċċċċ5ċċċċċċċċ6ċċċċċċċċ7ċċċċċċċċ8ċċċċċċċċ9ċċċċċċċċ:ċċċċċċċċ;ċċċċċċċċ<ċċċċċċċċ=ċċċċċċċċ>ċċċċċċċċ?ċċċċċċċċ@ċċċċċċċċAċċċċċċċċBċċċċċċċċCċċċċċċċċDċċċċċċċċEċċċċċċċċFċċċċċċċċGċċċċċċċċHċċċċċċċċIċċċċċċċċJċċċċċċċċKċċċċċċċċLċċċċċċċċ