OSDN Git Service

V309
[fast-forth/master.git] / forthMSP430FR_SD_RW.asm
index 6637cb5..4dc59bf 100644 (file)
@@ -1,6 +1,26 @@
  ; -*- coding: utf-8 -*-
 ; DTCforthMSP430FR5xxxSD_RW.asm
 
+; and only for FR5xxx and FR6xxx with RTC_B or RTC_C hardware if you want write file with date and time.
+
+; Tested with MSP-EXP430FR5969 launchpad
+; Copyright (C) <2015>  <J.M. THOORENS>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+
 ; ======================================================================
 ; READ" primitive as part of OpenPathName
 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
 ; ======================================================================
 
 ; ----------------------------------;
-OPEN_QREAD                          ;
+OPEN_1W                             ;
     CMP     #1,W                    ; open_type = READ" ?
-    JNZ     OPEN_QWRITE             ; no : goto next step
+    JNZ     OPEN_2W                 ; no : goto next step
 ; ----------------------------------;
 OPEN_READ                           ;
 ; ----------------------------------;
     CMP     #0,S                    ; open file happy end ?
     JNZ     OPEN_Error              ; no
-    MOV @IP+,PC                     ;
+    MOV     @IP+,PC                 ; no more to do
 ; ----------------------------------;
 
 ;Z READ            -- f
@@ -26,120 +46,199 @@ OPEN_READ                           ;
 ; sectors are loaded in SD_BUF and BufferLen leave the count of loaded bytes.
 ; when the last sector of file is loaded in buffer, the handle is automatically closed and flag is true (<>0).
 
-; ----------------------------------;
+; ==================================;
     FORTHWORD "READ"                ; -- fl     closed flag
-; ----------------------------------;
+; ==================================;
 READ
     SUB     #2,PSP                  ;
     MOV     TOS,0(PSP)              ;
     MOV     &CurrentHdl,TOS         ;
     CALL    #Read_File              ;SWX
-READ_END
-    SUB     &CurrentHdl,TOS         ; -- fl     if fl <>0 (if Z=0) handle is closed
-    MOV @IP+,PC                     ;
+    SUB     &CurrentHdl,TOS         ; -- fl     if fl<>0 (if Z=0) handle is closed
+    MOV     @IP+,PC                 ;
 ; ----------------------------------;
 
 
-;-----------------------------------------------------------------------
-; WRITE" (CREATE part) subroutines
-;-----------------------------------------------------------------------
-
-; parse all FAT sectors until free cluster is found 
-; this NewCluster is marked as the end's one (-1)
+; ==================================;
+SaveSectorWtoFATs                   ;SWXY W = FATsector loaded in SD_buf
+; ==================================;
+    MOV     W,Y                     ; Y = W
+    ADD     &OrgFAT1,W              ; update FAT#1
+    CALL    #WriteFATsectorW        ;SWX
+    MOV     Y,W                     ; W = FATsector
+    ADD     &OrgFAT2,W              ; update FAT#2
+WriteFATsectorW                     ;
+    MOV     #0,X                    ;
+    MOV     #WriteSectorWX,PC       ;SWX then RET
+; ----------------------------------;
 
+; parse all FAT sectors until free cluster is found
+; this New Cluster is marked as the end's one (-1)
 
-; input : CurFATsector
+; input : W = FATSector, Y = FAToffset
 ; use SWX registers
-; output: W = new FATsector, SD_BUF = [new FATsector], NewCluster
-;         SectorL is unchanged, FATS are not updated.
+; output: updated (ClusterHL, FATsector, W = FATsector), SD_BUF = [new FATsector]
+;         SectorHL is unchanged, FATS are updated.
 ;         S = 2 --> Disk FULL error
+; ==================================;
+SearchMarkNewClusterHL              ;SWXY <== WRITE_FILE, OPEN_WRITE_CREATE, OPEN_OVERWRITE
+; ==================================;
+    MOV     #8,S                    ; preset disk full return error
+    PUSH    W                       ;3  R-- FATsector
 ; ----------------------------------;
-SearchNewCluster                    ; <== CREATE file, WRITE_File
-; ----------------------------------;
-    MOV     #2,S                    ; preset disk full return error
-    PUSH    &CurFATsector           ; last known free cluster sector
-    MOV     &FATtype,Y              ;
-    ADD     Y,Y                     ;  Y = bytes size of Cluster number (2 or 4)
-; ----------------------------------;
-LoadFATsectorInBUF                  ; <== IncrementFATsector
+LoadFATsectorLoop                   ;
 ; ----------------------------------;
-    MOV     @RSP,W                  ; W = FATsector
-    CMP     W,&FATSize              ;
-    JZ      OPW_Error               ; FATsector = FATSize ===> abort disk full
-    ADD     &OrgFAT1,W              ;
-    MOV     #0,X                    ;
-    CALL    #ReadSectorWX           ;SWX (< 65536)
-    MOV     #0,X                    ; init FAToffset
+    MOV     @RSP,W                  ;2
+    CMP     W,&FATSize              ;3
+    JZ      OPWC_DiskFull           ;2 FATsector = FATSize ===> abort disk full
+    CALL    #ReadFAT1SectorW        ;SWX load FAT_buf with (new) FATsector
 ; ----------------------------------;
-SearchFreeClustInBUF                ; <== SearchNextCluster
+SearchFreeClusterLoop               ;
 ; ----------------------------------;
-    CMP     #2,Y                    ; FAT16 Cluster size ?
-    JZ      ClusterLowWordTest      ; yes
 ClusterHighWordTest                 ;
-    CMP     #0,SD_BUF+2(X)          ; cluster address hi word = 0 ?
-    JNZ     SearchNextNewCluster    ;
+    CMP     #0,SD_BUF+2(Y)          ;3 cluster address hi word = 0 ?
+    JNZ     SearchNextNewCluster    ;2
 ClusterLowWordTest                  ;
-    CMP     #0,SD_BUF(X)            ; Cluster address lo word = 0 ?
-    JZ      GNC_FreeClusterFound    ; 
+    CMP     #0,SD_BUF(Y)            ;3 Cluster address lo word = 0 ?
+    JZ      FreeClusterFound        ;2
 SearchNextNewCluster                ;
-    ADD     Y,X                     ; increment SD_BUF offset by size of Cluster address
-    CMP     #BytsPerSec,X           ;
-    JNE     SearchFreeClustInBUF    ; loopback while X < BytsPerSec
-IncrementFATsector                  ;
-    ADD     #1,0(RSP)               ; increment FATsector
-    JMP     LoadFATsectorInBUF      ; loopback
+    ADD     #4,Y                    ;1 increment SD_BUF offset by size of Cluster address
+    CMP     #BytsPerSec,Y           ;2
+    JNC     SearchFreeClusterLoop   ;2  18/15~   loopback while X U< BytsPerSec
+IncrementFATsector                  ;1
+    ADD     #1,0(RSP)               ;3 increment FATsector
+    MOV     #0,Y                    ;  clear FAToffset
+    JMP     LoadFATsectorLoop       ;5  34/23~    loopback
+; ----------------------------------;
+FreeClusterFound                    ; X =  cluster number low word in SD_BUF = FAToffset
 ; ----------------------------------;
