OSDN Git Service

V309
[fast-forth/master.git] / forthMSP430FR_SD_RW.asm
index d942826..4dc59bf 100644 (file)
@@ -1,4 +1,4 @@
-; -*- coding: utf-8 -*-
+ ; -*- 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.
 ; ======================================================================
 
 ; ----------------------------------;
-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
-    mNEXT                           ;
+    MOV     @IP+,PC                 ; no more to do
 ; ----------------------------------;
 
 ;Z READ            -- f
 ; sequentially read a file opened by READ".
-; sectors are loaded in BUFFER and BufferLen leave the count of loaded bytes.
+; 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 ?
-; ----------------------------------;
+; ==================================;
+    FORTHWORD "READ"                ; -- fl     closed flag
+; ==================================;
 READ
     SUB     #2,PSP                  ;
     MOV     TOS,0(PSP)              ;
     MOV     &CurrentHdl,TOS         ;
     CALL    #Read_File              ;SWX
-    SUB     &CurrentHdl,TOS         ; -- fl     if fl <>0 (if Z=0) handle is closed
-    mNEXT                           ;
+    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, BUFFER = [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
-    CALL    #ReadFAT1SectorW        ;SWX
-    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,BUFFER+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,BUFFER(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 BUFFER 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 BUFFER = 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,BUFFER(X)           ; mark NewCluster low word as end cluster (0xFFFF) in BUFFER
-    CMP     #2,Y                    ; Y = FAT16 size of Cluster number ?
-    JZ      FAT16EntryToClusterNum  ; yes
-    MOV     #0FFFh,BUFFER+2(X)      ; no: mark NewCluster high word as end cluster (0x0FFF) in BUFFER
+    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
 ; ----------------------------------;
-FAT16EntryToClusterNum              ; convert FAT16 address of Cluster in cluster number
+    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
 ; ----------------------------------;
-    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         ;
+
+
+; ==================================;
+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                 ;
 ; ----------------------------------;
-SearchNewClusterEnd                 ;
+    CALL    #ReadFAT1SectorW        ;SWX
 ; ----------------------------------;
-    MOV     @RSP+,W                 ; W = FATsector
-    MOV     W,&CurFATsector         ; refresh CurrentFATsector
-    RET                             ;
+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
+; ----------------------------------;
+SearchNextCluster2free              ;
+; ----------------------------------;
+    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                    ;
+; ----------------------------------;
+    MOV     @RSP+,W                 ;
+    MOV     #SaveSectorWtoFATs,PC   ; update FATs
 ; ----------------------------------;
 
+; 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 BUFFER content.
-; input : FATsector, FAToffset, BUFFER = [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
-    CALL    #WriteSectorW           ; SWX
-    MOV     @RSP+,W                 ;
-    ADD     &OrgFAT2,W              ; update FAT#2
-    MOV     #WriteSectorW,PC        ; then ret
+; 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
+;-----------------------------------------------------------------------
+
 
 
 ; FAT16/32 format for date and time in a DIR entry
@@ -165,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
 ; ----------------------------------;
@@ -192,39 +276,36 @@ 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                           ;
-    RET                             ;
+    MOV     @RSP+,PC                ;
 ; ----------------------------------;
 
 
 ; when create filename, forbidden chars are skipped
-ForbiddenChars ; 15 forbidden chars + dot char table
-;          "  *  +  ,  /  :  ;  <  =  >  ?  [  \  ]  |  .
-    .byte 34,42,43,44,47,58,59,60,61,62,63,91,92,93,124,46
+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,BUFFER(Y)             ;     to DIRentry
-    CMP     #0,W                    ; end of stringZ ?
-    JZ      OPWC_CompleteWithSpaces ;
+    MOV.B   W,SD_BUF(Y)             ;     to DIRentry
+;    CMP     #0,W                    ; end of stringZ ?
+;    JZ      OPWC_CompleteWithSpaces ;
+    CMP     T,&PathName_END         ; EOS < PTR ?
+    JNC     OPWC_CompleteWithSpaces ; yes
 ; ----------------------------------;
 SkipForbiddenChars                  ;
 ; ----------------------------------;
@@ -249,451 +330,423 @@ ForbiddenCharLoop                   ;
 ; ----------------------------------;
 OPWC_CompleteWithSpaces             ; 0 to n spaces !
 ; ----------------------------------;
-    CMP     #0,X                    ; 
+    CMP     #0,X                    ;
     JZ      OPWC_CWS_End            ;
 ; ----------------------------------;
 OPWC_CompleteWithSpaceloop          ;
 ; ----------------------------------;
-    MOV.B   #32,BUFFER(Y)           ; remplace dot by char space
-    ADD     #1,Y                    ; increment DIRentry ptr in buffer 
+    MOV.B   #' ',SD_BUF(Y)          ; remplace dot by char space
+    ADD     #1,Y                    ; increment DIRentry ptr in buffer
     SUB     #1,X                    ; dec countdown of chars space
     JNZ OPWC_CompleteWithSpaceloop  ;
 OPWC_CWS_End                        ;
-    RET                             ;
+    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                          ;
     .word   XSQUOTE                 ;
     .byte   12,"< WriteError",0     ;
-    .word   BRAN,SD_ERROR           ;
+    .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!)
-    MOV.B   #20h,BUFFER+11(Y)       ; file attribute = file
+    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,BUFFER+12(Y)         ; nt reserved = 0 and centiseconds are 0
-    MOV     W,BUFFER+14(Y)          ; time of creation
-    MOV     X,BUFFER+16(Y)          ; date of creation      20/08/2001
-    MOV     X,BUFFER+18(Y)          ; date of access        20/08/2001
-    MOV     &ClusterH,BUFFER+20(Y)  ; as first Cluster Hi 
-    MOV     &ClusterL,BUFFER+26(Y)  ; as first cluster LO   
-    MOV     #0,BUFFER+28(Y)         ; file lenghtLO  = 0 
-    MOV     #0,BUFFER+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
-    JZ      OPWC_InvalidPathname    ; write error 1
+    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)         ; 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
+    MOV     #4,W                    ; get handle for write
+    CALL    #GetFreeHandle          ; output : CurCluster and CurSector are set
+    MOV     @IP+,PC                 ; --
 ; ----------------------------------;
-    CMP     #0,S                    ; no error ?
-    JNZ     OPWC_NomoreHandle       ; ==> abort with error 16
-    mNEXT                           ; --
-; ----------------------------------;
-
-;-----------------------------------------------------------------------
-; 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,BUFFER+18(Y)          ; access date
-    MOV     W,BUFFER+22(Y)          ; modified time
-    MOV     X,BUFFER+24(Y)          ; modified date
-OPWW_UpdateEntryFileSize            ;
-    MOV HDLL_CurSize(T),BUFFER+28(Y); save new filesize
-    MOV HDLH_CurSize(T),BUFFER+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 and CloseHandleT
-; ==================================; 
-WriteBuffer                         ;SWXY input: T = CurrentHDL
-; ==================================; 
-    ADD &BufferPtr,HDLL_CurSize(T)  ; update handle CurrentSizeL
-    ADDC    #0,HDLH_CurSize(T)      ;
 ; ==================================;
-WriteSector                         ;SWX
+OPEN_OVERWRITE                      ; handle exists
 ; ==================================;
-    MOV     &SectorL,W              ; Low
-    MOV     &SectorH,X              ; High
-    MOV     #WriteSectorWX,PC       ; ...then RET
+; free all file clusters            ;
+; ----------------------------------;
+    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 sequentially the buffer in the post incremented SectorHL.
-; The first time, SectorHL is initialized by WRITE".
-; All used registers must be initialized.
+; ======================================================================
+; 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
+; ======================================================================
+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
 ; ==================================;
-Write_File                          ; <== WRITE, SD_EMIT, TERM2SD"
+OPEN_WRITE_APPEND                   ; yes
 ; ==================================;
-    MOV     #BytsPerSec,&BufferPtr  ; write always all the buffer
-    MOV     &CurrentHdl,T           ;
-    CALL    #WriteBuffer            ; write BUFFER and update Handle informations only for DIRentry update 
-    MOV     #0,&BufferPtr           ; reset buffer pointer
-; ----------------------------------;
-PostIncrementSector                 ;
+; 1- open file                      ; done
 ; ----------------------------------;
-    ADD.B   #1,HDLB_ClustOfst(T)    ; increment current Cluster offset
-    CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
-    JNZ     Write_File_End          ; no, 
+    MOV.B  #4,HDLB_Token(T)         ; update HDLB_Token(T)
 ; ----------------------------------;
-GetNewCluster                       ; input : T=CurrentHdl
+; 2.1- Compute Sectors count        ; Sectors = HDLL_CurSize/512
 ; ----------------------------------;
-    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
-    CALL    #ReadFAT1SectorW        ;SWX  reload current FATsector in buffer to link clusters
-LinkClusters                        ;
-    MOV     @RSP+,W                 ; W = current FATsector
-    MOV     @RSP+,Y                 ; pop current FAToffset
-    MOV     &NewClusterL,BUFFER(Y)  ; store new cluster to current cluster address in current FATsector buffer
-    CMP     #1,&FATtype             ; FAT16?
-    JZ UpdatePreviousClusterFATs    ; yes
-    MOV     &NewClusterH,BUFFER+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
+    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 (bytes)
+; ----------------------------------;
+; 2.2 Compute Clusters Count        ;
+; ----------------------------------;
+    MOV.B &SecPerClus,T             ;3 T = DIVISOR = SecPerClus = 0:SPClo
+DIVSECPERSPC                        ;
+    MOV #0,W                        ;1 W = 0:REMlo = 0
+    MOV #8,S                        ;1 S = CNT
+DIVSECPERSPC1                       ;
+    RRA Y                           ;1 0>0:SEC_HI>C
+    RRC X                           ;1 C>SEC_LO>C
+    RRC.B W                         ;1 C>REMlo>C
+    SUB #1,S                        ;1 CNT-1
+    RRA T                           ;1 0>SPChi:SPClo>C
+    JNC DIVSECPERSPC1               ;2 7~ loopback if carry clear
+DIVSECPERSPC2                       ;
+    RRA W                           ;1 0>0:REMlo>C
+    SUB #1,S                        ;1 CNT-1
+    JGE DIVSECPERSPC2               ;2 4~ loopback     Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
+; ----------------------------------;
+; 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)          ;
 ; ----------------------------------;
