; Xios for the Thinkertoy Discus 2D System: ; Double drive, single sided, double density. ; This sytem uses a modified DJ CBIOS routine. ; ; Dated September 1981 W6BSK org 0000H 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 ; basic i/o system jump vector ; jmp coldstart ;cold start wboot: jmp wboot0 ;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 setdrv ;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 sectran ;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 djdrv jmp djsel ;Hook for SINGLE.COM program. coldstart: warmstart: mvi c,0 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:) wboot0 lxi sp,80h lda cdisk sta temp mvi c,0 call setdrv call home jmp aldon aldon lda temp sta cdisk jmp xdos const: ; console status call ptbljmp ; compute and jump to hndlr dw pt0st ; console #0 status routine dw pt1st ; console #1 status routine conin: ; console input call ptbljmp ; compute and jump to hndlr dw pt0in ; console #0 input dw pt1in ; console #1 input conout: ; console output call ptbljmp ; compute and jump to hndlr dw pt0out ; console #0 output dw pt1out ; console #1 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: lxi h,mesg0 call pmesg 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 002h ;This is the keyboard port. sts0 equ data0+1 data1 equ 002h sts1 equ data1+1 ;and so is this one. lptport equ 001h lptsts equ lptport+2 ;This is the Selectric port. video equ 0f803h ;VIO-C input address. ; 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 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 02h xri 02h mvi a,00h rnz dcr a ret ; ; ; line printer driver: ; list: ; list output in lptsts ani 60h jnz lptrdy push b mvi c, poll mvi e, pllpt call xdos pop b lptrdy: mov a,c out lptport ret ; ; poll printer output ; pollpt: ; return 0ffh if ready, ; 000h if not in lptsts ani 60h rz mvi a,0ffh ret ; ; poll console #1 input ; polci1: pt1st: ; return 0ffh if ready, ; 000h if not in sts1 ani 2 xri 2 mvi a,0 rnz Š dcr a ret ; ; console #1 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 output ; pt1out: mov a,c call video ; dump it. ret ; wait for console #1 output ready pt1wait: mvi c,poll mvi e,plco1 jmp xdos ; poll console #1 output ; ret ; poll console #1 output polco1: ; return 0ffh if ready, ; 000h if not in sts1 ani 02h xri 02h mvi a,0 rnz dcr a 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: call boot1 bootr: ; note: this system init assumes that the usarts ; have been initialized by the coldstart boot ; setup restart jump vectors ret boot1 lxi h,80h shld cpmdma jmp bootr ; ; 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 poldsk mvi a,0ffh ret ; ; 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 temp: ds 1 ***************************************************************** origin equ 0E000H djram equ origin+400h ;Disk Jockey 2D RAM address djcin equ djram+3h ;Disk Jockey 2D character input routine djcout equ djram+6h ;Disk Jockey 2D character output routine djhome equ djram+9h ;Disk Jockey 2D track zero seek djtrk equ djram+0ch ;Disk Jockey 2D track seek routine djsec equ djram+0fh ;Disk Jockey 2D set sector routine djdma equ djram+012h ;Disk Jockey 2D set DMA address djread equ djram+15h ;Disk Jockey 2D read routine djwrite equ djram+18h ;Disk Jockey 2D write routine djsel equ djram+1bh ;Disk Jockey 2D select drive routine djtstat equ djram+21h ;Disk Jockey 2D terminal status routine djstat equ djram+27h ;Disk Jockey 2D status routine djerr equ djram+2ah ;Disk Jockey 2D error, flash led djden equ djram+2dh ;Disk Jockey 2D set density routine djside equ djram+30h ;Disk Jockey 2D set side routine cdisk equ 4 ;Address of last logged disk buff equ 80h ;Default buffer address tpa equ 100h ;Transient memory intioby equ 0 ;Initial IOBYTE iobyte equ 3 ;IOBYTE location wbot equ 0 ;Warm boot jump address entry equ 5 ;BDOS entry jump address retries equ 10 ;Max retries on disk i/o before error acr equ 0dh ;A carriage return alf equ 0ah ;A line feed aetx equ 3 ;A ETX char aack equ 6 ;A ACK char Šclear equ 1ah ;Clear screen char on ADM3 terminal maxdisk equ 4 ;Maximum # of disk drives dblsid equ 8 ;Side bit from controller setsec mov a,c ;Save the sector number sta cpmsec ;CP/M sector # ret setdma mov h,b ;hl <- bc mov l,c shld cpmdma ;CP/M dma address ret home mvi c,0 ;Track to seek to settrk mov a,c ;A <- track # sta cpmtrk ;CP/M track # ret sectran inx b push d ;Save table address push b ;Save sector # call getdpb ;Get DPB address into HL mov a,m ;Get # of CP/M sectors/track ora a ;Clear cary rar ;Divide by two sub c push psw ;Save adjusted sector jm sidetwo sidea pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restor address of xlt table sideone xchg ;hl <- &(translation table) dad b ;bc = offset into table mov l,m ;hl <- physical sector mvi h,0 ret sidetwo lxi b,15 ;Offset to side bit dad b mov a,m ani 8 ;Test for double sided jz sidea ;Media is only single sided pop psw ;Retrieve adjusted sector pop b cma ;Make sector request positive inr a mov c,a ;Make new sector the requested sector pop d call sideone mvi a,80h ;Side two bit ora l ; and sector mov l,a ret setdrv mov a,c ;Save the drive # sta cpmdrv cpi maxdisk ;Check for a valid drive # Š jnc zret ;Illegal drive # mov a,e ;Test if drive ever logged in before ani 1 jnz setdrv1 ;Bit 0 of E = 0 -> Never selected before mvi a,1 ;Select sector 1 of track 1 sta truesec sta cpmtrk call fill ;Flush buffer and refill jc zret ;Test for error return call djstat ;Get status on current drive ani 0ch ;Strip off unwanted bits push psw ;Used to select a DPB rar lxi h,xlts ;Table of XLT addresses mov e,a mvi d,0 dad d push h ;Save pointer to proper XLT call getdpb ;Get DPH pointer into DE xchg ; pop d mvi b,2 ;Number of bytes to move call movlop ;Move the address of XLT lxi d,8 ;Offset to DPB pointer dad d ;HL <- &DPH.DPB push h lhld origin+7 ;Get address of DJ terminal out routine inx h ;Bump to look at address of ; uart status location mov a,m xri 3 ;Adjust for proper rev DJ mov l,a mvi h,(origin+300h)/100h mov a,m ani dblsid ;Check double sided bit lxi d,dpb128s ;Base for single sided DPB's jnz sideok lxi d,dpb128d ;Base of double sided DPB's sideok xchg ;HL <- DBP base, DE <- &DPH.DPB pop d ;Restore DE (pointer into DPH) pop psw ;Offset to correct DPB ral ral mov c,a mvi b,0 dad b xchg ;Put DPB address in DPH mov m,e inx h mov m,d setdrv1 call getdpb ;Get address of DPB in HL lxi b,15 ;Offset to sector size dad b mov a,m ;Get sector size ani 7h Š sta secsiz mov a,m rar rar rar rar ani 0fh sta secpsec xchg ;HL <- DPH ret zret lxi h,0 ;Seldrv error exit ret getdpb lda cpmdrv ;Get drive # mov l,a ;Form offset mvi h,0 dad h dad h dad h dad h lxi d,dpzero ;Base of DPH's dad d push h ;Save address of DPH lxi d,10 ;Offset to DPB dad d mov a,m ;Get low byte of DPB address inx h mov h,m ;Get low byte of DPB mov l,a pop d ret xlts dw xlt128 ;Xlt for 128 byte sectors dw xlt256 ;Xlt for 256 byte sectors dw xlt512 ;Xlt for 512 byte sectors dw xlt124 ;Xlt for 1024 byte sectors write mov a,c ;Save write command type sta writtyp mvi a,1 ;Set write command db (mvi) or (b*8) ;This "mvi b" instruction causes ; the following "xra a" to ; be skipped over. read xra a ;Set the command type to read sta rdwr ;Save command type redwrt mvi b,0 ;The 0 is modified to contain the log2 secsiz equ $-1 ; of the physical sector size/128 ; on the currently selected disk. lda cpmsec ;Get the desired CP/M sector # push psw ;Temporary save ani 80h ;Save only the side bit mov c,a ;Remember the side pop psw ;Get the sector back Š ani 7fh ;Forget the side bit dcr a ;Temporary adjustment divloop dcr b ;Update repeat count jz divdone ora a ;Clear the cary flag rar ;Divide the CP/M sector # by the size ; of the physical sectors jmp divloop ; divdone inr a ora c ;Restore the side bit sta truesec ;Save the physical sector number lxi h,cpmdrv ;Pointer to desired drive,track, and sector lxi d,bufdrv ;Pointer to buffer drive,track, and sector mvi b,4 ;Count loop dtslop dcr b ;Test if done with compare jz move ;Yes, match. Go move the data ldax d ;Get a byte to compare cmp m ;Test for match inx h ;Bump pointers to next data item inx d jz dtslop ;Match, continue testing call fill ;Fill the buffer with correct physical sector rc ;No good, return with error indication move lda cpmsec ;Get the CP/M sector to transfer dcr a ;Adjust to proper sector in buffer ani 0 ;Strip off high ordered bits secpsec equ $-1 ;The 0 is modified to represent the # of ; CP/M sectors per physical sectors mov l,a ;Put into HL mvi h,0 dad h ;Form offset into buffer dad h dad h dad h dad h dad h dad h lxi d,buffer ;Beginning address of buffer dad d ;Form beginning address of sector to transfer xchg ;DE = address in buffer lxi h,0 ;Get DMA address, the 0 is modified to ; contain the DMA address cpmdma equ $-2 mvi a,0 ;The zero gets modified to contain ; a zero if a read, or a 1 if write rdwr equ $-1 ana a ;Test which kind of operation jnz into ;Transfer data into the buffer outof call mover xra a ret into xchg ; call mover ;Move the data, HL = destination Š ; DE = source mvi a,1 sta bufwrtn ;Set buffer written into flag mvi a,0 ;Check for directory write writtyp equ $-1 dcr a mvi a,0 sta writtyp ;Set no directory write rnz ;No error exit flush mvi a,0 ;The 0 is modified to reflect if ; the buffer has been written into bufwrtn equ $-1 ana a ;Test if written into rz ;Not written, all done lxi h,djwrite ;Write operation prep xra a ;Reset buffer written flag sta bufwrtn sh