;************************************************************************
;*	Super Famicom Disk Operatiing System  file I/O module		*
;*		    Programmed by Y.Nishida				*
;*						[ Nov.01, 1991 ]	*
;************************************************************************

		native
		extend

		include		CPUregs.h
		include		PPUregs.h
		include		sfxdos.h

DOS_fileIO	sect		rel
SFXDOS		group		DOS_fileIO

		dpage		DOS_variable

;===============  Cross reference  ======================================

		extern		FDC_Driver
		extern		Enable_SCC_Int
		extern		Disable_SCC_Int

;===============  Cross definition  =====================================

		global		Init_FDC_Driver		; Initial FDC(uPD72069) driver
		global		Enable_FDC_Int		; Enable FDC interrupt
		global		Disable_FDC_Int		; Disable FDC interrupt
		global		Disk_Format		; Disk format
		global		Disk_Free		; Disk free
		global		Files_First		; Search first file
		global		Files_Next		; Search next file
		global		Select_Drive		; Select dirve
		global		Load_File		; Load file
		global		Save_File		; Save file
		global		Purge_File		; Purge file
		global		Rename_File		; Rename file

;************************************************************************
;*	Reset Disk drive						*
;*									*
;************************************************************************

		mem8
		idx8
Init_FDC_Driver
		pha
		jsr		Disable_Int
		pla
		stz		<Disk_control+0
		sta		<Disk_control+1		; Set Device mode
		jsr		FDC_Driver
		jsr		Enable_Int

;=============== Initialize Disk information work =======================
Disk_Reset_10
		lda		<Disk_control+1
		asl		a
		asl		a
		asl		a
		asl		a
		tay
		ldx		#0
;------------------------------------------------------------------------
Repeat$		lda		Log_Format_2HD,y
		sta		<FloppyDisk_Info,x
		iny
		inx
		cpx		#16
		bne		Repeat$
		rts

;=============== Floppy disk information table ==========================

Log_Format_2HD	byte		1			; sector / cruster
		byte		8			; sector / track
		byte		6			; Directory top sector
		byte		6			; Directory sectors
		byte		2			; FAT sectors
		word		10			; Cruster top sector
		word		1223			; Crusters
		word		1024			; byte / sector
		word		6144			; directory size ( byte )
		byte		0FEH			; FAT code
		byte		0,0
;------------------------------------------------------------------------
Log_Format_2DD8 byte		2			; sector / cruster
		byte		8			; sector / track
		byte		6			; Directory top sector
		byte		7			; Directory sectors
		byte		2			; FAT sectors
		word		9			; Cruster top sector
		word		636			; Crusters
		word		512			; byte / sector
		word		3584			; directory size ( byte )
		byte		0FBH			; FAT code
		byte		0,0
;------------------------------------------------------------------------
Log_Format_2DD9 byte		2			; sector / cruster
		byte		9			; sector / track
		byte		8			; Directory top sector
		byte		7			; Directory sectors
		byte		3			; FAT sectors
		word		11			; Cruster top sector
		word		715			; Crusters
		word		512			; byte / sector
		word		3584			; directory size ( byte )
		byte		0F9H			; FAT code
		byte		0,0

;************************************************************************
;*	Enable FDC interrupt						*
;*									*
;************************************************************************

		mem8
		idx8
Enable_FDC_Int
		lda		#08H
		sta		<Disk_control
		jsr		FDC_Driver
		rts

;************************************************************************
;*	Disable FDC interrupt						*
;*									*
;************************************************************************

		mem8
		idx8
Disable_FDC_Int
		lda		#09H
		sta		<Disk_control
		jsr		FDC_Driver
		rts

;************************************************************************
;*	Get floppy disk drive status					*
;*									*
;************************************************************************

		mem8
		idx8
Select_Drive
		and		#00000001B
		sta		<current_drive
		sta		<Disk_control+1		; Set drive number
		lda		#01H
		sta		<Disk_control+0
		jsr		FDC_Driver		; Get drive status
		lda		<FDC_result+0
		rts

;************************************************************************
;*	Floppy disk phygical format					*
;*									*
;************************************************************************

		mem8
		idx8
Disk_Format
		sta		<Disk_control+1		; Set drive number
		jsr		Check_DiskDrive
		eor		#00100000B
		and		#01100000B		; Disk ready and Not write protect ?
		beq		Format$			; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Format$		jsr		Disable_Int
		lda		#07H
		sta		<Disk_control+0		; Set Format command
		jsr		FDC_Driver		; Disk phygical format
		jsr		Enable_Int
;------------------------------------------------------------------------
		lda		<FDC_result+0
		and		#11000000B
		beq		Logical_Format2
		jmp		Disk_IO_Error

;************************************************************************
;*	Floppy disk logacal format ( MS-DOS format )			*
;*									*
;************************************************************************

		mem8
		idx8
Logical_Format
		sta		<Disk_control+1		; Set drive number
		jsr		Check_DiskDrive
		eor		#00100000B
		and		#01100000B		; Disk ready and Not write protect ?
		beq		Logical_Format2		; yes.
		jmp		Disk_Set_Error

;=============== Initialize Directory  ==================================
Logical_Format2
		jsr		Disk_Recalibrate
		beq		Directory_init$
		jmp		Disk_IO_Error
;------------------------------------------------------------------------
Directory_init$ jsr		Initial_RootDir
		jsr		Disable_Int
		lda		<dir_top_sector
		sta		<current_dir_sec
;------------------------------------------------------------------------
Repeat$		jsr		Set_DirRW_param
		jsr		Write_Data		; Write Directory
		bne		Directory_err$
		inc		<current_dir_sec
		lda		<current_dir_sec
		sec
		sbc		<dir_top_sector		; A = number of searched sectors
		cmp		<dir_nsectors		; A < number of directory sectors ?
		bcc		Repeat$			; yes.
		bra		Logical_Format3