-
-;Z WRITE            -- 
-; sequentially write the BUFFER in a file opened by WRITE"
+; 2.4- load current sectorHL        ;
 ; ----------------------------------;
-    FORTHWORD "WRITE"               ;
+    MOV.B W,HDLB_ClustOfst(T)       ;3  update handle with W = REM8 = sectors offset in last cluster
+    CALL #LoadCurSectorHL           ;SWX in SD_buf
 ; ----------------------------------;
-    CALL    #Write_File             ;
-    mNEXT                           ;
+; 2.5- Compute SD_Buf ptr           ;
 ; ----------------------------------;
-
-;Z SD_EMIT  c --    output char c to a SD_CARD file opened as write
+    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
 ; ----------------------------------;
-    FORTHWORD "SD_EMIT"             ;
+    MOV @IP+,PC                     ; BufferPtr = first free byte offset
 ; ----------------------------------;
-SD_EMIT                             ;
-    CMP     #BytsPerSec,&BufferPtr  ; 4 file buffer is full ?
-    JLO     SD_EmitNext             ; 2
-    CALL    #Write_File             ;   BufferPtr = 0
-SD_EmitNext                         ;
-    MOV     &BufferPtr,Y            ; Y 
-    MOV.B   TOS,BUFFER(Y)           ; 3
-    ADD     #1,&BufferPtr           ; 4
-    MOV     @PSP+,TOS               ; 2
-    mNEXT                           ; 4
-; ----------------------------------; 19~ for SD_EMIT, 22~ for EMIT
 
 
+    .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.
 