-GNC_FreeClusterFound                ; Y =  cluster number low word in SD_BUF = FATsector
+    MOV     @RSP,&LastFATsector     ;
+    MOV     Y,&LastFAToffset        ;
 ; ----------------------------------;
     MOV     #0,S                    ; clear error
+    MOV     #-1,SD_BUF(Y)           ; mark New Cluster low word as end cluster (0xFFFF) in SD_BUF
     MOV.B   @RSP,W                  ; W = 0:FATsectorLo
-    MOV     #-1,SD_BUF(X)           ; mark NewCluster low word as end cluster (0xFFFF) in SD_BUF
-    CMP     #2,Y                    ; Y = FAT16 size of Cluster number ?
-    JZ      FAT16EntryToClusterNum  ; yes
-    MOV     #0FFFh,SD_BUF+2(X)      ; no: mark NewCluster high word as end cluster (0x0FFF) in SD_BUF
+    MOV     #0FFFh,SD_BUF+2(Y)      ; mark New Cluster high word as end cluster (0x0FFF) in SD_BUF
 ; ----------------------------------;
-FAT32EntryToClusterNum              ; convert FAT32 cluster address to cluster number
+FAT32ClustAdrToClustNum             ; convert FAT32 cluster address to cluster number (CluNum = CluAddr / 4)
 ; ----------------------------------;
-    RRA     X                       ; X = FATOffset>>1, FAToffset is byte size
+    RRA     Y                       ; Y = FATOffset>>1, (bytes to words conversion)
     SWPB    W                       ; W = FATsectorLo:0
-    ADD     W,X                     ; X = FATsectorLo:FATOffset>>1
+    ADD     W,Y                     ; Y = FATsectorLo:FATOffset>>1
     MOV.B   1(RSP),W                ; W = FATsectorHi
     RRA     W                       ; W = FATsectorHi>>1
-    RRC     X                       ; X = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
-    MOV     W,&NewClusterH          ; NewClusterH =  FATsectorHi>>1
-    MOV     X,&NewClusterL          ; NewClusterL = FATsectorLo>>1:FAToffset>>2
-    JMP     SearchNewClusterEnd     ; max cluster = 7FFFFF ==> 1FFFFFFF sectors ==> 256 GB
+    RRC     Y                       ; Y = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
+    MOV     W,&ClusterH             ; ClusterH =  FATsectorHi>>1
+    MOV     Y,&ClusterL             ; ClusterL = FATsectorLo>>1:FAToffset>>2
+; ----------------------------------;
+    MOV     @RSP,W                  ; W = FATsector of new cluster
+    CALL    #SaveSectorWtoFATs      ;SWXY W = FATsector loaded in SD_buf
+    MOV     @RSP+,W                 ; W = FATsector of New Cluster
+    MOV     @RSP+,PC                ; RET
+; ----------------------------------;
+
+
+; ==================================;
+FreeAllClusters                     ;SWXY input: HDLL_FirstClus(T), output:
+; ==================================;FATs are updated
+    MOV HDLL_FirstClus(T),ClusterL  ;
+    MOV HDLH_FirstClus(T),ClusterH  ;
+    CALL #ClusterHLtoFAT1sectWofstY ;WXY    output: W = FATsector, Y=FAToffset
+    MOV     W,&LastFATsector        ;
+    MOV     Y,&LastFAToffset        ;
+    PUSH    W                       ;       R-- FATsector ptr
+; ----------------------------------;
+LoadFAT1sectorWloop                 ;
+; ----------------------------------;
+    CALL    #ReadFAT1SectorW        ;SWX
+; ----------------------------------;
+GetAndFreeCluster                   ;
+; ----------------------------------;
+    MOV     SD_BUF(Y),W             ; get [clusterLO]
+    MOV     #0,SD_BUF(Y)            ; free CLusterLO
+GetAndFreeClusterHi                 ;
+    MOV     SD_BUF+2(Y),X           ; get [clusterHI]
+    MOV     #0,SD_BUF+2(Y)          ; free CLusterHI
+ClusterHiTest
+    AND     #00FFFh,X               ; select 12 bits significant
+    CMP     #00FFFh,X               ; [ClusterHI] was = 0FFFh?
+    JNE     SearchNextCluster2free  ; no
+ClusterLoTest                       ;
+    CMP     #-1,W                   ; [ClusterLO] was = FFFFh? last cluster used for this file
+    JZ      EndOfFileCluster        ; yes
 ; ----------------------------------;
-FAT16EntryToClusterNum              ; convert FAT16 address of Cluster in cluster number
+SearchNextCluster2free              ;
 ; ----------------------------------;
-    RRA     X                       ; X = Offset>>1, offset is word < 256
-    MOV.B   X,&NewClusterL          ; X = NewCluster numberLO (byte)
-    MOV.B   W,&NewClusterL+1        ; W = NewCluster numberHI (byte)
-    MOV     #0,&NewClusterH         ;
+    MOV     W,&ClusterL             ;
+    MOV     X,&ClusterH             ;
+    CALL #ClusterHLtoFAT1sectWofstY ;WXY    W = new FATsector, new FAToffset
+    CMP     @RSP,W                  ; new FATsector = FATsector ptr ?
+    JZ      GetAndFreeCluster       ; yes loop back
+    MOV     W,X                     ; no:   swap previous new FATsectors:
+    MOV     @RSP,W                  ;       W = previous FATsector
+    MOV     X,0(RSP)                ;       R-- new FATsector
+    CALL    #SaveSectorWtoFATs      ;SWXY update FATs from SD_BUF to W = previous FATsector
+    MOV     @RSP,W                  ;       W = new FATsector
+    JMP     LoadFAT1sectorWloop     ; loop back with W = new FATsector, new FAToffset
+; ----------------------------------;
+EndOfFileCluster                    ;
 ; ----------------------------------;
-SearchNewClusterEnd                 ;
+    MOV     @RSP+,W                 ;
+    MOV     #SaveSectorWtoFATs,PC   ; update FATs
 ; ----------------------------------;
-    MOV     @RSP+,W                 ; W = FATsector
-    MOV     W,&CurFATsector         ; refresh CurrentFATsector
-    MOV @RSP+,PC                             ;
+
+; this subroutine is called by Write_File (bufferPtr=512) and CloseHandle (0 =< BufferPtr =< 512)
+; ==================================;
+WriteSD_Buf                         ;SWX input: T = CurrentHDL
+; ==================================;
+    ADD &BufferPtr,HDLL_CurSize(T)  ; update handle CurrentSizeL
+    ADDC    #0,HDLH_CurSize(T)      ;
+; ==================================;
+WriteSectorHL                       ;SWX
+; ==================================;
+    MOV     &SectorL,W              ; Low
+    MOV     &SectorH,X              ; High
+    MOV     #WriteSectorWX,PC       ; ...then RET
 ; ----------------------------------;
 
 
-; update FATs with SD_BUF content.
-; input : FATsector, FAToffset, SD_BUF = [FATsector]
-; use : SWX registers
-; ----------------------------------; else update FATsector of the old cluster
-UpdateFATsSectorW                   ;
+; ======================================================================
+; DEL" primitive as part of OpenPathName
+; All "DEL"eted clusters are freed
+; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
+;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
+;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
+; output: nothing (no message if open error)
+; ======================================================================
+OPEN_2W                             ;
+    CMP     #2,W                    ; open_type = DEL ?
+    JNZ     OPEN_4W                 ; no : goto next step
 ; ----------------------------------;