;------------------------------------------------------------------------
Directory_err$	jsr		Enable_Int
		jmp		Disk_IO_Error

;=============== Initialize File Allocation Table =======================
Logical_Format3
		jsr		Initial_FAT
		jsr		Remove_Disk
		pha
		jsr		Enable_Int
		pla
		rts

;************************************************************************
;*	Get free size of disk						*
;*									*
;************************************************************************

		mem8
		idx8
Disk_Free
		sta		<Disk_control+1		; Set drive number
		jsr		Check_DiskDrive
		and		#00100000B		; Disk ready ?
		bne		Skip$			; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Skip$		jsr		Disable_Int		; Disable other interrupt
		jsr		Mount_Disk
		php
		jsr		Enable_Int		; Enable other interrupt
		plp
		bne		Disk_Free_210

;=============== Count free cruster =====================================
Disk_Free_100
		mem16
		idx16
		rep		#00110000B		; Memory,Index 16 bit mode
		stz		<work0			; (work0) = Cluster number
		ldy		#0000H			; IY  = free cluster count
;------------------------------------------------------------------------
Disk_Free_110	lda		<work0
		lsr		a
		bcs		Odd_Cluster$
;------------------------------------------------------------------------
Even_Cluster$	adc		<work0
		tax
		lda		>Disk_FAT,x
		and		#0000111111111111B
		bra		Check_Cluster$
;------------------------------------------------------------------------
Odd_Cluster$	clc
		adc		<work0
		tax
		lda		>Disk_FAT,x
		lsr		a
		lsr		a
		lsr		a
		lsr		a
;------------------------------------------------------------------------
Check_Cluster$	bne		Skip$
		iny
Skip$		inc		<work0
		lda		<work0
		cmp		<nclusters
		bne		Disk_Free_110

;=============== End of check ===========================================
Disk_Free_200
		sty		<Line_buffer+0
		sep		#00110000B		; Memory,Index 16 bit mode
		mem8
		lda		#00000000B
Disk_Free_210	rts

;************************************************************************
;*	Search first file name						*
;*									*
;************************************************************************

		mem8
		idx8
Files_First
		jsr		Check_DiskDrive
		and		#00100000B		; Disk ready ?
		bne		Disk_ready$		; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Disk_ready$	jsr		Disable_Int		; Disable other interrupt
		jsr		Sch_fname_first
		pha
		jsr		Enable_Int		; Enable all interrupt
;------------------------------------------------------------------------
		pla
		rts

;************************************************************************
;*	Search next file name						*
;*									*
;************************************************************************

		mem8
		idx8
Files_Next
		jsr		Check_DiskDrive
		and		#00100000B		; Disk ready ?
		bne		Disk_ready$		; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Disk_ready$	jsr		Disable_Int		; Disable other interrupt
		jsr		Sch_fname_next
		pha
		jsr		Enable_Int		; Enable all interrupt
;------------------------------------------------------------------------
		pla
		rts

;************************************************************************
;*	Purge file							*
;*									*
;************************************************************************

		mem8
		idx8
Purge_File
		jsr		Check_DiskDrive
		eor		#00100000B
		and		#01100000B		; Disk ready and Not write protect ?
		beq		Disk_Ready$		; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Disk_Ready$	jsr		Disable_Int		; Disable other interrupt
		jsr		Sch_fname_first		; Search directory entry
		bne		Exit$
;------------------------------------------------------------------------
		rep		#00010000B		; Index 16 bit mode
		ldx		<directory_entry+26
		stx		<current_cluster
;------------------------------------------------------------------------
		ldx		<current_dir_idx
		lda		#0E5H
		sta		>Disk_Directory,x	; Delete directory
		sep		#00010000B		; Index 8 bit mode
;------------------------------------------------------------------------
		jsr		Mount_Disk		; Read FAT
		bne		Exit$
		jsr		Unlink_FAT		; Unlink file allocation
		jsr		Write_RootDir		; Write directry
		bne		Exit$
		jsr		Remove_Disk		; Write FAT
;------------------------------------------------------------------------
Exit$		pha
		jsr		Enable_Int		; Enable other interrupt
		pla
		rts

;************************************************************************
;*	Rename								*
;*									*
;************************************************************************

		mem8
		idx8
Rename_File
		jsr		Check_DiskDrive
		eor		#00100000B
		and		#01100000B		; Disk ready and Not write protect ?
		beq		Rename_File_100		; yes.
		jmp		Disk_Set_Error

;=============== Check new file name ====================================
Rename_File_100
		jsr		Disable_Int		; Disable other interrupt
		jsr		Rename_File_900		; Set new file name
		jsr		Sch_fname_first		; Search directory entry
		bne		Skip$
		jsr		Enable_Int		; Enable other interrupt
		jmp		File_Exist		; if ( file exist )
;------------------------------------------------------------------------
Skip$		cmp		#04H			; file not found ?
		bne		Rename_File_400		; yes.

;=============== Check new file name ====================================
Rename_File_200
		jsr		Rename_File_900		; Set new file name
		jsr		Sch_fname_first		; Search directory entry
		bne		Rename_File_400

;=============== Set new file name ======================================
Rename_File_300
		idx16
		rep		#00010000B		; Index 16 bit mode
		ldx		<current_dir_idx
		ldy		#0000H
;------------------------------------------------------------------------
Copy_newname$	lda		rename_filename,y
		sta		>Disk_Directory,x
		inx
		iny
		cpy		#11
		bne		Copy_newname$
;------------------------------------------------------------------------
		sep		#00010000B		; Index 8 bit mode
		jsr		Write_RootDir		; Write directry
;------------------------------------------------------------------------
Rename_File_400 pha
		jsr		Enable_Int		; Enable other interrupt
		pla
		rts

;=============== Exchange old fname to new fname ========================
Rename_File_900
		idx8
		ldx		#10