-; ======================================================================
-; WRITE" (APPEND part) 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, BufferPtr=HDLW_BufOfst=0
-; output: nothing else abort on error
-; error 2  : DiskFull       
-; ======================================================================
-
+; ==================================;
+    FORTHWORD "TERM2SD\34"          ;
+; ==================================;
+    mDOCOL                          ;
+    .word   WRITEDQ                 ;  if already exist FreeAllClusters else create it as WRITE file
+    mNEXTADR                        ;
 ; ----------------------------------;
-OPEN_WRITE_APPEND                   ;
+T2S_GetSliceLoop                    ;   tranfert by slices of 512 bytes from terminal input to file on SD_CARD via SD_BUF
 ; ----------------------------------;
-; 1- open file                      ; done
+    MOV     #0,W                    ;1  reset W = BufferPtr
+    CALL    #RXON                   ;   use no registers
 ; ----------------------------------;
-; 2- compute missing Handle infos   ;
+T2S_Get_a_Char_Loop                 ;
 ; ----------------------------------;
-; 2.1- Compute Sectors count        ; Sectors = HDLL_CurSize/512
+    BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
+    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 ?
+    JZ      T2S_End_Of_File         ;2 yes
+    MOV.B   X,SD_BUF(W)             ;3
+    ADD     #1,W                    ;1
+    CMP     #BytsPerSec-1,W         ;2
+    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)
 ; ----------------------------------;