-    PUSH    W                       ;
-    ADD     &OrgFAT1,W              ; update FAT#1
-    MOV     #0,X                    ;
-    CALL    #WriteSectorWX          ; write a logical sector
-    MOV     @RSP+,W                 ;
-    ADD     &OrgFAT2,W              ; update FAT#2
-    MOV     #0,X                    ;
-    CALL    #WriteSectorWX          ; write a logical sector
+; 1- open file                      ; done
+; ----------------------------------;
+    CMP     #0,S                    ; open file happy end ?
+    JNE     DEL_END                 ; no: don't send message, don't abort
+; ----------------------------------;
+; 2- Delete DIR entry               ;
+; ----------------------------------;
+    MOV.B   #0E5h,SD_BUF(Y)         ;
+    CALL    #WriteSectorHL          ;SWX  write SectorHL=DIRsector
+; ----------------------------------;
+; 3- free all file clusters         ;
+; ----------------------------------;
+    CALL    #FreeAllClusters        ;SWXY input: HDLL_FirstClus(T), output: FATS are updated
+; ----------------------------------;
+; 4- Close Handle                   ;
+; ----------------------------------;
+    CALL    #CloseHandle            ;
 ; ----------------------------------;
+DEL_END                             ;
+    MOV @IP+,PC                     ;4
+; ----------------------------------;
+
+;-----------------------------------------------------------------------
+; WRITE" (CREATE part) subroutines
+;-----------------------------------------------------------------------
 
 
 
@@ -150,9 +249,9 @@ UpdateFATsSectorW                   ;
 ; modified time :   ofsset 16h = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
 ; dates :    offset 10, 12, 18 = 0byyyyyyymmmmddddd, with : y=year-1980, m=month, d=day
 
-; ----------------------------------; input:
-GetYMDHMSforDIR                     ;X=date, W=TIME
-; ----------------------------------;
+; ==================================;
+GetYMDHMSforDIR                     ; output: X=date, W=TIME
+; ==================================;
     .IFDEF    LF_XTAL               ;
     .IFNDEF   RTC                   ; RTC_B or RTC_C select
 ; ----------------------------------;
@@ -177,12 +276,12 @@ WaitRTC                             ; yes
     MOV     #512,&OP2               ;
     ADD     &RES0,X                 ;
     .ELSEIF
-    MOV     #0,X                    ; X=DATE 
+    MOV     #0,X                    ; X=DATE
     MOV     #0,W                    ; W=TIME
     .ENDIF
     .ENDIF
 SD_RW_RET                           ;
-    MOV @RSP+,PC                             ;
+    MOV     @RSP+,PC                ;
 ; ----------------------------------;
 
 
@@ -190,24 +289,22 @@ SD_RW_RET                           ;
 ForbiddenChars ; 15 forbidden chars table + dot char
     .byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
 
-; ----------------------------------;
+; ==================================;
 OPWC_SkipDot                        ;
-; ----------------------------------;
+; ==================================;
     CMP     #4,X                    ;
-    JL      FillDIRentryName        ; X < 4 : no need spaces to complete name entry
+    JNC     FillDIRentryName        ; X U< 4 : no need spaces to complete name entry
     SUB     #3,X                    ;
-    CALL    #OPWC_CompleteWithSpaces; complete name entry 
-    MOV     #3,X                    ; 
-; ----------------------------------;
-
-; ----------------------------------;
+    CALL    #OPWC_CompleteWithSpaces; complete name entry
+    MOV     #3,X                    ;
+; ==================================;
 FillDIRentryName                    ;SWXY use
-; ----------------------------------;
+; ==================================;
     MOV.B   @T+,W                   ; W = char of pathname
     MOV.B   W,SD_BUF(Y)             ;     to DIRentry
 ;    CMP     #0,W                    ; end of stringZ ?
 ;    JZ      OPWC_CompleteWithSpaces ;
-    CMP     T,&EndOfPath            ; EOS < PTR ?
+    CMP     T,&PathName_END         ; EOS < PTR ?
     JNC     OPWC_CompleteWithSpaces ; yes
 ; ----------------------------------;
 SkipForbiddenChars                  ;
@@ -233,56 +330,131 @@ ForbiddenCharLoop                   ;
 ; ----------------------------------;
 OPWC_CompleteWithSpaces             ; 0 to n spaces !
 ; ----------------------------------;
-    CMP     #0,X                    ; 
+    CMP     #0,X                    ;
     JZ      OPWC_CWS_End            ;
 ; ----------------------------------;
 OPWC_CompleteWithSpaceloop          ;
 ; ----------------------------------;
     MOV.B   #' ',SD_BUF(Y)          ; remplace dot by char space
-    ADD     #1,Y                    ; increment DIRentry ptr in buffer 
+    ADD     #1,Y                    ; increment DIRentry ptr in buffer
     SUB     #1,X                    ; dec countdown of chars space
     JNZ OPWC_CompleteWithSpaceloop  ;
 OPWC_CWS_End                        ;
-    MOV @RSP+,PC                             ;
+    MOV @RSP+,PC                    ;
 ; ----------------------------------;
 
 
+; ==================================;
+LoadUpdateSaveDirEntry              ;SWXY
+; ==================================;
+    MOV     HDLL_DIRsect(T),W       ;
+    MOV     HDLH_DIRsect(T),X       ;
+    CALL    #readSectorWX           ;SWX SD_buffer = DIRsector
+    MOV     HDLW_DIRofst(T),Y       ; Y = DirEntryOffset
+    CALL    #GetYMDHMSforDIR        ; X=DATE,  W=TIME
+    MOV     X,SD_BUF+18(Y)          ; access date
+    MOV     W,SD_BUF+22(Y)          ; modified time
+    MOV     X,SD_BUF+24(Y)          ; modified date
+    MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
+    MOV HDLH_CurSize(T),SD_BUF+30(Y);
+    MOV     HDLL_DIRsect(T),W       ;
+    MOV     HDLH_DIRsect(T),X       ;
+    MOV     #WriteSectorWX,PC       ;SWX then RET
+; ----------------------------------;
 