Repeat$		lda		<access_filename,x
		xba
		lda		<rename_filename,x
		sta		<access_filename,x
		xba
		sta		<rename_filename,x
		dex
		bpl		Repeat$
		rts

;************************************************************************
;*	Load file							*
;*									*
;************************************************************************

		mem8
		idx8
Load_File
		jsr		Disable_Int		; Disable other interrupt
		lda		#01H
		jsr		File_Open
		bne		Exit$
		jsr		File_Read
;------------------------------------------------------------------------
Exit$		pha
		jsr		Enable_Int		; Enable other interrupt
		pla
		rts

;************************************************************************
;*	Save file							*
;*									*
;************************************************************************

		mem8
		idx8
Save_File
		jsr		Disable_Int		; Disable other interrupt
		lda		#02H
		jsr		File_Open
		bne		Exit$
;------------------------------------------------------------------------
		jsr		File_Write
		bne		Error$
		jsr		File_Flush
		bra		Exit$
;------------------------------------------------------------------------
Error$		pha
		jsr		File_Flush
		pla
;------------------------------------------------------------------------
Exit$		pha
		jsr		Enable_Int		; Enable other interrupt
		pla
		rts

;************************************************************************
;*	Open file							*
;*									*
;*		ENTRY	A = open mode ( 1:read	2:write )		*
;************************************************************************

		mem8
		idx8
File_Open
		sta		<file_open_mode
		dec		a
		beq		Open_read$
		dec		a
		beq		Open_write$
		jmp		File_Open_Error
;------------------------------------------------------------------------
Open_read$	jsr		Check_DiskDrive
		and		#00100000B		; Disk ready ?
		bne		File_Open_100		; yes.
		jmp		Disk_Set_Error
;------------------------------------------------------------------------
Open_write$	jsr		Check_DiskDrive
		eor		#00100000B
		and		#01100000B		; Disk ready and Not write protect ?
		beq		File_Open_100		; yes.
		jmp		Disk_Set_Error

;=============== Floppy disk mount ======================================
File_Open_100
		jsr		Mount_Disk		; Mount disk
		beq		Mount_ok$
		jmp		Disk_Sys_Error
;------------------------------------------------------------------------
Mount_ok$	jsr		Sch_fname_first
		bne		File_Open_400		; if ( file not exist )
;------------------------------------------------------------------------
		lda		<directory_entry+11
		and		#00011110B		; Normal file ?
		beq		File_Open_300		; yes.
		jmp		File_Not_Found

;=============== When file already exist ================================
File_Open_300
		lda		<file_open_mode
		cmp		#01H			; File read mode ?
		bne		File_Open_320		; no.
;------------------------------------------------------------------------
File_Open_310	rep		#00100000B		; Memory 16 bit mode
		lda		<directory_entry+26
		sta		<current_cluster	; Set first cluster
		stz		<void_cluster		; Set void cluster
		stz		<logical_head+0
		stz		<logical_head+2		; Clear logical head position
		sep		#00100000B		; Memory 8 bit mode
		lda		#00000000B
		rts
;------------------------------------------------------------------------
File_Open_320	lda		<directory_entry+11
		lsr		a			; File read only ?
		bcc		File_Open_330		; no.
		jmp		File_Read_Only
;------------------------------------------------------------------------
File_Open_330	lda		<directory_entry+26
		sta		<current_cluster+0
		lda		<directory_entry+27
		sta		<current_cluster+1	; Set current cluster for delete
		jsr		Unlink_FAT		; Delete file
		bra		File_Open_430

;=============== File not exist =========================================
File_Open_400
		lda		<file_open_mode
		cmp		#01H			; File read mode ?
		bne		File_Open_410		; no.
		jmp		File_Not_Found
;------------------------------------------------------------------------
File_Open_410	lda		<notused_dir_idx+1	; Directory full ?
		bpl		File_Open_420		; no.
		jmp		Directory_Full
;------------------------------------------------------------------------
File_Open_420	sta		<current_dir_idx+1
		lda		<notused_dir_idx+0
		sta		<current_dir_idx+0
		lda		<notused_dir_sec
		sta		<current_dir_sec
		jsr		Read_RootDir2
		bne		File_Open_440
;------------------------------------------------------------------------
File_Open_430	jsr		File_Create
File_Open_440	rts

;************************************************************************
;*	Create File							*
;*									*
;************************************************************************

		mem8
		idx8
File_Create
		lda		#00100000B
		sta		<directory_entry+11	; Set File attribute
;------------------------------------------------------------------------
		ldx		#19
Repeat1$	stz		<directory_entry+12,x
		dex
		bpl		Repeat1$
;------------------------------------------------------------------------
		ldx		#10
Repeat2$	lda		<access_filename,x
		sta		<directory_entry,x
		dex
		bpl		Repeat2$

;=============== Store first cluster ====================================
File_Create_100
		stz		<void_cluster+0
		stz		<void_cluster+1
		jsr		Search_VoidClus
		bcc		Skip$
		jmp		Disk_Full
;------------------------------------------------------------------------
Skip$		mem16
		rep		#00100000B		; Memory 16 bit mode
		lda		<void_cluster
		sta		<directory_entry+26	; Set first cluster
		sta		<current_cluster	; Set current cluster
		stz		<logical_head+0
		stz		<logical_head+2		; Clear logical head position
		stz		<secbuf_count		; Clear sector buffer counter
;------------------------------------------------------------------------
		sep		#00100000B		; Memory 8 bit mode
		jmp		File_Flush_2

;************************************************************************
;*	Flush file							*
;*									*
;************************************************************************

		mem8
		idx8
File_Flush
		lda		<secbuf_count+0
		ora		<secbuf_count+1
		beq		File_Flush_2
;------------------------------------------------------------------------
		jsr		Set_SecRW_param
		jsr		Write_Cluster		; Write Data
		bne		File_Flush_exit
