OSDN Git Service

V3.7
[fast-forth/master.git] / forthMSP430FR_SD_RW.asm
1  ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FR5xxxSD_RW.asm
3
4 ; ======================================================================
5 ; READ" primitive as part of OpenPathName
6 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
7 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
8 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
9 ; output: nothing else abort on error
10 ; ======================================================================
11
12 ; ----------------------------------;
13 OPEN_QREAD                          ;
14     CMP     #1,W                    ; open_type = READ" ?
15     JNZ     OPEN_QWRITE             ; no : goto next step
16 ; ----------------------------------;
17 OPEN_READ                           ;
18 ; ----------------------------------;
19     CMP     #0,S                    ; open file happy end ?
20     JNZ     OPEN_Error              ; no
21     MOV @IP+,PC                     ;
22 ; ----------------------------------;
23
24 ;Z READ            -- f
25 ; sequentially read a file opened by READ".
26 ; sectors are loaded in SD_BUF and BufferLen leave the count of loaded bytes.
27 ; when the last sector of file is loaded in buffer, the handle is automatically closed and flag is true (<>0).
28
29 ; ----------------------------------;
30     FORTHWORD "READ"                ; -- fl     closed flag
31 ; ----------------------------------;
32 READ
33     SUB     #2,PSP                  ;
34     MOV     TOS,0(PSP)              ;
35     MOV     &CurrentHdl,TOS         ;
36     CALL    #Read_File              ;SWX
37 READ_END
38     SUB     &CurrentHdl,TOS         ; -- fl     if fl <>0 (if Z=0) handle is closed
39     MOV @IP+,PC                     ;
40 ; ----------------------------------;
41
42
43 ;-----------------------------------------------------------------------
44 ; WRITE" (CREATE part) subroutines
45 ;-----------------------------------------------------------------------
46
47 ; parse all FAT sectors until free cluster is found 
48 ; this NewCluster is marked as the end's one (-1)
49
50
51 ; input : CurFATsector
52 ; use SWX registers
53 ; output: W = new FATsector, SD_BUF = [new FATsector], NewCluster
54 ;         SectorL is unchanged, FATS are not updated.
55 ;         S = 2 --> Disk FULL error
56 ; ----------------------------------;
57 SearchNewCluster                    ; <== CREATE file, WRITE_File
58 ; ----------------------------------;
59     MOV     #2,S                    ; preset disk full return error
60     PUSH    &CurFATsector           ; last known free cluster sector
61     MOV     &FATtype,Y              ;
62     ADD     Y,Y                     ;  Y = bytes size of Cluster number (2 or 4)
63 ; ----------------------------------;
64 LoadFATsectorInBUF                  ; <== IncrementFATsector
65 ; ----------------------------------;
66     MOV     @RSP,W                  ; W = FATsector
67     CMP     W,&FATSize              ;
68     JZ      OPW_Error               ; FATsector = FATSize ===> abort disk full
69     ADD     &OrgFAT1,W              ;
70     MOV     #0,X                    ;
71     CALL    #ReadSectorWX           ;SWX (< 65536)
72     MOV     #0,X                    ; init FAToffset
73 ; ----------------------------------;
74 SearchFreeClustInBUF                ; <== SearchNextCluster
75 ; ----------------------------------;
76     CMP     #2,Y                    ; FAT16 Cluster size ?
77     JZ      ClusterLowWordTest      ; yes
78 ClusterHighWordTest                 ;
79     CMP     #0,SD_BUF+2(X)          ; cluster address hi word = 0 ?
80     JNZ     SearchNextNewCluster    ;
81 ClusterLowWordTest                  ;
82     CMP     #0,SD_BUF(X)            ; Cluster address lo word = 0 ?
83     JZ      GNC_FreeClusterFound    ; 
84 SearchNextNewCluster                ;
85     ADD     Y,X                     ; increment SD_BUF offset by size of Cluster address
86     CMP     #BytsPerSec,X           ;
87     JNE     SearchFreeClustInBUF    ; loopback while X < BytsPerSec
88 IncrementFATsector                  ;
89     ADD     #1,0(RSP)               ; increment FATsector
90     JMP     LoadFATsectorInBUF      ; loopback
91 ; ----------------------------------;
92 GNC_FreeClusterFound                ; Y =  cluster number low word in SD_BUF = FATsector
93 ; ----------------------------------;
94     MOV     #0,S                    ; clear error
95     MOV.B   @RSP,W                  ; W = 0:FATsectorLo
96     MOV     #-1,SD_BUF(X)           ; mark NewCluster low word as end cluster (0xFFFF) in SD_BUF
97     CMP     #2,Y                    ; Y = FAT16 size of Cluster number ?
98     JZ      FAT16EntryToClusterNum  ; yes
99     MOV     #0FFFh,SD_BUF+2(X)      ; no: mark NewCluster high word as end cluster (0x0FFF) in SD_BUF
100 ; ----------------------------------;
101 FAT32EntryToClusterNum              ; convert FAT32 cluster address to cluster number
102 ; ----------------------------------;
103     RRA     X                       ; X = FATOffset>>1, FAToffset is byte size
104     SWPB    W                       ; W = FATsectorLo:0
105     ADD     W,X                     ; X = FATsectorLo:FATOffset>>1
106     MOV.B   1(RSP),W                ; W = FATsectorHi
107     RRA     W                       ; W = FATsectorHi>>1
108     RRC     X                       ; X = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
109     MOV     W,&NewClusterH          ; NewClusterH =  FATsectorHi>>1
110     MOV     X,&NewClusterL          ; NewClusterL = FATsectorLo>>1:FAToffset>>2
111     JMP     SearchNewClusterEnd     ; max cluster = 7FFFFF ==> 1FFFFFFF sectors ==> 256 GB
112 ; ----------------------------------;
113 FAT16EntryToClusterNum              ; convert FAT16 address of Cluster in cluster number
114 ; ----------------------------------;
115     RRA     X                       ; X = Offset>>1, offset is word < 256
116     MOV.B   X,&NewClusterL          ; X = NewCluster numberLO (byte)
117     MOV.B   W,&NewClusterL+1        ; W = NewCluster numberHI (byte)
118     MOV     #0,&NewClusterH         ;
119 ; ----------------------------------;
120 SearchNewClusterEnd                 ;
121 ; ----------------------------------;
122     MOV     @RSP+,W                 ; W = FATsector
123     MOV     W,&CurFATsector         ; refresh CurrentFATsector
124     MOV @RSP+,PC                             ;
125 ; ----------------------------------;
126
127
128 ; update FATs with SD_BUF content.
129 ; input : FATsector, FAToffset, SD_BUF = [FATsector]
130 ; use : SWX registers
131 ; ----------------------------------; else update FATsector of the old cluster
132 UpdateFATsSectorW                   ;
133 ; ----------------------------------;
134     PUSH    W                       ;
135     ADD     &OrgFAT1,W              ; update FAT#1
136     MOV     #0,X                    ;
137     CALL    #WriteSectorWX          ; write a logical sector
138     MOV     @RSP+,W                 ;
139     ADD     &OrgFAT2,W              ; update FAT#2
140     MOV     #0,X                    ;
141     CALL    #WriteSectorWX          ; write a logical sector
142 ; ----------------------------------;
143
144
145
146 ; FAT16/32 format for date and time in a DIR entry
147 ; create time :     offset 0Dh = 0 to 200 centiseconds, not used.
148 ;                   offset 0Eh = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
149 ; access time :     offset 14h = always 0, not used as date
150 ; modified time :   ofsset 16h = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
151 ; dates :    offset 10, 12, 18 = 0byyyyyyymmmmddddd, with : y=year-1980, m=month, d=day
152
153 ; ----------------------------------; input:
154 GetYMDHMSforDIR                     ;X=date, W=TIME
155 ; ----------------------------------;
156     .IFDEF    LF_XTAL               ;
157     .IFNDEF   RTC                   ; RTC_B or RTC_C select
158 ; ----------------------------------;
159     BIT.B   #RTCHOLD,&RTCCTL1       ; rtc is running ?
160     JNZ     SD_RW_RET               ; no
161 WaitRTC                             ; yes
162     BIT.B   #RTCRDY,&RTCCTL1        ; rtc values are valid ?
163     JZ      WaitRTC                 ; no
164     MOV.B   &RTCSEC,W               ; yes
165     RRA.B   W                       ; 2 seconds accuracy time
166     MOV.B   &RTCDAY,X               ;
167     MOV.B   #32,&MPY                ; common MPY for minutes and months
168     MOV.B   &RTCMIN,&OP2            ;
169     ADD     &RES0,W                 ;
170     MOV.B   &RTCMON,&OP2            ;
171     ADD     &RES0,X                 ;
172     MOV.B   &RTCHOUR,&MPY           ;
173     MOV     #2048,&OP2              ;
174     ADD     &RES0,W                 ;
175     MOV     &RTCYEAR,&MPY           ;
176     SUB     #1980,&MPY              ;
177     MOV     #512,&OP2               ;
178     ADD     &RES0,X                 ;
179     .ELSEIF
180     MOV     #0,X                    ; X=DATE 
181     MOV     #0,W                    ; W=TIME
182     .ENDIF
183     .ENDIF
184 SD_RW_RET                           ;
185     MOV @RSP+,PC                             ;
186 ; ----------------------------------;
187
188
189 ; when create filename, forbidden chars are skipped
190 ForbiddenChars ; 15 forbidden chars table + dot char
191     .byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
192
193 ; ----------------------------------;
194 OPWC_SkipDot                        ;
195 ; ----------------------------------;
196     CMP     #4,X                    ;
197     JL      FillDIRentryName        ; X < 4 : no need spaces to complete name entry
198     SUB     #3,X                    ;
199     CALL    #OPWC_CompleteWithSpaces; complete name entry 
200     MOV     #3,X                    ; 
201 ; ----------------------------------;
202
203 ; ----------------------------------;
204 FillDIRentryName                    ;SWXY use
205 ; ----------------------------------;
206     MOV.B   @T+,W                   ; W = char of pathname
207     MOV.B   W,SD_BUF(Y)             ;     to DIRentry
208 ;    CMP     #0,W                    ; end of stringZ ?
209 ;    JZ      OPWC_CompleteWithSpaces ;
210     CMP     T,&EndOfPath            ; EOS < PTR ?
211     JNC     OPWC_CompleteWithSpaces ; yes
212 ; ----------------------------------;
213 SkipForbiddenChars                  ;
214 ; ----------------------------------;
215     PUSH    IP                      ;3
216     MOV     #15,IP                  ;2 forbidden chars count
217     MOV     #ForbiddenChars,S       ;2 here, S is free
218 ForbiddenCharLoop                   ;
219     CMP.B   @S+,W                   ;2
220     JZ      FillDIRentryName        ;2 skip forbidden char
221     SUB     #1,IP                   ;1
222     JNZ     ForbiddenCharLoop       ;2
223     MOV     @RSP+,IP                ;2
224 ; ----------------------------------;
225     CMP.B   @S,W                    ;1 46 (0x2E)
226     JZ      OPWC_SkipDot            ;2 skip '.'
227 ; ----------------------------------;
228     SUB     #33,W                   ;
229     JL      FillDIRentryName        ; skip char =< SPACE char
230     ADD     #1,Y                    ; increment DIRentry ptr
231     SUB     #1,X                    ; decrement count of chars entry
232     JNZ     FillDIRentryName        ;
233 ; ----------------------------------;
234 OPWC_CompleteWithSpaces             ; 0 to n spaces !
235 ; ----------------------------------;
236     CMP     #0,X                    ; 
237     JZ      OPWC_CWS_End            ;
238 ; ----------------------------------;
239 OPWC_CompleteWithSpaceloop          ;
240 ; ----------------------------------;
241     MOV.B   #' ',SD_BUF(Y)          ; remplace dot by char space
242     ADD     #1,Y                    ; increment DIRentry ptr in buffer 
243     SUB     #1,X                    ; dec countdown of chars space
244     JNZ OPWC_CompleteWithSpaceloop  ;
245 OPWC_CWS_End                        ;
246     MOV @RSP+,PC                             ;
247 ; ----------------------------------;
248
249
250
251
252 ; ======================================================================
253 ; WRITE" primitive as part of OpenPathName
254 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
255 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
256 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
257 ; output: nothing else abort on error
258 ; error 1  : PathNameNotFound
259 ; error 2  : NoSuchFile       
260 ; error 4  : DirectoryFull  
261 ; error 8  : AlreadyOpen    
262 ; error 16 : NomoreHandle   
263 ; ======================================================================
264
265 ; ----------------------------------;
266 OPEN_QWRITE                         ;
267     CMP     #2,W                    ; open_type = WRITE" ?
268     JNZ     OPEN_QDEL               ; no : goto next step
269 ; ----------------------------------;
270 ; 1 try to open                     ; done
271 ; ----------------------------------;
272 ; 2 select error "no such file"     ;
273 ; ----------------------------------;
274     CMP     #2,S                    ; "no such file" error ?
275     JZ      OPEN_WRITE_CREATE       ; yes
276     CMP     #0,S                    ; no open file error ?
277     JZ      OPEN_WRITE_APPEND       ; yes
278 ; ----------------------------------;
279 ; Write errors                      ;
280 ; ----------------------------------;
281 OPWC_InvalidPathname                ; S = 1
282 OPWC_DiskFull                       ; S = 2 
283 OPWC_DirectoryFull                  ; S = 4
284 OPWC_AlreadyOpen                    ; S = 8
285 OPWC_NomoreHandle                   ; S = 16
286 ; ----------------------------------;
287 OPW_Error                           ; set ECHO, type Pathname, type #error, type "< WriteError"; no return
288     mDOCOL                          ;
289     .word   XSQUOTE                 ;
290     .byte   12,"< WriteError",0     ;
291     .word   BRAN,ABORT_SD           ; to insert S error as flag, no return
292 ; ----------------------------------;
293
294
295 ; ======================================================================
296 ; WRITE" (CREATE part) primitive as part of OpenPathName
297 ; input from open:  S = NoSuchFile, W = open_type, SectorHL = DIRsectorHL,
298 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
299 ; output: nothing else abort on error:
300 ; error 1  : InvalidPathname
301 ; error 2  : DiskFull       
302 ; error 4  : DirectoryFull  
303 ; error 8  : AlreadyOpen    
304 ; error 16 : NomoreHandle   
305 ; ======================================================================
306
307 ; ----------------------------------;
308 OPEN_WRITE_CREATE                   ;
309 ; ----------------------------------;
310 ; 3 get free cluster                ;
311 ; ----------------------------------; input: FATsector
312     CALL    #SearchNewCluster       ;SWXY output:  W = new FATsector loaded in buffer,NewCluster 
313     MOV     &NewClusterL,&ClusterL  ;
314     MOV     &NewClusterH,&ClusterH  ;
315     CALL    #UpdateFATsSectorW      ;SWX update FATs with buffer
316 ; ----------------------------------;
317     CALL    #ReadSector             ; reload DIRsector
318     MOV     &EntryOfst,Y            ; reload entry offset (first free entry in DIR)
319 ; ----------------------------------;
320 ; 4 init DIRentryAttributes         ;
321 ; ----------------------------------;
322 OPWC_SetEntryAttribute              ; (cluster=DIRcluster!)
323     MOV.B   #20h,SD_BUF+11(Y)       ; file attribute = file
324     CALL    #GetYMDHMSforDIR        ;WX  X=DATE,  W=TIME
325     MOV     #0,SD_BUF+12(Y)         ; nt reserved = 0 and centiseconds are 0
326     MOV     W,SD_BUF+14(Y)          ; time of creation
327     MOV     X,SD_BUF+16(Y)          ; date of creation      20/08/2001
328     MOV     X,SD_BUF+18(Y)          ; date of access        20/08/2001
329     MOV     &ClusterH,SD_BUF+20(Y)  ; as first Cluster Hi 
330     MOV     &ClusterL,SD_BUF+26(Y)  ; as first cluster LO   
331     MOV     #0,SD_BUF+28(Y)         ; file lenghtLO  = 0 
332     MOV     #0,SD_BUF+30(Y)         ; file lenghtHI  = 0 
333 ; ----------------------------------;
334 ; 5 create DIRentryName             ;
335 ; ----------------------------------;
336     MOV     #1,S                    ; preset pathname error
337     MOV     &Pathname,T             ; here, pathname is "xxxxxxxx.yyy" format
338 ;    CMP.B   #0,0(T)                 ; forbidden null string
339     CMP     T,&EndOfPath            ;
340     JZ      OPWC_InvalidPathname    ; write error 1
341     CMP.B   #'.',0(T)               ; forbidden "." in first
342     JZ      OPWC_InvalidPathname    ; write error 1
343     MOV     #11,X                   ; X=countdown of chars entry
344     CALL    #FillDIRentryName       ;STWXY
345 ; ----------------------------------;
346 ; 6 save DIRsector                  ;
347 ; ----------------------------------;
348     CALL    #WriteSector            ;SWX update DIRsector
349 ; ----------------------------------;
350 ; 7 Get free handle                 ;
351 ; ----------------------------------;
352     MOV     #2,W                    ;
353     CALL    #GetFreeHandle          ; output : S = handle error, CurCluster and CurSector are set
354 ; ----------------------------------;
355     CMP     #0,S                    ; no error ?
356     JNZ     OPWC_NomoreHandle       ; ==> abort with error 16
357     MOV @IP+,PC                           ; --
358 ; ----------------------------------;
359
360 ;-----------------------------------------------------------------------
361 ; WRITE" subroutines
362 ;-----------------------------------------------------------------------
363
364 ; SectorL is unchanged
365 ; ----------------------------------;
366 OPWW_UpdateDirectory                ; <== CloseHandleT
367 ; ----------------------------------; Input : current Handle
368     MOV     HDLL_DIRsect(T),W       ;
369     MOV     HDLH_DIRsect(T),X       ;
370     CALL    #readSectorWX           ;SWX buffer = DIRsector
371     CALL    #GetYMDHMSforDIR        ; X=DATE,  W=TIME
372     MOV     HDLW_DIRofst(T),Y       ; Y = DirEntryOffset
373     MOV     X,SD_BUF+18(Y)          ; access date
374     MOV     W,SD_BUF+22(Y)          ; modified time
375     MOV     X,SD_BUF+24(Y)          ; modified date
376 OPWW_UpdateEntryFileSize            ;
377     MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
378     MOV HDLH_CurSize(T),SD_BUF+30(Y);
379     MOV     HDLL_DIRsect(T),W       ; 
380     MOV     HDLH_DIRsect(T),X       ;
381     MOV     #WriteSectorWX,PC       ;SWX then RET
382 ; ----------------------------------;
383
384 ; this subroutine is called by Write_File (bufferPtr=512) and CloseHandleT (0 =< BufferPtr =< 512)
385 ; ==================================; 
386 WriteBuffer                         ;STWXY input: T = CurrentHDL
387 ; ==================================; 
388     ADD &BufferPtr,HDLL_CurSize(T)  ; update handle CurrentSizeL
389     ADDC    #0,HDLH_CurSize(T)      ;
390 ; ==================================;
391 WriteSector                         ;SWX
392 ; ==================================;
393     MOV     &SectorL,W              ; Low
394     MOV     &SectorH,X              ; High
395     MOV     #WriteSectorWX,PC       ; ...then RET
396 ; ----------------------------------;
397
398
399
400 ; write sequentially the buffer in the post incremented SectorHL.
401 ; The first time, SectorHL is initialized by WRITE".
402 ; All used registers must be initialized.
403 ; ==================================;
404 Write_File                          ; <== WRITE, SD_EMIT, TERM2SD"
405 ; ==================================;
406     MOV     #BytsPerSec,&BufferPtr  ; write always all the buffer
407     MOV     &CurrentHdl,T           ;
408     CALL    #WriteBuffer            ; write SD_BUF and update Handle informations only for DIRentry update 
409     MOV     #0,&BufferPtr           ; reset buffer pointer
410 ; ----------------------------------;
411 PostIncrementSector                 ;
412 ; ----------------------------------;
413     ADD.B   #1,HDLB_ClustOfst(T)    ; increment current Cluster offset
414     CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
415     JNZ     Write_File_End          ; no, 
416 ; ----------------------------------;
417 GetNewCluster                       ; input : T=CurrentHdl
418 ; ----------------------------------;
419     MOV.B   #0,HDLB_ClustOfst(T)    ; reset handle ClusterOffset
420     CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
421     PUSH    Y                       ; push current FAToffset
422     PUSH    W                       ; push current FATsector
423     CALL    #SearchNewCluster       ;SWXY  output: W = new FATsector loaded in buffer, NewCluster 
424     CMP     @RSP,W                  ; current and new clusters are in same FATsector?
425     JZ      LinkClusters            ;     yes 
426 UpdateNewClusterFATs                ;
427     CALL    #UpdateFATsSectorW      ;SWX  no: UpdateFATsSectorW with buffer of new FATsector
428     MOV     @RSP,W                  ; W = current FATsector
429     ADD     &OrgFAT1,W              ;
430     MOV     #0,X                    ;
431     CALL    #ReadSectorWX           ;SWX (< 65536)
432 LinkClusters                        ;
433     MOV     @RSP+,W                 ; W = current FATsector
434     MOV     @RSP+,Y                 ; pop current FAToffset
435     MOV     &NewClusterL,SD_BUF(Y)  ; store new cluster to current cluster address in current FATsector buffer
436     CMP     #1,&FATtype             ; FAT16?
437     JZ UpdatePreviousClusterFATs    ; yes
438     MOV     &NewClusterH,SD_BUF+2(Y);
439 UpdatePreviousClusterFATs           ;
440     CALL    #UpdateFATsSectorW      ;SWX update FATS with current FATsector buffer
441 UpdateHandleCurCluster              ;
442     MOV &NewClusterL,HDLL_CurClust(T)  ; update handle with new cluster
443     MOV &NewClusterH,HDLH_CurClust(T) ;
444 ;    CALL #ComputeHDLcurrentSector   ; set Cluster first Sector as next Sector to be written
445 ;    MOV #OPWW_UpdateDirectory,PC    ; update DIRentry to avoid cluster lost, then RET
446 Write_File_End
447     MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
448 ; ----------------------------------;
449
450 ;Z WRITE            -- 
451 ; sequentially write the entire SD_BUF in a file opened by WRITE"
452 ; ----------------------------------;
453     FORTHWORD "WRITE"               ; in assembly : CALL &WRITE+2
454 ; ----------------------------------;
455     CALL #Write_File                ;
456     MOV @IP+,PC                     ;
457 ; ----------------------------------;
458
459
460 ; ======================================================================
461 ; WRITE" (APPEND part) primitive as part of OpenPathName
462 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
463 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
464 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
465 ; output: nothing else abort on error
466 ; error 2  : DiskFull       
467 ; ======================================================================
468
469 ; ----------------------------------;
470 OPEN_WRITE_APPEND                   ;
471 ; ----------------------------------;
472 ; 1- open file                      ; done
473 ; ----------------------------------;
474 ; 2- compute missing Handle infos   ;
475 ; ----------------------------------;
476 ; 2.1- Compute Sectors count        ; Sectors = HDLL_CurSize/512
477 ; ----------------------------------;
478     MOV.B   HDLL_CurSize+1(T),Y     ;Y = 0:CurSizeLOHi
479     MOV.B   HDLH_CurSize(T),X       ;X = 0:CurSizeHILo 
480     SWPB    X                       ;X = CurSizeHIlo:0 
481     ADD     Y,X                     ;X = CurSizeHIlo:CurSizeLOhi
482     MOV.B   HDLH_CurSize+1(T),Y     ;Y:X = CurSize / 256
483 ; ----------------------------------;
484 ; 2.2 Compute Clusters Count        ;
485 ; ----------------------------------;
486     MOV.B &SecPerClus,T             ;3 T = DIVISOR = SecPerClus = 0:SPClo
487 DIVSECPERSPC                        ;
488     MOV #0,W                        ;1 W = 0:REMlo = 0
489     MOV #8,S                        ;1 S = CNT
490 DIVSECPERSPC1                       ;
491     RRA Y                           ;1 0>0:SEC_HI>C
492     RRC X                           ;1 C>SEC_LO>C
493     RRC.B W                         ;1 C>REMlo>C
494     SUB #1,S                        ;1 CNT-1
495     RRA T                           ;1 0>SPChi:SPClo>C
496     JNC DIVSECPERSPC1               ;2 7~ loopback if carry clear
497 DIVSECPERSPC2                       ;
498     RRA W                           ;1 0>0:REMlo>C
499     SUB #1,S                        ;1 CNT-1
500     JGE DIVSECPERSPC2               ;2 4~ loopback     Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
501 ; ----------------------------------;
502     MOV &CurrentHDL,T               ;3  reload Handle ptr  
503 ; ----------------------------------;
504 ; 2.3- Compute last Cluster         ; X = Clusters numberLO, Y = Clusters numberHI 
505 ; ----------------------------------;
506     ADD  HDLL_FirstClus(T),X        ;
507     ADDC HDLH_FirstClus(T),Y        ;
508     MOV X,HDLL_CurClust(T)          ;  update handle
509     MOV Y,HDLH_CurClust(T)          ;
510 ; ----------------------------------;
511 ; 2.4- Compute Sectors offset       ;
512 ; ----------------------------------;
513     MOV.B W,HDLB_ClustOfst(T)       ;3  update handle with W = REMlo = sectors offset in last cluster
514 ; ----------------------------------;
515 ; 3- load last sector in SD_BUF     ;
516 ; ----------------------------------;
517     MOV HDLL_CurSize(T),W           ; example : W = 1013
518     BIC #01FFh,HDLL_CurSize(T)      ; substract 13 from HDLL_CurSize, because loaded in buffer
519     AND #01FFh,W                    ; W = 13
520     MOV W,&BufferPtr                ; init Buffer Pointer with 13
521     CALL #LoadHDLcurrentSector      ;SWX
522     MOV @IP+,PC                     ; BufferPtr = first free byte offset
523 ; ----------------------------------;
524
525
526 ; ======================================================================
527 ; DEL" primitive as part of OpenPathName
528 ; All "DEL"eted clusters are freed
529 ; If next DIRentry in same sector is free, DIRentry is freed, else hidden.
530 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
531 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
532 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
533 ; output: nothing (no message if open error)
534 ; ======================================================================
535
536
537 OPEN_QDEL                           ;
538 ;    CMP     #4,W                    ;   open_type = DEL"
539 ;    JNZ     OPEN_8W                 ;
540 ; ----------------------------------;
541 OPEN_DEL                            ;
542 ; ----------------------------------;
543 ; 1- open file                      ; done
544 ; ----------------------------------;
545     CMP     #0,S                    ; open file happy end ?
546     JNE     DEL_END                ; no: don't send message
547 ; ----------------------------------;
548 ; 2- Delete DIR entry               ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
549 ; ----------------------------------;
550 SelectFreeEntry                     ; nothing to do: S = 0 ready for free entry!
551 ; ----------------------------------;
552     CMP     #BytsPerSec-32,Y        ; Entry >= last entry in DIRsector ?
553     JC      SelectHideEntry         ; yes:  next DIR entry is out of sector
554     CMP.B   #0,SD_BUF+32(Y)         ; no:   next DIR entry in DIRsector is free?
555     JZ      WriteDelEntry           ;       yes
556 ; ----------------------------------;
557 SelectHideEntry                     ;       no
558 ; ----------------------------------;
559     MOV.B   #0E5h,S                 ;
560 ; ----------------------------------;
561 WriteDelEntry
562 ; ----------------------------------;
563     MOV.B   S,SD_BUF(Y)             ; 
564     CALL    #WriteSector            ;SWX  write SectorHL=DIRsector
565 ; ----------------------------------;
566 ; 3- free all file clusters         ; Cluster = FirstCluster
567 ; ----------------------------------;
568 ComputeClusterSectWofstY            ;     
569     CALL    #ClusterToFAT1sectWofstY;WXY    W = FATsector, Y=FAToffset
570     MOV     W,&CurFATsector         ; update CurrentFATsector
571 ; ----------------------------------;
572 LoadFAT1sector
573 ; ----------------------------------;
574     MOV     W,T                     ; T = W = current FATsector memory
575     ADD     &OrgFAT1,W              ;
576     MOV     #0,X                    ;
577     CALL    #ReadSectorWX           ;SWX (< 65536)
578 ; ----------------------------------;
579 GetAndFreeClusterLo                 ;
580 ; ----------------------------------;
581     MOV     SD_BUF(Y),W             ; get [clusterLO]
582     MOV     #0,SD_BUF(Y)            ; free CLusterLO
583 ClusterTestSelect                   ;
584     CMP     #1,&FATtype             ; FAT16 ?
585     JZ      ClusterLoTest           ; yes
586 GetAndFreeClusterHi                 ;
587     MOV     SD_BUF+2(Y),X           ; get [clusterHI]
588     MOV     #0,SD_BUF+2(Y)          ; free CLusterHI
589 ClusterHiTest
590     AND     #00FFFh,X               ; select 12 bits significant
591     CMP     #00FFFh,X               ; [ClusterHI] was = 0FFFh?
592     JNE     SearchNextCluster2free  ; no
593 ClusterLoTest                  
594     CMP     #-1,W                   ; [ClusterLO] was = FFFFh?
595     JZ      EndOfFileClusters       ; yes 
596 ; ----------------------------------;
597 SearchNextCluster2free
598 ; ----------------------------------;
599     MOV     W,&ClusterL             ;
600     MOV     X,&ClusterH             ;
601     CALL    #ClusterToFAT1sectWofstY;WXY
602     CMP     W,T                     ; new FATsector = current FATsector memory ?
603     JZ      GetAndFreeClusterLo     ; yes loop back
604     PUSH    W                       ; no: save new FATsector...
605     MOV     T,W                     ; ...before update current FATsector
606     CALL    #UpdateFATsSectorW      ;SWX
607     MOV     @RSP+,W                 ; restore new current FATsector
608     JMP     LoadFAT1sector          ; loop back with Y = FAToffset
609 ; ----------------------------------;
610 EndOfFileClusters                   ;
611 ; ----------------------------------;
612     MOV     T,W                     ; T = W = current FATsector
613     CALL    #UpdateFATsSectorW      ;SWX
614 ; ----------------------------------;
615 ; 3- Close Handle                   ;
616 ; ----------------------------------;
617     CALL    #CloseHandleT           ;
618 ; ----------------------------------;
619 DEL_END                             ;
620     MOV @IP+,PC                     ;4
621 ; ----------------------------------;
622
623
624
625     .IFNDEF TERMINAL_I2C ; if UART_TERMINAL
626
627 ; first TERATERM sends the command TERM2SD" file.ext" to FastForth which returns XOFF at the end of the line.
628 ; then when XON is sent below, TERATERM sends "file.ext" up to XOFF sent by TERM2SD" (slices of 512 bytes),
629 ; then TERATERM sends char EOT that closes the file on SD_CARD.
630
631     FORTHWORD "TERM2SD\34"
632     mDOCOL
633     .word   DELDQ                   ;                   DEL file if already exist
634     .word   lit,2                   ; -- open_type
635     .word   HERE,COUNT              ; -- open_type addr cnt
636     .word   PARENOPEN               ;                   reopen same filepath but as write
637     .word   $+2                     ;
638     MOV     @RSP+,IP                ;
639 ; ----------------------------------;
640 T2S_GetSliceLoop                    ;   tranfert by slices of 512 bytes terminal input to file on SD_CARD via SD_BUF 
641 ; ----------------------------------;
642     MOV     #0,W                    ;1  reset W = BufferPtr
643     CALL    #RXON                   ;   use no registers
644 ; ----------------------------------;
645 T2S_FillBufferLoop                  ;
646 ; ----------------------------------;
647     BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
648     JZ      T2S_FillBufferLoop      ;2
649     MOV.B   &TERM_RXBUF,X           ;3
650     MOV.B   X,&TERM_TXBUF
651     CMP.B   #4,X                    ;1 EOT sent by TERATERM ?
652     JZ      T2S_End_Of_File                 ;2 yes
653     MOV.B   X,SD_BUF(W)             ;3
654     ADD     #1,W                    ;1
655     CMP     #BytsPerSec-1,W         ;2
656     JNC     T2S_FillBufferLoop      ;2 W < BytsPerSec-1    21 cycles char loop
657     JZ      T2S_XOFF                ;2 W = BytsPerSec-1    send XOFF after RX 511th char
658 ; ----------------------------------;
659 T2S_WriteFile                       ;2 W = BytsPerSec
660 ; ----------------------------------;
661     CALL    #Write_File             ;TSWXY write all the buffer
662     JMP     T2S_GetSliceLoop        ;2 
663 ; ----------------------------------;
664 T2S_XOFF                            ;  27 cycles between XON and XOFF
665 ; ----------------------------------;
666     CALL    #RXOFF                  ;4  use no registers
667     JMP     T2S_FillBufferLoop      ;2  loop back once to get last char
668 ; ----------------------------------;
669 T2S_End_Of_File                     ;
670 ; ----------------------------------;
671     CALL    #RXOFF                  ;4  use no registers
672     MOV     W,&BufferPtr            ;3
673     CALL    #CloseHandleT           ;4
674     MOV @IP+,PC                     ;4
675 ; ----------------------------------;
676
677     .ELSE ; if I2C_TERMINAL
678
679     FORTHWORD "TERM2SD\34"
680     CALL    #WAITCHAREND            ; wait I2C_Master (re)START RX
681     BIC     #WAKE_UP,&TERM_IFG      ; clear UCSTTIFG before next test
682     mDOCOL
683     .word   DELDQ                   ;                   DEL file if already exist
684     .word   lit,2                   ; -- open_type
685     .word   HERE,COUNT              ; -- open_type addr cnt
686     .word   PARENOPEN               ;                   reopen same filepath but as write
687     .word   $+2                     ;
688 ; ----------------------------------;
689     CALL    #RXON                   ;
690     BIC     #WAKE_UP,&TERM_IFG      ; clear UCSTTIFG before next test
691 ; ----------------------------------;
692 T2S_ClearBuffer
693 ; ----------------------------------;
694     MOV     #0,W                    ;1  reset W = BufferPtr
695 ; ----------------------------------;
696 T2S_FillBufferLoop                  ;   move by slices of 512 bytes from TERMINAL input to file on SD_CARD via SD_BUF 
697 ; ----------------------------------;
698     BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
699     JZ      T2S_FillBufferLoop      ;2 no
700     MOV.B   &TERM_RXBUF,X           ;3
701     CMP.B   #4,X                    ;1 EOT sent by TERATERM ?
702     JZ      T2S_End_Of_File         ;2 yes
703     MOV.B   X,SD_BUF(W)             ;3
704     ADD     #1,W                    ;1
705     CMP.B   #0Ah,X                  ;2 Char LF ?
706     JNZ     T2S_Q_BufferFull        ;2 no
707 ; ----------------------------------;
708 T2S_GetNewLine                      ; after LF sent, I2C_Master automaticaly (re)STARTs in RX mode
709 ; ----------------------------------;
710     CALL    #WAITCHAREND            ; wait I2C_Master (re)START RX
711     BIC     #WAKE_UP,&TERM_IFG      ; clear UCSTTIFG before next test
712     ASMtoFORTH
713     .word   LIT,0Ah,EMIT            ; use Y reg
714     .word   $+2                     ;
715     CALL    #RXON                   ; tells I2C_Master to(re)START in TX mode and waits I2C_Master TX (re)STARTed,  use Y register
716     BIC     #WAKE_UP,&TERM_IFG      ; clear UCSTTIFG before next test
717 ; ----------------------------------;
718 T2S_Q_BufferFull                    ;
719 ; ----------------------------------;
720     CMP     #BytsPerSec,W           ;2 buffer full ?
721     JNC     T2S_FillBufferLoop      ;2 no    21 cycles char loop
722 ; ----------------------------------;
723 T2S_WriteFile                       ;2 yes
724 ; ----------------------------------;
725     CALL    #Write_File             ;4 TSWXY write all the buffer
726     JMP     T2S_ClearBuffer         ;2 
727 ; ----------------------------------;
728 T2S_End_Of_File                     ;
729 ; ----------------------------------;
730     MOV     @RSP+,IP                ; before CloseHandleT
731     MOV     W,&BufferPtr            ;3
732     CALL    #CloseHandleT           ;4
733 T2S_End_Of_EOT_Line                 ;
734     BIT     #RX_TERM,&TERM_IFG      ;3 new char in TERMRXBUF ?
735     JZ      T2S_End_Of_EOT_Line     ;2 no
736     MOV.B   &TERM_RXBUF,X           ;3 
737     CMP.B   #0Ah,X                  ;2 Char LF ?
738     JNZ     T2S_End_Of_EOT_Line     ;    
739     CALL    #WAITCHAREND            ; wait I2C_Master (re)START RX
740     BIC     #WAKE_UP,&TERM_IFG      ; clear UCSTTIFG before next test...
741     MOV     @IP+,PC                 ; ... i.e. ready for return to SLEEP via RXON.
742 ; ----------------------------------;
743
744     .ENDIF