;; This example shows how it is possible to detect a Amstrad
;; or Vortex floppy disc controller.
;;
;; Both controllers use a NEC765 compatible floppy disc controller,
;; and the same control method to read/write to the discs
;; using the controller (polling).
;;
;; But the NEC765 controller is accessed through different 
;; I/O port addressess for each controller.
;;
;; This example attempts to send a "invalid" command to the NEC765
;; FDC. If the correct responses are detected, then it is assumed
;; that the controller is present and connected.

org &4000
nolist

.txt_output equ &bb5a
.ams_fdc_io equ &fb7e		;; I/O address for main status register of NEC765 in Amstrad controller
.vtx_fdc_io equ &fbf6		;; I/O address for main status register of NEC765 in Vortex controller.

;;---------------------------------------------------
;; 
;; do detection and report result

.do_detect
ld hl,amstrad_di
call output_text

;;------------------------------------
;; detect amstrad floppy disc interface

ld bc,ams_fdc_io
call detect_fdc
ld hl,detected
jr nc,dd1
ld hl,not_detected
.dd1
call output_text

call crlf

;;------------------------------------
;; detect vortex floppy disc interface

ld hl,vortex_di
call output_text

ld bc,vtx_fdc_io
call detect_fdc
ld hl,detected
jr nc,dd2
ld hl,not_detected
.dd2
call output_text

call crlf
ret

;;-----------------------------------------------------
;; messages

.amstrad_di
defb "Amstrad disc interface",0
.vortex_di
defb "Vortex disc interface",0

.detected
defb " detected",0
.not_detected
defb " not detected",0



;;-----------------------------------------------------
;; new line

.crlf
ld a,13
call txt_output
ld a,10
call txt_output
ret

;;-----------------------------------------------------
;; output a null terminated string

.output_text
ld a,(hl)     ;; get character
inc hl      ;; update character pointer
or a      ;; termination char (0)?
ret z
call txt_output    ;; output character to screen
jr output_text    ;; loop for next character

;;-----------------------------------------------------------------
;; Entry conditions:
;; BC = I/O address for FDC main status register
;;
;; Exit conditions:
;; carry flag set -> not detected
;; carry flag clear -> detected
;;
;; assumes:
;; - I/O port for read data = I/O port for write data
;; - I/O port for read data = I/O port for write data = I/O port for main status register + 1
;; - FDC is not executing a command at this time
;;
;; Attempts to execute a invalid command.

.detect_fdc
;; initialise timeout
ld e,0

.df1
;; read main status register
in a,(c)
;; isolate flags we are interested in
and %11110000
;; test for the following flags:
;; - Data register of FDC is ready for data transfer
;; - Data transfer direction is from CPU->FDC
;; - Not in Execution Mode
;; - FDC not busy
cp %10000000
jr z,df2

;; decrease timeout
dec e
jr nz,df1
;; failed
scf
ret

.df2
;; ok... FDC is ready to accept a command

;;----------------------------------------
;; write the "invalid" command

inc c
;; BC = I/O address of FDC data register

;; code for invalid command
xor a
;; write to FDC data register
out (c),a
dec c
;; BC = I/O address of FDC main status register

;;--------------------------
;; wait for fdc to become busy
ld e,0
.df3
;; read main status register
in a,(c)
and %00010000
jr nz,df4

dec e
jr nz,df3
;; failed
scf
ret

.df4
;; saw fdc become busy

;;--------------------------------
;; wait for execution phase

ld e,0
.df5
in a,(c)
and %11110000
;; test for the following flags:
;; - Data register of FDC is ready for data transfer
;; - Data transfer direction is from CPU->FDC
;; - Not in Execution Mode
;; - FDC busy
cp %11010000
jr z,df6
dec e
jr nz,df5

;; failed
scf
ret

.df6
;; ok saw start of result phase
inc c
;; BC = I/O address of FDC data register

;; read result phase data
in a,(c)

dec c

cp &80
jr nz,df7

;; ok successful
or a
ret

.df7
;; failed
scf
ret