;------------------------------------------------------------------------
File_Flush_2	jsr		Copy_Directory		; Copy directory entry
		jsr		Write_RootDir		; Write directry
		bne		File_Flush_exit
		jsr		Remove_Disk		; Write FAT
File_Flush_exit rts

;************************************************************************
;*	Copy directory entry						*
;*									*
;************************************************************************

		mem16
		idx16
Copy_Directory
		php
		rep		#00110000B		; Memory,Index 16 bit mode
;------------------------------------------------------------------------
		ldy		#0000H
		ldx		<current_dir_idx
Repeat$		lda		directory_entry,y
		sta		>Disk_Directory,x
		inx
		inx
		iny
		iny
		cpy		#0020H
		bne		Repeat$
;------------------------------------------------------------------------
		plp
		rts

;************************************************************************
;*	Read file							*
;*									*
;************************************************************************

		mem16
		idx8
File_Read
		stz		<data_address+3
		stz		<data_length+3
		jsr		Set_SecRW_param
		rep		#00100000B
		stz		<access_size+0
		stz		<access_size+2

;=============== Read data to sector buffer =============================
File_Read_100
		lda		<data_length+0
		ora		<data_length+2		; Data length == 0 ?
		beq		Complete$		; yes.
;------------------------------------------------------------------------
		lda		<logical_head+2
		cmp		<directory_entry+30
		bne		Skip$
		lda		<logical_head+0
		cmp		<directory_entry+28	; Logical head pos. == bottom of file ?
Skip$		bcs		Complete$		; yes.
;------------------------------------------------------------------------
		lda		<logical_head+0
		and		#0000001111111111B
		sta		<work0
		bne		File_Read_200
		jsr		Read_Cluster
		beq		File_Read_200
		rts
;------------------------------------------------------------------------
Complete$	mem8
		sep		#00110000B
		lda		#00000000B
		rts

;=============== Calculate number of transfer datas =====================
File_Read_200
		mem16
		idx16
		rep		#00110000B		; Memory 16 bit mode
;------------------------------------------------------------------------
Calc_file_rem$	sec
		lda		<directory_entry+28
		sbc		<logical_head+0
		sta		<work2
		lda		<directory_entry+30
		sbc		<logical_head+2
		sta		<work3
;------------------------------------------------------------------------
Calc_bank_rem$	sec
		lda		#0000H
		sbc		<data_address+0
		sta		<work1			; work1 = Address counter
		bne		Calc_sec_rem$
		dec		<work1			; if ( work1 == 0 ) work1 =FFFFH ( dummy )
;------------------------------------------------------------------------
Calc_sec_rem$	sec
		lda		#0400H
		sbc		<work0			; Acc = Sector remains
;------------------------------------------------------------------------
		cmp		<work1			; Acc < Bank remains ?
		bcc		Skip1$			; yes.
		lda		<work1			; Acc = Bank remains
;------------------------------------------------------------------------
Skip1$		ldx		<work3
		bne		Skip2$
		cmp		<work2			; Acc < File remains ?
		bcc		Skip2$			; yes.
		lda		<work2			; Acc = File remains
;------------------------------------------------------------------------
Skip2$		ldx		<data_length+2
		bne		Skip3$
		cmp		<data_length+0		; Acc < Data length ?
		bcc		Skip3$			; yes.
		lda		<data_length+0		; Acc = Data length
;------------------------------------------------------------------------
Skip3$		sta		<work1			; Set number of transfer datas

;=============== transfer data ==========================================
File_Read_300
		mem8
		idx16
		sep		#00100000B
;------------------------------------------------------------------------
		phb
		lda		#bank Disk_Sector
		pha
		plb					; Set Data Bank Register
;------------------------------------------------------------------------
		ldx		<work0			; IX = Sector buffer pointer
		ldy		#0000H			; IY = Destination pointer
;------------------------------------------------------------------------
Repeat$		lda		Disk_Sector&0FFFFH,x
		sta		[data_address],y
		inx
		iny
		cpy		<work1
		bne		Repeat$
		plb

;=============== Set data pointer =======================================
File_Read_400
		mem16
		idx16
		rep		#00110001B
;------------------------------------------------------------------------
Add_nbytes$	lda		<access_size+0
		adc		<work1
		sta		<access_size+0
		bcc		Add_address$
		inc		<access_size+2
;------------------------------------------------------------------------
Add_address$	clc
		lda		<data_address+0
		adc		<work1
		sta		<data_address+0
		bcc		Add_secptr$
		inc		<data_address+2
		lda		<data_address+2
		cmp		#0040H
		bcs		Add_secptr$
		lda		#8000H
		sta		<data_address+0
;------------------------------------------------------------------------
Add_secptr$	clc
		lda		<logical_head+0
		adc		<work1
		sta		<logical_head+0
		bcc		Sub_ndatas$
		inc		<logical_head+2
;------------------------------------------------------------------------
Sub_ndatas$	sec
		lda		<data_length+0
		sbc		<work1
		sta		<data_length+0
		bcs		Next_read$
		dec		<data_length+2
;------------------------------------------------------------------------
Next_read$	sep		#00010000B		; Index 8 bit mode
		jmp		File_Read_100

;************************************************************************
;*	White file							*
;*									*
;************************************************************************

		mem16
		idx8
File_Write
		stz		<data_address+3
		stz		<data_length+3
		jsr		Set_SecRW_param
		rep		#00100000B
		stz		<access_size+0
		stz		<access_size+2

;=============== Write data to disk =====================================
File_Write_100
		lda		<data_length+0
		ora		<data_length+2		; Data length == 0 ?
		beq		Complete$		; yes.
;------------------------------------------------------------------------
		lda		<secbuf_count
		cmp		#0400H
		bne		File_Write_200
;------------------------------------------------------------------------
		stz		<secbuf_count
		jsr		Write_Cluster
		bne		Error$
		jsr		Search_VoidClus
		bcc		Skip$
		sep		#00110000B
		jmp		Disk_Full
