page 0 ORG 0000H ; ; Note: this module assumes that an ORG statement will be ; provided by concatenating either BASE0000.ASM or BASE0100.ASM ; to the front of this file before assembling. ; ; title 'Xios for the MDS-800' ; (four drive single density version) ; -or- ; (four drive mixed double/single density) ; Version 1.1 January, 1980 ; Copyright (C) 1979, 1980 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 false equ 0 true equ not false asm equ true mac equ not asm sgl equ true dbl equ not sgl if mac maclib diskdef endif numdisks equ 4 ;number of drives available ; external jump table (below xios base) pdisp equ $-3 xdos equ pdisp-3 ; mds interrupt controller equates revrt equ 0fdh ; revert port intc equ 0fch ; mask port icon equ 0f3h ; control port rtc equ 0ffh ; real time clock inte equ 1111$1101b ; enable rst 1 ; mds disk controller equates dskbase equ 78h ; base of disk io prts dstat equ dskbase ; disk status rtype equ dskbase+1 ; result type rbyte equ dskbase+3 ; result byte ilow equ dskbase+1 ; iopb low address ihigh equ dskbase+2 ; iopb high address readf equ 4h ; read function writf equ 6h ; write function iordy equ 4h ; i/o finished mask retry equ 10 ; max retries on disk i/o ; basic i/o system jump vector jmp coldstart ;cold start wboot: jmp warmstart ;warm start jmp const ;console status jmp conin ;console character in jmp conout ;console character out jmp list ;list character out jmp rtnempty ;punch not implemented jmp rtnempty ;reader not implemented jmp home ;move head to home jmp seldsk ;select disk jmp settrk ;set track number jmp setsec ;set sector number jmp setdma ;set dma address jmp read ;read disk jmp write ;write disk jmp pollpt ;list status jmp sect$tran ;sector translate ; extended i/o system jump vector jmp selmemory ; select memory jmp polldevice ; poll device jmp startclock ; start clock jmp stopclock ; stop clock jmp exitregion ; exit region jmp maxconsole ; maximum console number jmp systeminit ; system initialization jmp idle ; idle procedure coldstart: warmstart: mvi c,0 ; see system init ; cold & warm start included only ; for compatibility with cp/m jmp xdos ; system reset, terminate process ; MP/M 1.0 console handlers nmbcns equ 2 ; number of consoles poll equ 131 ; xdos poll function pllpt equ 0 ; poll printer pldsk equ 1 ; poll disk plco0 equ 2 ; poll console out #0 (CRT:) plco1 equ 3 ; poll console out #1 (TTY:) plci0 equ 4 ; poll console in #0 (CRT:) plci1 equ 5 ; poll console in #1 (TTY:) ; const: ; console status call ptbljmp ; compute and jump to hndlr dw pt0st ; console #0 status routine dw pt1st ; console #1 (TTY:) status rt conin: ; console input call ptbljmp ; compute and jump to hndlr dw pt0in ; console #0 input dw pt1in ; console #1 (TTY:) input conout: ; console output call ptbljmp ; compute and jump to hndlr dw pt0out ; console #0 output dw pt1out ; console #1 (TTY:) output ; ptbljmp: ; compute and jump to handler ; d = console # ; do not destroy mov a,d cpi nmbcns jc tbljmp pop psw ; throw away table address rtnempty: xra a ret tbljmp: ; compute and jump to handler ; a = table index add a ; double table index for adr offst pop h ; return adr points to jump tbl mov e,a mvi d,0 dad d ; add table index * 2 to tbl base mov e,m ; get handler address inx h mov d,m xchg pchl ; jump to computed cns handler ; ascii character equates rubout equ 7fh space equ 20h ; serial i/o port address equates data0 equ 0f6h sts0 equ data0+1 data1 equ 0f4h sts1 equ data1+1 lptport equ 0fah lptsts equ lptport+1 ; poll console #0 input polci0: pt0st: ; return 0ffh if ready, ; 000h if not in sts0 ani 2 rz mvi a,0ffh ret ; ; console #0 input ; pt0in: ; return character in reg a mvi c,poll mvi e,plci0 call xdos ; poll console #0 input in data0 ; read character ani 7fh ; strip parity bit ret ; ; console #0 output ; pt0out: ; reg c = character to output in sts0 ani 01h jnz co0rdy push b call pt0wait ; poll console #0 output pop b co0rdy: mov a,c out data0 ; transmit character ret ; ; wait for console #0 output ready ; pt0wait: mvi c,poll mvi e,plco0 jmp xdos ; poll console #0 output ; ret ; ; poll console #0 output ; polco0: ; return 0ffh if ready, ; 000h if not in sts0 ani 01h rz mvi a,0ffh ret ; ; ; line printer driver: ; list: ; list output in lptsts ani 01h jnz lptrdy push b mvi c, poll mvi e, pllpt call xdos pop b lptrdy: mov a,c cma out lptport ret ; ; poll printer output ; pollpt: ; return 0ffh if ready, ; 000h if not in lptsts ani 01h rz mvi a,0ffh ret ; ; poll console #1 (TTY:) input ; polci1: pt1st: ; return 0ffh if ready, ; 000h if not in sts1 ani 2 rz mvi a,0ffh ret ; ; console #1 (TTY:) input ; pt1in: ; return character in reg a mvi c,poll mvi e,plci1 call xdos ; poll console #1 input in data1 ; read character ani 7fh ; strip parity bit ret ; ; console #1 (TTY:) output ; pt1out: in sts1 ani 01h jnz co1rdy ; reg c = character to output push b call pt1wait pop b co1rdy: mov a,c out data1 ; transmit character ret ; wait for console #1 (TTY:) output ready pt1wait: mvi c,poll mvi e,plco1 jmp xdos ; poll console #1 output ; ret ; poll console #1 (TTY:) output polco1: ; return 0ffh if ready, ; 000h if not in sts1 ani 01h rz mvi a,0ffh ret ; ; ; MP/M 1.0 extended i/o system ; ; nmbdev equ 6 ; number of devices in poll tbl polldevice: ; reg c = device # to be polled ; return 0ffh if ready, ; 000h if not mov a,c cpi nmbdev jc devok mvi a,nmbdev; if dev # >= nmbdev, ; set to nmbdev devok: call tbljmp ; jump to dev poll code dw pollpt ; poll printer output dw poldsk ; poll disk ready dw polco0 ; poll console #0 output dw polco1 ; poll console #1 (TTY:) output dw polci0 ; poll console #0 input dw polci1 ; poll console #1 (TTY:) input dw rtnempty; bad device handler ; select / protect memory selmemory: ; reg bc = adr of mem descriptor ; bc -> base 1 byte, ; size 1 byte, ; attrib 1 byte, ; bank 1 byte. ; this hardware does not have memory protection or ; bank switching ret ; start clock startclock: ; will cause flag #1 to be set ; at each system time unit tick mvi a,0ffh sta tickn ret ; stop clock stopclock: ; will stop flag #1 setting at ; system time unit tick xra a sta tickn ret ; exit region exitregion: ; ei if not preempted lda preemp ora a rnz ei ret ; maximum console number maxconsole: mvi a,nmbcns ret ; system initialization systeminit: ; note: this system init assumes that the usarts ; have been initialized by the coldstart boot ; setup restart jump vectors mvi a,0c3h sta 1*8 lxi h,int1hnd shld 1*8+1 ; jmp int1hnd at restart 1 ; setup interrupt controller & real time clock mvi a,inte out intc ; enable int 0,1,7 xra a out icon ; clear int mask out rtc ; enable real time clock ret ; ; Idle procedure ; idle: mvi c,dsptch jmp xdos ; perform a dispatch, this form ; of idle must be used in systems ; without interrupts, i.e. all polled ; -or- ; ei ; simply halt until awaken by an ; hlt ; interrupt ; ret ; MP/M 1.0 interrupt handlers flagset equ 133 dsptch equ 142 int1hnd: ; interrupt 1 handler entry point ; ; location 0008h contains a jmp ; to int1hnd. push psw mvi a,2h out rtc ; reset real time clock out revrt ; revert intr cntlr lda slice dcr a ; only service every 16th slice sta slice jz t16ms ; jump if 16ms elapsed pop psw ei ret t16ms: mvi a,16 sta slice ; reset slice counter pop psw shld svdhl pop h shld svdret push psw lxi h,0 dad sp shld svdsp ; save users stk ptr lxi sp,intstk+48 ; lcl stk for intr hndl push d push b mvi a,0ffh sta preemp ; set preempted flag lda tickn ora a ; test tickn, indicates ; delayed process(es) jz notickn mvi c,flagset mvi e,1 call xdos ; set flag #1 each tick notickn: lxi h,cnt64 dcr m ; dec 64 tick cntr jnz not1sec mvi m,64 mvi c,flagset mvi e,2 call xdos ; set flag #2 @ 1 sec not1sec: xra a sta preemp ; clear preempted flag pop b pop d lhld svdsp sphl ; restore stk ptr pop psw lhld svdret push h lhld svdhl ; the following dispatch call will force round robin ; scheduling of processes executing at the same priority ; each 1/64th of a second. ; note: interrupts are not enabled until the dispatcher ; resumes the next process. this prevents interrupt ; over-run of the stacks when stuck or high frequency ; interrupts are encountered. jmp pdisp ; MP/M dispatch ; ; bios data segment ; slice: db 16 ; 16 slices = 16ms = 1 tick cnt64: db 64 ; 64 tick cntr = 1 sec intstk: ds 48 ; local intrpt stk svdhl: dw 0 ; saved regs hl during int hndl svdsp: dw 0 ; saved sp during int hndl svdret: dw 0 ; saved return during int hndl tickn: db 0 ; ticking boolean,true = delayed preemp: db 0 ; preempted boolean ; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Intel MDS-800 diskette interface routines * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * seldsk: ;select disk given by register c lxi h, 0 mov a,c cpi numdisks rnc ; first, insure good select ani 2 sta dbank ; then save it lxi h,sel$table mvi b,0 dad b mov a,m sta iof mov h,b mov l,c dad h dad h dad h dad h ; times 16 lxi d,dpbase dad d ret home: ;move to home position ; treat as track 00 seek mvi c,0 ; settrk: ;set track address given by c lxi h,iot mov m,c ret ; setsec: ;set sector number given by c mov a,c ;sector number to accum sta ios ;store sector number to iopb ret ; setdma: ;set dma address given by regs b,c mov l,c mov h,b shld iod ret sect$tran: ; translate the sector # in if needed mov h,b mov l,c inx h ; in case of no translation mov a, d ora e rz xchg dad b ; point to physical sector mov l,m mvi h,0 ret read: ;read next disk record (assuming disk/trk/sec/dma set) mvi c,readf ;set to read function jmp setfunc ; write: ;disk write function mvi c,writf ; setfunc: ; set function for next i/o (command in reg-c) lxi h,iof ;io function address mov a,m ;get it to accumulator for masking ani 1111$1000b ;remove previous command ora c ;set to new command mov m,a ;replaced in iopb ; single density drive 1 requires bit 5 on in sector # ; mask the bit from the current i/o function ani 0010$0000b ;mask the disk select bit lxi h,ios ;address the sector select byte ora m ;select proper disk bank mov m,a ;set disk select bit on/off ; waitio: mvi c,retry ;max retries before perm error rewait: ; start the i/o function and wait for completion call intype ;in rtype call inbyte ;clears the controller lda dbank ;set bank flags ora a ;zero if drive 0,1 and nz if 2,3 mvi a,iopb and 0ffh ;low address for iopb mvi b,iopb shr 8 ;high address for iopb jnz iodr1 ;drive bank 1? out ilow ;low address to controller mov a,b out ihigh ;high address jmp wait0 ;to wait for complete iodr1: ;drive bank 1 out ilow+10h ;88 for drive bank 10 mov a,b out ihigh+10h wait0: push b ; save retry count mvi c, poll ; function poll mvi e, pldsk ; device is disk call xdos pop b ; restore retry counter in ; check io completion ok call intype ;must be io complete (00) unlinked ; 00 unlinked i/o complete, 01 linked i/o complete (not used) ; 10 disk status changed 11 (not used) cpi 10b ;ready status change? jz wready ; must be 00 in the accumulator ora a jnz werror ;some other condition, retry ; check i/o error bits call inbyte ral jc wready ;unit not ready rar ani 11111110b ;any other errors? (deleted data ok) jnz werror ; read or write is ok, accumulator contains zero ret poldsk: call instat ; get current controller status ani iordy ; operation complete ? rz ; not done mvi a,0ffh ; done flag ret ; to xdos wready: ;not ready, treat as error for now call inbyte ;clear result byte jmp trycount werror: ;return hardware malfunction (crc, track, seek, etc.) ; the mds controller has returned a bit in each position ; of the accumulator, corresponding to the conditions: ; 0 - deleted data (accepted as ok above) ; 1 - crc error ; 2 - seek error ; 3 - address error (hardware malfunction) ; 4 - data over/under flow (hardware malfunction) ; 5 - write protect (treated as not ready) ; 6 - write error (hardware malfunction) ; 7 - not ready ; (accumulator bits are numbered 7 6 5 4 3 2 1 0) trycount: ; register c contains retry count, decrement 'til zero dcr c jnz rewait ;for another try ; cannot recover from error mvi a,1 ;error code ret ; intype, inbyte, instat read drive bank 00 or 10 intype: lda dbank ora a jnz intyp1 ;skip to bank 10 in rtype ret intyp1: in rtype+10h ;78 for 0,1 88 for 2,3 ret inbyte: lda dbank ora a jnz inbyt1 in rbyte ret inbyt1: in rbyte+10h ret instat: lda dbank ora a jnz insta1 in dstat ret insta1: in dstat+10h ret ; data areas (must be in ram) dbank: db 0 ;disk bank 00 if drive 0,1 ; 10 if drive 2,3 iopb: ;io parameter block db 80h ;normal i/o operation iof: db readf ;io function, initial read ion: db 1 ;number of sectors to read iot: db 2 ;track number ios: db 1 ;sector number iod: dw $-$ ;io address sel$table: if sgl db 00h, 30h, 00h, 30h ; drive select bits endif if dbl db 00h, 10h, 00h, 30h ; drive select bits endif if mac and sgl disks numdisks ; generate drive tables diskdef 0,1,26,6,1024,243,64,64,2 diskdef 1,0 diskdef 2,0 diskdef 3,0 endef endif if mac and dbl disks numdisks ; generate drive tables diskdef 0,1,52,,2048,243,128,128,2,0 diskdef 1,0 diskdef 2,1,26,6,1024,243,64,64,2 diskdef 3,2 endef endif if asm dpbase equ $ ;base of disk param blks dpe0: dw xlt0,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb0 ;dir buff, parm block dw csv0,alv0 ;check, alloc vectors dpe1: dw xlt1,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb1 ;dir buff, parm block dw csv1,alv1 ;check, alloc vectors dpe2: dw xlt2,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb2 ;dir buff, parm block dw csv2,alv2 ;check, alloc vectors dpe3: dw xlt3,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb3 ;dir buff, parm block dw csv3,alv3 ;check, alloc vectors dpb0 equ $ ;disk param block endif if asm and dbl dw 52 ;sec per track db 4 ;block shift db 15 ;block mask db 0 ;extnt mask dw 242 ;disk size-1 dw 127 ;directory max db 192 ;alloc0 db 0 ;alloc1 dw 32 ;check size dw 2 ;offset xlt0 equ 0 ;translate table dpb1 equ dpb0 xlt1 equ xlt0 dpb2 equ $ endif if asm dw 26 ;sec per track db 3 ;block shift db 7 ;block mask db 0 ;extnt mask dw 242 ;disk size-1 dw 63 ;directory max db 192 ;alloc0 db 0 ;alloc1 dw 16 ;check size dw 2 ;offset endif if asm and sgl xlt0 equ $ endif if asm and dbl xlt2 equ $ endif if asm db 1 db 7 db 13 db 19 db 25 db 5 db 11 db 17 db 23 db 3 db 9 db 15 db 21 db 2 db 8 db 14 db 20 db 26 db 6 db 12 db 18 db 24 db 4 db 10 db 16 db 22 endif if asm and sgl dpb1 equ dpb0 xlt1 equ xlt0 dpb2 equ dpb0 xlt2 equ xlt0 dpb3 equ dpb0 xlt3 equ xlt0 endif if asm and dbl dpb3 equ dpb2 xlt3 equ xlt2 endif if asm begdat equ $ dirbuf: ds 128 ;directory access buffer endif if asm and sgl alv0: ds 31 csv0: ds 16 alv1: ds 31 csv1: ds 16 endif if asm and dbl alv0: ds 31 csv0: ds 32 alv1: ds 31 csv1: ds 32 endif if asm alv2: ds 31 csv2: ds 16 alv3: ds 31 csv3: ds 16 enddat equ $ datsiz equ $-begdat endif db 0 ; this last db is req'd to ; ensure that the hex file ; output includes the entire ; diskdef end