;SETDISK - Utility for viewing and assigning logical drives to physical drives
;          on my 8080 computer.
;
;Version 1.0
;08-19-2024
;Jerry Davis
;
   CPU 8080 ;Specify architecture
   PAGE 0   ;Turn off page breaks in listings
;
;
;BIOS Routines
;
wboot   equ   0f403h   ;warm start
const   equ   0f406h   ;console status
conin   equ   0f409h   ;console character in
conout  equ   0f40ch   ;console character out
seldsk  equ   0f41bh   ;select disk
settrk  equ   0f41eh   ;set track number
setsec  equ   0f421h   ;set sector number
setdma  equ   0f424h   ;set dma address
read    equ   0f427h   ;read disk
write   equ   0f42ah   ;write disk
listst  equ   0f42dh   ;return list status
sectran equ   0f430h   ;sector translate
;
;
;BIOS Variables
;
drives   equ 4          ;number of drives in the system
diskmap  equ 0ff28h     ;physical disk to virtual disk translation
;
;
;BDOS Variables
;
tailcnt equ 80h        ;Length of command line options
tailstr equ 81h        ;null terminated command line options
;
;
   org 100h
;
;
start:
   lxi d, msg_start    ;point to start message
   call print          ;print it
   lda tailcnt         ;any command line options?
   ora a               ;set flags
   jnz st000           ;Get parameters and set drives
   call status         ;print current drive assignments
   ret                 ;return to CCP
;
st000:
   call getpdrive      ;get physical drive
   call getvdrive      ;get virtual drive
   lda pdrive          ;get stored physical drive
   cpi 0ffh            ;invalid?
   jz error            ;print invalid param message and exit
   lda vdrive          ;get stored virtual drive
   cpi 0ffh            ;invalid?
   jz error            ;print invalid param message and exit
   lxi h, diskmap      ;point to first physical drive
   lda pdrive          ;get stored physical drive
st001:
   cpi 0               ;is it zero yet?
   jz st002            ;update physical drive with virtual drive
   inx h               ;point to next physical drive
   dcr a               ;decrement pdrive counter
   jmp st001           ;do over   
st002:   
   lda vdrive          ;get stored physical drive
   mov m, a            ;save vdrive in pdrive
   call status         ;print current drive assignments
   jmp 0               ;warm start
;
;
;Print status of pdisk to vdisk map
;
status:
   call getvols        ;get volume labels
   lda volerr          ;check for volume label error
   cpi 0               ;Success?
   jz stat001          ;move on if no error
   mvi c, bclose       ;bdos close function call
   lxi d, volfcb       ;point to volume FCB
   call bdos           ;close the file
   lxi d, msg_volerr   ;point to volume label error
   call print          ;print it
stat001:
   lxi h, diskmap      ;point to drive map
stat002:
   call statline       ;print drive A map and label
   lda count           ;get drive counter
   cpi drives-1        ;done?
   jz statexit         ;exit if done
   inr a               ;increment counter
   sta count           ;save it
   inx h               ;point to next drive
   jmp stat002         ;do again
statexit:
   lxi d, msg_crlf     ;point to new line
   call print          ;print it
   ret                 ;done
;
;
statline:
   lxi d, msg_crlf     ;point to new line
   call print          ;print it
   lxi d, msg_pdisk    ;point to physical disk heading
   call print          ;print it
   lda count           ;get drive counter
   adi 'A'             ;make drive letter
   mov c, a            ;move it to C
   call conout         ;print it	
   lxi d, msg_vdisk    ;point to virtual disk heading
   call print          ;print it
   mov a, m            ;get virtual disk number
   mov c, a            ;put it in C
   call print_dec      ;print it
   mov a, m            ;get virtual disk number
   lxi d, msg_label    ;point to label heading
   call print          ;print it
   lda volerr          ;check for label error
   cpi 1               ;errored out?
   jz slexit           ;skip it
   mov a, m            ;get virtual disk number
   push h              ;save HL on the stack
   call getlabel       ;get the volume label in DE
   pop h               ;get HL from the stack
   call print          ;print it
slexit:
   ret
;
;
getlabel:
   lxi h, labels       ;point to labels list
   lxi b, 16           ;label increment
gl001:
   cpi 0               ;done?
   jz glexit           ;if so then exit
   dad b               ;move pointer to next label
   dcr a               ;decrement vdrive counter
   jmp gl001           ;next label
glexit:
   xchg                ;put HL in DE
   ret                 ;exit
;
;
;Print parameter error message
;
error:
   lxi d, msg_crlf     ;point to new line
   call print          ;print it
   lxi d, msg_usage    ;point to physical disk heading
   call print          ;print it
   call status         ;print physical to virtual disk map
   ret                 ;return to CCP
;
;
;Get physical drive from parameter string
;
getpdrive:
   lxi h, tailstr      ;point to option string
getpd01:
   mov a, m            ;get first character
   cpi 0               ;end of parameter string?
   rz                  ;return if end of string
   cpi 'A'             ;is it low drive letter?
   jc getpd02          ;if less than A try next param character
   cpi 'E'             ;is it low drive letter?
   jnc getpd02         ;if not try next param character
   sui 'A'             ;convert to hex
   sta pdrive          ;save physical drive
   ret
getpd02:
   inx h               ;point to next parameter char
   jmp getpd01         ;do again
;
;
;Get virtual drive from parameter string
;
getvdrive:
   lxi h, tailstr      ;point to option string