Skip$		jsr		Link_FAT
		bra		File_Write_200
;------------------------------------------------------------------------
Complete$	mem8
		sep		#00110000B
		lda		#00000000B
		rts
;------------------------------------------------------------------------
Error$		sep		#00110000B
		rts

;=============== Calculate number of transfer datas =====================
File_Write_200
		mem16
		idx16
		rep		#00110000B		; Memory 16 bit mode
;------------------------------------------------------------------------
Calc_bank_rem$	sec
		lda		#0000H
		sbc		<data_address+0
		sta		<work1			; work1 = Address counter
		bne		Calc_sec_rem$
		dec		<work1			; if ( work1 == 0 ) work1 =FFFFH ( dummy )
;------------------------------------------------------------------------
Calc_sec_rem$	sec
		lda		#0400H
		sbc		<secbuf_count		; Acc = Sector remains
;------------------------------------------------------------------------
		cmp		<work1			; Acc < Bank remains ?
		bcc		Skip1$			; yes.
		lda		<work1			; Acc = Bank remains
;------------------------------------------------------------------------
Skip1$		ldx		<data_length+2
		bne		Skip2$
		cmp		<data_length+0		; Acc < Data length ?
		bcc		Skip2$			; yes.
		lda		<data_length+0		; Acc = Data length
;------------------------------------------------------------------------
Skip2$		sta		<work1			; Set number of transfer datas

;=============== Transfer data ==========================================
File_Write_300
		mem8
		idx16
		sep		#00100000B
;------------------------------------------------------------------------
		phb
		lda		#bank Disk_Sector
		pha
		plb					; Set Data Bank Register
;------------------------------------------------------------------------
		ldx		<secbuf_count		; IX = Sector buffer pointer
		ldy		#0000H			; IY = Destination pointer
;------------------------------------------------------------------------
Repeat$		lda		[data_address],y
		sta		Disk_Sector&0FFFFH,x
		inx
		iny
		cpy		<work1
		bne		Repeat$
		plb

;=============== Set data pointer =======================================
File_Write_400
		mem16
		idx16
		rep		#00110001B
;------------------------------------------------------------------------
Add_nbytes$	lda		<access_size+0
		adc		<work1
		sta		<access_size+0
		bcc		Add_address$
		inc		<access_size+2
;------------------------------------------------------------------------
Add_address$	clc
		lda		<data_address+0
		adc		<work1
		sta		<data_address+0
		bcc		Add_head$
		inc		<data_address+2
		lda		<data_address+2
		cmp		#0040H
		bcs		Add_head$
		lda		#8000H
		sta		<data_address+0
;------------------------------------------------------------------------
Add_head$	clc
		lda		<logical_head+0
		adc		<work1
		sta		<logical_head+0
		bcc		Add_seccnt$
		inc		<logical_head+2
;------------------------------------------------------------------------
Add_seccnt$	clc
		lda		<secbuf_count
		adc		<work1
		sta		<secbuf_count
;------------------------------------------------------------------------
Sub_ndatas$	sec
		lda		<data_length+0
		sbc		<work1
		sta		<data_length+0
		bcs		Set_file_size$
		dec		<data_length+2
;------------------------------------------------------------------------
Set_file_size$	lda		<logical_head+0
		sta		<directory_entry+28
		lda		<logical_head+2
		sta		<directory_entry+30
;------------------------------------------------------------------------
		sep		#00010000B
		jmp		File_Write_100

;************************************************************************
;*	Read one cluster from disk					*
;*									*
;************************************************************************

		mem16
		idx8
Read_Cluster
		lda		<current_cluster
		cmp		#0FF8H
		bcs		Read_Cluster_11
;------------------------------------------------------------------------
Read_Cluster_10 jsr		Set_TrkSec1
		mem8
		sep		#00100000B
		jsr		Read_Data
		beq		Read_Cluster_20
;------------------------------------------------------------------------
Read_Cluster_11 sep		#00110000B
		jmp		Disk_IO_Error
;------------------------------------------------------------------------
Read_Cluster_20 jsr		Next_Cluster
		lda		#00000000B
Complete$	rts

;************************************************************************
;*	Write sector buffer to disk					*
;*									*
;************************************************************************

		mem8
		idx8
Write_Cluster
		rep		#00100000B
		lda		<current_cluster
		jsr		Set_TrkSec1
		sep		#00100000B
		jsr		Write_Data
		beq		Complete$
		jmp		Disk_IO_Error
Complete$	rts

;************************************************************************
;*	Calculate track number and sector number			*
;*									*
;*		ENTRY	Set_TrkSec1: Acc = Cluster No.			*
;*			Set_TrkSec2: Acc = Logical sector No.		*
;************************************************************************

		mem16
		idx8
Set_TrkSec1
		ldx		<sectors_cruster
		bra		Skip$
Repeat$		asl		a
Skip$		dex
		bne		Repeat$
;------------------------------------------------------------------------
		clc
		adc		<cls_top_sector		; Acc = Logical sector number
;------------------------------------------------------------------------
Set_TrkSec2	dec		a
		sta		>Dividend
		mem8
		sep		#00100000B
		lda		<sectors_track
		sta		>Divisor
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
;------------------------------------------------------------------------
		lda		>Divide+0
		sta		<Disk_control+2		; Set track No.
		lda		>Rest+0
		inc		a
		sta		<Disk_control+3		; Set sector No.
		rts

;************************************************************************
;*	Set parameter for data read/write				*
;*									*
;************************************************************************

		mem8
Set_SecRW_param
		lda		<sectors_cruster
		sta		<Disk_control+4		; Set sector / cruster
		lda		#low  Disk_Sector
		sta		<Disk_control+5		; Set address low of sector buffer
		lda		#high Disk_Sector
		sta		<Disk_control+6		; Set address high of sector buffer
		lda		#bank Disk_Sector
		sta		<Disk_control+7		; Set bank of sector buffer
		rts