+;-----------------------------------------------------------------------
+; WRITE" subroutines
+;-----------------------------------------------------------------------
+
+
+; write sequentially the buffer in the post incremented SectorHL.
+; The first time, SectorHL is initialized by WRITE".
+; All used registers must be initialized.
+; ==================================;
+Write_File                          ;STWXY <== WRITE, SD_EMIT, TERM2SD"
+; ==================================;
+    MOV     #BytsPerSec,&BufferPtr  ; write always all the buffer
+    MOV     &CurrentHdl,T           ;
+    CALL    #WriteSD_Buf            ;SWX write SD_BUF and update Handle informations only for DIRentry update
+    MOV     #0,&BufferPtr           ; reset buffer pointer
+; ----------------------------------;
+PostIncrementSector                 ;
+; ----------------------------------;
+    ADD.B   #1,HDLB_ClustOfst(T)    ; increment current Cluster offset
+    CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
+    JNC     Write_File_End          ; no,
+; ----------------------------------;
+    CALL    #HDLcurClus2FATsecWofstY;WXY  Output: FATsector W=FATsector, Y=FAToffset
+    PUSH    Y                       ; push previous FAToffset
+    PUSH    W                       ; push previous FATsector
+; ----------------------------------;
+GetNewCluster                       ; input : T=CurrentHdl
+; ----------------------------------;
+    CALL    #SearchMarkNewClusterHL ;SWXY input: W = FATsector Y = FAToffset, output: ClusterHL, W = FATsector of New cluster
+    CMP     @RSP,W                  ; previous and new clusters are in same FATsector?
+    JZ      LinkClusters            ;     yes
+; ----------------------------------;
+UpdateNewClusterFATs                ;
+; ----------------------------------;
+;    CALL    #SaveSectorWtoFATs      ;SWXY no: already done by SearchMarkNewClusterHL
+    MOV     @RSP,W                  ; W = previous FATsector
+    CALL    #ReadFAT1SectorW        ;SWX  reload previous FATsector in buffer to link clusters
+; ----------------------------------;
+LinkClusters                        ;
+; ----------------------------------;
+    MOV     @RSP+,W                 ; W = previous FATsector
+    MOV     @RSP+,Y                 ; Y = previous FAToffset
+    MOV     &ClusterL,SD_BUF(Y)     ; store new cluster to current cluster address in previous FATsector buffer
+    MOV     &ClusterH,SD_BUF+2(Y)   ;
+    CALL    #SaveSectorWtoFATs      ;SWXY update FATs from SD_BUF to W = previous FATsector
+; ==================================;
+HDLSetCurClustSetFrstSect           ;
+; ==================================;
+    MOV     #4,HDLB_Token(T)        ; and clear ClustOfst
+; ==================================;
+HDLSetCurClustSetCurSect            ;
+; ==================================;
+    MOV &ClusterL,HDLL_CurClust(T)  ; update handle with new cluster
+    MOV &ClusterH,HDLH_CurClust(T)  ;
+Write_File_End
+    MOV #ClusterHL2sectorHL,PC      ;W set current SectorHL to be written then RET
+; ----------------------------------;
+
+;Z WRITE            --
+; sequentially write the entire SD_BUF in a file opened by WRITE"
+; ==================================;
+    FORTHWORD "WRITE"               ; in assembly : CALL #WRITE,X   CALL 2(X)
+; ==================================;
+    CALL #Write_File                ;STWXY
+    MOV @IP+,PC                     ;
+; ----------------------------------;
 
 ; ======================================================================
 ; WRITE" primitive as part of OpenPathName
 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
-; output: nothing else abort on error
-; error 1  : PathNameNotFound
-; error 2  : NoSuchFile       
-; error 4  : DirectoryFull  
-; error 8  : AlreadyOpen    
-; error 16 : NomoreHandle   
+; output: Current Sector is set else abort on WRITE error
+; error 4  : InvalidPathname
+; error 8  : DiskFull
 ; ======================================================================
-
-; ----------------------------------;
-OPEN_QWRITE                         ;
-    CMP     #2,W                    ; open_type = WRITE" ?
-    JNZ     OPEN_QDEL               ; no : goto next step
+OPEN_4W                             ;
+    CMP     #4,W                    ; open_type = WRITE" ?
+    JNZ     OPEN_8W                 ; no : goto next step
 ; ----------------------------------;
 ; 1 try to open                     ; done
 ; ----------------------------------;
 ; 2 select error "no such file"     ;
 ; ----------------------------------;
     CMP     #2,S                    ; "no such file" error ?
-    JZ      OPEN_WRITE_CREATE       ; yes
-    CMP     #0,S                    ; no open file error ?
-    JZ      OPEN_WRITE_APPEND       ; yes
+    JZ      OPEN_WRITE_CREATE       ; yes, Handle is to be created !
+    CMP     #0,S                    ; well opened file ?
+    JZ      OPEN_OVERWRITE          ; yes
 ; ----------------------------------;
-; Write errors                      ;
+OPWC_Write_Errors                   ;
 ; ----------------------------------;
-OPWC_InvalidPathname                ; S = 1
-OPWC_DiskFull                       ; S = 2 
-OPWC_DirectoryFull                  ; S = 4
-OPWC_AlreadyOpen                    ; S = 8
-OPWC_NomoreHandle                   ; S = 16
+OPWC_InvalidPathname                ; S = 4
+OPWC_DiskFull                       ; S = 8
 ; ----------------------------------;
 OPW_Error                           ; set ECHO, type Pathname, type #error, type "< WriteError"; no return
     mDOCOL                          ;
@@ -291,195 +463,108 @@ OPW_Error                           ; set ECHO, type Pathname, type #error, type
     .word   BRAN,ABORT_SD           ; to insert S error as flag, no return
 ; ----------------------------------;
 
-
 ; ======================================================================
-; WRITE" (CREATE part) primitive as part of OpenPathName
-; input from open:  S = NoSuchFile, W = open_type, SectorHL = DIRsectorHL,
-;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
-; output: nothing else abort on error:
-; error 1  : InvalidPathname
-; error 2  : DiskFull       
-; error 4  : DirectoryFull  
-; error 8  : AlreadyOpen    
-; error 16 : NomoreHandle   
+; WRITE" primitive as part of OpenPathName
+; All "DEL"eted clusters are freed
+; input from open:  W = open_type, SectorHL = DIRsectorHL,
+;                   Buffer = [DIRsector], ClusterHL = FirstCluster
+;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl,
+; output: nothing (no message if open error)
 ; ======================================================================
 
+
+; ==================================;
+OPEN_WRITE_CREATE                   ; a new Handle is to be created
+; ==================================;
+; 1- open file                      ; done
 ; ----------------------------------;
-OPEN_WRITE_CREATE                   ;
-; ----------------------------------;
-; 3 get free cluster                ;
-; ----------------------------------; input: FATsector
-    CALL    #SearchNewCluster       ;SWXY output:  W = new FATsector loaded in buffer,NewCluster 
-    MOV     &NewClusterL,&ClusterL  ;
-    MOV     &NewClusterH,&ClusterH  ;
-    CALL    #UpdateFATsSectorW      ;SWX update FATs with buffer
+; 2 get free cluster                ;
 ; ----------------------------------;
-    CALL    #ReadSector             ; reload DIRsector
-    MOV     &EntryOfst,Y            ; reload entry offset (first free entry in DIR)
+    MOV     #0,W                    ; init FATsector = 0, search new cluster
+    MOV     #0,Y                    ; init FAToffset
+    CALL    #SearchMarkNewClusterHL ;WXY  output: updated (ClusterHL, FATsector, W = FATsector), SD_BUF = [new FATsector]
 ; ----------------------------------;
-; 4 init DIRentryAttributes         ;
+; 3 init DIRentryAttributes         ;
 ; ----------------------------------;
-OPWC_SetEntryAttribute              ; (cluster=DIRcluster!)
+    CALL    #ReadSectorHL           ; reload DIRsector
+    MOV     &DIREntryOfst,Y         ; Y = entry offset (first free entry in DIR)
     MOV.B   #20h,SD_BUF+11(Y)       ; file attribute = file
     CALL    #GetYMDHMSforDIR        ;WX  X=DATE,  W=TIME
     MOV     #0,SD_BUF+12(Y)         ; nt reserved = 0 and centiseconds are 0
     MOV     W,SD_BUF+14(Y)          ; time of creation
     MOV     X,SD_BUF+16(Y)          ; date of creation      20/08/2001