getvd01:
   mov a, m            ;get first character
   cpi 0               ;end of parameter string?
   rz                  ;return if end of string
   cpi '0'             ;is it low drive number?
   jc getvd02          ;if not try next param character
   cpi ':'             ;is it greater than 9?
   jc getvd03          ;if not check if second digit exists
getvd02:
   inx h               ;point to next parameter char
   jmp getvd01         ;do again
getvd03:
   sui '0'             ;convert to hex
   mov b, a            ;save first digit in b
   inx h               ;point to next parameter char
   mov a, m            ;get next digit if any
   cpi '0'             ;is it low drive number?
   jc getvd04          ;if not convert first digit and exit
   cpi ':'             ;is it greater than 9?
   jnc getvd04         ;if not convert first digit and exit
   sui '0'             ;convert to hex
   mov c, a            ;save second digit in C
   mov a, b            ;get first digit in A
   cpi 2h              ;greater than one?
   rnc                 ;return if it is
   cpi 0               ;is first digit a zero?
   jz getdv05          ;if it is skip first digit
   mov a, c            ;get second digit in A
   adi 0ah             ;add in decimal 10
   cpi 0fh             ;greater than 14?
   rnc                 ;return if it is
   sta vdrive          ;save virtual drive
   ret                 
getvd04:
   mov a, b            ;Get first digit in A
   sta vdrive          ;save virtual drive
   ret
getdv05:
   mov a, c            ;Get second digit in A
   sta vdrive          ;save virtual drive
   ret
;
;
;Print one or two digit decimal number from 4 bit hex
;Modifies: a, c
;
print_dec:
    mov a, c         ;move C into A
    ani 00fh         ;mask off high bits
    adi 0            ;for decimal adjust
    daa              ;decimal adjust A
    push psw         ;save A on the stack
	mov c, a         ;save it in C
	ani 0f0h         ;mask off low bits
	jz pd001         ;suppress leading zero
    rrc              ;shift to low bits
	rrc
	rrc
	rrc
    adi '0'          ;convert to ASCII
	mov c, a         ;save it in C
    call conout      ;print it
pd001:
    pop psw          ;restore A from the stack
	ani 00fh         ;mask off high bits
	adi '0'          ;convert to ASCII
	mov c, a         ;put it in C
    call conout      ;print it
    ret
;
print:               ;print a message on the console
	ldax d           ;get char pointed to by D into A
	cpi 0            ;end of string?
	jz pend          ;exit if end of string
	mov c, a         ;move shar into C for console out
	call conout      ;print it
	inx d            ;point to next character
	jmp print        ;repeat
pend:
	ret              ;and exit
;
;
;Open the volumes file 'volumes.dat' and read in the volume
;labels for each virtual disk.
;Returns 0ffh or non-zero on fail, 0 on success.
;
bopen  equ 15  ;BDOS open function
bclose equ 16  ;BDOS close function
bread  equ 20  ;BDOS sequential read function
bsdma  equ 26  ;BDOS set DMA 
bdos   equ 5   ;BDOS jump address
;
getvols:
   mvi c, bopen            ;bdos open function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;open the file
   cpi 0ffh                ;file error?
   jz gverror              ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels           ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bread            ;bdos read function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   mvi c, bsdma            ;bdos set dma function call
   lxi d, labels+128       ;point to volumes buffer
   call bdos               ;set dma for volume list
   mvi c, bread            ;bdos read function call
   lxi d, volfcb           ;point to volume fcb
   call bdos               ;read one record
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   mvi c, bclose           ;bdos close function call
   lxi d, volfcb           ;point to volume FCB
   call bdos               ;close the file
   cpi 0                   ;any errors?
   jnz gverror             ;signal error and exit
   ret                     ;done
gverror:
   mvi a, 1                ;signal volume label read error
   sta volerr              ;save it
   ret
;
;
msg_start:
   dw 0d0ah
   db 'SETVOL v1.0 - Volume to logical disk assignment'
   dw 0d0ah
   db 0
;
msg_pdisk:
   db 'Logical Disk: '
   db 0
;
msg_vdisk:
   db '  Volume: '
   db 0
;
msg_label:
   db '  Label: '
   db 0
;
msg_usage:
   db 'USAGE: SETVOL <drive letter> <volume number>'
   dw 0d0ah
   dw 0d0ah
   db 'drive letter = A..D'
   dw 0d0ah
   db 'volume number = 0..14'
   dw 0d0ah
   db 0
msg_volerr:
   db '*** Error reading volume labels!'
   dw 0d0ah
   db 0
msg_crlf:
   dw 0d0ah
   db 0
;
pdrive db 0ffh               ;physical drive number
vdrive db 0ffh               ;virtual drive number
count  db 0                  ;physical drives to display
;
volerr: db 0                 ;volume error flag
;
volfcb:
fcbdisk: db 1                ;always use drive A
fcbname: db 'VOLUMES', 20h   ;volume labels file name
fcbtype: db 'DAT'            ;volume labels file type
fcbextn: db 0                ;volume labels extent
fcbresv: db 0,0              ;reserved
fcbrecs: db 0                ;volume labels records used
fcbaloc: dw 0,0,0,0,0,0,0,0  ;allocation blocks
fcbsrec: db 0                ;sequential record number
fcbrrec: dw 0                ;random record number
fcbreco: db 0                ;random record overflow
;
labels ds 256                ;storage for volume labels
;
   end