-    MOV.B   HDLL_CurSize+1(T),Y     ; Y = 0:CurSizeLoHi
-    MOV.B   HDLH_CurSize(T),S       ; S = 0:CurSizeHiLo 
-    SWPB    S                       ; S = CurSizeHiLo:0 
-    ADD     Y,S                     ; S = CurSizeHiLo:CurSizeLoHi
-    MOV.B   HDLH_CurSize+1(T),W     ; W:S = CurSize / 256
-    RRA     W                       ; W = Sectors number_High
-    RRC     S                       ; S = Sectors number_Low
+T2S_WriteFile                       ;2 W = BytsPerSec
 ; ----------------------------------;
-; 2.2- Compute Buffer offset        ; tested with 4100 bytes and SecPerClus=8
+    CALL    #Write_File             ;STWXY write all the buffer
+    JMP     T2S_GetSliceLoop        ;2
 ; ----------------------------------;
-    MOV     HDLL_CurSize(T),Y       ; Y = 1004
-    BIC     #01FFh,HDLL_CurSize(T)  ; substract 4 from HDLL_CurSize
-    AND     #01FFh,Y                ; Y = 4
-    MOV     Y,&BufferPtr            ; init Buffer Pointer with 4
+T2S_XOFF                            ;  27 cycles between XON and XOFF
 ; ----------------------------------;
-ComputeClustersCount                ; with  W:S / T ==> quotient = Y:X, remainder = W
+    CALL    #RXOFF                  ;4  use no registers
+    JMP     T2S_Get_a_Char_Loop     ;2  loop back once to get char sent by TERMINAL during XOFF time
 ; ----------------------------------;
-    MOV.B &SecPerClus,T             ;3 T = DIVISOR = SecPerClus
-    CALL #UDIVQ32                   ; unsigned division 32/16 ==> Q32,R16 i.e. W:S/T ==> Y:X,W     use S,T,W,X,Y
-    MOV &CurrentHDL,T               ;
+T2S_End_Of_File                     ;  wait CR before sending XOFF
 ; ----------------------------------;
-; 2.3- Compute Cluster offset       ;
+T2S_Wait_CR                         ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
 ; ----------------------------------;
-    MOV.B W,HDLB_ClustOfst(T)       ;3  update handle with W = R16 (remainder) = sectors offset in cluster
+    CMP.B   #0Dh,&TERM_RXBUF        ; also clears RX_IFG !
+    JZ      T2S_Wait_CR             ; wait CR
 ; ----------------------------------;
-; 2.4- Compute last Cluster         ; X = Q32lo = Clusters numberLO, Y = Q32hi = Clusters numberHI 
+    CALL    #RXOFF                  ;4  use no registers
 ; ----------------------------------;
-    ADD  HDLL_FirstClus(T),X        ;
-    ADDC HDLH_FirstClus(T),Y        ;
-    MOV X,HDLL_CurClust(T)          ;  update handle
-    MOV Y,HDLH_CurClust(T)          ;
+T2S_Wait_LF                         ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
 ; ----------------------------------;
-; 3- load last sector in BUFFER     ;
+    CMP.B   #0Ah,&TERM_RXBUF        ; also clears RX_IFG !
+    JZ      T2S_Wait_LF             ; wait LF
+; ----------------------------------;
+    MOV     W,&BufferPtr            ;3
+    CALL    #CloseHandle            ;4
+; ----------------------------------;
+    MOV     @RSP+,IP                ;
+    MOV     @IP+,PC                 ;4
 ; ----------------------------------;