;************************************************************************
;*	Search first file name						*
;*									*
;************************************************************************

		mem8
		idx16
Sch_fname_first
		rep		#00010000B		; Index 16 bit mode
;------------------------------------------------------------------------
		ldx		#0000H
		stx		<current_dir_idx	; Initial currect directory index
		ldx		#0FFFFH
		stx		<notused_dir_idx	; Initial not used directory index
		lda		<dir_top_sector
		sta		<current_dir_sec	; Initial directory sector
		jsr		Read_RootDir1
		beq		Skip$
		sep		#00110000B		; Memory,Index 8 bit mode
		rts
;------------------------------------------------------------------------
Skip$		ldx		<current_dir_idx
		bra		Search_next_10

;************************************************************************
;*	Search hnext file name						*
;*									*
;************************************************************************

		mem8
		idx16
Sch_fname_next
		rep		#00010000B		; Index 16 bit mode
		ldx		<current_dir_idx
		phx
		bra		Search_next_11

;=============== Comapre file name ======================================
Search_next_10
		lda		>Disk_Directory,x	; End of directory ?
		beq		Search_next_40		; yes.
		cmp		#0E5H			; Deleted entry ?
		beq		Search_next_30		; yes.
;------------------------------------------------------------------------
		phx
		jsr		Compare_fname		; Compare file name
		beq		Search_next_50		; if ( the same )
;------------------------------------------------------------------------
Search_next_11	mem16
		rep		#00100001B		; Memory 16 bit mode
		pla
		adc		#0020H
		tax
		mem8
		sep		#00100000B		; Memory 8 bit mode
		cpx		<sector_length
		bne		Search_next_10

;=============== Read next directory sector =============================
Search_next_20
		lda		<current_dir_sec
		inc		a
		sec
		sbc		<dir_top_sector		; A = number of searched sectors
		cmp		<dir_nsectors		; A < number of directory sectors ?
		bcs		Search_next_41		; no.
;------------------------------------------------------------------------
		inc		<current_dir_sec
		jsr		Read_RootDir2		; Read next sector
		bne		Search_next_51		; if ( error )
		ldx		#0000H
		bra		Search_next_10

;=============== Found free directory entry =============================
Search_next_30
		phx
		ldy		<notused_dir_idx
		bpl		Search_next_11
;------------------------------------------------------------------------
		stx		<notused_dir_idx
		lda		<current_dir_sec
		sta		<notused_dir_sec
		bra		Search_next_11

;=============== File not found =========================================
Search_next_40
		ldy		<notused_dir_idx
		bpl		Search_next_41
;------------------------------------------------------------------------
		stx		<notused_dir_idx
		lda		<current_dir_sec
		sta		<notused_dir_sec
;------------------------------------------------------------------------
Search_next_41	stx		<current_dir_idx
		sep		#00110000B		; Memory,Index 8 bit mode
		jmp		File_Not_Found

;=============== Found file name ========================================
Search_next_50
		plx
		phx
		ldy		#0000H
;------------------------------------------------------------------------
Copy_filename$	lda		>Disk_Directory,x
		sta		directory_entry,y
		inx
		iny
		cpy		#0020H
		bne		Copy_filename$
;-----------------------------------------------------------------------
		plx
		stx		<current_dir_idx
		lda		#00000000B
;-----------------------------------------------------------------------
Search_next_51	sep		#00110000B		; Memory,Index 8 bit mode
		rts

;************************************************************************
;*	Compare file name to directory					*
;*									*
;*		Exit	Z=0: Different;	   Z=1: The same		*
;************************************************************************

		mem8
		idx16
Compare_fname
		ldy		#0000H
;------------------------------------------------------------------------
Next_character$ lda		search_filename,y
		cmp		#'?'
		beq		Same_char$
		cmp		>Disk_Directory,x
		bne		Different_char$
Same_char$	inx
		iny
		cpy		#000BH
		bne		Next_character$
;------------------------------------------------------------------------
Different_char$ rts

;************************************************************************
;*	Read root directory from disk					*
;*									*
;*		EXIT	A = Error code					*
;************************************************************************

		mem8
		idx8
Read_RootDir1
		jsr		Disk_Recalibrate	; Head recalibrate
		beq		Read_RootDir2
		jmp		Disk_IO_Error
;------------------------------------------------------------------------
Read_RootDir2	jsr		Set_DirRW_param
		jsr		Read_Data		; Read Directory sectors
		beq		Complete$
		jmp		Disk_Sys_Error
;------------------------------------------------------------------------
Complete$	rts

;************************************************************************
;*	Write root directory to disk					*
;*									*
;************************************************************************

		mem8
		idx8
Write_RootDir
		jsr		Set_DirRW_param
		jsr		Write_Data		; Read Directory sector
		beq		Complete$
		jmp		Disk_Sys_Error
;------------------------------------------------------------------------
Complete$	rts

;************************************************************************
;*	Set parameter for directory read/write				*
;*									*
;************************************************************************

		mem8
Set_DirRW_param
		stz		<Disk_control+2		; Set track No.
		lda		<current_dir_sec
		cmp		<sectors_track
		beq		Skip$
		bcc		Skip$
		sbc		<sectors_track
		inc		<Disk_control+2
Skip$		sta		<Disk_control+3		; Set sector No.
;------------------------------------------------------------------------
		lda		#1
		sta		<Disk_control+4		; Set number of sectors in directory
		lda		#low  Disk_Directory
		sta		<Disk_control+5		; Set address low of directory buffer
		lda		#high Disk_Directory
		sta		<Disk_control+6		; Set address high of directory buffer
		lda		#bank Disk_Directory
		sta		<Disk_control+7		; Set bank of directory buffer
		rts