-    MOV     X,SD_BUF+18(Y)          ; date of access        20/08/2001
-    MOV     &ClusterH,SD_BUF+20(Y)  ; as first Cluster Hi 
-    MOV     &ClusterL,SD_BUF+26(Y)  ; as first cluster LO   
-    MOV     #0,SD_BUF+28(Y)         ; file lenghtLO  = 0 
-    MOV     #0,SD_BUF+30(Y)         ; file lenghtHI  = 0 
-; ----------------------------------;
-; 5 create DIRentryName             ;
-; ----------------------------------;
-    MOV     #1,S                    ; preset pathname error
-    MOV     &Pathname,T             ; here, pathname is "xxxxxxxx.yyy" format
-;    CMP.B   #0,0(T)                 ; forbidden null string
-    CMP     T,&EndOfPath            ;
-    JZ      OPWC_InvalidPathname    ; write error 1
+;    MOV     X,SD_BUF+18(Y)          ; date of access        20/08/2001
+    MOV     &ClusterH,SD_BUF+20(Y)  ; as first Cluster Hi
+    MOV     &ClusterL,SD_BUF+26(Y)  ; as first cluster LO
+    MOV     #0,SD_BUF+28(Y)         ; set file_sizeLO  = 0
+    MOV     #0,SD_BUF+30(Y)         ; set file_sizeHI  = 0
+; ----------------------------------;
+; 4 create DIRentryName             ; file name format "xxxxxxxx.yyy"
+; ----------------------------------;
+    MOV     #4,S                    ; preset pathname error
+    MOV     &PathName_PTR,T         ; here, PathName_PTR is set to file name
+    CMP     T,&PathName_END         ; end of string reached ?
+    JZ      OPWC_InvalidPathname    ; yes write error 1
     CMP.B   #'.',0(T)               ; forbidden "." in first
     JZ      OPWC_InvalidPathname    ; write error 1
     MOV     #11,X                   ; X=countdown of chars entry
     CALL    #FillDIRentryName       ;STWXY
 ; ----------------------------------;
-; 6 save DIRsector                  ;
+; 5 update DIRsector                ;
 ; ----------------------------------;
-    CALL    #WriteSector            ;SWX update DIRsector
+    CALL    #WriteSectorHL          ;SWX update DIRsector
 ; ----------------------------------;
 ; 7 Get free handle                 ;
 ; ----------------------------------;
-    MOV     #2,W                    ;
-    CALL    #GetFreeHandle          ; output : S = handle error, CurCluster and CurSector are set
-; ----------------------------------;
-    CMP     #0,S                    ; no error ?
-    JNZ     OPWC_NomoreHandle       ; ==> abort with error 16
-    MOV @IP+,PC                           ; --
-; ----------------------------------;
-
-;-----------------------------------------------------------------------
-; WRITE" subroutines
-;-----------------------------------------------------------------------
-
-; SectorL is unchanged
-; ----------------------------------;
-OPWW_UpdateDirectory                ; <== CloseHandleT
-; ----------------------------------; Input : current Handle
-    MOV     HDLL_DIRsect(T),W       ;
-    MOV     HDLH_DIRsect(T),X       ;
-    CALL    #readSectorWX           ;SWX buffer = DIRsector
-    CALL    #GetYMDHMSforDIR        ; X=DATE,  W=TIME
-    MOV     HDLW_DIRofst(T),Y       ; Y = DirEntryOffset
-    MOV     X,SD_BUF+18(Y)          ; access date
-    MOV     W,SD_BUF+22(Y)          ; modified time
-    MOV     X,SD_BUF+24(Y)          ; modified date
-OPWW_UpdateEntryFileSize            ;
-    MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
-    MOV HDLH_CurSize(T),SD_BUF+30(Y);
-    MOV     HDLL_DIRsect(T),W       ; 
-    MOV     HDLH_DIRsect(T),X       ;
-    MOV     #WriteSectorWX,PC       ;SWX then RET
-; ----------------------------------;
-
-; this subroutine is called by Write_File (bufferPtr=512) and CloseHandleT (0 =< BufferPtr =< 512)
-; ==================================; 
-WriteBuffer                         ;STWXY input: T = CurrentHDL
-; ==================================; 
-    ADD &BufferPtr,HDLL_CurSize(T)  ; update handle CurrentSizeL
-    ADDC    #0,HDLH_CurSize(T)      ;
-; ==================================;
-WriteSector                         ;SWX
-; ==================================;
-    MOV     &SectorL,W              ; Low
-    MOV     &SectorH,X              ; High
-    MOV     #WriteSectorWX,PC       ; ...then RET
+    MOV     #4,W                    ; get handle for write
+    CALL    #GetFreeHandle          ; output : CurCluster and CurSector are set
+    MOV     @IP+,PC                 ; --
 ; ----------------------------------;
 
-
-
-; write sequentially the buffer in the post incremented SectorHL.
-; The first time, SectorHL is initialized by WRITE".
-; All used registers must be initialized.
 ; ==================================;
-Write_File                          ; <== WRITE, SD_EMIT, TERM2SD"
+OPEN_OVERWRITE                      ; handle exists
 ; ==================================;
-    MOV     #BytsPerSec,&BufferPtr  ; write always all the buffer
-    MOV     &CurrentHdl,T           ;
-    CALL    #WriteBuffer            ; write SD_BUF and update Handle informations only for DIRentry update 
-    MOV     #0,&BufferPtr           ; reset buffer pointer
-; ----------------------------------;
-PostIncrementSector                 ;
-; ----------------------------------;
-    ADD.B   #1,HDLB_ClustOfst(T)    ; increment current Cluster offset
-    CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
-    JNZ     Write_File_End          ; no, 
-; ----------------------------------;
-GetNewCluster                       ; input : T=CurrentHdl
-; ----------------------------------;
-    MOV.B   #0,HDLB_ClustOfst(T)    ; reset handle ClusterOffset
-    CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
-    PUSH    Y                       ; push current FAToffset
-    PUSH    W                       ; push current FATsector
-    CALL    #SearchNewCluster       ;SWXY  output: W = new FATsector loaded in buffer, NewCluster 
-    CMP     @RSP,W                  ; current and new clusters are in same FATsector?
-    JZ      LinkClusters            ;     yes 
-UpdateNewClusterFATs                ;
-    CALL    #UpdateFATsSectorW      ;SWX  no: UpdateFATsSectorW with buffer of new FATsector
-    MOV     @RSP,W                  ; W = current FATsector
-    ADD     &OrgFAT1,W              ;
-    MOV     #0,X                    ;
-    CALL    #ReadSectorWX           ;SWX (< 65536)
-LinkClusters                        ;
-    MOV     @RSP+,W                 ; W = current FATsector
-    MOV     @RSP+,Y                 ; pop current FAToffset
-    MOV     &NewClusterL,SD_BUF(Y)  ; store new cluster to current cluster address in current FATsector buffer
-    CMP     #1,&FATtype             ; FAT16?
-    JZ UpdatePreviousClusterFATs    ; yes
-    MOV     &NewClusterH,SD_BUF+2(Y);
-UpdatePreviousClusterFATs           ;
-    CALL    #UpdateFATsSectorW      ;SWX update FATS with current FATsector buffer
-UpdateHandleCurCluster              ;
-    MOV &NewClusterL,HDLL_CurClust(T)  ; update handle with new cluster
-    MOV &NewClusterH,HDLH_CurClust(T) ;
-;    CALL #ComputeHDLcurrentSector   ; set Cluster first Sector as next Sector to be written
-;    MOV #OPWW_UpdateDirectory,PC    ; update DIRentry to avoid cluster lost, then RET
-Write_File_End
-    MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
-; ----------------------------------;
-
-;Z WRITE            -- 
-; sequentially write the entire SD_BUF in a file opened by WRITE"
+; free all file clusters            ;
 ; ----------------------------------;
