;*****************************************************************************; ; ; ; SSS DDDD SSS Y Y SSS TTTTT EEEEE M M SSS ; ; S S D D S S Y Y S S T E MM MM S S ; ; S D D S Y Y S T E M MM M S ; ; SSS D D SSS Y SSS T EEE M M SSS ; ; S D D S Y S T E M M S ; ; S S D D S S Y S S T E M M S S ; ; SSS DDDD SSS Y SSS T EEEEE M M SSS ; ; ; ; ; ; SD SYSTEMS, INC. ; ; 10111 MILLER RD. ; ; DALLAS, TX 75238 ; ; ; ; (214) - 340 - 0303 ; ; ; ; COPYRIGHT (C) 1983 ; ; ; ;*****************************************************************************; title 'Character I/O handler for SBC-200 based system' ;=============================================================================; ; V/R Description Initials-Date ; ;-----------------------------------------------------------------------------; ; 0.0 DRI Original Release DRI... ; ; 1.0 Modified for use on SBC-300 efj,wbd.4/22/83 ; ; 1.1 Addition of io8 drivers wbd...5/24/83 ; ; 1.2 Addition of sbc200 drivers wbd...5/27/83 ; ; 1.3a Modify for io8 or io4 wbd...6/7/83 ; ; 1.3b SPECIAL RELEASE function key mod. CPM30 rel 1.5 wbd...6/9/83 ; ; 1.4a update console initialization (sysgen-able baudrates) dkb...6/24/83 ; ; 1.4b addition of mpc4 drivers for rel 1.6 wbd...6/29/83 ; ; 1.4c add stack save routine in ?ci and ?co dkb,wbd.7/8/83 ; ; 1.4d Make DIRETRN and EIRETRN public for new BOOT.ASM wbd...7/26/83 ; ; 1.4 RELEASE for distribution CPM30 rel 1.6 dkb...7/26/83 ; ;=============================================================================; ; Character I/O for the Modular CP/M 3 BIOS ; limitations: ; baud rates 7200,3600 and 1800 are approximations. ; 9600 is the maximum baud rate that is likely ; to work. ; baud rate 19200 is not supported. public ?cinit,?ci,?co,?cist,?cost public @ctbl,diretrn,eiretrn ; wbd..1.4d extrn @civec,?conin,?bank,@cbnk maclib Z80 ; define Z80 op codes maclib cond ; define system ( sbc$300 ) maclib ports ; define port addresses maclib modebaud ; define mode bits and baud equates data$off equ 0 ; offsets into device tables stat$off equ 1 rxmask$off equ 2 tx$mask$off equ 3 strob$off equ 4 inv$mask$off equ 5 init$off equ 6 null$strobe equ 0 inv$data equ 1111$1111b non$inv$data equ 0000$0000b tab equ 09h sdata equ 7Ch sstat equ 7Dh txmsk equ 1 rxmsk equ 2 psdata equ 7Eh psstat equ 7Fh lsmsk equ 81h psmsk equ 1 p$200$strobe equ 2 ctc0 equ 78h ctc1 equ ctc0+1 ctc2 equ ctc1+1 ctc3 equ ctc2+1 mpcadr equ 07h ; mpc4 board addresses... wbd-1 idata equ 5 ; wbd-1 odata equ 13 ; wbd-1 mpcmem equ 1000h ; wbd-1 ubyte equ mpcmem+3ACh ; wbd-1 mpcbr equ mpcmem+3ADh ; wbd-1 handshake equ mpcmem+3B6h ; wbd-1 brstrt equ mpcmem+3B7h ; wbd-1 io8$base equ 0A0h ; io8 board base address io8$clk equ 001h sys$clk equ 003h cl$4mhz equ false ; not using buss clock baud$loc equ 0FF80h+10 ; location of baud rate constants cseg ?cinit: if not loader call get$bauds ; set up default baud rates mov a,c ! cpi max$devices ; c holds device number 0-15 rnc ; invalid device call setix ldx l,init$off ldx h,init$off+1 pchl vdb$init: ; vdb board, no init req'd wbd-2 pio$init: ; 200 parallel, no init req'd wbd-2 unset$ix: lixd ix$reg$save ; restore original ix ret ; calls return through here if mpc4 and not io8 ; wbd-2 mpc$init: ; wbd-1 lxi h,mpc1$baud ! call adjust ; make bauds compatible wbd-2 lxi d,8 ! dad d ! push psw ; save the low nibble wbd-1 call adjust ; get next baud wbd-1 rlc ! rlc ! rlc ! rlc ; wbd-1 mov b,a ! pop psw ! ora b ; combine 1st 2 bauds wbd-1 push psw ! dad d ! call adjust ; wbd-1 push psw ! dad d ! call adjust ; wbd-1 rlc ! rlc ! rlc ! rlc ; wbd-1 mov b,a ! pop psw ! ora b ; combine 2nd 2 bauds wbd-1 mov h,a ! pop psw ! mov l,a ; wbd-1 mvi a,mpcadr ! call diretrn ; enable mpc memory wbd-1 call ?bank ! shld mpcbr ; wbd-1 mvi a,1 ! sta brstrt ; tell mpc of baud change " mvi a,-1 ! sta mpcmem+odata ; start the board wbd-1 lda @cbnk ! sta bank ! call ?bank ; restore bank & ret. wbd-1 call eiretrn ! jmp unset$ix ; return thru unset$ix wbd-1 adjust: ; wbd-1 mov a,m ! cpi 10 ! rnc ! dcr a ! ret ; wbd-1 bank: ds 1 ; wbd-1 mpcuser: ds 1 ; wbd-1 endif ; mpc4 and not io8 ; wbd-2 if io8 or io4 io8$init: mov b,c ! call io8$sel ; put device in b, select proper scc if cl$4mhz mvi a,sys$clk! lxi h,sys$speeds ; get proper clock values else mvi a,io8$clk! lxi h,io8$speeds ; get proper clock values endif ; cl$4mhz push h! sta scc$clk ; set clock, save tbl on stack ; scc$init: call baud$adr ; wbd-1 mov l,m ! mov h,0 ! dad h ; get baud rate, times 2 pop d ! dad d ; point to counter entry mov a,m ! sta speed$lsb ; get and save scc count inx h ! mov a,m ! sta speed$msb ldx a,stat$off sta scc$port ; get status port byte lxi h,scc$init$tbl jmp stream$out endif ; io8 or io4 ctc$init: mvi a,1 ! out ctc1 ; set up for load registers call baud$adr ; wbd-1 mov l,m ! mov h,0 ! push h ; get baud rate & save lxi d,baudtbl ! dad d mov a,m ! sta baudbyt ; set divisor pop h ! mov a,l ! cpi baud$600 ; check for >300 mvi a,4Fh ! jrc hispeed dcr a ; make it a 4Eh wbd-2 hispeed: sta hilow ! lxi h,initbaud ; table in hl ; removed jmp stream$out wbd-2 stream$out: mov a,m ! ora a ! jz unset$ix mov b,a ! inx h ! mov c,m ! inx h outir jr stream$out ; changed jmp to jr wbd-2 endif ; not loader if io8 or io4 io8$sel: mov a,b ! sui io8$dev1 ! rc ; io8 device? no, return if io8 cpi io8$num$dev ! rnc ; also check if above else cpi io4$num$dev ! rnc endif ; io8 srlr a ; else make select info: ; port #: 1 2 3 4 5 6 7 8 out io8$base+4 ; scc # : 0 0 1 1 2 2 3 3 ret endif ; io8 or io4 ; set$ix: ; clobbers a,hl,de -saves old ix, sets new ix lxi h,device$table ! ora a ; setup base addr jrz gotit$now ; zero? ok no index lxi d,tabl$size ; else table size in de getdev: dad d ! dcr a ; next device, decr device count jrnz getdev ; not it, do it agn gotit$now: ; now hl has device addr sixd ix$reg$save ; save user's ix reg push h ! popix ; put our hl in ix for index ret diretrn: ; wbd-1 push psw ! push h ! ldai ; get the iff into the p/v flg wbd-1 push psw ! pop h ! shld iffsvx ; save the flag wbd-1 pop h ! pop psw ! di ! ret ; disable interrupts & return wbd-1 eiretrn: ; wbd-1 push h ! lhld iffsvx ! bit 2,l ; check saved flag wbd-1 pop h ! jrz inotena ; wbd-1 ei ; else enable interrupts wbd-1 inotena: ; wbd-1 ret ; return to caller wbd-1 iffsvx: ds 2 ; wbd-1 baud$adr: ; GET POINTER TO BAUD RATE FOR DEVICE wbd-1 mov l,c ! mvi h,0 ; make 16 bits from device number dad h ! dad h ! dad h ; times 8 lxi d,@ctbl+7 ! dad d ! ret ; hl -> baud rate for device ?ci: ; character input sspd spsav ; save users stack pointer wbd-3 lxi sp,loc$stack ; wbd-3 lxi h,spret ; wbd-3 push h ; setup return wbd-3 mov a,b ! cpi max$devices jrnc null$input ; invalid device call setix ci1: call cist1 ! jz ci1 ; wait for character ready if mpc4 and not io8 ; wbd-2 mov a,b ! sui mpc$dev1 ! jc not$mpin ; mpc4 device? wbd-1 cpi mpc$num$dev ! jnc not$mpin ; wbd-1 sta mpcuser ! siyd iy$reg$save ; save user's iy reg wbd-1 ldx a,data$off ; get user offset wbd-1 lxi h,mpcmem ! add l ! mov l,a ; add to mpc memory base wbd-1 push h ! popiy ; stuff in iy reg wbd-1 lda @cbnk ! sta bank ! call diretrn ; dis int, adr mpc wbd-1 mvi a,mpcadr ! call ?bank ; enable mpc wbd-1 ldy a,idata ; get input data wbd-1 push psw ! ldx a,rxmask$off ; wbd-1 call hndshk ! pop psw ; finish handshake, restore char "-2 jmp not$func ; and continue input wbd-1 hndshk: ; wbd-1 push b ! mov b,a ! sta ubyte ; tell mpc rdy to send wbd-1 lda handshake ! ora b ! sta handshake ; set handshake byte wbd-1 lda bank ! call ?bank ; restore current bank wbd-1 ldx c,stat$off ; get mpc control port wbd-1 lda mpcuser ! outp a ; force status update wbd-1 tstmpc: inp a ; input the status wbd-1 ana b ! jrnz tstmpc ; loop if not updated wbd-1 pop b ! liyd iy$reg$save ; restore data and user iy reg wbd-1 jmp eiretrn ; re-enable interrupts wbd-1 iy$reg$save: dw 0 ; wbd-1 endif ; mpc4 and not io8 wbd-2 not$mpin: ldx c,data$off ; get port # and input data inp a ; if function$keys ***************************************************************** * Function Key Routine for Qume Terminal * * wbd 6/19/83 * ***************************************************************** ; cpi 1 ! jrnz not$char ; is it cntl-a? no, bypass following dcr b ! jrnz not$char ; is it cons-1? no, bypass following mvi b,0 ; set timout counter check$agn: call cist1 ! jrnz gotit djnz check$agn inr a ! jmp unset$ix ; if no char, return cntl-a in a-reg gotit: ldx c,data$off ; get the character inp a ani 7Fh ! cpi '@' ! jc unset$ix ; less than PF1? cpi 'D' ! jnc unset$ix ; grtr than PF4? lxi h,fun$tab+0 ! sui '@' ; get table & strip bias sta con$sav ; save remote cons # for later jrz nx$fn ; if zero, must be console 1 set$lop: inx h ! dcr a ! jrnz set$lop ; adjust hl to proper mask byte nx$fn: mov a,m ! sta fun$sav ; save mask in fun$sav gob1: call cist1 ! jrz gob1 ldx c,data$off ; get & gobble last character inp a lhld @civec ! lda fun$sav ; vector in hl, mask in a xra h ! mov h,a ! shld @civec ; update conin vector call unset$ix lda con$sav ! srlr a ; select proper io8 scc out io8$base+4 lda con$sav ! adi io8$dev1 call set$ix ldx c,data$off ; flush proper cons buff mvi a,7 outp a inp a inp a inp a inp a ldx c,stat$off inp a call unset$ix ; restore user ix jmp ?conin fun$sav: db 0 fun$tab: db 00001000b,00000100b,00000010b,00000001b con$sav: ds 1 not$char: endif ; function$keys not$func: ; wbd-1 cpi 99h ! jnz unset$ix ; sd vdb tab code mvi a,tab ! jmp unset$ix ; return thru ix reg restore null$input: mvi a,1Ah ! ret ; return a ctl-Z for no device ; ?cist: ; character input status mov a,b ! cpi max$devices ; check for valid device number jnc null$status lxi h,unset$ix ! push h ; set up return through unset$ix call set$ix ; set ix to device table cist1 if io8 or io4 call io8$sel endif ; io8 or io4 ldx c,stat$off ; read from status port inp a andx rxmask$off ; isolate RxRdy rz ; not ready, exit ori 0FFh ! ret ; else set FF in a and return null$status: xra a ! dcr a ! ret ; let invalid device #'s return ready spret: lspd spsav ; retriev users stack wbd-3 ret ; wbd-3 ; ?co: ; character output sspd spsav ; save users stack pointer wbd-3 lxi sp,loc$stack ; wbd-3 lxi h,spret ; wbd-3 push h ; setup return wbd-3 mov a,b ! cpi max$devices ; check for valid device # rnc ; return if invalid ........dkb1 ora a ! jrnz notvdb ; gobble nulls to vdb board..dkb1 mov a,c ! ora a ! rz ; so no alpha characters on scrn..dkb1 mov a,b ; ..dkb1 notvdb: call setix ! push b ; save char out co$spin: call cost1 ! jz co$spin ; wait for ready status if mpc4 and not io8 ; wbd-2 mov a,b ! sui mpc$dev1 ! jc not$mpout ; mpc4 device? wbd-1 cpi mpc$num$dev ! jnc not$mpout ; wbd-1 sta mpcuser ! siyd iy$reg$save ; save user's iy reg wbd-1 ldx a,data$off ; get user # wbd-1 lxi h,mpcmem ! add l ! mov l,a ; add to mpc mem base wbd-1 push h ! popiy ; stuff it in iy reg wbd-1 lda @cbnk ! sta bank ! call diretrn ; dis int, adr mpc wbd-1 mvi a,mpcadr ! call ?bank ; enable mpc wbd-1 pop b ! mov a,c ! sty a,odata ; output data to mpc wbd-1 ldx a,txmask$off ; set user vector wbd-1 call hndshk ! jmp unset$ix ; finish handshake wbd-1 endif ; mpc4 and not io8 wbd-2 not$mpout: ; wbd-1 pop b ! mov a,c ; retrieve char out xorx inv$mask$off ; invert data if necessary ldx c,data$off ; get port addr outp a ; send data ldx a,strob$off ; get strobe needed flag ora a ! jz unset$ix ; need strobe? return if not ldx c,stat$off ; else send strobe outp a inr a ! outp a jmp unset$ix ; all calls return through unset$ix ; ?cost: ; character output status mov a,b ! cpi max$devices ; valid device? jnc null$status ; return ready to prevent hang lxi h,unset$ix ! push h ; set up return thru unset$ix call set$ix ; set up ix register cost1 if io8 or io4 call io8$sel endif ; io8 or io4 ldx c,stat$off ; status port in c ldx h,tx$mask$off ; ready mask in h inp a ; get input status ana h ! xra h ; mask proper bits mvi a,0 ! jrnz co$not$rdy dcr a ! ret ; else set ready co$not$rdy ora a ! ret ; set not ready device$table: ; 0 console entry$strt db p$vdb$data,p$vdb$stat,p$vdb$rxmask db p$vdb$txmask,null$strobe,non$inv$data dw vdb$init entry$end tabl$size equ entry$end-entry$strt ; 1 console (sbc200) db sdata,sstat,rxmsk db txmsk,null$strobe,non$inv$data dw ctc$init if not loader ; 2 parallel line printer (sbc200) db psdata,psstat,psmsk db psmsk,p$200$strobe,non$inv$data dw pio$init ; 3 serial line printer (sbc200) db sdata,sstat,rxmsk db lsmsk,null$strobe,non$inv$data dw ctc$init if mpc4 and not io8 ; wbd-2 mpc$dev1 equ ($-device$table)/tabl$size ; 4 MPC4 port 1 wbd-1 db 00h,mpcadr+0F0h,01h ; wbd-1 db 10h,null$strobe,non$inv$data ; wbd-1 dw mpc$init ; wbd-1 ; 5 MPC4 port 2 wbd-1 db 10h,mpcadr+0F0h,02h ; wbd-1 db 20h,null$strobe,non$inv$data ; wbd-1 dw mpc$init ; wbd-1 ; 6 MPC4 port 3 wbd-1 db 20h,mpcadr+0F0h,04h ; wbd-1 db 40h,null$strobe,non$inv$data ; wbd-1 dw mpc$init ; wbd-1 ; 7 MPC4 port 4 wbd-1 db 30h,mpcadr+0F0h,08h ; wbd-1 db 80h,null$strobe,non$inv$data ; wbd-1 dw mpc$init ; wbd-1 mpc$num$dev equ ($-device$table)/tabl$size-mpc$dev1 endif ; mpc4 and not io8 wbd-2 if io8 or io4 io8$dev1 equ ($-device$table)/tabl$size ; 4 IO8 port 1 db io8$base+3,io8$base+1,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 5 IO8 port 2 db io8$base+2,io8$base,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 6 IO8 port 3 db io8$base+3,io8$base+1,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 7 IO8 port 4 db io8$base+2,io8$base,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init io4$num$dev equ ($-device$table)/tabl$size-io8$dev1 endif ; io8 or io4 if io8 ; 8 IO8 port 5 db io8$base+3,io8$base+1,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 9 IO8 port 6 db io8$base+2,io8$base,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 10 IO8 port 7 db io8$base+3,io8$base+1,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init ; 11 IO8 port 8 db io8$base+2,io8$base,p$sccb$rxmask db p$sccb$txmask,null$strobe,non$inv$data dw io8$init io8$num$dev equ ($-device$table)/tabl$size-io8$dev1 endif ; io8 endif ; not loader ; end$device$table: max$devices equ (end$device$table-device$table)/tabl$size ***************************************************************** * BAUD RATE INITIALIZATION ROUTINE * * (this occurs only at cold boot) * * dkb/wbd... 6/24/83 * ***************************************************************** ; get$bauds: lda baud$init$flag ! ora a ! rz ; check 1st time flag xra a ! sta baud$init$flag ; reset if true push b ! mvi b,(max$devices/2) ; # of devices assigned/2 lxi h,@ctbl+7 ! lxi d,baud$loc ; set constants binit$loop: push b ! lxi b,8 ; set loop count ldax d ! push psw ! ani 0F0h ; get upper nibble rrc ! rrc ! rrc ! rrc ; shift to lower nibble mov m,a ! pop psw ! ani 0Fh dad b ! mov m,a ! dad b ; bump pointer inx d ! pop b ! djnz binit$loop ; do 12 devices pop b ! ret ; restore bc & return ; ***************************************************************** * DEVICE TABLE REQUIRED FOR I/O REDIRECTION FOR CP/M+ * * Version 3.0 dkb...6/25/83 * ***************************************************************** @ctbl: ; "DEVICE" must be 6 chars- blank fill if nec. db 'VDB ' ; device 0, CRT port 0 db mb$in$out db baud$none db 'SERCRT' ; device 1, CRT serial port 7Ch db mb$in$out+mb$serial+mb$softbaud db baud$9600 if not loader db 'PARLPT' ; device 2, LPT parallel port db mb$output db baud$none db 'SERLPT' ; device 3, LPT serial port 7Eh db mb$output+mb$serial+mb$softbaud db baud$9600 if mpc4 and not io8 ; IO8 takes precedence wbd-2 db 'MPC1 ' ; device 4, MPC4 port 1 wbd-1 db mb$in$out+mb$serial+mb$softbaud ; wbd-1 mpc1$baud: ; wbd-2 db baud$9600 ; wbd-1 db 'MPC2 ' ; device 5, MPC4 port 2 wbd-1 db mb$in$out+mb$serial+mb$softbaud ; wbd-1 db baud$9600 ; wbd-1 db 'MPC3 ' ; device 6, MPC4 port 3 wbd-1 db mb$in$out+mb$serial+mb$softbaud ; wbd-1 db baud$9600 ; wbd-1 db 'MPC4 ' ; device 7, MPC4 port 4 wbd-1 db mb$in$out+mb$serial+mb$softbaud ; wbd-1 db baud$9600 ; wbd-1 endif ; mpc4 and not io8 wbd-2 if io8 or io4 db 'IO8-1 ' ; device 4, IO8 port 1 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-2 ' ; device 5, IO8 port 2 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-3 ' ; device 6, IO8 port 3 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-4 ' ; device 7, IO8 port 4 db mb$in$out+mb$serial+mb$softbaud db baud$9600 endif ; io8 or io4 if io8 db 'IO8-5 ' ; device 8, IO8 port 5 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-6 ' ; device 9, IO8 port 6 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-7 ' ; device 10, IO8 port 7 db mb$in$out+mb$serial+mb$softbaud db baud$9600 db 'IO8-8 ' ; device 11, IO8 port 8 db mb$in$out+mb$serial+mb$softbaud db baud$9600 endif ; io8 endif ; not loader dw 0,0,0,0 ; table terminator + 7 DUMMYS (just in case) if io8 or io4 sys$speeds: ; assumes 4.0 Mhz dw 0,2498,1665,1134,927,831,415,206 dw 102,67,50,33,24,17,11,5 io8$speeds: ; assumes 2.4576 Mhz dw 0,1534,1022,696,569,510,254,126 dw 62,41,30,19,14,9,6,2 endif ; io8 or io4 baudtbl: db 0,208,208,208,208,208,104,208 db 104,104,52,52,26,26,13,13 initbaud: db 4 ; 4 bytes to output db sstat ; usart status port db 134,64 ; lead-in bytes hilow: db 78,55 ; divisors db 2 ; 2 bytes to count db ctc0 ; ctc-0 port db 69 baudbyt: db 13 ; 2 bytes and db 0 ; terminator vdb$init$tbl: db 0 if io8 or io4 scc$init$tbl: ; SCC init table db scc$data$end-scc$data$strt scc$port ds 1 ; port address of scc scc$data$strt db 3, 0C1h db 4, 044h db 5, 0EAh db 11, 56h db 12 speed$lsb ds 1 ; count (lsb) db 0Dh ; scc reg 13 speed$msb ds 1 ; count (msb) db 0eh scc$clk ds 1 ; which clock db 0fh, 0h ; reset all ie bits for status bits scc$data$end db 0 ; terminator endif ; io8 or io4 baud$init$flag db -1 ; 1st time cold boot flag ix$reg$save: dw 0 dw 0,0,0,0,0,0,0,0 ; 8 level stack loc$stack equ $ ; LOCAL stack for spsav: dw 0 ; users stack pointer save end