;************************************************************************
;*	Create Initial directory data					*
;*									*
;************************************************************************

		mem16
		idx16
Initial_RootDir
		rep		#00110000B		; Memory,Index 16 bit mode
		ldx		<sector_length
		dex
		dex
;------------------------------------------------------------------------
Repeat1$	lda		#0E5E5H
		ldy		#15
Repeat2$	sta		>Disk_Directory,x
		dex
		dex
		dey
		bne		Repeat2$
;------------------------------------------------------------------------
		lda		#0E500H
		sta		>Disk_Directory,x
		dex
		dex
		bpl		Repeat1$
;------------------------------------------------------------------------
		sep		#00110000B		; Memory,Index 8 bit mode
		rts








;************************************************************************
;*	Link cluster							*
;*									*
;************************************************************************

		mem16
		idx16
Link_FAT
		php
		rep		#00110000B		; Memory,Index 16 bit mode
;------------------------------------------------------------------------
		lda		<current_cluster
		lsr		a
		bcs		Odd_Cluster$

;=============== when cluster number is even ============================
Even_Cluster$
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		and		#1111000000000000B
		ora		<void_cluster
		sta		>Disk_FAT,x
		lda		<void_cluster
		sta		<current_cluster
;------------------------------------------------------------------------
		plp
		rts

;=============== when cluster number is odd =============================
Odd_Cluster$
		clc
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		and		#0000000000001111B
		sta		>Disk_FAT,x
		lda		<void_cluster
		sta		<current_cluster
		asl		a
		asl		a
		asl		a
		asl		a
		ora		>Disk_FAT,x
		sta		>Disk_FAT,x
;------------------------------------------------------------------------
		plp
		rts

;************************************************************************
;*	Get next cluster number from FAT				*
;*									*
;************************************************************************

		mem16
		idx16
Next_Cluster
		php
		rep		#00110000B		; Memory,Index 16 bit mode
;------------------------------------------------------------------------
		lda		<current_cluster
		lsr		a
		bcs		Odd_Cluster$

;=============== when cluster number is even ============================
Even_Cluster$
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		and		#0000111111111111B
		sta		<current_cluster
;------------------------------------------------------------------------
		plp
		rts

;=============== when cruster number is odd =============================
Odd_Cluster$
		clc
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		lsr		a
		lsr		a
		lsr		a
		lsr		a
		sta		<current_cluster
;------------------------------------------------------------------------
		plp
		rts

;************************************************************************
;*	Search null cluster						*
;*									*
;************************************************************************

		mem16
		idx16
Search_VoidClus
		php
		rep		#00110000B		; Memory,Index 16 bit mode
;------------------------------------------------------------------------
Sch_VoidClus_10 inc		<void_cluster
		lda		<void_cluster
		cmp		<nclusters
		bcs		Error$
;------------------------------------------------------------------------
		lsr		a
		bcs		Sch_VoidClus_30
		bra		Sch_VoidClus_20
;------------------------------------------------------------------------
Error$		plp
		sec
		rts

;=============== when cluster number is even ============================
Sch_VoidClus_20
		adc		<void_cluster
		tax
		lda		>Disk_FAT,x
		and		#0000111111111111B
		bne		Sch_VoidClus_10
;------------------------------------------------------------------------
		lda		>Disk_FAT,x
		ora		#0000111111111111B
		sta		>Disk_FAT,x
		bra		Sch_VoidClus_31

;=============== when cluster number is odd =============================
Sch_VoidClus_30
		clc
		adc		<void_cluster
		tax
		lda		>Disk_FAT,x
		and		#1111111111110000B
		bne		Sch_VoidClus_10
;------------------------------------------------------------------------
		lda		>Disk_FAT,x
		ora		#1111111111110000B
		sta		>Disk_FAT,x
;------------------------------------------------------------------------
Sch_VoidClus_31 plp
		clc
		rts

;************************************************************************
;*	Free cluster used file						*
;*									*
;************************************************************************

		mem16
		idx16
Unlink_FAT
		php
		rep		#00110000B		; Memory,Index 16 bit mode

;=============== Check end of allocation ================================
Unlink_FAT_10
		lda		<current_cluster
		cmp		#0FF8H
		bcs		Exit$
;------------------------------------------------------------------------
		lsr		a
		bcs		Unlink_FAT_30		; if ( cluster is odd  )
		bra		Unlink_FAT_20		; if ( cluster is even )
;------------------------------------------------------------------------
Exit$		plp
		rts

;=============== when cluster number is even  ===========================
Unlink_FAT_20
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		and		#0000111111111111B
		sta		<current_cluster	; Set Next cluster number
;------------------------------------------------------------------------
		lda		>Disk_FAT,x
		and		#1111000000000000B
		sta		>Disk_FAT,x
		bra		Unlink_FAT_10

;=============== when cluster number is odd =============================
Unlink_FAT_30
		clc
		adc		<current_cluster
		tax
		lda		>Disk_FAT,x
		lsr		a
		lsr		a
		lsr		a
		lsr		a
		sta		<current_cluster	; Set Next cluster number
;------------------------------------------------------------------------
		lda		>Disk_FAT,x
		and		#0000000000001111B
		sta		>Disk_FAT,x
		bra		Unlink_FAT_10

;************************************************************************
;*	Mount disk ( Read FAT from disk )				*
;*									*
;*		EXIT	A = Error code					*
;************************************************************************

		mem8
		idx8
Mount_Disk
		jsr		Disk_Recalibrate	; Head recalibrate
		beq		Read_FAT$
		jmp		Disk_IO_Error
;------------------------------------------------------------------------
Read_FAT$	jsr		Set_FATRW_param
		jsr		Read_Data		; Read File Allocation Table main
		beq		Complete$
		jmp		Disk_Sys_Error
;------------------------------------------------------------------------
Complete$	rts

;************************************************************************
;*	Remove disk ( Write FAT to disk )				*
;*									*
;*		EXIT	A = Error code					*
;************************************************************************

		mem8
		idx8
