;
;       BITMAP for CP/M 2.0+            as of 7/11/80
;
;
;       Lauren Guimont
;       14211 8th Avenue South
;       Seattle, Washington  98168
;
;
;
;The bitmap idea is based upon Ward Christensen's original
;  bitmap program, which refused to run on 2.0+ systems.
;  After giving his program a quick going over with SID, I
;  decided it would be easier to rewrite it than to try and
;  patch it for 2.0, 2.1, 2.2.
;
;
;               ***** EQUATES *****
;
base    equ     0               ; 'normal' CP/M
bdos    equ     base+5          ; jump to bdos
ochar   equ     2               ; bdos console output
sdsk    equ     14              ; select disk
curdsk  equ     25              ; current disk
gtaloc  equ     27              ; get allocation address
dskpar  equ     31              ; get disk parameters
fcb     equ     base+5ch        ; file control block
;
;
;
        org     base+100h       ; start of TPA
;
        lxi     h,0             ; clear HL
        dad     sp              ; load HL with CCP sp
        shld    oldsp           ; save it for later
        lxi     sp,stack        ; initialize our own sp
        jmp     start           ; bypass some subroutines
        ds      48              ; stack space
stack   equ     $               ; our own stack
oldsp   ds      2               ; old stack from ccp
;
inlprt:                         ; in line print
        xthl                    ; HL to stack...pointer to HL
inlprt1 mov     a,m             ; get a character
        inx     h               ; increment the pointer
        cpi     '$'             ; endmark?
        jz      inlprt2         ; if so, prepare to exit
        call    conout          ; output to console
        jmp     inlprt1         ; go get another
inlprt2 xthl                    ; orig HL...sp at end of msg
        ret                     ; return to end of msg
;
conout  push    h               ; single character console
        push    d               ; ...output; 1st save all
        push    b               ; ...the registers
        push    psw
        mvi     c,ochar         ; tell bdos
        mov     e,a             ; bdos wants it in E
        call    bdos            ; let bdos do it
        pop     psw             ; reinstate all registers
        pop     b
        pop     d
        pop     h
        ret                     ; return to caller
;
crlf    call    inlprt          ; use in line print
        db      0dh,0ah,'$'     ; ...for cr & lf
        ret                     ; return to caller
;
one     push    psw             ; save Acc
        mvi     a,'1'           ; print a '1' to console
        call    conout          ; do it
        pop     psw             ; restore Acc
        ret                     ; return to caller
;
zero    push    psw             ; save Acc
        mvi     a,'0'           ; print a '0' to console
        call    conout          ; do it
        push    h               ; save <hl>
        lhld    free            ; get nb of free blocks
        inx     h               ; add one free
        shld    free            ; store total free count
        pop     h
        pop     psw             ; restore Acc
        ret                     ; return to caller
;
;Binary to decimal output routine. Enter with 8 bit binary
;number in <A>. Second entry at BNDEC2 assumes 16 bit nb. in <HL>
;
bndec1  mvi     h,0
        mov     l,a             ;<HL> now has number
;
bndec2  push    b
        push    d
        push    h
        lxi     b,-10
        lxi     d,-1
bndc    dad     b
        inx     d
        jc      bndc
        lxi     b,10
        dad     b
        xchg
        mov     a,h
        ora     l
        cnz     bndec2
        mov     a,e
        adi     '0'
        call    conout
        pop     h
        pop     d
        pop     b
        ret
;
err1    call    inlprt          ; in line print
        db      0dh,0ah,'Nonstandard disk '
        db      'parameter block error'
        db      0dh,0ah,'$'
;
finis   lhld    oldsp           ; get CCP sp
        sphl                    ; retore it
        ret                     ; direct return to CCP
