Programming:A simple disc formatter using BDOS functions

From CPCWiki - THE Amstrad CPC encyclopedia!
Jump to: navigation, search
;; A simple disc formatter which uses the BDOS functions.
;;
;; This example will work on CPC and CPC+.
;;
;; Format program supports:
;; - 40 track single sided disc drive ONLY
;; - Vendor and Data formats ONLY
;;
;; Comment Nworc, 23.02.2022: 
;;   This code is useful as a learning experience, but be careful not to use it in a productive environment, because
;;   the formatting routine formats the sectors consecutively (e.g. C1 C2 C3 C4 ... for Data format). While this works,
;;   read and write performance is poor on a disk with such a format, as the disk needs to spin 9 times to write a full
;;   track instead of just 2 turns if the format would be interleaved. The format_track method need be changed to produce
;;   an interleaved format (e.g. C1 C6 C2 C7 ... for Data format) in order to fix this. Changing that is a nice exercise.

org &2000
nolist
write"format.bin"

;;------------------------------------------
;; operating system functions used

.kl_find_command equ &bcd4
.txt_output equ &bb5a
.bdos_set_message equ 1
.bdos_format equ 6
.bdos_move_track equ 7
.bdos_set_retry_count equ 9
.bdos_get_status equ 8
.bdos_select_format equ 3
.km_read_char equ &bb09
.km_wait_char equ &bb06

;;------------------------------------------
;; offsets into our data 

.DRIVE equ 0
.TRACK equ 1
.SECTOR_ID equ 2

;;------------------------------------------
;; search roms to find commands required for format

ld hl,disc_command
call kl_find_command
ret nc

ld hl,format_command
call kl_find_command
ret nc
ld (format_cmd_data),hl
ld a,c
ld (format_cmd_data+2),a

ld hl,select_format_command
call kl_find_command
ret nc
ld (select_format_cmd_data),hl
ld a,c
ld (select_format_cmd_data+2),a

ld hl,move_track_command
call kl_find_command
ret nc
ld (move_track_cmd_data),hl
ld a,c
ld (move_track_cmd_data+2),a

ld hl,set_retry_count_command
call kl_find_command
ret nc
ld (set_retry_count_cmd_data),hl
ld a,c
ld (set_retry_count_cmd_data+2),a

ld hl,set_message_command
call kl_find_command
ret nc
ld (set_message_cmd_data),hl
ld a,c
ld (set_message_cmd_data+2),a

;;------------------------------------------

ld ix,data

;; display format question
ld hl,format_type_txt
call print

.copy2
call flush_keyboard
call km_wait_char
and &df
cp "V"
ld c,&41
jr z,copy3
cp "D"
ld c,&c1
jr z,copy3
ld a,7
call txt_output
jp copy2

.copy3
call txt_output

ld (ix+SECTOR_ID),c

call crlf

;; display drive question
ld hl,sel_drive_txt
call print
ld hl,drive_txt
call print

;; ask user to select drive
call get_drive
ld (ix+DRIVE),c

ld hl,insert_disc_txt
call print
ld a,(ix+DRIVE)
add a,"A"
call txt_output
ld hl,any_key_txt
call print

call flush_keyboard
call km_wait_char

;; select the format (initialises some of the XDPB parameters that are required
;; by the format function)
ld a,(ix+SECTOR_ID)
call do_select_format

;; do format
ld b,40
xor a
.format_disc
ld (ix+TRACK),a
push af
push bc

ld hl,format_track_txt
call print
call disp_track

call format_track

pop bc
pop af
inc a
djnz format_disc
ret

;;------------------------------------
;; remove all characters from keyboard input buffer

.flush_keyboard
call km_read_char
jr nc,flush_keyboard
ret

;;------------------------------------
;; Exit: C = drive index

.get_drive
;; remove keys from keyboard buffer
call flush_keyboard
;; wait for next character from keyboard
call km_wait_char
;; convert to upper case
and &df

cp "A"
ld c,0
jr z,gd2
cp "B"
ld c,1
jr z,gd2

;; error (beep)
ld a,7
call txt_output
jr get_drive

.gd2
call txt_output
call crlf
ret

;;-------------------------
;; display CR,LF control codes (go to next line)
.crlf
ld a,13
call txt_output
ld a,10
call txt_output
ret

;;-------------------------------------
;; display a message starting at memory address pointed to by HL. 
;; (message is terminated with 0 character)

.print
ld a,(hl)
inc hl
or a
ret z
call txt_output
jr print

;;----------------------------------------------
;; output the number of the current track to the screen

.disp_track
ld a,(ix+TRACK)
call print_decimal
ret

;;----------------------------------------------
;; display a decimal number to the screen 

.print_decimal
ld e,1
ld b,100
call print_decimal_digit
ld b,10
call print_decimal_digit
dec e
ld b,1

.print_decimal_digit
ld c,0
.dd
sub b
jr c,dd2
inc c
jr dd
.dd2
add a,b
push af
ld a,e
or a
ld a,c
jr z,dd4
or a
jr z,dd5
dec e

.dd4
add a,"0"
call txt_output
.dd5
pop af
ret


;;-------------------------------------

.do_set_retry_count
push ix
rst 3
defw set_retry_count_cmd_data
pop ix
ret

.do_move_track
push ix
rst 3
defw move_track_cmd_data
pop ix
ret

.do_format
push ix
rst 3
defw format_cmd_data
pop ix
ret

.do_select_format
push ix
rst 3
defw select_format_cmd_data
pop ix
ret

.do_set_message
push ix
rst 3
defw set_message_cmd_data
pop ix
ret

;;----------------------------------------------

.format_track
;; setup format data
ld hl,format_data
push hl
ld b,9
ld a,(ix+SECTOR_ID)
ld c,(ix+TRACK)
.wt1 
ld (hl),c
inc hl
ld (hl),0
inc hl
ld (hl),a
inc hl
ld (hl),2
inc hl
inc a
djnz wt1
pop hl

ld e,(ix+DRIVE)
ld d,(ix+TRACK)
call do_move_track

ld e,(ix+DRIVE)
ld d,(ix+TRACK)
call do_format
ret

;;-------------------------------------

.disc_command
defb "DIS","C"+&80

.format_command
defb bdos_format+&80

.select_format_command
defb bdos_select_format+&80

.move_track_command
defb bdos_move_track+&80

.set_retry_count_command
defb bdos_set_retry_count+&80

.set_message_command
defb bdos_set_message+&80

;;-------------------------------------


.format_cmd_data
defw 0
defb 0

.select_format_cmd_data
defw 0
defb 0

.move_track_cmd_data
defw 0
defb 0

.set_retry_count_cmd_data
defw 0
defb 0

.set_message_cmd_data
defw 0
defb 0

;;--------------------------------------

.format_type_txt
defb "Vendor or Data (V or D):",0

.sel_drive_txt
defb "Drive ",0
.drive_txt
defb "(A or B):",0

.insert_disc_txt
defb "Insert disc into drive ",0

.any_key_txt
defb " and press any key",13,10,0

.format_track_txt
defb 13,"Format track ",0

.data
defs 16

.format_data
defs 9*4