    ;; 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

    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