-    FORTHWORD "WRITE"               ; in assembly : CALL &WRITE+2
-; ----------------------------------;
-    CALL #Write_File                ;
-    MOV @IP+,PC                     ;
+    CALL    #FreeAllClusters        ;SWXY input: HDLL_FirstClus(T), output: FATS are updated
+    MOV     #0,HDLL_CurSize(T)      ; clear currentSize
+    MOV     #0,HDLH_CurSize(T)      ;
+    MOV HDLL_FirstClus(T),ClusterL  ; Set ClusterHL
+    MOV HDLH_FirstClus(T),ClusterH  ;
+    CALL #ClusterHLtoFAT1sectWofstY ;WXY    output: W = FATsector, Y=FAToffset
+    CALL    #SearchMarkNewClusterHL ;SWXY input: W = FATsector, Y = FAToffset output: ClusterHL, W = updated new FATsector loaded in SD_BUF
+    CALL #HDLSetCurClustSetFrstSect ;
+    MOV     @IP+,PC                 ; --
 ; ----------------------------------;
 
 
 ; ======================================================================
-; WRITE" (APPEND part) primitive as part of OpenPathName
-; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
+; APPEND" primitive as part of OpenPathName
+; input from open:  SectorHL = DIRsectorHL,
 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
 ; output: nothing else abort on error
-; error 2  : DiskFull       
+; error 2  : DiskFull
 ; ======================================================================
-
-; ----------------------------------;
-OPEN_WRITE_APPEND                   ;
-; ----------------------------------;
+OPEN_8W                             ;
+    CMP     #2,S                    ; "no such file" error ?
+    JZ      OPEN_WRITE_CREATE       ; yes
+    CMP     #0,S                    ; well opened file ?
+    JNZ     OPWC_Write_Errors       ; no
+; ==================================;
+OPEN_WRITE_APPEND                   ; yes
+; ==================================;
 ; 1- open file                      ; done
 ; ----------------------------------;
-; 2- compute missing Handle infos   ;
+    MOV.B  #4,HDLB_Token(T)         ; update HDLB_Token(T)
 ; ----------------------------------;
 ; 2.1- Compute Sectors count        ; Sectors = HDLL_CurSize/512
 ; ----------------------------------;
-    MOV.B   HDLL_CurSize+1(T),Y     ;Y = 0:CurSizeLOHi
-    MOV.B   HDLH_CurSize(T),X       ;X = 0:CurSizeHILo 
-    SWPB    X                       ;X = CurSizeHIlo:0 
+    MOV.B   HDLL_CurSize+1(T),Y     ;Y = 0:CurSizeLOHi (bytes)
+    MOV.B   HDLH_CurSize(T),X       ;X = 0:CurSizeHILo
+    SWPB    X                       ;X = CurSizeHIlo:0
     ADD     Y,X                     ;X = CurSizeHIlo:CurSizeLOhi
-    MOV.B   HDLH_CurSize+1(T),Y     ;Y:X = CurSize / 256
+    MOV.B   HDLH_CurSize+1(T),Y     ;Y:X = CurSize / 256 (bytes)
 ; ----------------------------------;
 ; 2.2 Compute Clusters Count        ;
 ; ----------------------------------;
@@ -499,153 +584,52 @@ DIVSECPERSPC2                       ;
     SUB #1,S                        ;1 CNT-1
     JGE DIVSECPERSPC2               ;2 4~ loopback     Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
 ; ----------------------------------;
-    MOV &CurrentHDL,T               ;3  reload Handle ptr  
-; ----------------------------------;
-; 2.3- Compute last Cluster         ; X = Clusters numberLO, Y = Clusters numberHI 
+; 2.3- Compute Current Cluster      ; X = ClusterCountLO, Y = ClusterCountHI
 ; ----------------------------------;
+    MOV &CurrentHDL,T               ;3  reload Handle ptr
     ADD  HDLL_FirstClus(T),X        ;
     ADDC HDLH_FirstClus(T),Y        ;
     MOV X,HDLL_CurClust(T)          ;  update handle
     MOV Y,HDLH_CurClust(T)          ;
 ; ----------------------------------;
-; 2.4- Compute Sectors offset       ;
+; 2.4- load current sectorHL        ;
 ; ----------------------------------;
-    MOV.B W,HDLB_ClustOfst(T)       ;3  update handle with W = REMlo = sectors offset in last cluster
+    MOV.B W,HDLB_ClustOfst(T)       ;3  update handle with W = REM8 = sectors offset in last cluster
+    CALL #LoadCurSectorHL           ;SWX in SD_buf
 ; ----------------------------------;
-; 3- load last sector in SD_BUF     ;
+; 2.5- Compute SD_Buf ptr           ;
 ; ----------------------------------;
-    MOV HDLL_CurSize(T),W           ; example : W = 1013
-    BIC #01FFh,HDLL_CurSize(T)      ; substract 13 from HDLL_CurSize, because loaded in buffer
-    AND #01FFh,W                    ; W = 13
-    MOV W,&BufferPtr                ; init Buffer Pointer with 13
-    CALL #LoadHDLcurrentSector      ;SWX
-    MOV @IP+,PC                     ; BufferPtr = first free byte offset
+    MOV HDLL_CurSize(T),W           ; example :  W = $A313 bytes
+    BIC #01FFh,HDLL_CurSize(T)      ; HDLL_CurSize = $A200 bytes
+    AND #01FFh,W                    ; remainder  W = $0113 bytes
+    MOV W,&BufferPtr                ; init Buffer Pointer with $0113
 ; ----------------------------------;