;
;We need a little internal storage
;
drive   ds      1               ; current drive
aldrv   ds      1               ; alternate specified drv
dpb     ds      2               ; disk parameter block add
tbtr    ds      2               ; total bits to read
alloc   ds      2               ; allocation address
blksiz  ds      1               ; block size code
free    dw      0               ; count of free blocks
;
;The actual start of it all
;
start   lda     fcb             ; get any alternate drv
        sta     aldrv           ; save it for later
        call    inlprt          ; in line print
        db      'BITMAP 2.2    AS OF '
        db      '7/11/80',0dh,0ah,0dh,0ah,'$'
        mvi     c,curdsk        ; get current disk in
        call    bdos            ; ...use from bdos
        sta     drive           ; save it
        lda     aldrv           ; get any alternate drv
        ora     a               ; any specified?
        jz      dpblk           ; if not, skip next
        dcr     a               ; less one
        sta     drive           ; save as drive to use
;
dpblk   lda     drive           ; get drive to bitmap
        mvi     c,sdsk          ; set call for disk select
        mov     e,a             ; bdos wants it in E
        call    bdos            ; let bdos do it
        mvi     c,dskpar        ; we want dsk parameter blk
        call    bdos            ; get it, and.....
        shld    dpb             ; ...save it
        lxi     d,5             ; offset for total blks used
        dad     d               ; add it to HL
        mov     e,m             ; lsb into E
        inx     h               ; point to msb
        mov     d,m             ; get it
        xchg                    ; put it in HL...
        inx     h               ; alloc size = (dsm/8)+1
        shld    tbtr            ; ...and save it
        lhld    dpb             ; get dsk parameter blk add
        inx     h               ; ...and increment HL to
        inx     h               ; ...the 3rd byte
        mov     a,m             ; it has the block size
        sui     2               ; it will be 3-7 (make it 1-5)
        cpi     5+1             ; check for over 5
        jnc     err1            ; nonstandard size
        cpi     1               ; check for less than 1
        jc      err1            ; nonstandard size
        push    psw             ; save it
        call    inlprt          ; in line print
        db      'Allocated disk block size is $'
        pop     psw             ; get block size back
        sta     blksiz          ; save it for end
        lxi     h,512           ; set 1/2k counter
lp      dad     h               ; multiply * 2=1024
        dcr     a               ; less block size code count
        jnz     lp              ; loop till <A>= 0
        call    bndec2          ; print size in K
;
dpbend  call    inlprt          ; finish message
        db      ' bytes per block',0dh,0ah,'$'
        lhld    tbtr            ; total bits to read
        push    h               ; save it in the stack
        lda     drive           ; again to be safe
        mov     e,a             ; into E for bdos
        mvi     c,sdsk          ; reselect disk
        call    bdos            ; let bdos do it
        mvi     c,gtaloc        ; get the allocation address
        call    bdos            ; ...from bdos
        pop     d               ; tbtr from stack
        dcx     h               ; back allocation up one
;
;
;We now have the total number of bits to read in DE, and
;  the address to start reading them at in HL for the
;  proper drive. So now let's print the bitmap.
;
;
bmap    mvi     c,48            ; 1's and 0's per line
        call    crlf            ; followed by a cr,lf
bmap1   inx     h               ; kick the pointer
        mov     a,m             ; get the byte
        mvi     b,8             ; it has 8 bits
bmap2   rlc                     ; runn'em through carry
        cc      one             ; carry set = print '1'
        cnc     zero            ; carry not set = print '0'
        dcx     d               ; decrement bit count
        push    psw             ; save the bit pattern
        mov     a,d             ; check to see if...
        ora     e               ; ...DE = 0
        jz      bmapend         ; if so, we're finished
        pop     psw             ; restore bit pattern
        dcr     c               ; decrement line count
        jz      bmap            ; new line if zero
        dcr     b               ; decrment bit count
        jz      bmap1           ; new byte if zero
        jmp     bmap2           ; finish this byte
;
bmapend pop     psw             ; not neccessary, but keeps the
        call    crlf            ; ...stack straight..send cr,lf
        call    crlf
        lda     drive           ;get drive used
        adi     'A'
        call    conout
        call    inlprt
        db      ': R/W, Space: $'
        lda     blksiz          ; get block size code
        lhld    free            ; get nb of free blocks
lp1     dcr     a
        jz      don             ; multiplied by size of block
        dad     h               ; times 2
        jmp     lp1
;
don     call    bndec2          ; print size of free space
        call    inlprt
        db      'k',0dh,0ah,'$'
        jmp     finis           ; restore things and GET OUT
;
        end