Remove_Disk
		jsr		Set_FATRW_param
		jsr		Write_Data		; Write File Allocation Table main
		sta		<work0
;------------------------------------------------------------------------
		clc
		lda		<Disk_control+3
		adc		<FAT_nsectors
		sta		<Disk_control+3
		jsr		Write_Data		; Write File Allocation Table sub
		ora		<work0
		beq		Complete$
		jmp		Disk_Sys_Error
;------------------------------------------------------------------------
Complete$	rts

;************************************************************************
;*	Set parameter for FAT read/write				*
;*									*
;************************************************************************

		mem8
Set_FATRW_param
		stz		<Disk_control+2		; Set track No.
		lda		#2
		sta		<Disk_control+3		; Set sector No.
		lda		<FAT_nsectors
		sta		<Disk_control+4		; Set number of sectors in FAT
		lda		#low  Disk_FAT
		sta		<Disk_control+5		; Set address low of FAT buffer
		lda		#high Disk_FAT
		sta		<Disk_control+6		; Set address high of FAT buffer
		lda		#bank Disk_FAT
		sta		<Disk_control+7		; Set bank of FAT buffer
		rts

;************************************************************************
;*	Create initial FAT data						*
;*									*
;************************************************************************

		mem16
		idx16
Initial_FAT
		rep		#00110000B		; Memory,Index 16 bit mode
		lda		#0000H
		ldx		#07FEH
;------------------------------------------------------------------------
Repeat$		sta		>Disk_FAT,x
		dex
		dex
		bne		Repeat$
;------------------------------------------------------------------------
		lda		#0FFFFH
		sta		>Disk_FAT+1
;------------------------------------------------------------------------
		mem8
		sep		#00100000B		; Memory 8 bit mode
		lda		<FAT_code
		sta		>Disk_FAT+0
;------------------------------------------------------------------------
		sep		#00110000B		; Memory,Index 8 bit mode
		rts







;************************************************************************
;*	Disk recalibrate						*
;*									*
;*		EXIT	A = Error flag					*
;************************************************************************

		mem8
		idx8
Disk_Recalibrate
		lda		#02H
		sta		<Disk_control+0		; Set Verify command
		lda		<current_drive
		sta		<Disk_control+1		; Set Drive number
		jsr		FDC_Driver
		lda		<FDC_result+0
		and		#11000000B		; Normal terminate ?
		rts

;************************************************************************
;*	Read data							*
;*									*
;*		ENTRY	(Disk_control) = parameters			*
;*		EXIT	A = Error flag					*
;************************************************************************

		mem8
		idx8
Read_Data
		lda		#04H
		sta		<Disk_control+0		; Set Read command
		lda		<current_drive
		sta		<Disk_control+1		; Set Drive number
		jsr		FDC_Driver
		lda		<FDC_result+0
		and		#11000000B		; Normal terminate ?
		rts

;************************************************************************
;*	Write data with verify						*
;*									*
;*		ENTRY	(Disk_control) = parameters			*
;*		EXIT	A = Error flag					*
;************************************************************************

		mem8
		idx8
Write_Data
		lda		#05H
		sta		<Disk_control+0		; Set Write command
		lda		<current_drive
		sta		<Disk_control+1		; Set Drive number
		jsr		FDC_Driver
;------------------------------------------------------------------------
		mem16
		rep		#00100000B		; Memory 16 bit mode
		lda		#400H
Wait$		dec		a
		bne		Wait$
;------------------------------------------------------------------------
		mem8
		sep		#00100000B		; Memory 8 bit mode
		lda		<FDC_result+0
		and		#11000000B		; Normal terminate ?
		beq		Verify_Data		; no.
		rts

;************************************************************************
;*	Verify data							*
;*									*
;*		ENTRY	(Disk_control) = parameters			*
;*		EXIT	A = Error flag					*
;************************************************************************

		mem8
		idx8
Verify_Data
		lda		#06H
		sta		<Disk_control+0		; Set Verify command
		lda		<current_drive
		sta		<Disk_control+1		; Set Drive number
		jsr		FDC_Driver
		lda		<FDC_result+0
		and		#11000000B		; Normal terminate ?
		rts

;************************************************************************
;*	Get Disk drive status						*
;*									*
;*		EXIT	A = Device status				*
;************************************************************************

		mem8
		idx8
Check_DiskDrive
		lda		#01H
		sta		<Disk_control+0		; Set Device status command
		lda		<current_drive
		sta		<Disk_control+1		; Set Drive number
		jsr		FDC_Driver		; Get Device status
;-----------------------------------------------------------------------
		lda		<FDC_result+0
		rts

;************************************************************************
;*	Enable all interrupt						*
;*									*
;************************************************************************

		mem8
Enable_Int
		jsr		Enable_SCC_Int		; Enable IRQ
		lda		NMI_status
		lda		<NMI_switch
		sta		Int_control		; Enable NMI
		rts

;************************************************************************
;*	Disable NMI & SCC & HV counter Interrupt			*
;*									*
;************************************************************************

		mem8
Disable_Int
		jsr		Disable_SCC_Int		; Disable IRQ
		lda		<NMI_switch
		and		#01001110B
		sta		Int_control		; Disable NMI & HV counter
		rts

;************************************************************************
;*	Set error code							*
;*									*
;*		EXIT	A = Error code					*
;************************************************************************

		mem8

Disk_Set_Error	lda		#01H
		rts
Disk_IO_Error	lda		#02H
		rts
Disk_Sys_Error	lda		#03H
		rts
File_Not_Found	lda		#04H
		rts
File_Open_Error lda		#05H
		rts
Directory_Full	lda		#06H
		rts
File_Read_Only	lda		#07H
		rts
Disk_Full	lda		#08H
		rts
File_Exist	lda		#09H
		rts

		end