-
-
-; ======================================================================
-; DEL" primitive as part of OpenPathName
-; All "DEL"eted clusters are freed
-; If next DIRentry in same sector is free, DIRentry is freed, else hidden.
-; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
-;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
-;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
-; output: nothing (no message if open error)
-; ======================================================================
-
-
-OPEN_QDEL                           ;
-;    CMP     #4,W                    ;   open_type = DEL"
-;    JNZ     OPEN_8W                 ;
-; ----------------------------------;
-OPEN_DEL                            ;
-; ----------------------------------;
-; 1- open file                      ; done
-; ----------------------------------;
-    CMP     #0,S                    ; open file happy end ?
-    JNE     DEL_END                ; no: don't send message
-; ----------------------------------;
-; 2- Delete DIR entry               ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
-; ----------------------------------;
-SelectFreeEntry                     ; nothing to do: S = 0 ready for free entry!
-; ----------------------------------;
-    CMP     #BytsPerSec-32,Y        ; Entry >= last entry in DIRsector ?
-    JC      SelectHideEntry         ; yes:  next DIR entry is out of sector
-    CMP.B   #0,SD_BUF+32(Y)         ; no:   next DIR entry in DIRsector is free?
-    JZ      WriteDelEntry           ;       yes
-; ----------------------------------;
-SelectHideEntry                     ;       no
-; ----------------------------------;
-    MOV.B   #0E5h,S                 ;
-; ----------------------------------;
-WriteDelEntry
-; ----------------------------------;
-    MOV.B   S,SD_BUF(Y)             ; 
-    CALL    #WriteSector            ;SWX  write SectorHL=DIRsector
-; ----------------------------------;
-; 3- free all file clusters         ; Cluster = FirstCluster
-; ----------------------------------;
-ComputeClusterSectWofstY            ;     
-    CALL    #ClusterToFAT1sectWofstY;WXY    W = FATsector, Y=FAToffset
-    MOV     W,&CurFATsector         ; update CurrentFATsector
-; ----------------------------------;
-LoadFAT1sector
-; ----------------------------------;
-    MOV     W,T                     ; T = W = current FATsector memory
-    ADD     &OrgFAT1,W              ;
-    MOV     #0,X                    ;
-    CALL    #ReadSectorWX           ;SWX (< 65536)
-; ----------------------------------;
-GetAndFreeClusterLo                 ;
-; ----------------------------------;
-    MOV     SD_BUF(Y),W             ; get [clusterLO]
-    MOV     #0,SD_BUF(Y)            ; free CLusterLO
-ClusterTestSelect                   ;
-    CMP     #1,&FATtype             ; FAT16 ?
-    JZ      ClusterLoTest           ; yes
-GetAndFreeClusterHi                 ;
-    MOV     SD_BUF+2(Y),X           ; get [clusterHI]
-    MOV     #0,SD_BUF+2(Y)          ; free CLusterHI
-ClusterHiTest
-    AND     #00FFFh,X               ; select 12 bits significant
-    CMP     #00FFFh,X               ; [ClusterHI] was = 0FFFh?
-    JNE     SearchNextCluster2free  ; no
-ClusterLoTest                  
-    CMP     #-1,W                   ; [ClusterLO] was = FFFFh?
-    JZ      EndOfFileClusters       ; yes 
-; ----------------------------------;
-SearchNextCluster2free
-; ----------------------------------;
-    MOV     W,&ClusterL             ;
-    MOV     X,&ClusterH             ;
-    CALL    #ClusterToFAT1sectWofstY;WXY
-    CMP     W,T                     ; new FATsector = current FATsector memory ?
-    JZ      GetAndFreeClusterLo     ; yes loop back
-    PUSH    W                       ; no: save new FATsector...
-    MOV     T,W                     ; ...before update current FATsector
-    CALL    #UpdateFATsSectorW      ;SWX
-    MOV     @RSP+,W                 ; restore new current FATsector
-    JMP     LoadFAT1sector          ; loop back with Y = FAToffset
-; ----------------------------------;
-EndOfFileClusters                   ;
-; ----------------------------------;
-    MOV     T,W                     ; T = W = current FATsector
-    CALL    #UpdateFATsSectorW      ;SWX
-; ----------------------------------;
-; 3- Close Handle                   ;
-; ----------------------------------;
-    CALL    #CloseHandleT           ;
-; ----------------------------------;
-DEL_END                             ;
-    MOV @IP+,PC                     ;4
+    MOV @IP+,PC                     ; BufferPtr = first free byte offset
 ; ----------------------------------;
 
 
-
     .IFNDEF TERMINAL_I2C ; if UART_TERMINAL
 
 ; first TERATERM sends the command TERM2SD" file.ext" to FastForth which returns XOFF at the end of the line.
 ; then when XON is sent below, TERATERM sends "file.ext" up to XOFF sent by TERM2SD" (slices of 512 bytes),
 ; then TERATERM sends char EOT that closes the file on SD_CARD.
 
-    FORTHWORD "TERM2SD\34"
-    mDOCOL
-    .word   DELDQ                   ;                   DEL file if already exist
-    .word   lit,2                   ; -- open_type
-    .word   HERE,COUNT              ; -- open_type addr cnt
-    .word   PARENOPEN               ;                   reopen same filepath but as write
-    .word   $+2                     ;
-    MOV     @RSP+,IP                ;
+; ==================================;
+    FORTHWORD "TERM2SD\34"          ;
+; ==================================;
+    mDOCOL                          ;
+    .word   WRITEDQ                 ;  if already exist FreeAllClusters else create it as WRITE file
+    mNEXTADR                        ;
 ; ----------------------------------;
-T2S_GetSliceLoop                    ;   tranfert by slices of 512 bytes terminal input to file on SD_CARD via SD_BUF 
+T2S_GetSliceLoop                    ;   tranfert by slices of 512 bytes from terminal input to file on SD_CARD via SD_BUF
 ; ----------------------------------;
     MOV     #0,W                    ;1  reset W = BufferPtr
     CALL    #RXON                   ;   use no registers
 ; ----------------------------------;
-T2S_FillBufferLoop                  ;
+T2S_Get_a_Char_Loop                 ;
 ; ----------------------------------;
     BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
-    JZ      T2S_FillBufferLoop      ;2
+    JZ      T2S_Get_a_Char_Loop     ;2
     MOV.B   &TERM_RXBUF,X           ;3
     MOV.B   X,&TERM_TXBUF
     CMP.B   #4,X                    ;1 EOT sent by TERATERM ?
@@ -653,25 +637,38 @@ T2S_FillBufferLoop                  ;
     MOV.B   X,SD_BUF(W)             ;3
     ADD     #1,W                    ;1
     CMP     #BytsPerSec-1,W         ;2
-    JNC     T2S_FillBufferLoop      ;2 W < BytsPerSec-1    21 cycles char loop
     JZ      T2S_XOFF                ;2 W = BytsPerSec-1    send XOFF after RX 511th char
+    JNC     T2S_Get_a_Char_Loop     ;2 W < BytsPerSec-1    21 cycles char loop (476 kBds/MHz)
 ; ----------------------------------;
 T2S_WriteFile                       ;2 W = BytsPerSec
 ; ----------------------------------;
-    CALL    #Write_File             ;TSWXY write all the buffer
-    JMP     T2S_GetSliceLoop        ;2 
+    CALL    #Write_File             ;STWXY write all the buffer
+    JMP     T2S_GetSliceLoop        ;2
 ; ----------------------------------;
 T2S_XOFF                            ;  27 cycles between XON and XOFF
 ; ----------------------------------;
     CALL    #RXOFF                  ;4  use no registers
-    JMP     T2S_FillBufferLoop      ;2  loop back once to get last char
+    JMP     T2S_Get_a_Char_Loop     ;2  loop back once to get char sent by TERMINAL during XOFF time
 ; ----------------------------------;
-T2S_End_Of_File                     ;
+T2S_End_Of_File                     ;  wait CR before sending XOFF
+; ----------------------------------;
+T2S_Wait_CR                         ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
+; ----------------------------------;
+    CMP.B   #0Dh,&TERM_RXBUF        ; also clears RX_IFG !
+    JZ      T2S_Wait_CR             ; wait CR
 ; ----------------------------------;
     CALL    #RXOFF                  ;4  use no registers
