ve equ's. ; 8-28-85: modified morhdc.a86 morrow hard disk controller driver. ; 9-6-85: added vcsbuf equ for virtual console screen buffers. ; 10-15-85: fixed error print-out. ; 10-22-85: made local stack for disk routines. ; 10-31-85: put in support for Otari C-526 hard disk. ; 11-20-85: changed to allow up to 12 logical hard disk drives. ; 12-13-85: made two separate step rates for 5-inch and 8-inch. ; 01-26-86: support for ADES controller with 33 meg PRIAM hard disk. true equ -1 ; value of0 ; disk time-out time in seconds. nflop8 equ 2 ; number of 8-inch floppy drives. nflop5 equ 2 ; number of 5-inch floppy drives. nhard equ 8 ; number of logical hard disk drives. morrow equ false ; true for Morrow hard disk controller. teletek equ true ; true for Teletek hard disk controller. ades equ true ; true for ADES hard disk controller. rms12 equ false ; true for RMS-12 hard disk. cmi19 equ false ; true for CMI-19 hard disk. rod20 equ false ; true for Rodime-20 hard disk. min20 eq; Drive L. if nhard le 7! drivel equ 0ffh! endif if nhard gt 8! drivem equ 16! endif ; Drive M. if nhard le 8! drivem equ 0ffh! endif if nhard gt 9! driven equ 17! endif ; Drive N. if nhard le 9! driven equ 0ffh! endif if nhard gt 10! driveo equ 18! endif ; Drive O. if nhard le 10! driveo equ 0ffh! endif if nhard gt 11! drivep equ 19! endif ; Drive P. if nhard le 11! drivep equ 0ffh! endif ; define disk control variables for system. hlab equ 8 ; fdc head load: 8=before, 0=after, ready. lpttbe equ 04h ; transmit buffer empty mask. lptrda equ 01h ; receive data available mask. lbaud equ 0bh ; Baud Rate: b=9600, c=19200. ; Serial Port Board Addresses and Mask Bytes. ; Currently set up for 2 Tarbell 4S/2P Boards. spbase equ 0 ; board starting address. spimsk equ 2 ; input status mask. if not dtrcon ; if no dtr handshaking on console. spomsk equ 1 ; output status mask. endif if dtrcon ; if dtr handshaking on console. spomsk equ 81h ; output status mask. e true for assembler. false equ not true ; value of false for assembler. ; Console options. conint equ false ; true for console interrupts. cibmax equ 20 ; console input buffer maximum characters. nvirt0 equ 1 ; number of virtual consoles on console 0. nvirt1 equ 0 ; number of virtual consoles on console 1. nvirt2 equ 0 ; number of virtual consoles on console 2. nvirt3 equ 0 ; number of virtual consoles on console 3. nvirt4 equ 0 ; number of virtual consoles on console 4. nvirt5 equ 0 ; u false ; true for Miniscribe 4020. ota26 equ false ; true for Otari C-526 hard disk. ats33 equ true ; true for Atasi 33 hard disk. q540 equ false ; true for Quantum Q540. ; define which drives are 8-inch and which are 5-inch. ; 5-inch floppy drives are numbered 0-3, 8-inch from 4-7. ; Hard disk drives are numbered from 8-19. ; Undefined drive letters are numbered 0ffh. if not mini ; for booting on 8-inch drives. drivea equ 4 ; drive a is 8-inch drive 0. driveb equ 5 ; drive b is 8-seek. pctrk equ 43 ; pre-compensation above this track. ibmtpd equ 40 ; ibm tracks per 5-inch floppy. rtcnt equ 10 ; fdc read/write, fail retry count. srtcnt equ 2 ; fdc seek retry count. pcsbas equ 0f000h ; 80186 peripheral ports base address. ; Virtual Control Keys. ; These are the codes for the keyboard keys that cause ; switching to another virtual console. vkey0 equ 1ch ; ctl \ - go to virtual console 0. vkey1 equ 1dh ; ctl ] - go to virtual console 1. vkey2 equ 1eh ; ctl ^ - gndif ; Auxilliary Port Addresses. if not vio ; aux is on Tarbell 4S/2P. auxist equ spbase+7 ; aux in status port. auxin equ spbase+6 ; aux in data port. auxost equ spbase+7 ; aux out status port. auxout equ spbase+6 ; aux out data port. auximk equ spimsk ; aux in mask. auxomk equ spomsk ; aux out mask. endif if vio ; aux is first port on Duplex 816. auxist equ pcsbas+182h auxin equ auxist+4 auxost equ auxist auxout equ auxin auximk equ 1 auxomk equ 4 endif ; Floppy disk cnumber of virtual consoles on console 5. nvirt6 equ 0 ; number of virtual consoles on console 6. nvirt7 equ 0 ; number of virtual consoles on console 7. ncrts equ 1 ; number of physical crt consoles. nvirt equ nvirt0+nvirt1+nvirt2+nvirt3+nvirt4+nvirt5+nvirt6+nvirt7 vcsbuf equ false ; true if virtual console screen buffers. nptrs equ 1 ; number of printers. stprat8 equ 0 ; 8" step rate: 0=3ms, 1=6ms, 2=10ms, 3=20ms. stprat5 equ 1 ; 5" step rate: 0=6ms, 1=12ms, 2=20ms, 3=40ms. nsio equ 0 ; inch drive 1. drivec equ 0 ; drive c is 5-inch drive 0. drived equ 1 ; drive d is 5-inch drive 1. endif if mini ; for booting on 5-inch drives. drivea equ 0 ; drive a is 5-inch drive 0. driveb equ 1 ; drive b is 5-inch drive 1. drivec equ 4 ; drive c is 8-inch drive 0. drived equ 5 ; drive d is 8-inch drive 1. endif ; Hard Disk Drives. if nhard gt 0! drivee equ 8! endif ; Drive E. if nhard le 0! drivee equ 0ffh! endif if nhard gt 1! drivef equ 9! endif ; Drive F. if nhard o to virtual console 2. vkey3 equ 1fh ; ctl _ - go to virtual console 3. ; console port addresses and mask bytes. if not vio ; console is Duplex 816 first port. cbase equ pcsbas+180h ; port base address. condat equ cbase+06h ; data port. consts equ cbase+02h ; status port. contbe equ 04h ; transmit buffer empty mask. conrda equ 01h ; receive data available mask. endif if vio ; console is Fulcrum VIO video board. cbase equ 0 condat equ cbase+1 consts equ cbase contbe equ 1 conr dmabas+04h ; destination pointer lower. dmaspu0 equ dmabas+02h ; source pointer upper. dmaspl0 equ dmabas ; source pointer lower. fdmard equ 0a266h ; floppy-to-memory command. fdmawt equ 016a6h ; memory-to-floppy command. ; 80186 Timer Ports and Constants. timbas equ pcsbas+0f50h ; timer base address. timct0 equ timbas ; timer 0 count register. timca0 equ timbas+02h ; timer 0 max count register a. timcb0 equ timbas+04h ; timer 0 max count register b. timmc0 equ timbas+06h ; timer 0 mode/rd ptr .38H mpmseg equ ds: word ptr .40H endseg equ ds: word ptr .44H rlr equ ds: word ptr .68H thrdrt equ ds: word ptr .72H qlr equ ds: word ptr .74H version equ ds: word ptr .78H vernum equ ds: word ptr .7AH mpmvernum equ ds: word ptr .7CH tod equ ds: byte ptr .7EH open_vector equ ds: word ptr .88H ;********************************************************************* ;* end of system data area definition ;********************************************************************* dph12! endif ; drive I. if nhard le 4! dw 0! endif if nhard gt 5! dw offset dph13! endif ; drive J. if nhard le 5! dw 0! endif if nhard gt 6! dw offset dph14! endif ; drive K. if nhard le 6! dw 0! endif if nhard gt 7! dw offset dph15! endif ; drive L. if nhard le 7! dw 0! endif if nhard gt 8! dw offset dph16! endif ; drive M. if nhard le 8! dw 0! endif if nhard gt 9! dw offset dph17! endif ; drive N. if nhard le 9! dw 0! endif if nhard gt 10! dw offset dph18! endif ; drivdw io_auxout ; 6 - aux out. dw io_switch ; 7 - switch screen. dw io_statline ; 8 - display status line. dw io_seldsk ; 9 - select disk. dw io_read ;10 - read sector. dw io_write ;11 - write sector. dw io_flushbuf ;12 - flush buffer. dw io_poll ;13 - poll device. dw io_ret ;14 - dummy return. dw io_ret ;15 - dummy return. dw io_ret ;16 - dummy return. dw ww_key ;17 - wait for a key. dw io_ret ;18 - dummy return. dw io_ret ;19 - dummy return. dw io_ret ;20 - dummy return. control word. timcnt equ 33340 ; max count for 16 milliseconds. timbeg equ 0e001h ; code to begin timer. ; 80186 Interrupt Controller Ports. intbas equ pcsbas+0f20h ; interrupt port base. inteoi equ intbas+02h ; eoi register. intmsk equ intbas+08h ; mask register. inttcr equ intbas+12h ; timer interrupt control register. intcr1 equ intbas+1ah ; int1 (8259) interrupt control register. ; 8259 Interrupt Controller Ports. inta0 equ pcsbas ; input a0 = 0. inta1 equ pcsbas+2 ; input a0 = 1 ; ; XIOS Header Definition ; cseg org 0c00h jmp init ; system initialization. jmp entry ; xios entry point. sysdat dw 0 ; Sysdat Segment. supervisor rw 2 dseg org 0c0ch tick db clock ; tick enable flag. ticks_sec db 60 ; # of ticks per second. door db 0 ; global drive door open. rsvd db 0 ; reserved for operating system. npcns db ncrts ; number of physical consoles. nvcns db nvirt ; number of virtual consoles. nccb db nvirt ; total number of ccbs. ne O. if nhard le 10! dw 0! endif if nhard gt 11! dw offset dph19! endif ; drive P. if nhard le 11! dw 0! endif alloc dw 0 ; Console Characteristic Table. ; This section may be written into by an INSTALL program, ; as it is always at the same offset relative to DS. ; For sequences, first byte is number of characters ; in sequence. If most significant bit of first byte ; is set, that means column comes before row. ; Any other byte with bit 7 set means add cursor ; position or o dw io_ret ;21 - dummy return. dw io_ret ;22 - dummy return. dw io_ret ;23 - dummy return. dw io_ret ;24 - dummy return. dw io_ret ;25 - dummy return. dw io_ret ;26 - dummy return. dw io_ret ;27 - dummy return. dw io_ret ;28 - dummy return. dw io_ret ;29 - dummy return. dw io_screen ;30 - get/set screen mode. dw io_video ;31 - video i/o. dw io_keybd ;32 - keyboard info. dw io_shft ;33 - shift status. dw io_eqck ;34 - equipment check. dw io_int13_read ;35 - read DOS di. ; additional system equates. fresh equ 1 ; bdos fresh disk access bit mask. ticflg equ 1 ; 1/n system interrupt tick flag. secflg equ 2 ; 1 second interrupt flag. flgset equ 133 ; xdos code to set flag. ; Standard ASCII CRT codes. cr equ 0dh ; carriage return. lf equ 0ah ; line feed. bs equ 08h ; back space. bel equ 07h ; bell. esc equ 1bh ; escape. ; psh equ byte ptr 15 ; physical sector shift position. ; define address refs for system. bdos_int equ 224 ; reservelst db nptrs ; number of list devices. ccb dw offset ccb0 ; offset of first ccb. lcb dw offset lcb0 ; offset of first lcb. ; disk parameter header offset table. ; for dphx, x = 0-3 for 5-inch, ; x = 4-7 for 8-inch, ; x = 8-15 for hard disk. dph_tbl equ offset $ if not mini ; for booting on 8-inch drive. dw offset dph4 ; drive A. dw offset dph5 ; drive B. dw offset dph0 ; drive C. dw offset dph1 ; drive D. endif if mini ; for booting on 5-inch dther variable for code to send. ; Table shown here is for Televideo 910+ CRT. ; maxcol, maxrow determine maximum screen size. maxcol equ 80 ; maximum number of columns. maxrow equ 24 ; maximum number of rows. ; actual table starts here. nocols db maxcol ; number of columns. norows db maxrow ; number of rows. nochrs dw maxcol * maxrow ; number of characters. inslin db 02h,esc,'E',00h ; insert line at cursor. dellin db 02h,esc,'R',00h ; delete line at cursor. setdim db 02h,esc,')'sk. dw io_int13_write ;36 - write DOS disk. initof equ offset $ cseg org initof ; ********************************************************* ; ******************* cold-start entry ******************** ; ********************************************************* init: ; initialize system. cli ; disable interrupts during ini. mov sysdat,ds ; save sysdat for sysdat access. mov ax,supmod ; place copy of SUPMOD in data seg. mov supervisor,ax ; into code segment (supervisord bdos interrupt. ovec1 equ 1 * 4 ; SID's interrupt vector. svec1 equ ovec1 + 2 ovec3 equ 3 * 4 svec3 equ ovec3 + 2 ovece1 equ 0e1h * 4 svece1 equ ovece1 + 2 ovece6 equ 0e6h * 4 ; int e6 address. svece6 equ ovece6 + 2 p_uda equ word ptr 010h ; pd uda segment adr. ;********************************************************************* ;* sysdat for a RASM86 system. ;********************************************************************* supmod equ ds: word ptr .0H dispatcher equ cs: worive. dw offset dph0 ; drive a. dw offset dph1 ; drive b. dw offset dph4 ; drive c. dw offset dph5 ; drive d. endif ; Hard Disk Drives. if nhard gt 0! dw offset dph8! endif ; Drive E. if nhard le 0! dw 0! endif if nhard gt 1! dw offset dph9! endif ; drive F. if nhard le 1! dw 0! endif if nhard gt 2! dw offset dph10! endif ; drive G. if nhard le 2! dw 0! endif if nhard gt 3! dw offset dph11! endif ; drive H. if nhard le 3! dw 0! endif if nhard gt 4! dw offset ,00h ; set intensity to dim. setbrt db 02h,esc,'(',00h ; set intensity to bright. clreos db 02h,esc,'Y',00h ; clear to end of screen. setcur db 04h,esc,'=',0A0h ; load (set) cursor position. db 0A0h,00h,00h,00h db 0ffh ; marks end of modifiable space. ; ; XIOS Function Table. ; functab dw io_const ; 0 - console status. dw io_conin ; 1 - console input. dw io_conout ; 2 - console output. dw io_listst ; 3 - list status. dw io_list ; 4 - list output. dw io_auxin ; 5 - aux in. debug mov int0_offset,(offset int_trap) ; set int 0 vector. mov int0_segment,cs mov di,4 ; start at int 1. mov si,0 ; come from int 0. mov cx,510 ; do rest of 255 int's. rep movsw ; write em out. mov word ptr .0008h,offset nmiint ; set nmi. mov word ptr .000ah,cs endif ; end debug conditional. ; set e6 interrupt vector. mov ax,offset xios_v1_entry mov es:word ptr .ovece6,ax mov ax,cs mov es:word ptr .svece6,ax if clock ; if tick interrupt. ; set timer port on Duplex 816. mov dx,lbase ; port for data format. mov al,13h ; char, no parity, out dx,al mov al,07h ; 8 data bits, 1 stop bit. out dx,al mov dx,lptsts ; get clock select port. mov al,(lbaud shl 4)+lbaud ; get baud rate code. out dx,al ; set baud rate. mov dx,lptcom ; get command port. mov al,45h ; reset errors, enable. out dx,al if nsio gt 0 ; if 1 or more 4S/2P ports. ; Initialize 4S/2P Serial Ports. mov dx,spbase+1 ; dx = starting port number. mo User Data Area ; ah, si, di, bp are undefined. ; Exit: ax = return or XIOS error code ; bx = ax ; ds = SYSDAT segment ; es = User Data Area ; si, di, bp, dx, cx are undefined. entry: push ds ; save segment registers. push es cld ; set auto-increment. push bx ; save PC-DOS function code. mov bx,cs ; get code segment. mov ds,bx ; make data segment the same. mov bl,al ; bx = function number. mov bh,0 shl bx,1 ; bx = 2 * bx. mov si,bx ; get index to tabal = sysdat ticks/second. mov tickct,al ; reset count to N ticks. ; set second flag. mov dx,secflg ; dx = code for second flag. mov cx,flgset ; cx = code for flag set. call supif ; set second flag. ; decrement disk time-out counter once per second till it's zero. cmp diskto,0 ; is disk time-out counter 0? je ticksf ; hop if so. dec diskto ; else decrement counter. ; set tick flag. ticksf: mov dx,ticflg ; dx = code for tick flag. mov cx,flgset ; cx = code for flag setinterrupt vector. mov es:word ptr .020h,offset tick_int ; set offset. mov es:word ptr .022h,cs ; set segment. ; initialize hardware timer. mov dx,timca0 ; timer 0 max count a. mov ax,timcnt ; ax = interval count. out dx,ax ; set max count register. mov dx,timmc0 ; timer 0 mode/control word port. mov ax,timbeg ; ax = code to begin timer 0. out dx,ax ; start timer 0 running. ; Allow timer interrupts to occur. mov dx,inttcr ; dx = timer int. control reg. mov ax,0003h ; av cx,nsio ; cx = number of ports to init. initsl: mov al,0aah ; force idle. out dx,al call fdelay ; wait a little. mov al,040h ; reset. out dx,al call fdelay ; wait a little. mov al,0ceh ; 8 stop bits. out dx,al call fdelay ; wait a little. mov al,037h ; enable. out dx,al call fdelay ; wait a little. inc dx ! inc dx ; dx = next port address. loop initsl ; loop until done. endif ; Initialize screen buffers. mov ax,cs ; es = cs. mov es,ax cld le. pop bx ; restore PC-DOS function code. call functab[si] ; call function through table. mov bx,ax ; for return. pop es ; restore segment registers. pop ds retf ; ; SUPIF - Routine to allow XIOS to make calls to CCP/M XDOS. ; Entry: cx = function # ; dx = parameter ; ds = parameter segment if address ; es = user data area ; Exit: bx = ax = return ; cx = error code for RTM functions ; es = return segment if address ; supif: push es ; save extra segment. m. call supif ; set tick flag. ; reset timer interrupt. mov dx,inteoi ; dx = end-of-interrupt port. mov ax,8000h ; ax = non-specific eoi code. out dx,ax ; reset timer interrupt. ; restore registers. pop es ! pop di pop si ! pop bp pop dx ! pop cx pop bx ! pop ax mov ss,tickss mov sp,ticksp pop ds jmpf cs:dword ptr .0038h ; to dispatcher. endif ; end of clock conditional. ; IO_CISR - Console Input Interrupt Service Routine. if conint ; if using console intex = clear mask bit, priority=3. out dx,ax ; send to 80186. endif ; end tick conditional. if conint ; if console interrupts. ; initialize console interrupt vectors. mov es:word ptr .080h,offset io_cisr ; vector 20h. mov es:word ptr .082h,cs ; initialize 8259 interrupt controller. mov dx,inta0 ; dx = control port a0 = 0. mov al,19h ; al = ICW1. out dx,al mov dx,inta1 ; dx = control port a0 = 1. mov al,20h ; al = vector #20. out dx,al mov al,0 ; al = slave #0.; direction = forward. if vcsbuf ; if virtual console screen buffers. mov cx,nvirt*maxcol*maxrow ; cx = number of words. mov di,offset scbuf0 ; di = starting address. mov ax,0f20h ; ax = bright space. rep stosw ; write ax to cx words. endif ; Initialize cursor positions. mov cx,nvirt ; cx = number of virtual consoles. mov di,offset curpos ; di = start of cursor position table. mov al,0 ; al = column 0. mov ah,23 ; ah = row 23. rep stosw ; write ax to cx words at di. ov bx,rlr mov es,p_uda[bx] mov ch,0 callf cs:dword ptr supervisor pop es ; restore extra segment. ret nmiint: retf ; fill in later. ; Timer Interrupt Handler. tickss dw 0 ; user stack segment. ticksp dw 0 ; user stack offset. tickax dw 0 ; user ax register. tickct db 60 ; tick count tickint: if clock ; if clock enabled. push ds ; save current data segment. mov ds,sysdat ; use xios data segment instead. mov tickss,ss ; save user stack segment. mov ticksrrupts. coniss dw 0 ; user stack segment. conisp dw 0 ; user stack offset. coniax dw 0 ; user ax register. io_cisr: ; save registers. push ds mov ds,sysdat ; use xios data segment. mov coniss,ss mov conisp,sp mov coniax,ax mov ax,cs mov ss,ax mov sp,offset cistkb ; use stack in xios. push coniax! push bx! push cx! push dx push bp! push si! push di! push es mov bx,ds! mov es,bx ; es = ds. mov ds,ax ; ds = cs. ; poll console keyboards to determine which caused int out dx,al mov al,1 ; al = 8086/8088 mode. out dx,al mov al,0feh ; al = enable v0. out dx,al ; initialize 80186 interrupt controller. mov dx,intcr1 ; dx = int1 control register port. mov ax,0032h ; set cascade mode, priority=2. out dx,al ; send to 80186 interrupt controller. ; set 2681 console input interrupt mask bit. mov dx,conimr ; dx = 2681 DUART int mask reg port. mov al,2 ; set bit 1 on. out dx,al endif ; end console interupts. ; initialize printer ; Print sign-on message. mov bx,(offset signon) call prtmsg ; print signon. pushf ; ax = flags. pop ax cli ; clear interrupt flag. mov ss,int_ssreg ; restore stack for return. mov sp,int_spreg push ax ; flags = ax. popf mov bx,rlr ; restore ES. mov es,p_uda[bx] retf ; back to CCP/M's init. ; XIOS Entry Routine. ; Entry: al = function number ; bx = PC-MODE parameter ; cx = first parameter ; dx = second parameter ; ds = SYSDAT segment ; es =p,sp ; save user stack offset. mov tickax,ax ; save user ax register. mov ax,cs ; ax = code segment. mov ss,ax ; ss = code segment. mov sp,offset ticktos ; use local stack. push tickax! push bx ; save machine context on stack. push cx ! push dx push bp ! push si push di ! push es mov bx,ds ; es = sysdat page. mov es,bx mov ds,ax ; ds = cs. ; check to set second flag. dec tickct ; count down tick flag. jnz ticksf ; not zero, continue. mov al,es:ticks_sec ; er. io_cicr: sub bx,offset cnstbl+2 ; bx = 4 * keyboard number. shr bx,1 ; bx = 2 * keyboard number. push bx ; save 2 * keyboard number. mov dx,cndtbl[bx] ; dx = data port. in al,dx ; al = keyboard data. and al,7fh ; strip most significant bit. shl bx,1 ; bx = 4 * keyboard number. shl bx,1 ; bx = 8 * keyboard number. add bx,offset cibtab ; bx = console input table entry adr. mov di,4[bx] ; di = position to put character. mov [di],al ; put character into buffer. cmp dd out top 4 bits. and cl,0fh ; mask for top 4 bits only. and ax,0fff0h add dx,ax ; add shifted segment to offset. mov al,0 ; clear. adc al,cl ; add top 4 & carry. mov msb20,al ; save bits a16-a19. mov lsb20,dx ; save bits a00-a15. ret ; All undefined interrupt call come here. ; It usually means a process has crashed. int_trap: cli ; disable interrupts during service. mov ax,cs mov ds,ax ; get our data segment. mov bx,(offset trpmsg) call prtmsg ; print tdw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,1,nvirt0+1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt1 gt 2 dw offset ccb12,0 ; virtual console link, reserved. ccb12 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,1,nvirt0+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt1 gt 3 dw offset if ncrts gt 3 ; physical console 3. nv02 equ nv01+nvirt2 ; number of virtuals on consoles 0-2. ccb30 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,3,nv02 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt3 gt 1 dw offset ccb31,0 ; virtual console link, reserved. ccb31 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,3,nv02+1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reserved, stati,2[bx] ; was that last buffer position? jne io_ciin ; hop if not. mov ax,[bx] ; ax = buffer addrecй if so. mov 4[bx],ax ; wrap around to buffer beginning. jmps io_cini ; skip over increment. io_ciin: inc word ptr 4[bx] ; bump to next buffer position. io_cini: ; reset interrupt in 8259. io_ciex: mov al,60h ; issue non-specific eoi. mov dx,inta0 ; dx = 8259 a0=0 port number. out dx,al ; do it. ; reset interrupt in 80186. mov dx,inteoi ; dx = end-of-interrupt port. rap message. mov cx,0 int 224 ; go to the system. ; Console Control Blocks (CCB's). ; physical console 0. ccb0 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,0,0 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt0 gt 1 dw offset ccb01,0 ; virtual console link, reserved. ccb01 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,0,1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reccb13,0 ; virtual console link, reserved. ccb13 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,1,nvirt0+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif if ncrts gt 2 ; physical console 2. nv01 equ nvirt0+nvirt1 ; number of virtuals on physical 0 and 1. ccb20 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,2,nv01 ; res, mimic, msource, phe flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt3 gt 2 dw offset ccb32,0 ; virtual console link, reserved. ccb32 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,3,nv02+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt3 gt 3 dw offset ccb33,0 ; virtual console link, reserved. ccb33 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,3,nv02+3 ; res, mimic, msource, phys, v mov ax,8000h ; ax = non-specific eoi code. out dx,ax ; reset interrupt. pop dx ; dx = 2 * keyboard number. ; see if there's a process waiting for a keyboard character. shr dx,1 ; dx = keybord number. mov bx,dx ; bx = keyboard number. cmp byte ptr ciftab[bx],0 ; is a process waiting? je io_cirt ; return if not. ; set flag in ccpm. mov byte ptr ciftab[bx],0 ; clear process waiting flag. add dl,4 ; first 4 are reserved. mov cx,flgset ; cx = code for flag set. call served, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt0 gt 2 dw offset ccb02,0 ; virtual console link, reserved. ccb02 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,0,2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt0 gt 3 dw offset ccb03,0 ; virtual console link, reserved. ccb03 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,0,3 ; res, mimic, msource, phys,ysical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt2 gt 1 dw offset ccb21,0 ; virtual console link, reserved. ccb21 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,2,nv01+1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt2 gt 2 dw offset ccb22,0 ; virtual console link, reserved. ccb22 dw 0,0,0 ; owner, reserved. irt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif if ncrts gt 4 ; physical console 4. nv03 equ nv02+nvirt3 ; number of virtuals on consoles 0-3. ccb40 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,4,nv03 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt4 gtsupif ; set console flag. ; restore registers. io_cirt: pop es! pop di! pop si! pop bp pop dx! pop cx! pop bx! pop ax mov ss,coniss mov sp,conisp pop ds iret ; return from interrupt. endif ; end of conint conditional. ; Compute physical dma address from segment and offset. ; Inputs: ax = segment, dx = offset. ; Outputs: msb20 = most signifcant bits, lsb20 = least sig. comdma: mov cl,4 ; shift count. rol ax,cl ; shift segment left 4. mov cl,al ; save shifte virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. if ncrts gt 1 ; physical console 1. ccb10 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,1,nvirt0 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt1 gt 1 dw offset ccb11,0 ; virtual console link, reserved. ccb11 db 0,0,0ffh,0ffh,2,nv01+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt2 gt 3 dw offset ccb23,0 ; virtual console link, reserved. ccb23 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,2,nv01+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif rved. dw 0,0,0,0,0 ; reserved. if nvirt4 gt 3 dw offset ccb43,0 ; virtual console link, reserved. ccb43 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,4,nv03+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif if ncrts gt 5 ; physical console 5. nv04 equ nv03+nvirt4 ; number of virtuals on consoles 0-4. ccb50 dw 0,0,0 ; owner, resermic, source, physical, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt6 gt 2 dw offset ccb62,0 ; virtual console link, reserved. ccb62 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,6,nv05+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt6 gt 3 dw offset ccb63,0 ; virtual console link, reserved. ccb63 dw 0,0,0 ; owner. ified ; serial I/O device. ; Entry: al=0, dl=serial i/o device number. ; Exit: al=0 if no character ready. ; al=0ffh if character ready. ; bl=al. io_const: mov dh,0 ; clear upper dx. shl dx,1 ; device number by 4. shl dx,1 mov bx,dx ; put into index register. add bx,offset cnstbl ; address of port number. mov dx,[bx] ; get port number. in al,dx ; read status port. add bx,2 ; point at mask. mov ah,[bx] ; get input ready mask. and al,ah ; test for readydl right 5 bits = number within category. ; Exit: dl right 5 bits = number within category. ; z flag set if time-out error. ; Preserve: ax, cx, 5 least significant bits of dx. wait: if conint ; if console interrupts. test dl,11100000b ; is it a console input? jnz waitpol ; handle with poll if not. ; Must be console input. See if there's a character ready. push ax ; save registers. push cx push dx mov bx,dx ; bx = keyboard number. mov cl,3 ; cl = number of shifts. shl ved. db 0,0,0ffh,0ffh,5,nv04 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt5 gt 1 dw offset ccb51,0 ; virtual console link, reserved. ccb51 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,5,nv04+1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt5 gt 2 dw offset ccb52,0 ; virtual console db 0,0,0ffh,0ffh,6,nv05+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif if ncrts gt 7 ; physical console 7. nv06 equ nv05+nvirt6 ; number of virtuals on consoles 0-6. ccb70 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,7,nv06 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0. jz cs_ext ; result zero, exit test (00=not ready). or al,0ffh ; not zero, set al (ff=ready). mov bl,al ; for return. ret ; return from console status (flag in al). ; Console output status check. ; Return the output status of the specified ; serial I/O device. ; Entry: al=0, dl=serial i/o device number. ; Exit: al=0 if no character ready. ; al=0ffh if character ready. ; bl=al. io_pollco: mov dh,0 ; clear upper dx. shl dx,1 ; device number by 4. shl dxbx,cl ; bx = 8 * keyboard number. add bx,offset cibtab ; bx = adr of keyboard entry. mov cx,4[bx] ; cx = address to put character. cmp 6[bx],cx ; is it same as address to get char? jne waitxt ; no need to wait if not. ; Wait for interrupt if no characters are ready. mov bx,dx ; bx = keyboard number. mov ciftab[bx],1 ; set process waiting flag. add dl,4 ; flags 0-3 are reserved. mov cl,84h ; code for dev_waitflag. call supif ; set wait flag, wait for interrupt. jmps waitxt ; relink, reserved. ccb52 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,5,nv04+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt5 gt 3 dw offset ccb53,0 ; virtual console link, reserved. ccb53 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,5,nv04+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif end,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt7 gt 1 dw offset ccb71,0 ; virtual console link, reserved. ccb71 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,7,nv06+1 ; res, mimic, source, physical, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt7 gt 2 dw offset ccb72,0 ; virtual console link, reserved. ccb72 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,7,nv06+2 ; res, mimic, msource, phys, virt. dw 0,2,10 ; ,1 mov bx,dx ; put into index register. add bx,offset cnstbl ; address of port number. mov dx,[bx] ; get port number. in al,dx ; read status port. add bx,3 ; point at mask. mov ah,[bx] ; get output ready mask. and al,ah ; look only at ready bit(s). xor al,ah ; compare the bit(s). jnz io_cnrd ; if not same, exit not ready. if dtrcon ; if dtr handshaking for console. cmp dh,0 ; is it a Duplex port? jz io_crdy ; ready if not. mov dx,coninp ; else dx = input port address. store registers and return. waitpol: endif if not debugp ; if not debugging. push ax ; save operation code. push cx ; save possible character. push dx ; save device number. mov al,13 ; make it look like outside call. call io_poll ; see if device is ready. cmp al,0ffh ; is device ready? je waitxt ; exit if so. mov cl,83h ; get dev_poll code for xdos. pop dx ; recover device # for dev_poll. push dx ; save it back for i/o routines. call supif ; do dev_poll. jmps waitxtif dw 0,0 ; virtual console link, reserved. endif if ncrts gt 6 ; physical console 6. nv05 equ nv04+nvirt5 ; number of virtuals on consoles 0-5. ccb60 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,6,nv05 ; res, mimic, msource, physical, virt. dw 0,0,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt6 gt 1 dw offset ccb61,0 ; virtual console link, reserved. ccb61 dw 0,0,0 ; owner, reserved. db 0,0,0ffh,0ffh,6,nv05+1 ; res, mireserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. if nvirt7 gt 3 dw offset ccb73,0 ; virtual console link, reserved. ccb73 dw 0,0,0 ; owner. db 0,0,0ffh,0ffh,7,nv06+3 ; res, mimic, msource, phys, virt. dw 0,2,10 ; reserved, state flags, max buffer. dw 0,0,0,0,0,0 ; reserved. dw 0,0,0,0,0 ; reserved. endif endif endif dw 0,0 ; virtual console link, reserved. endif ; Console input status check. ; Return the input status of the spec in al,dx ; al = dsr bits from input port. test al,condsr ; look at console dsr bit. jnz io_cnrd ; hop if not ready. endif io_crdy: mov al,0ffh ; exit with ready condition. jmps cs_ext ; exit. io_cnrd: mov al,0 ; not ready exit. cs_ext: mov bl,al ; for return. ret ; return from console status (flag in al). ; Wait for i/o device to become ready. ; Relinquish control to xdos until ready. ; Entry: dl = device number. ; dl left 3 bits = device category. (see polltbl) ; waitxt: pop dx ; restore registers. and dx,001fh ; clear device category bits. pop cx pop ax cmp ercode,80h ; is there a disk time-out error? ret ; Check status device whose number is in dl. ; Device numbers are assigned thusly: ; left 3 bits = device category ; right 5 bits = number within category io_poll: mov bh,0 ; bx = device number. mov bl,dl and dl,1fh ; clear category bits. mov cl,4 ; divide by 16. shr bx,cl and bx,0fffeh ; clear bit 0. jmp polltbl[bx] ; rio_csw ; switch if so. inc bl ; set code for 1. cmp al,vkey1 ; virtual key 1? jz io_csw ; switch if so. inc bl ; set code for 2. cmp al,vkey2 ; virtual key 2? jz io_csw ; switch if so. inc bl ; set code for 3. cmp al,vkey3 ; virtual key 3? jz io_csw ; switch if so. ret io_csw: mov ax,bx ; use bx that has switch codes. ret ; must be in pc mode, so return scan code in ah. io_nosw: mov bx,ax ; bx = ke9board character. mov ah,ksctbl[bx] ; ah = scan code from table. t36 6 db 8 ; 37 7 db 9 ; 38 8 db 10 ; 39 9 db 39 OR 80h ; 3A : db 39 ; 3B ; db 51 OR 80h ; 3C < db 13 OR 80h ; 3D = db 52 OR 80h ; 3E > db 53 OR 80h ; 3F ? db 3 OR 80h ; 40 @ db 30 OR 80h ; 41 A db 48 OR 80h ; 42 B db 46 OR 80h ; 43 C db 32 OR 80h ; 44 D db 18 OR 80h ; 45 E db 33 OR 80h ; 46 F db 34 OR 80h ; 47 G db 35 OR 80h ; 48 H db 23 OR 80h ; 49 I db 36 OR 80h ; 4A J db 37 OR 80h ; 4B K db 38 OR 80h ; 4C L db 39 OR 80h ; 4D M db 49 OR 80h ; 4E N db 2 mov dx,curpos[di] ; get cursor position. cmp al,lf ; line feed? je io_colf ; hop if so. dec dl ; col = col-1, possible bs. cmp al,bs ; back space? je io_cocp ; hop if so. mov dl,0 ; column = 0 for possible cr. cmp al,cr ; is it a carriage-return? je io_cosp2 cmp al,20h ; is it some other control character? jc io_coex ; exit if so. ; write character and attribute byte into screen buffer. call io_vsad ; bx = address in buffer. if vcsbuf ; if virtual console screen buest is in status routine. ; console input. ; Return a character from the console keyboard or ; a serial I/O device. ; Entry: al = 1, dl = serial i/o device number. ; Exit: ah = 0 if returning data, 0ffh if switch. ; ah = scan code if in pc mode. ; al = character or virtual console number. io_conin: call wait ; wait until device is ready. if conint ; if console interrupts. ; read keyboard character from console input buffer. mov dh,0 ; dx = console number. mov bxest ah,80h ; would shift be down on pc? jz io_noex ; normal exit if not. mov bh,1 ; set shift flag. and ah,7fh ; remove shift bit io_noex: mov shflg,bh ; store shift flag. ret ; return from console input (char in al). ; Scan code table for PC-DOS software. ; Position is input ascii code, 0-7fh. ; Lower 7 bits of entry is pc-mode scan code. ; Most significant bit is set to indicate shift. ; scan code shift hex ascii ; --------- ----- --------- ksctbl db 0 ; 00 n4 OR 80h ; 4F O db 25 OR 80h ; 50 P db 16 OR 80h ; 51 Q db 19 OR 80h ; 52 R db 31 OR 80h ; 53 S db 20 OR 80h ; 54 T db 22 OR 80h ; 55 U db 47 OR 80h ; 56 V db 17 OR 80h ; 57 W db 45 OR 80h ; 58 X db 21 OR 80h ; 59 Y db 44 OR 80h ; 5A Z db 26 ; 5B [ db 54 ; 5C \ db 27 ; 5D ] db 7 OR 80h ; 5E ^ db 12 OR 80h ; 5F _ db 41 ; 60 ` db 30 ; 61 a db 48 ; 62 b db 46 ; 63 c db 32 ; 64 d db 18 ; 65 e db 33 ; 66 f db 34 ; 67 g db 35 ; 68 h db 23 ; 69 i dffer. mov [bx],al ; put character into buffer. endif ; Increment curpos (cursor position). io_incp: mov dx,curpos[di] ; dh = row, dl = column. inc dl ; increment column. cmp dl,nocols ; is it past end of line? jc io_cocp ; exit if not. mov dl,0 ; start at left again. io_colf: inc dh ; down to next row. cmp dh,norows ; is it past end of screen? jc io_cocp ; exit if not. mov dh,norows ; set to last row. dec dh call io_vbup ; scroll buffer up. ; Check limits,dx ; bx = console number. mov cl,3 ; cl = 3 for multiply by 8. shl bx,cl ; bx = 8 * console number. add bx,offset cibtab ; bx = cons. input buf entry adr. mov si,6[bx] ; si = next position to get char. mov al,[si] ; al = character from buffer. cmp si,2[bx] ; is pointer at last position? jne io_conn ; hop if not. mov cx,[bx] ; cx = buffer address if so. mov 6[bx],cx ; reset pointer to begining. jmps io_conm ; skip the increment. io_conn: inc word ptr 6[bx] ; increment bull db 0 ; 01 soh db 0 ; 02 stx db 0 ; 03 etx db 0 ; 04 eot db 0 ; 05 enq db 0 ; 06 ack db 0 ; 07 bel db 14 ; 08 bs backspace db 15 ; 09 ht tab db 80 ; 0A lf cursor down db 72 ; 0B vt cursor up db 77 ; 0C ff cursor right db 28 ; 0D cr return db 0 ; 0E so db 0 ; 0F si db 0 ; 10 dle db 0 ; 11 dc1 db 0 ; 12 dc2 db 0 ; 13 dc3 db 0 ; 14 dc4 db 0 ; 15 nak db 80 ; 16 syn cursor down db 0 ; 17 etb db 0 ; 18 can db 0 ; 19 em db 0 ; 1b 36 ; 6A j db 37 ; 6B k db 38 ; 6C l db 39 ; 6D m db 49 ; 6E n db 24 ; 6F o db 25 ; 70 p db 16 ; 71 q db 19 ; 72 r db 31 ; 73 s db 20 ; 74 t db 22 ; 75 u db 47 ; 76 v db 17 ; 77 w db 45 ; 78 x db 21 ; 79 y db 44 ; 7A z db 26 OR 80h ; 7B { db 54 OR 80h ; 7C | db 27 OR 80h ; 7D } db 41 OR 80h ; 7E ~ db 83 ; 7F del ; console output. ; Display and/or output a character to the specified ; serial i/o device. Also put character into screen ; on row (dl) and column (dh) then ; set cursor = dx. io_cocp: test dl,80h ; is column negative? jz io_cosp1 ; hop if not. mov dl,0 ; else set column = 0. io_cosp1: cmp dl,nocols ; is column => no of columns? jc io_cosp2 ; hop if not. mov dl,nocols ; else get last column number. dec dl io_cosp2: test dh,80h ; is row negative? jz io_cosp3 ; hop if not. mov dh,0 ; else set row = 0. io_cosp3: cmp dh,norows ; is row => no of rows? jc io_cosp ; hop if not. mov dhuffer pointer. io_conm: endif if not conint ; if not console interrupts. shl dx,1 ; multiply by 2 for table. mov di,dx ; put into index register. mov dx,cndtbl[di] ; get console data port adr. in al,dx ; read console data. endif and al,7fh ; strip parity. mov ah,0 ; code for no virtual switch. cmp pcflag,1 ; is it in pc mode? je io_nosw ; ignore virtual keys if so. mov bh,0ffh ; code for virtual switch. mov bl,0 ; set code for 0. cmp al,vkey0 ; virtual key 0? jz A sub db 1 ; 1B esc escape db 0 ; 1C fs db 0 ; 1D gs db 71 ; 1E rs home db 0 ; 1F us db 0 ; 20 sp db 2 OR 80h ; 21 ! db 40 OR 80h ; 22 " db 4 OR 80h ; 23 # db 5 OR 80h ; 24 $ db 6 OR 80h ; 25 % db 8 OR 80h ; 26 & db 40 ; 27 ' db 10 OR 80h ; 28 ( db 11 OR 80h ; 29 ) db 9 OR 80h ; 2A * db 13 OR 80h ; 2B + db 51 ; 2C , db 12 ; 2D - db 52 ; 2E . db 53 ; 2F / db 11 ; 30 0 db 2 ; 31 1 db 3 ; 32 2 db 4 ; 33 3 db 5 ; 34 4 db 6 ; 35 5 db 7 ; buffer in the right place. ; Entry: al = 2, cl = character, dl = virtual console. ; Exit: whatever. io_conout: push dx ; save virtual console number. call divirt ; di = virt cons * 2, dl = physical. pop ax ; al = virtual console number. mov bx,dx ; bx = physical console number. cmp forgnd[bx],al ; is this virtual in foreground? jne io_conc ; hop if not. call io_conu ; write character to console. io_conc: mov al,cl ; al = character. ; check for screen control characters. egory = 1. call wait ; wait until it's ready. shl dx,1 ; multiply by 2 for table. mov di,dx ; put into index register. mov dx,cndtbl[di] ; get port address. mov al,cl ; get character from cl. out dx,al ; send character to console. pop di ; restore virtual console number * 2. ret ; Print character in cl, saving main registers. ; This is used as a utility print routine for ; messages. It's also currently called from the ; video routines. conout: push ax ; save registerat bx. mov si,bx ; si = starting string address. io_swl3: mov ax,[si] ; ax = attribute, character. add si,2 ; point si at next character. call io_vonu ; print character. loop io_swl3 ; dec cx, loop until cx = 0. io_swno: mov cl,nocols ; cx = number of columns. mov ch,0 shl cx,1 ; cx = number of bytes. add bx,cx ; bx = address of next row. shr cx,1 ; cx = number of words. dec dh ; decrement row counter. jnz io_swl1 ; repeat if not zero. endif ret ; Display statindex register. add bx,offset lpstbl ; address of port number. mov dx,[bx] ; get status port number. in al,dx ; read printer status. add bx,3 ; point to status mask. mov ah,[bx] ; get status mask. and al,ah ; look at important bit(s). xor al,ah ; compare status bits. jnz io_lnrd ; if not same, exit not ready. cmp dh,0 ; is it a Duplex port? jz io_lrdy ; ready if not. mov dx,lptinp ; get input port address. in al,dx ; read input port. test al,lptdsr ; look at dsr bit. jn io_pollao: mov dx,auxost ; get aux output status port. in al,dx ; read aux output status. and al,auxomk ; is aux output ready? jz io_auxe ; exit with al = 00 if not. or al,0ffh ; exit with al = ff if so. jmps io_auxe ; rest is above. ; ********************************************************* ; ************ subroutine to print messages *************** ; ********************************************************* prtmsg: mov cl,[bx] ; get next character from string. test cs. push bx push cx push dx mov dl,0 ; console 0, call io_conout ; print character. pop dx ; restore registers. pop cx pop bx pop ax ret ; IO_SWITCH - Switch Screen. ; Place the current virtual console into the background ; and the specified virtual console into the foreground. ; Entry: al = 7, dl = virtual console # to switch to. ; Exit: set foreground table. io_switch: if vcsbuf ; if virtual console screen buffer. push dx ; save virtual console number. call dius line. ; Display specified text on the status line. ; Entry: al = 8, if cx = 0, continue to update the normal ; status line. If cx = offset, print string at dx:cx. ; If cx = 0ffffh, resume normal status line display. ; dl = physical console to display status line on. ; dx = segment address of optional string (cx<>0). ; Exit values: none. io_statline: ; not implemented. ret ; List control blocks. lcb0 dw 0 ; owner. dw 0,0,0 ; reserved. db 0,0ffh ; reserved, m-source. z io_lnrd ; hop if not ready. io_lrdy: mov al,0ffh ; set ready flag. jmps ps_ext ; exit. io_lnrd: mov al,0 ; set not ready flag. ps_ext: mov bl,al ; bl = al for exit. ret ; return from printer status (flag in al). ; List output. ; Output character to specified list device. ; Entry: al = 4, cl = character, dl = list device number. ; Exit value: none. io_list: or dl,2 shl 5 ; set device category = 2. call wait ; wait until device is ready. mov dh,0 ; set dx = device nl,cl ; check if zero. jz prtex ; if zero branch to return. call conout ; print character at console. inc bx ; point to next character. jmps prtmsg ; loop till string terminator found. prtex: ret ; exit from print routine. ; ********************************************************* ; ************ PC-MODE Character I/O Routines ************* ; ********************************************************* ; XIOS BACK DOOR ENTRY (whatever that means) xios_v1_entry: mov bx,offsetvirt ; dl = physical, di = virtual*2. mov bx,dx ; bx = physical console number. pop ax ; al = virtual console number. mov forgnd[bx],al ; set foreground for this physical console. mov bx,scbuft[di] ; bx = screen buffer address. mov dh,norows ; dh = number of rows. mov cl,nocols ; cl = number of columns. mov ch,0 ; cx = number of columns. io_swl1: mov si,bx ; si --> first character in row. shl cx,1 ; cx = number of bytes. add si,cx ; si --> last character in row+1. shr cx,1 ; c if nptrs gt 1 lcb1 dw 0 ; owner. dw 0,0,0 ; reserved. db 0,0ffh ; reserved, m-source. endif if nptrs gt 2 lcb2 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved, m-source. endif if nptrs gt 3 lcb3 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved, m-source. endif if nptrs gt 4 lcb4 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved, m-source. endif if nptrs gt 5 lcb5 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved m-source. umber. shl dx,1 ; multiply by 2 for table. mov di,dx ; put into index register. mov dx,lpdtbl[di] ; get printer data port address. mov al,cl ; get character from cl. out dx,al ; print character. ret ; return from printer output. ; Auxilliary Input Driver. io_auxin: or dl,3 shl 5 ; set category = 3. call wait ; wait until device is ready. mov dx,auxin ; get port address. in al,dx ; read the incoming byte. ret ; Auxilliary Output Driver. io_auxout: or dl,4 shl 5 ; e6msg ; print "INT E6" call prtmsg iret ; WW_KEY Read a window. ; Back door entry to pass window manager a key stroke. ; Entry: ; cl = 0ffh => input/status ; exit: al = char if char ready ; al = 0 if no char ready ; cl = 0feh => status only ; exit: al = 0ffh if char ready ; al = 0 if no char ready ; cl < 0feh => wait for input ; exit: al = char when ready ; Exit: ; if al = char then ; ah = key type ; 0 means regular ; 0ffh means special ww_key: mov dlx = number of words. inc cx ; cx = number of words + 1. io_swl2: sub si,2 ; point si at previous character. mov ax,[si] ; ax = character and attribute. cmp al,' ' ; is character a space? loope io_swl2 ; dec cx, loop while equal to space. ; print carriage-return and line-feed. mov al,cr ; al = carriage-return. call io_vonu ; print it. mov al,lf ; print line-feed. call io_vonu cmp cx,0 ; are there any characters to print? je io_swno ; hop if not. ; print cx characters endif if nptrs gt 6 lcb6 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved m-source. endif if nptrs gt 7 lcb7 dw 0 ; owner. dw 0,0,0 ; reserved. dw 0,0ffh ; reserved m-source. endif ; List status. ; Return list output status. ; Entry: al = 3, dl = list device number. ; Exit: al = 0ffh if device ready, ; al = 0 if device not ready. ; bl = al. io_listst: mov dh,0 ; make dx = device number. shl dx,1 ; multiply by 4. shl dx,1 mov bx,dx ; put into set category = 4. call wait ; wait until device is ready. mov dx,auxout ; get port address. mov al,cl ; get byte. out dx,al ; send byte out. ret ; Poll Auxilliary Device Input Status. io_pollai: mov dx,auxist ; get aux input status port. in al,dx ; read aux input status. and al,auximk ; is aux input ready? jz io_auxe ; exit with al = 00 if not. or al,0ffh ; exit with al = ff if so. io_auxe: mov bl,al ; make the same. ret ; Poll Auxilliary Device Output Status.only. ww_keyso: jmp io_const ; read console status. ; IO_SCREEN GET/SET SCREEN ; Get or set the current screen. ; Entry: ; al = 1eh (30) ; ch = 0 for set, 1 for get ; cl = mode if ch = 0 (set) ; dl = virtual console number ; Exit: ; ax = mode if ch = 1 (get) ; ax = 0ffffh if mode not supported (set) ; ax = 0fffeh if bad parameters (set) ; ax = 00000h if successful (set) ; es, ds, ss, sp preserved. io_screen: cmp ch,0 ; is it a set? je io_scs ; hop if so. ; musrpos[di] ; new position same as old one? je io_vrcpx ; exit if so. mov dx,cx ; dx = cursor position. call io_cocp ; check limits, set curpos. mov bx,offset setcur ; get set cursor sequence adr. jmp io_vseq ; do video sequence. ; read cursor position. io_vrcp: call divirt ; di = virtual console number * 2. mov ax,curpos[di] ; get cursor position. io_vrcpx: ret ; DIVIRT ; Entry: dl = virtual console number. ; Exit: dl = physical console number. ; dh = 0. ; dul ; loop back if not zero. endif ret ; Clear screen. ; Called by io_vsup and io_vsdn. ; Entry: bx = cursor address to start clear. io_vcls: if vcsbuf ; if virtual console screen buffer. push bx ; save starting cursor position. mov bx,offset clreos ; bx = clear screen sequence adr. call io_vseq ; send sequence to CRT. pop bx ; bx = starting cursor position. call io_vsab ; bx = starting address. mov ah,vidatr ; ah = video attribute. mov al,20h ; ax = attribute/s restore address in buffer. push bx ; save it back. call io_vbdd ; insert line in screen buffer. pop bx ; restore di. pop dx ; restore count and console no. dec dh ; decrement line counter. jnz io_vsdl ; loop back if not zero. endif ret ; read attribute/character. io_vrat: call divirt ; di = virtual console number * 2. call io_vsad ; bx = address in screen buffer. mov ax,[bx] ; get attribute and character. ret ; write attribute/character. io_vwat: callt be get screen. mov ch,nocols ; get number of columns. mov cl,scmode ; get screen mode. mov ax,cx ; not clear which one. ret ; must be set screen. io_scs: mov scmode,cl ; set screen mode. mov ax,0 ; show successful set. ret ; IO_VIDEO VIDEO INPUT/OUTPUT ; Manipulate the video screen. ; Entry: ; al = 1fh (31) ; bl = subfunction ; cx = input parameter ; dx = input parameter ; Exit: ; depends upon subfunction. ; es, ds, ss, sp preserved. io_video: cmp bl,15 i = virtual console number times 2. divirt: mov dh,0 ; dx = virtual console number. mov di,dx ; di = virtual console number. mov dl,vpcont[di] ; dl = physical console number. shl di,1 ; di = virtual console number * 2. ret ; scroll up. io_vsup: if vcsbuf ; if virtual console screen buffer. call io_vgp ; es = parameter segemnt, si = ofs. call divirt ; di = virtual console number * 2. mov ah,es:3[si] ; ah = attribute of blank line(s). call io_vatr ; set attribute if cpace. mov cx,cs ; get current segment. mov es,cx ; segment to send the blanks. mov cx,nochrs ; cx = no of words in buffer. shl cx,1 ; cx = no of bytes in buffer. add cx,scbuft[di] ; cx = 1 byte past end of buffer. mov di,bx ; di = starting address. sub cx,di ; cx = no of bytes to clear. shr cx,1 ; cx = number of words to clear. cld ; increment di. rep stosw ; write bright blanks into buffer. endif ret ; scroll down. io_vsdn: if vcsbuf ; if virtual consol io_vgp ; get parameter segment, offset. call divirt ; di = virtual console number * 2. call io_vsad ; bx = address in screen buffer. mov al,es:0[si] ; get character in al. mov ah,es:2[si] ; get attribute in ah. call io_vatr ; test and send attribute. mov cx,es:4[si] ; get character repeat count. jmps io_vwatb ; hop around increment for now. io_vwatl: call io_incp ; increment cursor position. io_vwatb: if vcsbuf ; if virtual console screen buffer. mov [bx],ax ; write ; is it greater than 14? jc io_vide ; hop if not. jmp io_ret ; print error message if so. io_vide: mov bh,0 ; bx = sub function number. shl bx,1 ; it's a word table. jmp subtab[bx] ; jump to the routine. ; Table of video subfunction addresses. subtab dw io_ret ; 0: set mode not implemented. dw io_ret ; 1: set cursor type not imp. dw io_vscp ; 2: set cursor position. dw io_vrcp ; 3: read cursor position. dw io_ret ; 4: read light pen not imp. dw io_ret ; hanged. mov dh,es:0[si] ; dh = number of lines to scroll. mov bx,es:4[si] ; bx = upper left of window. mov bl,0 ; bl = left column for now. push bx ; save starting cursor position. push dx ; save number of lines to scroll. mov cx,bx ; cx = starting cursor position. mov bx,offset setcur ; bx = set cursor sequence adr. call io_vseq ; set cursor on physical CRT. pop dx ; dx = number of lines to scrolм. pop bx ; restore starting cursor pos. cmp dh,0 ; if zero lines to scre screen buffer. call io_vgp ; es = parameter segemnt, si = ofs. call divirt ; di = virtual console number * 2. mov ah,es:3[si] ; ah = attribute of blank line(s). call io_vatr ; set attribute if changed. mov dh,es:0[si] ; dh = number of lines to scroll. mov bx,es:4[si] ; bx = upper left of window. mov bl,0 ; bl = left column for now. push bx ; save starting cursor position. push dx ; save number of lines to scroll. mov cx,bx ; cx = starting cursor position. mov bx,offsattribute and char. endif add bx,2 ; increment screen buffer ptr. call io_vonc ; send cяaracter to screen. loop io_vwatl ; loop until all chars sent. ret ; write character. io_vwc: call io_vgp ; get parameter segment, offset. call divirt ; di = virtual console number * 2. call io_vsad ; bx = address in screen buffer. mov al,es:0[si] ; al = character to write. mov cx,es:4[si] ; cx = number of chars to write. jmps io_vwcb ; no increment on first time. io_vwcl: ca5: select display not imp. dw io_vsup ; 6: scroll up. dw io_vsdn ; 7: scroll down. dw io_vrat ; 8: read attribute/character. dw io_vwat ; 9: write attribute/character. dw io_vwc ; 10: write character. dw io_vgni ; 11: set color palette not imp. dw io_vgni ; 12: write dot not implemented. dw io_vgni ; 13: read dot not implemented. dw io_vwsc ; 14: write serial character. ; set cursor position. io_vscp: call divirt ; di = virtual console number * 2. cmp cx,cuoll, je io_vcls ; clear the screen. call io_vsab ; bx = address to delete lines. io_vsul: push dx ; save count and console no. push bx ; save address in screen buffer. mov bx,offset dellin ; bx = adr of delete line seq. call io_vseq ; do it. pop bx ; restore address in screen buf. push bx ; save it back. call io_vbud ; delete line in screen buffer. pop bx ; restore adr in buf. pop dx ; restore count and console no. dec dh ; decrement line counter. jnz io_vset setcur ; bx = set cursor sequence adr. call io_vseq ; set cursor on physical CRT. pop dx ; dx = number of lines to scroll. pop bx ; restore starting cursor pos. cmp dh,0 ; if zero lines to scroll, je io_vcls ; clear the screen. call io_vsab ; bx = address to insert lines. io_vsdl: push dx ; save count and console no. push bx ; save address in screen buffer. mov bx,offset inslin ; bx = adr of insert line seq. call io_vseq ; insert line on physical CRT. pop bx ;aracter. call divirt ; di = virtual console number * 2. call io_vsad ; bx = address in buffer. mov ah,1[bx] ; ah = attribute there. call io_vatr ; change attribute if different. pop cx ; cl = character to write. call io_vck ; check cursor for bottom right. jnc io_vwsx ; exit if at bottom right. mov dl,0 ; use console 0 for now. jmp io_conout ; write character to console. io_vwsx: ret ; Check cursor to see if it's at or past bottom right. ; If not, exit with carry fry: ah = attribute for this transfer. ; Exit: vidatr is set if changed. io_vatr: cmp ah,vidatr ; same attribute as before? je io_vatx ; exit if so. push ax ; save ax. push bx ; save bx. push cx ; save cx. push si ; save si. push es ; save es. mov vidatr,ah ; save new attribute byte. test ah,08h ; is bright bit (3) set? mov bx,offset setbrt ; default is set bright. jnz io_vasa ; hop if bright bit high. mov bx,offset setdim ; else bx = set dim seq adr. io_vasa: tents of video buffer. ; Entry: bx = location in buffer. ; di = virtual console number times 2. io_vbdd: ; enter with insert line adr in0di. if vcsbuf ; if virtual console screen buffer. push ax ; save ax, cx. push cx push di ; save address of line to clear. push bx ; save screen buffer address. mov ax,cs ; get segmut we're in. mov es,ax mov cx,nochrs ; cx = number of screen chars. shl cx,1 ; cx = number of screen bytes. mov di,scbuft[di] ; di = top of buffer ad al,bh ; al = row. mov bh,nocols ; bh = number of columns. mul bh ; ax = address of row. shl ax,1 mov bh,0 ; bx = column. shl bx,1 ; bx = adr offset into row. add ax,bx ; ax = location of character. mov bx,scbuft[di] ; bx = screen buffer address. add bx,ax ; bx = address of character. pop ax ; restore ax. ret ; Send sequence of control codes at bx to video screen. ; Add in ch and cl to codes that have bit 7 set. ; Do not update screen buffer. io_vseq: mov ah,[blag set. ; If so, exit with carry flag clear. io_vck: push ax ; save ax. mov ax,curpos[di] ; al = current column number. mov ah,nocols ; ah = number of columns. dec ah ; ah = last column number. cmp al,ah ; is cursor at or past last col? jc io_vckx ; exit if not. mov ax,curpos[di] ; ah = current row number. mov al,norows ; al = number of rows. dec al ; al = last row number. cmp ah,al ; is cursor at or past last row? io_vckx: pop ax ; restore ax. ret ; Send call io_vseq ; send sequence to CRT. pop es ; restore es. pop si ; restore si. pop cx ; restore cx. pop bx ; restore bx. pop ax ; restore ax. io_vatx: ret ; Scroll up contents of screen buffer. io_vbup: mov bx,scbuft[di] ; bx = screen buffer address. io_vbud: ; enter with starting adr in di. if vcsbuf ; if virtual console screen buffer. push ax ; save ax. push cx ; save cx. push di ; save virtual console * 2. mov ax,cs ; get segment we're in. mov dress. add di,cx ; di = 1 byte past end of buffer. sub di,2 ; di = address of last word. mov si,di ; si = address of last word. mov al,nocols ; ax = number of words in a line. mov ah,0 shl ax,1 ; ax = number of bytes in a line. sub si,ax ; si = last word of (last line-1). pop ax ; ax = adr of line to insert. push ax ; save it back. mov cx,si ; cx = bottom word to move. add cx,2 ; cx = past bottom word. sub cx,ax ; cx = number of bytes to move. shr cx,1 ; cx =x] ; get character count. cmp ah,0 ; can it be done on this terminal? je io_vseqx ; exit if not. test ah,80h ; is bit 7 of first byte set? jz io_vseql ; hop into loop if not. and ah,7fh ; else clear bit 7. xchg cl,ch ; exchange row and column. io_vseql: inc bx ; point at next character. push ax ; save counter. mov al,[bx] ; get next character. test al,80h ; should we add to code? jz io_vseqs ; hop to send if not. and al,7fh ; else clear bit 7. add al,ch ; character in al to console 0, ignore control characters, ; check for bottom right, and don't update screen buffer. io_vonc: cmp al,20h ; is it a control character? jc io_vonx ; exit if so. call io_vck ; is it at bottom right? jnc io_vonx ; exit if so. ; IO_VONU - Send character to console, no screen buffer update. ; Entry: al = character. ; dl = physical console number. ; Preserve ax, bx, cx, dx, si, and di. io_vonu: push ax ; save ax. push bx ; save bx, cx. push cxes,ax ; set for move. mov al,nocols ; ax = number of words to next line. mov ah,0 shl ax,1 ; ax = no. of bytes to next line. mov si,bx ; si = address of first line. add si,ax ; si = address of next line. mov cx,nochrs ; cx = number of screen chars. shl cx,1 ; cx = number of bytes in buffer. add cx,scbuft[di] ; cx = 1 byte past end of screen. mov di,bx ; di = screen buffer address. push cx ; save end of screen address. sub cx,si ; cx = number of bytes to move. shr c number of words to move. std ; auto-decrement si, di. rep movsw ; slide all but first line down. ; clear out top line. mov ah,vidatr ; ah = video attribute. mov al,20h ; al = space. pop di ; di = address of line to clear. mov cl,nocols ; cx = number of words to write. mov ch,0 cld ; auto-increment di. rep stosw ; make top line all spaces. pop di ; di = virtual console * 2. pop cx ; restore cx, ax. pop ax endif ret ; es = screen parameter structure sadd row or column. xchg cl,ch ; exchange row and column. io_vseqs: call io_vonu ; send to video screen. pop ax ; restore counter. dec ah ; decrement counter. jnz io_vseql ; loop back if more. io_vseqx: ret ; IO_KEYBD KEYBOARD MODE ; Enable/Disable PC-MODE. ; Entry: ; al = 20h (32) ; cl = 1 for enable, cl = 2 for disable ; dl = virtual console number ; Exit: ; ax = 0 if ok, ax = 0ffffh if error. ; es, ds, ss, sp preserved. io_keybd: mov pcflag,cl ; store pc-m push dx push si push di ; save console no. mov cl,al ; character was in al. call io_conu ; output character in cl. pop di ; restore console no. pop si pop dx pop cx ; restore cx, bx. pop bx pop ax ; restore ax. io_vonx: ret ; Print message: "Graphics not implemented." io_vgni: mov bx,offset gnimsg ; bx = message address. call prtmsg ; print message. jmp io_ret ; print function, subfunction no. ; If the video attribute has changed, set new one. ; Entx,1 ; cx = number of words to move. cld ; set to auto-incrment si, di. rep movsw ; slide all up from si down. ; clear out bottom line. pop di ; di = end of buffer address. sub di,ax ; di = address of bottom line. mov ax,0f20h ; ax = attribute, character. mov cl,nocols ; cx = number of words to move. mov ch,0 rep stosw ; make bottom line all spaces. pop di ; restore virt console * 2. pop cx ; restore cx. pop ax ; restore ax. endif ret ; Scroll down conegment, si = offset. ; dl = virtual console number. io_vgp: mov es,cx ; get parameter structure seg. mov si,dx ; si = parameter structure offset. mov dl,es:8[si] ; dl = virtual console number. ret ; Get address of cursor in virtual screen buffer. ; Entry: di = virtual console number * 2. ; curpos = column, row. ; Exit: bx = address in screen buffer. io_vsad: mov bx,curpos[di] ; bh = row, bl = column. io_vsab: ; for ext entry with bx=position. push ax ; save ax. mov ; Read DOS sector(s) defined by the IOPB. ; Entry: ; al = 23h (35) ; DOS IOPB filled in (on stack) ; Exit: ; al = 0 if no error ; al = 1 if physical error ; al = 0ffh if media density has changed ; ah = extended error code ; bx = ax ; es, ds, ss, sp preserved. io_int13_read: jmp io_read ; same except for head no in IOPB. ; IO_INT13_WRITE WRITE DOS SECTOR ; Write DOS sector(s) defined by the IOPB. ; Entry: ; al = 24h (36) ; DOS IOPB filled in (on stack) ; Exit: ; aystem. selflp: push si ; save drive number. mov byte ptr diskno,0ffh ; force new controller setup. ; Restore head to track 0 to read from that track. mov al,cl ; al = drive number. mov ah,stprat5+hlab ; ah = 5" restore command. test al,4 ; is it 5 or 8-inch? jz selfcp ; hop if 5-inch. or al,8 ; set ENMF* bit. mov ah,stprat8+hlab ; ah = 8" restore command. selfcp: mov dx,fcont ; get floppy control port ad. out dx,al ; tell controller which disk. mov clatch,al ; save tlatch ; get current latch value. or al,10h ; set to single density. mov dx,fcont ; get latch port address. out dx,al ; set floppy control latch. mov clatch,al ; save the value. mov dx,offset chkbuf ; get temporary buffer offset. mov ax,cs ; get temporary buffer segment. call comdma ; compute dma address. mov cx,84d0h ; get 2793 read command. mov dx,4080h ; get 128-byte dma read. mov al,1 ; read sector one. call dmarw ; do dma read operation. jnz selnr ; jump out if address of DPH. pop bx ; bx = ptr to xlate table adr. mov ax,[bx] ; get xlt table pointer. xchg bx,dx ; bx=DPH adr, dx=code table adr. mov [bx],ax ; put xlt pointer into dph table. ; put Disk Parameter Block address into Disk Parameter Header. xchg bx,dx ; dx=DPH adr, bx=code table ptr. add bx,2 ; bx = ptr to DBP address. mov ax,[bx] ; ax = Disk Parameter Block adr. mov bx,dx ; bx = Disk Parameter Header adr. add bx,8 ; bx = adr of DPB in DPH. mov [bx],ax ; put Dl = 0 if no error ; al = 1 if physical error ; al = 0ffh if media density has changed ; ah = extended error code ; bx = ax ; es, ds, ss, sp preserved io_int13_write: jmp io_write ; same except head number in IOPB. ; ********************************************************* ; ************* disk interface routines *************** ; ********************************************************* ; Select disk. ; Entry: al = 9, cl = disk drive number, ; dl bit 0 = 0 if first he value. mov al,ah ; restore at fast step rate. mov dx,fdisk ; get command port adr. out dx,al ; start restore. call waitio ; wait for completion. jz selnr ; hop if disk not ready. mov bx,(offset trtab) ; get address of track table. if dual ; if persci drive and cl,2 ; index to 1 of 2 entries endif add bx,cx ; add drive offset mov byte ptr [bx],00h ; set to track 0 mov sektrk,0 ; First see if it's a 5-inch or 8-inch disk. test cl,4 ; is it an 8-inch drive? error during read. mov al,chkbuf+7eh ; get Tarbell ID byte from buffer. or al,al ; is it a zero? jnz selnz ; hop if not. mov al,0e5h ; big trouble for it to be zero. ; Figure internal density code byte from disk code byte (in al). ; Note that there are two kinds of density codes. The one ; that's in register al at this point is the one that comes ; from the first track of the floppy disk itself. The one ; that's stored in dens is different, and is coded thusly: ; bit 0 = PB adr into DPH. ; Save current sectors per track & physical sector shift. selset: mov bx,ax ; bx = DPB address. cmp word ptr [bx],0ffffh ; is it a PC-DOS DPB? jne notpc ; hop if not. add bx,12 ; increment past extension if so. notpc: mov al,psh[bx] ; get physical sector shift. mov curpsh[si],al ; put in current psh table. mov ax,[bx] ; ax = physical sectors per track. shl si,1 ; multiply by 2 for word table. mov curspt[si],ax ; put in current spt table. mov ax,dx ; ax =select. ; Exit: ax = offset of dph if no error, ; ax = 0 if invalid drive, io_seldsk: mov ercode,0 ; clear error code. mov diskto,dsktim ; set disk time-out. mov erdisk,cl ; save letter code (0-15). xor ax,ax ; clear ax for possible error. mov ch,0 ; clear upper cx for index. mov si,offset drvmap ; get drive map table address. add si,cx ; figure address of entry. mov cl,[si] ; get physical drive number. cmp cl,0ffh ; is it undefined? jz selex ; error to cpm if so. jnz nonibm ; hop if so. ; Next see if it's a 512-byte or 128-byte format. call rdadrc ; read id into chkbuf. jnz nonibm ; not 512 sectors if it can't. ; must be 512-byte format. could be CP/M-86 or PC-DOS format. mov cx,094d0h ; ch = floppy read command. mov dx,04400h ; dx = 1024-byte dma read. mov al,1 ; al = starting sector number. call dmarw ; read 2 512-byte sectors. jnz selnr ; exit if error. mov al,chkbuf + 512 ; ax = possible fat word. mov ah,chkbuf + 513 1 for double density, ; bit 1 = 1 for double sided, ; bit 2 = 1 for 512-byte sectors. ; bit 3 = 1 for DR/IBM formats. ; bit 4 = 1 for PC-DOS formats. selnz: mov bx,(offset dpbt5) ; 5" dpb table address. mov cl,sekdsk ; get drive number. test cl,4 ; is it 5-inch floppy? jz selop ; hop if so. mov bx,(offset dpbt8) ; 8" floppy dpb table address. selop: cmp byte ptr [bx],0 ; is it last table entry (0)? je setden ; hop out of loop if so. cmp al,[bx] ; is it this densit Disk Parameter Header adr. ret ; Get address of Disk Parameter Header in ax and dx. ; Get internal disk number in si. index: xor bh,bh ; load disk number and zero byte. mov bl,sekdsk mov si,bx ; put disk number in si. mov dx,(offset dphtab) ; get disk param header table adr. shl bx,1 ; drive number times 2. add bx,dx ; figure table entry address. mov dx,word ptr [bx] ; get address of dph from table. mov ax,dx ; put it in ax. ret ; return from seldsk (& other places). mov si,cx ; si = internal disk number. mov sekdsk,cl ; save new disk number. test dl,fresh ; fresh access? jz sellog ; skip if not logged in. jmp index ; jump if already logged in. selex: ret ; error return to op sys. ; This disk not logged in yet, so must do it. sellog: cmp cl,8 ; is it a hard disk drive? jc selflp ; hop if not. jmp selhrd ; jump if so. ; This floppy disk is not logged in, so we must determine ; it's size, sector length, format, and operating s cmp ax,0fffch ; is it PC-DOS fat word? jnc selnz ; hop if it is. ; must be a DR/IBM (non-PCDOS) format for CP/M-86. mov al,chkbuf + 511 ; al = DR's id byte. inc al ; let's not use zero. jmps selnz ; hop to figure rest of it. ; error encountered. selnr: pop bx ; make stack right. selnrh: mov al,3 ; set select error code. call recov ; print error message. mov ax,0 ; return bad select. ret ; must not be ibm format, so read single density sector 1. nonibm: mov al,cy code? je setden ; hop out of loop if so. add bx,6 ; else to next code entry. jmps selop ; try the next one. ; set internal density code byte (dens). setden: inc bx ; point at internal code byte. mov al,[bx] ; get density byte from table. pop si ; si = internal drive number. mov dens[si],al ; set current drive density. ; put translate table address into Disk Parameter Header. inc bx ; point at xlate table address. push bx ; save table pointer. call index ; dx = - Get hard disk error parameters from registers. iogete: mov ercyl,bx ; error cylinder. mov erhead,ch ; error head. mov ersect,dl ; error sector. mov ercode,ah ; error status. ret endif selmap: call mapper ; log in hard disk drive. jc selher ; hop if error. selner: call index ; ax, dx = DPH address. add ax,8 ; ax = pointer to DPB. mov bx,ax ; bx = pointer to DPB. mov ax,[bx] ; ax = address of DPB. jmp selset ; set spt, psh, return with dph adr. selher: jmp sedskss = old stack segment. mov dsksp,sp ; dsksp = old stack pointer. mov ax,ds ; stack segment = data segment. mov ss,ax mov sp,offset dskstk ; stack pointer = disk stack. mov ax,offset dskret ; put return address on new stack. push ax cmp mcnt,0 ; is multisector count=0? jne io_dlp jmp io_dbc ; exit with bad command error. io_dlp: mov diskto,dsktim ; set disk time-out timer. mov dl,drive ; dx = logical drive number. mov dh,0 mov erdisk,dl ; save it for error print-outent sector number. shr si,1 ; now it's a byte table. mov cl,7 ; track 0 default. cmp trk0,true ; track 0 flag true? je io_t0 ; hop if so. mov cl,curpsh[si] ; get sector shift factor. add cl,7 ; adjust. 128-byte psh = 0. io_t0: shl dx,cl ; multiply by bytes/sector. mov bytcnt,dx ; save byte count. ; decide whether floppy or hard disk, then make transfer. if nhard gt 0 ; if one or more hard disks. cmp sekdsk,8 ; is it a hard disk transfer? jc io_tfl ; hop if floppy. ,0101h ; return bad command error. io_dex: ret ; other errors. io_rec: mov al,oper ; al = operation code. call recov ; print error message. mov ax,0110h ; crc code for now. ret ; Do read or write from/to floppy disk at current track. ; Multiple sectors on same track are allowed. ; Set or clear write-precompensation bit as needed. ; This is where the error retry is performed. ; Actual transfer is done in subroutine dmarw. ; Entry: ax = starting sector number ; dx = numblnrh ; print error message & return. endif ; Read the next id field into chkbuf. rdadrc: mov dx,offset chkbuf ; dx = destination offset. mov ax,cs ; ax = destination segment. call comdma ; compute dma adr (lsb20,msb20). mov cx,0c4d0h ; read address code. mov dx,04006h ; disk-memory, 6 bytes. jmp dmarwe ; read 6 bytes into chkbuf. ; IO_READ and IO_WRITE ; Read sector and Write sector. ; Note: io_init13_read and io_init13_write come here too. ; Entry: ; al = 0ah (10. mov si,dx ; si = drive number from os. mov dl,drvmap[si] ; dx = internal drive number. mov sekdsk,dl ; save for dmarw poll. mov cx,track ; get track # in cx. call seekls ; seek the disk to the proper track. jz io_dok ; hop if good seek. ret ; else return with seek error. ; restore stack for common return from disk i/o. dskret: mov ss,dskss ; restore stack segment. mov sp,dsksp ; restore stack offset. ret io_dok: mov dx,dmaoff ; get destination offset. mov ax,dmas if ades ; if ADES controller. cmp sekdsk,12 ; is it for ADES controller? jc ionad ; hop if not. mov es,dmaseg ; es = transfer segment. mov di,dmaoff ; di = transfer offset. mov bx,track ; bx = cylinder number. mov cx,nosecs ; cx = number of sectors to transfer. mov dx,sector ; dx = starting sector within cylinder. mov al,sekdsk ; al = logical drive number. sub al,12 ; make 0-3 for ADES controller. mov ah,oper ; ah = 1 for read, 2 for write. call ad_th ; call ADES drer of bytes to transfer ; Exit: ZF set if no error. io_tf: mov diskto,5 ; set disk time-out counter. cmp oper,1 ; is it a read operation? je io_rd ; hop if so. ; must be write transfer - make write-precompensation bit right. push dx ; save byte count and sector number. push ax mov dx,ftrk ; dx = track register port. in al,dx ; al = current physical track number. cmp al,pctrk ; do we need pre-compensation? mov al,clatch ; al = current latch value. jc io_tfn ; hop i) for io_read ; al = 0bh (11) for io_write ; al = 23h (35) for io_init13_read ; al = 24h (36) for io_init13_write ; IOPB on stack has parameters as noted above. ; Exit: ; al = 0 if no error ; al = 1 if physical error ; al = 0ffh if media density has changed ; ah = extended error code ; bx = ax io_read: mov oper,1 ; read operation. jmps io_disk ; now do common disk routine. io_write: mov oper,2 ; write operation. ; Perform disk i/o transfer. io_disk: mov ercode,0 eg ; get destination segment. call comdma ; compute physical dma adr. ; get internal drive number into si to index into tables. mov al,sekdsk ; get drive number. mov ah,0 mov si,ax shl si,1 ; curspt word table is first. ; figure number of sectors to ask controller to transfer. mov ax,sector ; get starting sector to transfer. mov cx,ax ; save in cx. mov dl,mcnt ; get multi-sector count. mov dh,0 cmp trk0,true ; track zero flag true? je io_tz ; hop if so. add ax,diver. jnc iotok ; hop if no errors. call iogete ; get error parameters from registers. jmps io_rec ; print error message and return. endif ionad: call io_th ; do hard disk transfer. jmps io_der ; check for errors. endif io_tfl: call io_tf ; do floppy disk transfer. ; check for error, see if more to do. io_der: jnz io_rec ; exit if transfer error. ; see if there's more multi sectors to transfer. iotok: mov ax,mlft ; update multi-sector count. mov mcnt,al cmp axf no precomp needed. or al,20h ; else set bit 5 of latch. jmps io_tfs ; set latch. io_tfn: and al,0dfh ; clear bit 5 of latch. io_tfs: mov dx,fcont ; dx = latch port address. out dx,al ; set the latch. mov clatch,al ; remember what's there. pop ax ; restore sector number and byte count. pop dx ; set up for write transfer. mov cx,0b4d0h ; floppy write, force interrupt cmds. or dx,08000h ; dma write, dma count byte cmds. jmps io_tr ; do transfer. ; set up for read t ; clear any old error codes. mov bp,sp ; get stack address. ; get parameters for transfer from stack. mov al,19[bp] ; mcnt = multi-sector count. mov mcnt,al mov al,18[bp] ; drive = drive number. mov drive,al mov ax,16[bp] ; track = cylinder number. mov track,ax mov ax,14[bp] ; sector = sector number. mov sector,ax mov ax,12[bp] ; dmaseg = transfer segment. mov dmaseg,ax mov ax,10[bp] ; dmaoff = transfer offset. mov dmaoff,ax ; set up local stack. mov dskss,ss ; x ; what would be the last sector? dec ax ; make comparison work. sub ax,curspt[si] ; is it past end of track? jnc io_tend ; hop if past end of track. io_tz: mov ax,-1 ; multi-count will be zero. io_tend: inc ax ; set new multi-sector count. mov mlft,ax ; this is the count left. sub dx,ax ; sectors for THIS transfer. mov nosecs,dx ; save number of sectors to do. ; now get ready to do the transfer operation. mov ax,cx ; restore starting sector number. inc ax ; increm,0 ; any multi-sectors left? je io_dex ; exit if not. mov sector,0 ; start with first sector, inc track ; since it must be new track. mov ax,bytcnt ; add byte count to dmaoff. add dmaoff,ax jc io_dec ; hop if add overflowed. jmp io_dlp ; loop back for some more. io_dec: add dmaseg,1000h ; add carry into segment. jmp io_dlp ; loop back for some more. ; zero sector count error. io_dbc: mov al,oper ; al = current operation. call recov ; print error message. mov axoper ; al = current operation. call recov ; print error message. pop bx ; restore error code. io_trx: mov ax,bx ; ax = error code. or al,al ret ; disk error handler: on entry al = error type. ; print type, track, sector, & status. recov: push ax ; save error flag. mov bx,(offset errmsg) call prtmsg ; error intro message. pop ax ; get flag back. xor ah,ah ; clear high bits. mov cl,7 ; table offset. mul cl ; multiply by offset. inc bx ; past eom. aov cl,dl ; get bcd value. add cl,'0' ; add ascii bias. call conout ; print the digit. pop dx ; recover next bcd value. ret ; print all digits recursivly. ; ; SEEKLS - Seek selected floppy disk to track. ; If hard disk, just return. Seek will be done in io_th. ; If floppy disk, seek drive dl to track in cl. ; If ch <> 0 then must be PC-DOS disk head number. ; Set latch with correct density, drive, and side code. ; Update track table if the track has changed. ; Perform read id fu mov al,dens[si] ; get density type byte. ; figure whether to treat this track special. test al,00011000b ; 512-byte sectors on track 0? jnz seeka ; hop ahead if so. cmp bl,0 ; are we on track zero? jne seeka ; hop ahead if not. mov trk0,true ; else set track 0 flag true. seeka: test al,00010000b ; is it a PC-DOS disk? jnz seekpc ; hop if so. test al,00001000b ; is it a DR/IBM for CP/M-86? jz seekni ; hop if not. ; must be Digital Research format for CP/M-86 on IBnew track number? jnz nothr ; nope, go move it. pop cx ; restore cx. xor ax,ax ; return no error flags. ret ; return from seek. nothr: ; note: this routine is to allow time for the drive ; tunnel erase to terminate before moving the ; head. the delay is aprx. 700 micro-seconds. mov al,0 ; delay count = 256. busy1: dec al ; decrease count. jnz busy1 ; loop till zero. mov al,cl ; put dest. in al from cl. mov dx,fdata ; get data port adr. out dx,al ; trackdd bx,ax ; add offset. call prtmsg ; print the error type. mov bx,(offset drvmsg) call prtmsg ; drive message. mov cl,erdisk ; cl = crive letter code. add cl,'A' ; make into actual letter. call conout ; print the letter. inc bx ; past eom. call prtmsg ; cylinder message. mov cx,ercyl ; get current cylinder #. call decout ; print in decimal. inc bx ; past eom. call prtmsg ; print 'head'. mov cl,erhead ; cl = head number. call prtdec ; print it. inc bx nction to recalibrate disk if seek error. ; Exit: z clear if error, set if no error. ; seekls: mov trk0,false ; assume no special treatment. cmp sekdsk,8 ; is it floppy or hard disk? jc seeklf ; hop if floppy. xor ax,ax ; set z flag, return no errors. ret seeklf: mov diskto,5 ; set disk time-out counter. cmp byte ptr diskno,dl ; test for new drive jz samedsk ; not a new drive so just seek. mov byte ptr diskno,dl ; update current disk # ; new drive so get present track anM-PC. and bh,0efh ; clear single density bit. cmp bl,ibmtpd ; is track greater than 39? jc trksd5 ; hop if not. mov al,2*ibmtpd-1 ; subtrack track no. from 79. sub al,bl mov bl,al or bh,40h ; set side select bit. jmps trksd5 ; finish below. seekni: or bl,bl ; is it track zero? jz trksd ; hop if so. seekpc: test al,2 ; test for double sided jz trkss ; don't /2 if single sided ; figure track to go to and which side to select. test bl,1 ; is it an even track to data register. ; get the seek command with correct step rate. mov al,14h+stprat5+hlab ; al = 5" seek command. cmp sekdsk,4 ; is it a 5" or 8" floppy? jc seekt ; hop if 5-inch. mov al,14h+stprat8+hlab ; al = 8" seek command. seekt: mov dx,fdisk ; get command port adr. out dx,al ; set rate, seek with verify. call waitio ; poll process complete. jz sknr ; hop if not ready error. mov dx,fdisk ; get status port adr. in al,dx ; read status. mov ercode,al ; save status ; past eom. call prtmsg ; sector message. mov cl,ersect ; get current sector #. call prtdec ; print in decimal. inc bx ; past eom. call prtmsg ; status message. mov ah,ercode ; get status bits. mov ch,8 ; eight bits in status. bitlop: mov cl,'0' ; assume bit is 0. rol ah,1 ; test next bit. jnc prtbit ; it's off, leave 0. inc cl ; it's on, make 1. prtbit: call conout ; print bit value. dec ch ; dec bit counter. jnz bitlop ; print all bits. ret d seek to it to ; to inform the controller that the head is unloaded. push dx ; save dx. mov dx,ftrk ; get track register port. in al,dx ; read track register. mov dx,fdata ; get data port. out dx,al ; send track to data port. mov al,10h ; get seek command no verify mov dx,fdisk ; get command port adr. out dx,al ; do the (non) seek. call waitio ; wait till done pop dx ; restore dx. jnz samedsk ; hop if disk was ready. jmp sknr2 ; seek not ready error. ; no? jz trkev ; hop if so. or bh,40h ; or in side select if not. trkev: shr bl,1 ; divide track by 2. trkss: test al,1 ; test for double density jz trksd ; hop if single density. and bh,0efh ; clear single density bit. trksd: test dl,4 ; is it 5 or 8-inch floppy? jz trksd5 ; hop if 5-inch floppy. or bh,8 ; set weird bit 3 if 8-inch. trksd5: mov al,bh ; get density-select code mov dx,fcont ; get floppy control port. out dx,al ; set up the latch. mov clatch,al ; bits. test al,91h ; look at success bits. jnz skerr ; zero if ok. pop cx ; recover cx. mov dx,diskno ; get drive index if dual ; if using persci drives. and dl,2 ; index to 1 of 2 entries endif mov bx,(offset trtab) ; point at track table add bx,dx ; add index mov [bx],cl ; update track table xor ax,ax ; set z flag, return no errors. ret ; return seek ok. ; error handling. skerr: dec sercnt ; decrement error counter. jnz sretry ; retry if not zero ; convert cl to decimal and display at console. prtdec: xor ch,ch ; clear top eight bits. decout: push dx ; save value on stack. mov dx,-1 ; this becomes number / radix. sub10: sub cx,10 ; subtract 10. inc dx ; inc remainder. jnc sub10 ; loop till carry out. add cx,10 ; add radix back in. xchg dx,cx ; switch new/current. test cx,cx ; test for zero reminder. jz cndone ; if zero, conversion complete. call decout ; build bcd digits recursivly. cndone: msetup density & such samedsk: xor dh,dh ; clear dh mov si,dx ; save drive number. if dual ; if persci drive and dl,2 ; index to 1 of 2 entries endif mov bx,offset trtab ; get track table adr. add bx,dx ; get address in table. mov al,[bx] ; get old track #. mov dx,ftrk ; get track port adr. out dx,al ; update track register. mov bl,cl ; save track # in bl mov dl,byte ptr diskno ; get drive # or dl,10h ; set single density bit. mov bh,dl ; save in bh save the value. ; set erhead for error routine. test al,40h ; is it head 1? mov al,0 ; default is zero. jz headst ; hop if head zero. inc al ; inc if head 1. headst: mov erhead,al ; set head number for error routine. mov cl,bl ; put track in cl. ; perform actual seek to track given by cl. seek: push cx ; save cx. mov sercnt,srtcnt ; reset seek retry error counter. mov dx,ftrk ; get track register port. in al,dx ; read present track no. cmp al,cl ; same as al = restore at 8-inch rate. sretr2: mov dx,fdisk ; get status port. in al,dx ; read status. call waitio ; wait for completion. jz sknr ; hop if seek not ready error. jmps chks2 ; go re-seek track. chks1: mov dx,fsect ; get floppy sector port. in al,dx ; read sector. mov dx,ftrk ; get floppy track port. out dx,al ; re-inform controller of proper track. chks2: pop cx ; restore track #. jmp seek ; move head to it. ; Common floppy DMA read & write subroutine.v dx,dmadpl0 ; get dest lower port. out dx,ax ; set destination lower. mov ax,cx ; get source lower. mov dx,dmaspl0 ; get source lower port. out dx,ax ; set source lower. ; set dma count and command. pop bx ; restore read or write comd. pop ax ; restore transfer count. and ah,3fh ; clear old command bits. mov dx,dmatc0 ; get transfer count port. out dx,ax ; set transfer count. mov ax,bx ; get read or write command. mov dx,dmacon0 ; get dma control port. out dxrd not found error? jz dmaer3 ; hop if not. or bh,4h ; set if so. dmaer3: test al,8 ; crc error? jz dmaer4 ; hop if not. or bh,10h ; set crc bit for bdos. dmaer4: test al,1 ; is controller still busy? jz dmaer5 ; hop if not. or bh,20h ; controller failed if so. dmaer5: or bl,bl ; clear z flag for error return. ret ; Wait until last floppy disk operation is complete. ; If disk is not ready, exit with al=0, Z status flag set. ; If disk is ready, exit back to CCPM Xal. ret endif seeksf: mov dx,fdisk ; get floppy status port. in al,dx ; read status. and al,1 ; is busy bit set? jz seekex ; hop if not busy. mov al,0ffh ; will be 0 for busy. seekex: not al ; this makes it all ok. mov bl,al ret ; Provide a delay after commands for status to become valid. fdelay: push cx ; save cx. mov cx,80h ; this seems to work. fdloop: loop fdloop ; count down till cx=0. pop cx ; restore cx. ret ; Disk time-out error. diskte: ; Entry: ch = command to write to floppy controller chip. ; dh upper 2 bits = dma operation code. ; if bit 7 = 0, read operation, 1 for write. ; dx lower 14 bits = number of bytes to transfer. ; al = sector number dmarw: ; set floppy sector register from sect. mov ersect,al ; save sector # for error message. push dx ; save dx. mov dx,fsect ; get sector port adr. out dx,al ; set sector number. pop dx ; restore dx. dmarwe: push cx ; save cx. push dx ; save dx,ax ; initialize dma operation. ; start floppy controller running. pop cx ; restore floppy read/write comd. mov al,ch ; get floppy read/write command. mov dx,fdisk ; get floppy command port adr. out dx,al ; start read or write operation. cmp al,0c4h ; was it a read address? je dmarda ; hop if so. mov dl,sekdsk ; get physical drive number. or dl,5 shl 5 ; set operation category 5. call wait ; wait until it's done. mov al,80h ; al = not ready code. jz dmaex ; exiDOS until op done. ; Then exit with al = 0ffh, Z status flag clear. waitio: call fdelay ; wait for valid status. push dx ; save dx. mov dx,fdisk ; get floppy status port. in al,dx ; read status. and al,80h ; is the disk even ready? jnz waitnr ; hop if disk not ready. mov dl,sekdsk ; dl = physical drive number. or dl,6 shl 5 ; set poll category = 6. call wait ; wait until operation done. jz waitnr ; hop if time-out error. mov al,0ffh ; set device ready flag. ormov ercode,80h ; set not-ready error code. mov al,0ffh ; return with ready status. mov bl,al ret ; poll for current disk dma activity completed. ; Exit: al = 0 if not ready. ; al = ff if ready. ; bl = al. diskst: cmp diskto,0 ; is time-out down to zero yet? je diskte ; time-out error if so. if nhard gt 0 ; if one or more hard disks. cmp sekdsk,8 ; is it hard or floppy disk? jnc seeksh ; jump if hard disk. endif mov dx,dmatc0 ; get transfer count port. in . mov dx,fdisk ; get floppy status port. in al,dx ; read floppy status. test al,80h ; is floppy ready? jnz dma_xt ; hop out if not ready. ; get floppy port address and memory transfer address. mov al,msb20 ; get 4 hi bits of adress. mov ah,0 ; get 4 hi bits of floppy port. mov bx,lsb20 ; get 16 lo bits of address. mov cx,fdata ; get 16 lo bits of floppy port. pop dx ; get command flag and count. push dx ; save it back. test dh,80h ; is it a write or read op? movt if time-out. call fdelay ; let crc bytes get written. mov dx,fdisk ; get floppy command port. mov al,0d0h ; issue force interrupt command. out dx,al dmarda: call waitio ; wait until 2793 not busy. mov al,80h ; al = time-out code. jz dmaex ; exit if time-out. push cx ; make stack right. push dx mov dx,fdisk ; get status port. in al,dx ; read status. dma_xt: pop dx ; restore dx,cx. pop cx dmaex: mov ercode,al ; save status code. and al,99h ; look at erro al,al pop dx ; restore dx. ret waitnr: xor al,al ; set not ready flag. pop dx ; restore dx. ret ; return from waitio. ; Determine whether a disk controller operation is done. ; Assumes that initial status valid delay was done above. ; Entry: dl = logical drive number. ; Exit: al = 0ffh if operation complete. ; al = 0 if operation not complete. ; bl = al. seekst: cmp diskto,0 ; is time-out down to zero yet? je diskte ; time-out error if so. if nhard gt 0ax,dx ; read count register. test ax,ax ; is it zero yet? jz diskstex ; exit ready if so. mov al,0ffh ; so al=0 on exit for not ready. diskstex: not al ; make it right. mov bl,al ; make bl same as al. ret ; Flush Buffers. ; Since there are currently no buffers internal to ; this XIOS, this routine doesn't have to do anything. io_flushbuf: mov ax,0 ; set no error. mov bx,ax ; make bx same as ax. ret ; return. ; Dummy I/O Return. io_ret: push bx ; s dx,fdmard ; get dma read command. jz dmard ; must be read if bit 7=0. xchg al,ah ; exchange source and dest ptrs. xchg bx,cx mov dx,fdmawt ; get dma write command. dmard: push dx ; save on stack. ; at this point: destination=bx,al; source=cx,ah. mov dx,dmadpu0 ; get dest upper port. out dx,ax ; set destination upper. mov al,ah ; get source upper in al. mov dx,dmaspu0 ; get source upper port. out dx,ax ; set source upper. mov ax,bx ; get destinaiton lower. mor bits. jnz dmaer ; hop if error in dmarw. xor bx,bx ; else show no error. ret ; return from dma common. ; error detected in dmarw routine. ; convert error bits from 2793 to error bits for operating system. dmaer: mov bx,1 ; initialize error flag. test al,80h ; was it not ready? jz dmaer1 ; hop if not that bit. or bh,80h ; else set respond bit. dmaer1: test al,40h ; was it write-protected? jz dmaer2 ; hop if not. or bh,3 ; set if so. dmaer2: test al,10h ; reco ; if one or more hard disks. cmp sekdsk,8 ; is it floppy or hard disk? jc seeksf ; hop if floppy. seeksh: if ades ; if ADES controller. cmp sekdsk,12 ; is it ades? jc seeksk ; hop if so. mov ah,3 ; ah = code to check status. call ad_th ; call ades hard disk driver. jmps seekso ; do rest below. endif seeksk: cmp dmastat,0 ; is hard disk busy? seekso: mov al,0 ; set al to busy. je seeksx ; exit if busy. not al ; set al to complete. seeksx: mov bl,al ; bl = if Rodime-20. include w20 endif if min20 ; if Miniscribe 4020. include wm4020 endif if ota26 ; if Otari C-526. include wo526 endif if ats33 ; if Atasi 33. include w33 endif if q540 ; if Quantum Q540. include wq540 endif if morrow ; if morrow hard disk controller. include morhdc endif if teletek ; if teletek hard disk controller. include telhdc endif if ades ; if ADES hard disk controller. include ades33 endif endif ;*********** ENr,lf endif if nhard gt 0 if morrow db ' Morrow' endif if teletek db ' Teletek' endif db ' controller with ' if rms12 ; if RMS-12. db 'RMS-12' endif if cmi19 ; if CMI-19. db 'CMI-19' endif if rod20 ; if Rodime-20. db 'Rodime-20' endif if min20 ; if Miniscribe 4020. db 'Miniscribe 4020' endif if ota26 ; if Otari C-526. db 'Otari C-526' endif if ats33 ; if Atasi-33. db 'Atasi-33' endif if q540 ; if Quantum Q540. db 'Quantum Q-540' endi0 ; dma abs bits a00-a15. sekdsk db 0 ; selected logical disk. sektrk dw 0 ; track to seek to. mlft dw 0 ; sectors left to transfer. bytcnt dw 0 ; bytes left to transfer. nosecs dw 0 ; number of sectors to transfer. diskto rb 1 ; disk time-out counter. ; disk (hard and floppy) parameters for error message only. erdisk db 0 ; drive letter 0-15. ercyl dw 0 ; physical drive cylinder. erhead db 0 ; head 0-7. ersect db 0 ; sector number. ercode db 0 ; error status. ; Lo endif ; hard disk 4. if nhard gt 5! dw offset dph13! endif ; hard disk 5. if nhard gt 6! dw offset dph14! endif ; hard disk 6. if nhard gt 7! dw offset dph15! endif ; hard disk 7. if nhard gt 8! dw offset dph16! endif ; hard disk 8. if nhard gt 9! dw offset dph17! endif ; hard disk 9. if nhard gt 10! dw offset dph18! endif ; hard disk 10. if nhard gt 11! dw offset dph19! endif ; hard disk 11. ; - 5-inch floppy diskette - unit 0. dph0 equ (offset $) if nflop5 gt 0 dw 0,0,0,0 ;D OF HARD DISK DRIVER AREA ****************** ; bios data area. data_offset equ (offset $) dseg org data_offset ; start of data segment area. ; PC-MODE VARIABLES pcflag db 2 ; pc mode mode: 1=enabled, 2=disabled. shflg db 0 ; shift flag. scmode db 1 ; screen mode. 1 = general alphanumeric. vidatr db 0fh ; video attribute byte. ; Address Table of Poll Device Routines. ; Device numbers are allocated thusly: ; left 3 bits = category of device operation ; right 5 bf if ades ; if ADES-33 db cr,lf,' and ADES controller with PRIAM 3350' endif db ' hard disk',cr,lf endif db 0 ; end of message. trpmsg db cr,lf,7 db 'XIOS detected undefined interrupt' db cr,lf,0 funmsg db cr,lf,7,'Function ',0 submsg db ', subfunction ',0 notmsg db ' not implemented.',cr,lf,0 gnimsg db cr,lf,'Graphics not implemented',0 e6msg db cr,lf,7,'E6 INT',0 errmsg db cr,lf db 'error during ',0 db 'seek: ',0 ; error 0. db 'read: ',0 ; error 1. db 'write:'gical (letter) to physical (number) drive map. ; These should always stay in this order. To change ; the map, change the EQU's at the beginning of BIOS. drvmap db drivea ; drive a number. db driveb ; drive b number. db drivec ; drive c number. db drived ; drive d number. db drivee ; drive e number. db drivef ; drive f number. db driveg ; drive g number. db driveh ; drive h number. db drivei ; drive i number. db drivej ; drive j number. db drivek ; drive k nu translate table, scratch. dw f5sgen ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; 5-inch floppy unit 1. dph1 equ (offset $) if nflop5 gt 1 dw 0,0,0,0 ; translate table, scratch. dw f5dbds ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; 5-inch floppy unit 2. dph2 equ (offset $)its = number within category polltbl dw io_const ; 0: console input. dw io_pollco ; 1: console output. dw io_listst ; 2: printer output. dw io_pollai ; 3: aux input. dw io_pollao ; 4: aux output. dw diskst ; 5: disk read/write. dw seekst ; 6: disk operation. ; System messages. signon db cr,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf db cr,lf,cr,lf,'Duplex 816 XIOS of 1-26-86',cr,lf db '(c) 1986 Tarbell Electronics',cr,lf db 'Support for:',cr,lf db ' ',,0 ; error 2. db 'select:',0 ; error 3. drvmsg db ' drive ',0 db ', cylinder ',0 db ', head ',0 db ', sector ',0 db ', status ',0 ; Local stack for disk i/o routines. rw 100 ; 100 words for stack. dskstk equ $ dskss rw 1 ; old stack segment. dsksp rw 1 ; old stack pointer. ; disk transfer parameters from concurrent stack. mcnt rb 1 ; multi-sector count. drive rb 1 ; drive number. track rw 1 ; cylinder number. sector rw 1 ; sector number. dmaseg rw 1 ; transfer mber. db drivel ; drive l number. db drivem ; drive m number. db driven ; drive n number. db driveo ; drive o number. db drivep ; drive p number. ; ; curspt rw 16 ; current physical sectors/track. curpsh rb 16 ; current physical sector shift factor. oper rb 1 ; 0=seek, 1=read, 2=write disk operation. ; Disk Parameter Header (DPH) address table. ; these tables allow bdos to index the drive attrib info tables. dphtab dw (offset dph0) ; 5-inch floppy 0. dw (offset dph if nflop5 gt 2 dw 0,0,0,0 ; translate table, scratch. dw f5dbds ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; 5-inch floppy unit 3. dph3 equ (offset $) if nflop5 gt 3 dw 0,0,0,0 ; translate table, scratch. dw f5dbds ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; - 8-inch ncrts+'0',' physical console' if ncrts gt 1! db 's'! endif db cr,lf if nvirt gt 1 db ' ',nvirt+'0',' total virtual consoles',cr,lf endif if clock db ' Clock Interrupt',cr,lf endif if conint db ' Console Input Interrupt',cr,lf endif if dtrcon db ' Console Output Handshaking',cr,lf endif if nptrs gt 1 db ' ',nptrs+'0',' printers',cr,lf endif if nflop5 gt 0 db ' ',nflop5+'0',' 5-inch diskettes',cr,lf endif if nflop8 gt 0 db ' ',nflop8+'0',' 8-inch diskettes',csegment. dmaoff rw 1 ; trnasfer offset. ; disk control storage. dens db 0,0,0,0,0,0,0,0 ; density info for 8 floppies. diskno dw 0 ; current disk number and zero byte. trk0 db true ; track 0 Tarbell format flag. trtab db 0,0,0,0,0,0,0,0 ; head position info for 8 floppies. ercnt db 0 ; counter for r/w retrys. sercnt db 0 ; counter for seek retrys. clatch db 0 ; current code in latch. iobyte db 0 ; system i/o redefinition byte. msb20 db 0 ; dma abs bits a16-a19. lsb20 dw 1) ; 5-inch floppy 1. dw (offset dph2) ; 5-inch floppy 2. dw (offset dph3) ; 5-inch floppy 3. dw (offset dph4) ; 8-inch floppy 0. dw (offset dph5) ; 8-inch floppy 1. dw (offset dph6) ; 8-inch floppy 2. dw (offset dph7) ; 8-inch floppy 3. if nhard gt 0! dw offset dph8! endif ; hard disk 0. if nhard gt 1! dw offset dph9! endif ; hard disk 1. if nhard gt 2! dw offset dph10! endif ; hard disk 2. if nhard gt 3! dw offset dph11! endif ; hard disk 3. if nhard gt 4! dw offset dph12!um, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; end condition (nflop>1_true). ; - 8-inch floppy diskette - unit 2. dph6 equ (offset $) if nflop8 gt 2 ; start condition (nflop>2_true). dw 0,0,0,0 ; translate table, scratch. dw f8dbds ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; end condition (nflop>2_true). ; - 8-inch floppy diskette -te table address. dw offset f5p8ds db 00h,00000000b ; default sd ss 128x18 codes. dw offset xlt5 ; translate table address. dw offset f5sdss endif ; 8-inch table of disk parameter block addresses. dpbt8 equ (offset $) if nflop8 gt 0 db 0e7h,00000010b ; Tarbell sd ds 128x26 codes. dw 0 ; translate table address. dw (offset f8sdds) db 0ddh,00000001b ; Tarbell dd ss 128x51 codes. dw 0 ; translate table address. dw (offset f8ddss) db 0dfh,00000011b ; Tarbell dd ds 128tended DPB. dw 2 ; nfats dw 1 ; nfatrecs dw 320 ; nclstrs dw 512*1 ; clsize dw 1 ; fatadd dw 8 ; sectors per track db 3 ; cp/m block shift db 7 ; cp/m block mask db 0 ; cp/m extnt mask dw 159 ; cp/m disk size in 1k blocks dw 63 ; directory max db 0 ; cp/m alloc0 db 0 ; cp/m alloc1 dw 16 ; check size dw 0 ; offset db 2 ; phys sec shift db 3 ; phys sec mask ; 5-inch PC-DOS 512 x 8 double density doubl 0 ; cp/m alloc1 dw 16 ; check size dw 0 ; offset db 2 ; phys sec shift db 3 ; phys sec mask ; 5-inch Tarbell 512 x 10 double density single sided floppy. f5dbss dw 10 ; physical sectors per track. db 4 ; block shift factor. db 15 ; block mask. db 0 ; null mask. dw 94 ; disk size-1. dw 81 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 32 ; check size. dw 2 ; track offset. db 2 ; physical record shift. db 3 ; physical record mask. unit 3. dph7 equ (offset $) if nflop8 gt 3 ; start condition (nflop>3_true). dw 0,0,0,0 ; translate table, scratch. dw f8dbds ; io_seldsk puts DPB address here. dw 0ffffh,0ffffh ; checksum, allocation vectors. dw 0ffffh,0ffffh,0ffffh ; DIRBCB, DATBCB, TBLSEG. endif ; end condition (nflop>3_true). ; Disk Parameter Blocks (DPB's). ; these tables define the drive physical attributes. ; 5-inch table of disk parameter block addresses. ; 6 bytes per entry: ; 1 byte for cx51 codes. dw 0 ; translate table address. dw (offset f8ddds) db 0deh,00000101b ; Tarbell dd ss 512x16 codes. dw 0 ; translate table address. dw (offset f8dbss) db 0dch,00000111b ; Tarbell dd ds 512x16 codes. dw 0 ; translate table address. dw (offset f8dbds) db 00h,00000000b ; DR/IBM sd ss 128x26 codes. dw offset xlt8 ; translate table address. dw (offset f8sdss) endif if nflop5 gt 0 ; 5-inch disk parameter blocks. ; 5-inch dummy DPB for genccpm process only. e sided floppy. f5p8ds dw 0ffffh ; DOS media - extended DPB. dw 2 ; nfats dw 1 ; nfatrecs dw 320 ; nclstrs dw 512*2 ; clsize dw 1 ; fatadd dw 8 ; sectors per track db 3 ; cp/m block shift db 7 ; cp/m block mask db 0 ; cp/m extnt mask dw 320-1 ; cp/m disk size in 1k blocks dw 111 ; directory max db 0 ; cp/m alloc0 db 0 ; cp/m alloc1 dw 16 ; check size dw 0 ; offset db 2 ; phys sec shift db 3 ; phys s ; 5-inch Tarbell 512 x 10 double density, double sided floppy. f5dbds dw 10 ; physical sectors per track. db 5 ; block shift factor. db 31 ; block mask. db 0 ; extent mask. dw 94 ; disk size - 1. dw 81 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 32 ; check size. dw 2 ; track offset. db 2 ; physical record shift. db 3 ; physical record mask. ; 5-inch 128 x 18 single density, single sided floppy. f5sdss dw 18 ; physical sectors per track. db 3 ode that is read from track 0 ; 1 byte for internal density/sides code ; 1 word for translate table address (0 if none) ; 1 word for disk parameter block address dpbt5 equ (offset $) if nflop5 gt 0 db 01,00001101b ; DR/IBM dd ss 8-sector codes. dw 0 ; translate table address. dw offset f5i8ss db 02,00001111b ; DR/IBM dd ds 8-sector codes. dw 0 ; translate table address. dw offset f5i8ds db 0deh,00000101b ; Tarbell dd ss 512x10 codes. dw 0 ; translate table address. dw f5sgen dw 8 db 3 db 7 db 0 dw 157 dw 255 db 10000000b db 0 dw 16 dw 1 db 2 db 3 ; 5-inch DR/IBM 512 x 8 double density single sided floppy. f5i8ss dw 8 ; physical sectors per track. db 3 ; block shift factor. db 7 ; block mask. db 0 ; null mask. dw 155 ; disk size - 1. dw 63 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 1 ; track offset. db 2 ; physical record shift. db 3 ; physical record mask. ; 5-inch DR/ec mask ; 5-inch PC-DOS 512 x 9 double density sяngle sided floppy. f5p9ss dw 0ffffh ; DOS media - extended DPB. dw 2 ; nfats dw 2 ; nfatrecs dw 360 ; nclstrs dw 512*1 ; clsize dw 1 ; fatadd dw 9 ; sectors per track db 3 ; cp/m block shift db 7 ; cp/m block mask db 0 ; cp/m extnt mask dw 179 ; cp/m disk size in 1k blocks dw 63 ; directory max db 0 ; cp/m alloc0 db 0 ; cp/m alloc1 dw 16 ; check size dw ; block shift factor. db 7 ; block mask. db 0 ; null mask. dw 71 ; disk size - 1. dw 63 ; directory max. db 11000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 3 ; track offset. db 0 ; physical record shift. db 0 ; physical record mask. endif ; end of 5-inch disk parameter blocks. if nflop8 gt 0 ; 8-inch disk parameter blocks. ; 8-inch single density, double sided floppy diskette. f8sdds dw 26 ; physical sectors per track. db 0004 ; block shift. d offset f5dbss db 0dch,00000111b ; Tarbell dd ds 512x10 codes. dw 0 ; translate table address. dw offset f5dbds db 0fch,00010101b ; PC-DOS dd ss 9-sector codes. dw 0 ; translate table address. dw offset f5p9ss db 0fdh,00010111b ; PC-DOS dd ds 9-sector codes. dw 0 ; translate table address. dw offset f5p9ds db 0feh,00010101b ; PC-DOS dd ss 8-sector codes. dw 0 ; translate table address. dw offset f5p8ss db 0ffh,00010111b ; PC-DOS dd ds 8-sector codes. dw 0 ; translaIBM 512 x 8 double density double sided floppy. f5i8ds dw 8 ; physical sectors per cylinder. db 4 ; block shift factor for 2k blocks. db 15 ; block mask for 2k blocks. db 1 ; null mask. dw 009dh ; disk size - 1. dw 63 ; directory max. db 10000000b ; alloc 0. db 0 ; alloc 1. dw 16 ; check size. dw 1 ; track offset. db 2 ; physical record shift. db 3 ; physical record mask. ; 5-inch PC-DOS 512 x 8 double density single sided floppy. f5p8ss dw 0ffffh ; DOS media - ex0 ; offset db 2 ; phys sec shift db 3 ; phys sec mask ; 5-inch PC-DOS 512 x 9 double density double sided floppy. f5p9ds dw 0ffffh ; DOS media - extended DPB. dw 2 ; nfats dw 2 ; nfatrecs dw 360 ; nclstrs dw 512*2 ; clsize dw 1 ; fatadd dw 9 ; sectors per track db 3 ; cp/m block shift db 7 ; cp/m block mask db 0 ; cp/m extnt mask dw 360-1 ; cp/m disk size in 1k blocks dw 111 ; directory max db 0 ; cp/m alloc0 db db 0192 ; alloc0. db 0000 ; alloc1. dw 0032 ; check size. dw 0002 ; number of system tracks. db 0 ; physical record shift. db 0 ; physical record mask. ; 8-inch double density, double sided floppy diskette. f8ddds dw 51 ; physical sectors per track. db 0005 ; block shift. db 0031 ; block mask. db 0000 ; extnt mask. dw 0237 ; disk size - 1. dw 0095 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0024 ; check size. dw 0002 ; number of system tracksb 21,02,08,14,20,26 db 06,12,18,24,04,10 db 16,22 endif ; Screen Tables. forgnd db 0 ; foreground console number. if ncrts gt 1 db nvirt0 endif if ncrts gt 2 db nvirt0+nvirt1 endif if ncrts gt 3 db nvirt0+nvirt1+nvirt2 endif if ncrts gt 4 db nvirt0+nvirt1+nvirt2+nvirt3 endif if ncrts gt 5 db nvirt0+nvirt1+nvirt2+nvirt3+nvirt4 endif if ncrts gt 6 db nvirt0+nvirt1+nvirt2+nvirt3+nvirt4+nvirt5 endif if ncrts gt 7 db nvirt0+nvirt1+nvirt2+nvirt3+nvirt4+nvir gt 11 dw scbufB endif if nvirt gt 12 dw scbufC endif if nvirt gt 13 dw scbufD endif if nvirt gt 14 dw scbufE endif if nvirt gt 15 dw scbufF endif endif ; Buffers. chkbuf rb chksiz ; buffer to check disk density code. ; SCREEN BUFFERS - one for each virtual console. if vcsbuf ; if virtual console screen buffers. scbuf0 rw maxcol*maxrow ; screen buffer. if nvirt gt 1 scbuf1 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 2 scbuf2 rw maxcol*m position to put character. dw cibuf0 ; next position to get character. if ncrts gt 1 dw offset cibuf1 ; console 1 input buffer adr. dw offset cibuf1+cibmax-1 ; buffer max position. dw cibuf1 ; next position to put character. dw cibuf1 ; next position to get character. endif if ncrts gt 2 dw offset cibuf2 ; console 2 input buffer adr. dw offset cibuf2+cibmax-1 ; buffer max position. dw cibuf2 ; next position to put character. dw cibuf2 ; next position to get character. db 0 ; physical record shift. db 0 ; physical record mask. ; 8-inch 512 x 16 single sided diskette. f8dbss dw 16 ; physical sectors per track. db 0004 ; block shift. db 0015 ; block mask. db 0000 ; extnt mask. dw 0299 ; disk size - 1. dw 0127 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0032 ; check size. dw 0002 ; number of system tracks. db 2 ; physical record shift. db 3 ; physical record mask. ; 8-inch 512 x 16 double sided diskette. f8dt5+nvirt6 endif curpos rw nvirt ; cursor position table. vpcont db 0 ; virtual-to-physical console table. if nvirt0 gt 1! db 0! endif if nvirt0 gt 2! db 0! endif if nvirt0 gt 3! db 0! endif if ncrts gt 1 db 1 if nvirt1 gt 1! db 1! endif if nvirt1 gt 2! db 1! endif if nvirt1 gt 3! db 1! endif endif if ncrts gt 2 db 2 if nvirt2 gt 1! db 2! endif if nvirt2 gt 2! db 2! endif if nvirt2 gt 3! db 2! endif endif if ncrts gt 3 db 3 if nvirt3 gt 1! db 3! endif if nvirt3 gaxrow ; screen buffer. endif if nvirt gt 3 scbuf3 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 4 scbuf4 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 5 scbuf5 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 6 scbuf6 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 7 scbuf7 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 8 scbuf8 rw maxcol*maxrow ; screen buffer. endif if nvirt gt 9 scbuf9 rw maxcol*maxrow ; screen buffer. endif if nvirt . endif if ncrts gt 3 dw offset cibuf3 ; console 3 input buffer adr. dw offset cibuf3+cibmax-1 ; buffer max position. dw cibuf3 ; next position to put character. dw cibuf3 ; next position to get character. endif if ncrts gt 4 dw offset cibuf4 ; console 4 input buffer adr. dw offset cibuf4+cibmax-1 ; buffer max position. dw cibuf4 ; next position to put character. dw cibuf4 ; next position to get character. endif if ncrts gt 5 dw offset cibuf5 ; console 5 input bds dw 16 ; physical sectors per track. db 0005 ; block shift. db 0031 ; block mask. db 0000 ; extnt mask. dw 0303 ; disk size - 1. dw 0169 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 42 ; check size. dw 0002 ; number of system tracks. db 2 ; physical record shift. db 3 ; physical record mask. ; 8-inch single density, single sided floppy diskette. f8sdss dw 26 ; physical sectors per track. db 0003 ; block shift. db 0007 ; block mask. db 0000 ; et 2! db 3! endif if nvirt3 gt 3! db 3! endif endif if ncrts gt 4 db 4 if nvirt4 gt 1! db 4! endif if nvirt4 gt 2! db 4! endif if nvirt4 gt 3! db 4! endif endif if ncrts gt 5 db 5 if nvirt5 gt 1! db 5! endif if nvirt5 gt 2! db 5! endif if nvirt5 gt 3! db 5! endif endif if ncrts gt 6 db 6 if nvirt6 gt 1! db 6! endif if nvirt6 gt 2! db 6! endif if nvirt6 gt 3! db 6! endif endif if ncrts gt 7 db 7 if nvirt7 gt 1! db 7! endif if nvirt7 gt 2! db 7! endif if nvirt7gt 10 scbufA rw maxcol*maxrow ; screen buffer. endif if nvirt gt 11 scbufB rw maxcol*maxrow ; screen buffer. endif if nvirt gt 12 scbufC rw maxcol*maxrow ; screen buffer. endif if nvirt gt 13 scbufD rw maxcol*maxrow ; screen buffer. endif if nvirt gt 14 scbufE rw maxcol*maxrow ; screen buffer. endif if nvirt gt 15 scbufF rw maxcol*maxrow ; screen buffer. endif endif ; console input interrupt buffers. if conint ; if console interrupts. cibuf0 rb cibmax ; cbuffer adr. dw offset cibuf5+cibmax-1 ; buffer max position. dw cibuf5 ; next position to put character. dw cibuf5 ; next position to get character. endif if ncrts gt 6 dw offset cibuf6 ; console 6 input buffer adr. dw offset cibuf6+cibmax-1 ; buffer max position. dw cibuf6 ; next position to put character. dw cibuf6 ; next position to get character. endif if ncrts gt 7 dw offset cibuf7 ; console 7 input buffer adr. dw offset cibuf7+cibmax-1 ; buffer max position. dxtnt mask. dw 0242 ; disk size - 1. dw 0063 ; directory max. db 0192 ; alloc0. db 0000 ; alloc1. dw 0016 ; check size. dw 0002 ; number of system tracks. db 0 ; physical record shift. db 0 ; physical record mask. endif ; end of 8-inch disk parameter blocks. ; Sector translation tables. ; 5-inch if nflop5 gt 0 xlt5 db 1,4,7,10,13,16 db 2,5,8,11,14,17 db 3,6,9,12,15,18 endif ; 8-inch if nflop8 gt 0 xlt8 db 01,07,13,19,25,05 db 11,17,23,03,09,15 d gt 3! db 7! endif endif scbuft equ $ if vcsbuf ; if virtual console screen buffers. dw scbuf0 ; screen buffer address table. if nvirt gt 1 dw scbuf1 endif if nvirt gt 2 dw scbuf2 endif if nvirt gt 3 dw scbuf3 endif if nvirt gt 4 dw scbuf4 endif if nvirt gt 5 dw scbuf5 endif if nvirt gt 6 dw scbuf6 endif if nvirt gt 7 dw scbuf7 endif if nvirt gt 8 dw scbuf8 endif if nvirt gt 9 dw scbuf9 endif if nvirt gt 10 dw scbufA endif if nvirtonsole 0 input buffer. if ncrts gt 1 cibuf1 rb cibmax ; console 1 input buffer. endif if ncrts gt 2 cibuf2 rb cibmax ; console 2 input buffer. endif if ncrts gt 3 cibuf3 rb cibmax ; console 3 input buffer. endif if ncrts gt 4 cibuf4 rb cibmax ; console 4 input buffer. endif if ncrts gt 5 cibuf5 rb cibmax ; console 5 input buffer. endif cibtab dw offset cibuf0 ; console 0 input buffer adr. dw offset cibuf0+cibmax-1 ; buffer max position. dw cibuf0 ; nextnumber. ; Third byte of each entry is input ready mask. ; Fourth byte of each entry is output ready mask. cnstbl dw consts ; console 0 status port. db conrda,contbe ; console 0 status masks. dw spbase+1 ; console 1 status port. db spimsk,spomsk ; console 1 status masks. dw spbase+3 ; console 2 status port. db spimsk,spomsk ; console 2 status masks. dw spbase+5 ; console 3 status port. db spimsk,spomsk ; console 3 status masks. dw spbase+7 ; console 4 status port. db spimsk,spomsk ;outine. stkbase equ (offset $) ; define stack base address. if clock rw 32 ; tick interrupt stack. ticktos rw 0 ; top of stack. endif if conint rw 32 ; console input interrupt stack. cistkb rw 0 ; stack base. endif lastoff equ (offset $) ; last used area address. tpaseg equ (lastoff+0400h+15) / 16 tpalen equ 0800h - tpaseg ; compute start and length of main tpa. db 0 ; fill to last for gencmd. ; assign external address locations. dseg 0 ; obtain absolute low memory.; Tarbell Duplex 816 BOOT Module for Concurrent CP/M-86. ; Will work for CP/M-86 also, but note it requires 128K minimum. ; Copyright (c) 1984, Tarbell Electronics ; Last changed 10-28-84 by Don Tarbell ; logical equates false equ 0 true equ not false dubsid equ false ; this disk double sided? mini equ false ; true for 5-inch floppy disks. ; memory addresses. bootad equ 200h ; address of this module. lodseg equ 1e00h ; segment to load the sectors. lsb20 equ lodseg shl 4 ; lower 16 of 2,ax mov sp,bootad+100h ; put stack above this module. ; set up the 80186 dma controller. mov dx,dmaspu0 ; source upper port. out dx,ax ; source upper port=0. mov ax,msb20 ; get upper 4 bits of 20-bit load address. mov dx,dmadpu0 ; destination upper. out dx,ax ; upper 4 bits of abs adr. mov ax,lsb20 ; get lower 16 bits of 20-bit load address. mov dx,dmadpl0 ; destination lower. out dx,ax ; lower 16 bits of abs adr. mov ax,nbytes-t0bps ; get number of bytes to move. mov dx,dmatc0 console 4 status masks. dw spbase+11 ; console 5 status port. db spimsk,spomsk ; console 5 status masks. ; Console Data Port Address Table. cndtbl dw condat ; console 0 data port. dw spbase ; console 1 data port. dw spbase+2 ; console 2 data port. dw spbase+4 ; console 3 data port. dw spbase+6 ; console 4 data port. dw spbase+10 ; console 5 data port. ; List status port and mask table. lpstbl dw lptsts ; list device 0 status port. db 0,lpttbe ; list device 0 status mask. org 0 ; for interrupt vector ini info. int0_offset rw 1 ; interrupt offset address. int0_segment rw 1 ; interrupt segment address. rw 2*(bdos_int-1) ; pad to the system entry vector. ; end fset $) ; last used area address. tpaseg equ (lastoff+0400h+15) / 16 tpalen equ 0800h - tpaseg ; compute start and length of main tpa. db 0 ; fill to last for gencmd. ; assign external address locations. dseg 0 ; obtain absolute low memory.0-bit load address. msb20 equ lodseg shr 12 ; upper 4 of 20-bit load address. nxtseg equ lodseg ; next segment to execute. ; sector and byte counts. if not mini ; if 8-inch floppy. t0spt equ 26 ; track 0 sectors per track. t1spt equ 16 ; track 1 sectors per track. fsize equ 0ch ; bits 2 & 3 high for 8-inch. endif if mini ; if 5-inch floppy. t0spt equ 18 ; track 0 sectors per track. t1spt equ 10 ; track 1 sectors per track. fsize equ 00h ; bits 2 & 3 low for latch. endif t0; transfer count. out dx,ax mov ax,fdmard ; dma command. mov dx,dmacon0 ; dma control port. out dx,ax ; arm the dma. ; set up 2793 floppy controller. mov dx,fcont ; get control register port. mov al,10h+fsize ; get single density code for latch. out dx,al ; do it. mov bh,2 ; init track count = 2. mov bl,t0spt+1 ; track 0 last sector + 1. mov al,2 ; set starting sector = 2. rdtrk: mov dx,fsect ; get sector port. out dx,al ; write al to sector port. mov al,94h ; read multipl dw spbase+7 ; list device 1 status port. db 0,spomsk ; list device 1 status mask. dw spbase+15 ; list device 2 status port. db 0,spomsk ; list device 2 status mask. dw spbase+11 ; list device 3 status port. db 0,spomsk ; list device 3 status mask. dw spbase+5 ; list device 4 status mask. db 0,spomsk ; list device 4 status mask. ; List device data port table. lpdtbl dw lptdat ; list device 0 data port. dw spbase+6 ; list device 1 data port. dw spbase+14 ; list device 2 data portееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееbps equ 128 ; track 0 bytes per sector. t1bps equ 512 ; track 1 bytes per sector. t0bpt equ t0spt * t0bps ; track 0 bytes per track. t1bpt equ t1spt * t1bps ; track 1 bytes per track. nbytes equ t0bpt + t1bpt ; total bytes on system tracks. ; 2793 floppy interface port addresses. pcsbas equ 0f000h ; peripheral register base adr. fbase equ pcsbas + 80h ; 2793 floppy ic base address. fdisk equ fbase ; command/status port. fsect equ fbase + 4 ; sector port. fcont equ pcsbas + 100h ; control poe sectors. mov dx,fdisk ; get command port number. out dx,al ; commence multi-sector read. call delay ; fool around a little. ; wait for track completion. sectlp: mov dx,fsect ; get sector port address. in al,dx ; read sector number. cmp al,bl ; is it past last one yet? jnz sectlp ; keep checking if not. ; terminate multi-sector read operation. mov al,0d0h ; code to force interrupt. mov dx,fdisk ; command port address. out dx,al ; force interrupt. call delay ; wait for g. dw spbase+10 ; list device 3 data port. dw spbase+2 ; list device 4 data port. dispatch rw 2 ; entry address of dispatcher. intssreg rw 1 ; stack segment of calling routine. intspreg rw 1 ; stack pointer of calling routine. ; SID's interrupt vectors are stored here during init. vec1_off dw 0 ; interrupt vector 1. vec1_seg dw 0 vec3_off dw 0 ; interrupt vector 3. vec3_seg dw 0 vece1_off dw 0 ; interrupt vector e1. vece1_seg dw 0 ; Local Stacks. rw 32 ; stack for initialization rееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееrt. ; 80186 dma port addresses. conbas equ 0ff00h ; control block base after reset. dmacon0 equ conbas+0cah ; control word. dmatc0 equ conbas+0c8h ; transfer count. dmadpu0 equ conbas+0c6h ; destination pointer upper. dmadpl0 equ conbas+0c4h ; destination pointer lower. dmaspu0 equ conbas+0c2h ; source pointer upper. dmaspl0 equ conbas+0c0h ; source pointer lower. fdmard equ 0a266h ; dma floppy to memory code. cseg org bootad xor ax,ax ; clear segment registers. mov ds,ax mov ssd al,80h ; is it still busy stepping? jnz steplp ; loop back if so. endif if dubsid ; if double-sided disk. mov al,40h+fsize ; get side-one latch code. mov dx,fcont ; get control reg port adr. out dx,al ; flip to other side. endif ; prepare to read next track. mov bl,t1spt+1 ; get last sector + 1. mov al,1 ; get first sector number. jmps rdtrk ; loop back and read track. ; Provide some delay for status valid, etc. delay: mov cx,1000h ; initialize counter. delayl: loop; Tarbell CP/M-86 Bios for Duplex 816 Board ; Copyright (c) 1983, 1984 by Tarbell Electronics. ; Last changed 6-24-84 by Don Tarbell. ; truth equates. true equ -1 ; value of true for assembler. false equ not true ; value of false for assembler. loader equ true ; true if loader bios / false if system bios. mpmldr equ false ; true if MP/M-86 loader bios. sizmem equ true ; true if size cp/m-86 for maximum memory. chksiz equ 128 ; bytes/sector on track 0. dual equ false ; true if perscint equ 2 ; fdc seek retry count. pcsbas equ 0f000h ; peripheral ports base address. ; console port addresses and mask bytes. cbase equ pcsbas+180h ; port base address. condat equ cbase+06h ; data port. consts equ cbase+02h ; status port. contbe equ 04h ; transmit buffer empty mask. conrda equ 01h ; receive data available mask. conpos equ true ; true if positive logic. ; printer port addresses and mask bytes. lbase equ pcsbas+190h ; port base address. lptdat equ lbase+06h ; data por/trk hstblk equ hstsiz/128 ;CP/M sects/host buff ; secshf equ 2 ;log2(hstblk) cpmspt equ hstblk * hstspt ;CP/M sectors/track secmsk equ hstblk-1 ;sector mask ; Bdos constants on entry to write wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ; define address refs for system or loader. bdos_int equ 224 ; reserved bdos interrupt. if not loader ; start condition (loader_false). bios_code equ 2500h ; offset to start of bios within s delayl ; decrement until zero. ret ; Define the density selection byte. org bootad+7dh if not dubsid ; if not double-sided. db not(0deh), 0deh endif if dubsid ; if double-sided. db not(0dch), 0dch endif ; Define entry point of secondary loader. cseg nxtseg org 0 entry: end  back and read track. ; Provide some delay for status valid, etc. delay: mov cx,1000h ; initialize counter. delayl: loop drives. ; Define number and kind of disk drives on system. nflop8 equ 2 ; number of 8-inch floppy drives. nflop5 equ 0 ; number of 5-inch floppy drives. nhard equ 0 ; number of hard disk drives. mcmi19 equ false ; true for Morrow and CMI-19 hard disk. mq540 equ false ; true for Morrow and Quantum Q540. ; define which drives are 8-inch and which are 5-inch. ; 5-inch floppy drives are numbered 0-3, 8-inch from 4-7. ; Hard disk drives are numbered from 8-0feh. ; Undefined drive lettet. lptsts equ lbase+02h ; status port. lptcom equ lbase+04h ; command port. lptinp equ lbase+0ah ; input port (for both channels). lptdsr equ 40h ; bit 6 of lptdat = 0 for dsr ready. lpttbe equ 04h ; transmit buffer empty mask. lptrda equ 01h ; receive data available mask. lbaud equ 0bh ; Baud Rate: b=9600, c=19200. ; Floppy disk controller port addresses. fbase equ pcsbas+80h ; 2793 base address. fdisk equ fbase ; command/status port. ftrk equ fbase+2 ; track port. fsect equ fbase+4egment. ccp_offset equ 0000h ; offset to base of cp/m within segment. bdos_ofst equ 0b06h ; offset to bdos entry point within segment. endif ; end condition (loader_false). if loader ; start condition (loader_true). bios_code equ 1200h ; offset to start of bios within segment. if not mpmldr ; if not mp/m loader. ccp_offset equ 0003h ; offset to base of cp/m within segment. endif if mpmldr ; if mp/m loader. ccp_offset equ 0103h ; offset to base of mp/m within segment. endif bdos_ofst ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееrs are numbered 0ffh. drivea equ 4 ; drive a is 8-inch drive 0. driveb equ 5 ; drive b is 8-inch drive 1. drivec equ 0 ; drive c is 5-inch drive 0. drived equ 1 ; drive d is 5-inch drive 1. drivee equ 8 ; drive e is hard disk. drivef equ 0ffh ; drive f is undefined. driveg equ 0ffh ; drive g is undefined. driveh equ 0ffh ; drive h is undefined. drivei equ 0ffh ; drive i is undefined. drivej equ 0ffh ; drive j is undefined. drivek equ 0ffh ; drive k is undefined. drivel equ 0ffh ; d ; sector port. fdata equ fbase+6 ; data port. fcont equ pcsbas+100h ; control port. ; Floppy DMA port addresses and command words. dmabas equ pcsbas+0fc0h ; dma controller base adr. dmacon0 equ dmabas+0ah ; control port. dmatc0 equ dmabas+08h