-    CALL    #LoadHDLcurrentSector   ;SWX
-    mNEXT                           ; --
-; ----------------------------------; BufferPtr leaves first free byte offset
-
 
-; ======================================================================
-; 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, BufferPtr=HDLW_BufOfst=0
-; output: nothing (no message if open error)
-; ======================================================================
+    .ELSE ; if I2C_TERMINAL
 
+; first TERATERM sends the command TERM2SD" file.ext" to I2C_FastForth.
+; 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.
 
-OPEN_QDEL                           ;
-;    CMP     #4,W                    ;   open_type = DEL"
-;    JNZ     OPEN_8W                 ;
-; ----------------------------------;
-OPEN_DEL                            ;
-; ----------------------------------;
-; 1- open file                      ; done
+; ==================================;
+    FORTHWORD "TERM2SD\34"          ; here, I2C_Master is reSTARTed in RX mode
+; ==================================;
+    mDOCOL                          ;
+    .word   WRITEDQ                 ; if already exist FreeAllClusters else create it as WRITE file
+    mNEXTADR                        ;
 ; ----------------------------------;
-    CMP     #0,S                    ; open file happy end ?
-    JNE     OPND_END                ; no: don't send message
+    MOV     #0,W                    ; reset W = SD_Buf_Ptr
+    MOV.B   #0Ah,IP                 ; IP = char 'LF'
 ; ----------------------------------;
-; 2- Delete DIR entry               ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
+T2S_GetLineLoop                     ; tranfert line by line from terminal input to SD_BUF
 ; ----------------------------------;
-SelectFreeEntry                     ; nothing to do: S = 0 ready for free entry!
+    CALL    #RXON                   ; use Y reg; send I2C Ctrl_Char $00 to request I2C_Master to switch from RX to TX
 ; ----------------------------------;
-    CMP     #BytsPerSec-32,Y        ; Entry >= last entry in DIRsector ?
-    JHS     SelectHideEntry         ; yes:  next DIR entry is out of sector
-    CMP.B   #0,BUFFER+32(Y)         ; no:   next DIR entry in DIRsector is free?
-    JZ      WriteDelEntry           ;       yes
+T2S_Get_a_Char_Loop                 ;
 ; ----------------------------------;
-SelectHideEntry                     ;       no
+T2S_Q_BufferFull                    ; test it before to take data in RX buffer and so to do SCL strech low during Write_File !!!!
 ; ----------------------------------;
-    MOV.B   #0E5h,S                 ;
+    CMP     #BytsPerSec,W           ;2 buffer full ?
+    JNC     T2S_Get_a_Char          ;2 no
 ; ----------------------------------;
-WriteDelEntry
+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
 ; ----------------------------------;
-    MOV.B   S,BUFFER(Y)             ; 
-    CALL    #WriteSector            ;SWX  write SectorHL=DIRsector
+T2S_Get_a_Char                      ;
 ; ----------------------------------;
-; 3- free all file clusters         ; Cluster = FirstCluster
+    BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
+    JZ      T2S_Get_a_Char          ;2 no
+    MOV.B   &TERM_RXBUF,X           ;3 SCL is released here
 ; ----------------------------------;
-ComputeClusterSectWofstY            ;     
-    CALL    #ClusterToFAT1sectWofstY;WXY    W = FATsector, Y=FAToffset
-    MOV     W,&CurFATsector         ; update CurrentFATsector
+T2S_Q_EOF                           ;
 ; ----------------------------------;
-LoadFAT1sector
+    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
 ; ----------------------------------;
-    MOV     W,T                     ; T = W = current FATsector memory
-    CALL    #ReadFAT1SectorW        ;SWX
+T2S_Q_Char_LF                       ; when Master send the Ack on char 'LF', it reStarts automatically in RX mode
 ; ----------------------------------;
-GetAndFreeClusterLo                 ;
+    CMP.B   IP,X                    ;1 Char LF received ?
+    JNZ     T2S_Get_a_Char_Loop     ;2 no, 22 cycles loop back (< 1us @ 24 MHz)
 ; ----------------------------------;
