*************************************************************** * * * Module ID: CPMIO.LIB By: GLH/W6BSK * * Last Updated: 27 Apr 85 * * Function : Console IO Version : 1.00 * * Subroutines * * Entry: * * Exit : * * * *************************************************************** ; *** EQU Tables *** cr equ 0dh ; Carriage return lf equ 0ah ; Line feed ctrlz equ 1ah ; Operator interrupt rconf equ 01h ; Dump input from console wconf equ 02h ; Write A contents to console cstaf equ 0bh ; Check con: status drive equ 04h ; Current drive number rbuff equ 0ah ; Read a console line tbuff equ 80h ; Base page default buffer bdos equ 05h ; BDOS entry point versf equ 0ch ; CP/M version function vers3 equ 30h ; CP/M plus versf return org 100h ; TPA start address begin: lxi h,0 ; Clear HL before loading dad sp ; old stack pointer shld cpmsp ; and save it. lxi sp, stak ; Set new stack lda drive ; Get current drive sta drsav ; and save it mvi c,cstaf ; Get console status call bdos ora a jz begin1 ; No input, get some. mvi c,rconf ; Ignore any if present. begin1: call ccrlf call spmsg db ' Demo program for CPMMAP ',0 call ccrlf jmp start ; Go to main program entry point. ; Display message to console spmsg: xthl ; Load phony RET to HL regs xra a ; Clear flags etc. add m ; Move one message character inx h ; and point to next. xthl ; restore stack to return if done. rz ; Done if 00 in A. call conout ; If not done, display it Š jmp spmsg ; and continue. ; Do a CR/LF to console twocr: call ccrlf ccrlf: mvi a,cr call conout mvi a,lf conout: push b ; Display one character push d ; Push all regs push h mvi c,wconf ; Select the write function mov e,a ; and put in correct reg call bdos ; Do the function pop h pop d ; Pop all back. pop b ret ; Show spaces spaces: push b ; Enter with count in C mov c,a ; Save temp reg for count ora a ; Test for none jz space2 ; and quit if so. space1: mvi a, ' ' ; Load a space call conout dcr c jnz space1 ; Test countdown space2: pop b ; Clear stack ret ; Console operator interrupt opint: mvi c,cstaf ; Check for operator kill call bdos ora a ; Test if keypress rz ; Return if none. mvi c,rconf ; Was, check it. call bdos cpi ctrlz rnz done: lda drsav ; All done, check out. sta drive ; Restore current drive lhld cpmsp ; Get old stack pointer sphl ; load it, and go ret ; Input console message into buffer- cimsg: push b push d ; Push all regs push h lxi h,inbuf+1 ; Point to message start mvi m,0 ; and zero counter Š dcx h ; Back to length cell mvi m,80 ; and set max line xchg ; Input pointer to DE- mvi c,rbuff ; Set read buffer function call bdos ; and do it. lxi h,inbuf+1 ; Point to counter mov e,m ; and save it mvi d,0 ; Clear upper byte dad d ; and add length to start inx h ; add one more for end mvi m,0 ; and set 00 to end it. pop h pop d ; Restore them all pop b ret ; (Y)es or (N)o from console getyn: call spmsg ; Prompt for input db ' (Y/N)?: ',0 ; This is the prompt. call cimsg ; Read an input line call ccrlf ; and do a CR/LF lda inbuf+2 ; Use first character only. ani 5fh ; Make upper case only cpi 'Y' rz cpi 'N' jnz getyn xra a ret ; Message out to console comsg: mov a,m ora a ; Test for 00 rz call conout inx h jmp comsg ; Local storage area drsav db 0 ; Current drive storage cpmsp dw 0 ; Old stack pointer inbuf ds 83 ; Line input buffer org 200h stak: equ $ * CPMMAP program begins here * start: call ccrlf call ramtop ; Get top of RAM address call spmsg ; Report Š db ' RAM top is: ',0 call co6bhd ; in binary, hex and decimal call ccrlf mvi c,versf ; Only V1.x, 2.x allowed call bdos ; so filter out Plus. mov a,h ora a ; Tell us if unable to show jnz cpmerr mov a,l cpi vers3 ; Squeal also if Plus. jnc cpmerr lhld 1 ; Get CBIOS entry address dcx h dcx h ; which is 3 less than cold dcx h ; boot address. call spmsg db 'CBIOS is at: ',0 call co6bhd call ccrlf lhld 6 ; Get BDOS entry address from lxi d,0-6 ; location 6. Actual BDOS start dad d ; is 6 cells earlier. call spmsg db 'BDOS is at: ',0 call co6bhd call ccrlf lxi d,0-800h ; CCP is 800 cells below BDOS. dad d call spmsg db 'CCP is at: ',0 call co6bhd call ccrlf jmp done cpmerr: call ccrlf call spmsg db 'Unable to map this version.',0 call ccrlf jmp done ramtop: lxi h,2000h ; Move to above program lxi d,1024 ; Test 1k byte increments mvi c,56 ; but stop after 64k. ramto1: mov b,m ; Move memory to B reg xra a ; Clear to write 00 mov m,a ; Write it cmp m ; Get there? mov m,b ; Restore original value jnz ramto3 ; Jump if failed write. dcr a ; Make FF in accum mov m,a ; now write 1's cmp m ; Written? mov m,b ; Write in original value jnz ramto3 ramto2: dad d Š dcr c ; Try next block jnz ramto1 ramto3: dcx h ; Back up one location ret ; and that is RAMtop. ; Display values from HL co6bhd: call co6bin mvi a,'B' call conout mvi a,5 ; Space over to next format call spaces co6hd: call co6hex mvi a,'H' call conout mvi a,5 call spaces call co6dec mvi a,'D' jmp conout co8bhd: call co8bin mvi a,'B' call conout mvi a,5 call spaces co8hd: call co8hex mvi a,'H' call conout mvi a,5 call spaces call co8dec mvi a,'D' jmp conout co6bin: mov a,h ; Get byte in H call co8bin ; and display it. mov a,l ; Do same for L co8bin: push b ; Save the BC entry values mvi c,8 ; Set count co8bi1: ral mov b,a ; Save remainder mvi a,'0' ; Load ASCII 0 jnc co8bi2 ; and display if no carry mvi a,'1' ; else display ASCII 1 co8bi2: call conout ; Dump the character mov a,b ; Restore the remainder dcr c ; update the count jnz co8bi1 ; and continue until done. pop b ; Restore entry values ret ; Binary display done co6hex: mov a,h ; Load high byte call co8hex ; and dump it. mov a,l ; Do same for low. Šco8hex: push psw ; Save entry values ani 0F0h ; Strip low nibble rrc rrc ; Swap nibbles rrc rrc call co4hex ; Display value as hex pop psw ; Restore entry value ani 0fh ; Strip high nibble co4hex: cpi 10 ; Test if 0-9 jm co4he1 ; Yes, use as is adi 7 ; No, convert to A-F co4he1: adi '0' ; Make value ASCII jmp conout ; and output it. co8dec: push h ; Stack entry values mvi h,0 ; Enter with value in A mov l,a ; Clear high byte, set low. jmp co6de1 ; Display single-byte value. co6dec: push h ; Entry for 16-bit number co6de1: push d push b xra a ; Clear leading-zero flag sta zflag mvi c,5 ; Count for 5 characters shld value ; Save current value lxi h,tthou ; Point to ten thou divider shld index ; and save it. co6de2: lhld index ; Get current divider mov e,m inx h ; and put in DE mov d,m inx h ; Move to next divider shld index ; Character starts at zero mvi b,0 lhld value ; Subtract divider until co6de3: dad d ; borrow occurs jnc co6de4 shld value inr b ; Keep count of subs jmp co6de3 co6de4: mov a,b ; Get count value ora a ; and test for inhibit jz co6de7 ; No div, inhibit leading zeros sta zflag ; Is, flag first non-zero co6de5: mov a,b ; Get count and adi '0' ; convert to ASCII co6de6: call conout ; Display character dcr c ; update character count jnz co6de2 ; and get next until done. pop b pop d pop h ret Šco6de7: lda zflag ; Test for suppression of ora a ; leading zero. jnz co6de5 ; No, display zero mov a,c ; Test for last character. cpi 1 ; All zeroes? jz co6de5 ; Yes, display them. mvi a,' ' ; No, dump a space jmp co6de6 zflag ds 1 ; Leading zero flag value ds 2 ; Current value index ds 2 ; index into different tthou dw 0-10000 ; "dividers" uthou dw 0-1000 hunds dw 0-100 tens dw 0-10 units dw 0-1