+; ----------------------------------;
+T2S_Wait_LF                         ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
+; ----------------------------------;
+    CMP.B   #0Ah,&TERM_RXBUF        ; also clears RX_IFG !
+    JZ      T2S_Wait_LF             ; wait LF
+; ----------------------------------;
     MOV     W,&BufferPtr            ;3
-    CALL    #CloseHandleT           ;4
-    MOV @IP+,PC                     ;4
+    CALL    #CloseHandle            ;4
+; ----------------------------------;
+    MOV     @RSP+,IP                ;
+    MOV     @IP+,PC                 ;4
 ; ----------------------------------;
 
     .ELSE ; if I2C_TERMINAL
@@ -680,59 +677,75 @@ T2S_End_Of_File                     ;
 ; then when RXON is sent below, I2C_Master sends "file.ext" line by line
 ; then TERATERM sends char EOT that closes the file on SD_CARD.
 
+; ==================================;
     FORTHWORD "TERM2SD\34"          ; here, I2C_Master is reSTARTed in RX mode
-    mDOCOL
-    .word   DELDQ                   ;                   DEL file if already exist
-    .word   lit,2                   ; -- open_type
-    .word   HERE,COUNT              ; -- open_type addr cnt
-    .word   PARENOPEN               ;                   reopen same filepath but as write
-    .word   $+2                     ;
+; ==================================;
+    mDOCOL                          ;
+    .word   WRITEDQ                 ; if already exist FreeAllClusters else create it as WRITE file
+    mNEXTADR                        ;
 ; ----------------------------------;
-    CALL    #RXON                   ; send I2C Ctrl_Char $00 to I2C_Master
+    MOV     #0,W                    ; reset W = SD_Buf_Ptr
+    MOV.B   #0Ah,IP                 ; IP = char 'LF'
 ; ----------------------------------;
-T2S_ClearBuffer                     ;
+T2S_GetLineLoop                     ; tranfert line by line from terminal input to SD_BUF
 ; ----------------------------------;
-    MOV     #0,W                    ;1  reset W = BufferPtr
+    CALL    #RXON                   ; use Y reg; send I2C Ctrl_Char $00 to request I2C_Master to switch from RX to TX
+; ----------------------------------;
+T2S_Get_a_Char_Loop                 ;
 ; ----------------------------------;
-T2S_FillBufferLoop                  ;   move by slices of 512 bytes from TERMINAL input to file on SD_CARD via SD_BUF 
+T2S_Q_BufferFull                    ; test it before to take data in RX buffer and so to do SCL strech low during Write_File !!!!
+; ----------------------------------;
+    CMP     #BytsPerSec,W           ;2 buffer full ?
+    JNC     T2S_Get_a_Char          ;2 no
+; ----------------------------------;
+T2S_WriteFile                       ;  tranfert all 512 bytes of SD_BUF to the opened file in SD_CARD
+; ----------------------------------;  SCL is stretched low by Slave (it's my)
+    CALL    #Write_File             ;STWXY Write_File write always all the buffer
+    MOV     #0,W                    ;  reset SD_Buf_Ptr
+; ----------------------------------;
+T2S_Get_a_Char                      ;
 ; ----------------------------------;
     BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
-    JZ      T2S_FillBufferLoop      ;2 no
-    MOV.B   &TERM_RXBUF,X           ;3
-    CMP.B   #4,X                    ;1 EOT sent by TERMINAL (teraterm.exe) ?
+    JZ      T2S_Get_a_Char          ;2 no
+    MOV.B   &TERM_RXBUF,X           ;3 SCL is released here
+; ----------------------------------;
+T2S_Q_EOF                           ;
+; ----------------------------------;
+    CMP.B   #4,X                    ;1 EOF sent by TERMINAL (teraterm.exe) ?
     JZ      T2S_End_Of_File         ;2 yes
     MOV.B   X,SD_BUF(W)             ;3
     ADD     #1,W                    ;1
-    CMP.B   #0Ah,X                  ;2 Char LF ?
-    JNZ     T2S_Q_BufferFull        ;2 no
 ; ----------------------------------;
-T2S_GetNewLine                      ; here I2C_Master automatically (re)START in RX mode, one char must be sent to
-; ----------------------------------; clear I2C_Slave UCSTTIFG, so we must send LF a minima
-    ASMtoFORTH                      ;
-    .word   CR                      ; (CR+LF instead of LF is sent to beautify TERMINAL display, if ECHO is ON obviously)
-    .word   $+2                     ;
-    CALL    #RXON                   ; send I2C Ctrl_Char $00 to I2C_Master
+T2S_Q_Char_LF                       ; when Master send the Ack on char 'LF', it reStarts automatically in RX mode
 ; ----------------------------------;
-T2S_Q_BufferFull                    ;
+    CMP.B   IP,X                    ;1 Char LF received ?
+    JNZ     T2S_Get_a_Char_Loop     ;2 no, 22 cycles loop back (< 1us @ 24 MHz)
 ; ----------------------------------;
-    CMP     #BytsPerSec,W           ;2 buffer full ?
-    JNC     T2S_FillBufferLoop      ;2 no    21 cycles char loop
+T2S_Send_CR                         ; because I2C_Master doesn't echo it on TERMINAL
+; ----------------------------------;
+    BIT     #TX_TERM,&TERM_IFG      ;
+    JZ      T2S_Send_CR             ; wait TX buffer empty
+    MOV.B   #0Dh,&TERM_TXBUF        ; send CR to beautify TERMINAL display (if ECHO is ON, obviously)
+; ----------------------------------;
+T2S_Send_LF                         ; because I2C_Master doesn't echo it on TERMINAL
 ; ----------------------------------;
-T2S_WriteFile                       ;2 yes
+    BIT     #TX_TERM,&TERM_IFG      ;
+    JZ      T2S_Send_LF             ; wait TX buffer empty
+    MOV.B   IP,&TERM_TXBUF          ; send LF to beautify TERMINAL display (if ECHO is ON, obviously)
 ; ----------------------------------;
-    CALL    #Write_File             ;4 TSWXY write all the buffer
-    JMP     T2S_ClearBuffer         ;2 
+    JMP     T2S_GetLineLoop         ;
 ; ----------------------------------;
 T2S_End_Of_File                     ;
 ; ----------------------------------;
-    BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
-    JZ      T2S_End_Of_File         ;2 no
-    CMP.B   #0Ah,&TERM_RXBUF        ;4 Char LF ?
-    JNZ     T2S_End_Of_File         ;    
+T2S_Wait_LF                         ; warning! EOT is followed by CR+LF, because I2C_Master uses LF to switch from TX to RX
 ; ----------------------------------;
-    MOV     W,&BufferPtr            ;3
-    CALL    #CloseHandleT           ;4
-    MOV     @RSP+,IP                ; moved here because ASMtoFORTH use above
+    CMP.B   IP,&TERM_RXBUF          ; and also clears RX_IFG !
+    JNZ     T2S_Wait_LF             ;
+; ----------------------------------; here I2C_Master switches from TX to RX
+    MOV     W,&BufferPtr            ; to add it to HDLL_CurSize
+    CALL    #CloseHandle            ;   tranfert SD_BUF to last sector of opened file in SD_CARD then close it
+; ----------------------------------;
+    MOV     @RSP+,IP                ;
     MOV     @IP+,PC                 ;
 ; ----------------------------------;