-    MOV     BUFFER(Y),W             ; get [clusterLO]
-    MOV     #0,BUFFER(Y)            ; free CLusterLO
-ClusterTestSelect                   ;
-    CMP     #1,&FATtype             ; FAT16 ?
-    JZ      ClusterLoTest           ; yes
-GetAndFreeClusterHi                 ;
-    MOV     BUFFER+2(Y),X           ; get [clusterHI]
-    MOV     #0,BUFFER+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 
+T2S_Send_CR                         ; because I2C_Master doesn't echo it on TERMINAL
 ; ----------------------------------;
-SearchNextCluster2free
+    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)
 ; ----------------------------------;
-    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
+T2S_Send_LF                         ; because I2C_Master doesn't echo it on TERMINAL
 ; ----------------------------------;
-EndOfFileClusters                   ;
+    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)
 ; ----------------------------------;
-    MOV     T,W                     ; T = W = current FATsector
-    CALL    #UpdateFATsSectorW      ;SWX
+    JMP     T2S_GetLineLoop         ;
 ; ----------------------------------;
-; 3- Close Handle                   ;
+T2S_End_Of_File                     ;
 ; ----------------------------------;
-    CALL    #CloseHandleT           ;
+T2S_Wait_LF                         ; warning! EOT is followed by CR+LF, because I2C_Master uses LF to switch from TX to RX
 ; ----------------------------------;
-OPND_End                            ;
+    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
 ; ----------------------------------;
-    mNEXT
-
-
-
-; 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" by slices of 512 bytes,
-; until it sends char ETX that closes the file on SD_CARD.
-
-    FORTHWORD "TERM2SD\34"
-    mDOCOL
-    .word   DELDQ                   ;   DEL file if already exist
-    .word   HERE                    ;
-    FORTHtoASM                      ;
-    ADD     #2,RSP                  ; pop IP of OPEN
-    SUB     #2,PSP                  ;
-    MOV     #2,0(PSP)               ; -- open_type HERE     open_type = open as write
-    MOV     #TERM2SD,IP             ;                       IP = ParenOpen return address
-    MOV     #PARENOPEN,PC           ; open_type HERE --     open as write the file whose HERE is the c-addr of pathname
-TERM2SD                             ;
-    FORTHtoASM                      ; T = CurrentHdl
-    BIC     #UCRXIFG,&TERMIFG       ;   clean up RX buffer  
-; ----------------------------------;
-T2S_GetSliceLoop                    ;   tranfert by slices of 512 bytes terminal input to file on SD_CARD via BUFFER 
-; ----------------------------------;
-    MOV     #0,Y                    ;1  reset Y = BufferPtr
-    CALL    #RXON                   ;   use no registers
-; ----------------------------------;
-T2S_FillBufferLoop                  ;
-; ----------------------------------;
-    BIT     #UCRXIFG,&TERMIFG       ;3 new char in TERMRXBUF ?
-    JZ      T2S_FillBufferLoop      ;2
-    MOV.B   &TERMRXBUF,X            ;3
-    CMP.B   #4,X                    ;1 ETX sent by TERATERM ?
-    JZ      T2S_END                 ;2 yes
-    MOV.B   X,BUFFER(Y)             ;3
-    ADD     #1,Y                    ;1
-    CMP     #BytsPerSec-1,Y         ;2
-    JZ      T2S_XOFF                ;2 Y=511    send XOFF after RX 511th char
-    JLO     T2S_FillBufferLoop      ;2 Y<511    21 cycles char loop
-; ----------------------------------;
-T2S_WriteFile                       ;2 Y>511
-; ----------------------------------;
-    CALL    #Write_File             ;TSWXY 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 to get 512th char
-; ----------------------------------;
-T2S_END                             ;
-; ----------------------------------;
-    CALL    #RXOFF                  ;4  use no registers
-    MOV     Y,&BufferPtr            ;3
-    CALL    #CloseHandleT           ;4
-    MOV     @RSP+,IP                ;2
-    mNEXT                           ;4
+    MOV     @RSP+,IP                ;
+    MOV     @IP+,PC                 ;
 ; ----------------------------------;
 
+    .ENDIF