1 ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FR5xxxSD_RW.asm
4 ; and only for FR5xxx and FR6xxx with RTC_B or RTC_C hardware if you want write file with date and time.
6 ; Tested with MSP-EXP430FR5969 launchpad
7 ; Copyright (C) <2015> <J.M. THOORENS>
9 ; This program is free software: you can redistribute it and/or modify
10 ; it under the terms of the GNU General Public License as published by
11 ; the Free Software Foundation, either version 3 of the License, or
12 ; (at your option) any later version.
14 ; This program is distributed in the hope that it will be useful,
15 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ; GNU General Public License for more details.
19 ; You should have received a copy of the GNU General Public License
20 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
24 ; ======================================================================
25 ; READ" primitive as part of OpenPathName
26 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
27 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
28 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
29 ; output: nothing else abort on error
30 ; ======================================================================
32 ; ----------------------------------;
34 CMP #1,W ; open_type = READ" ?
35 JNZ OPEN_QWRITE ; no : goto next step
36 ; ----------------------------------;
38 ; ----------------------------------;
39 CMP #0,S ; open file happy end ?
42 ; ----------------------------------;
45 ; sequentially read a file opened by READ".
46 ; sectors are loaded in SD_BUF and BufferLen leave the count of loaded bytes.
47 ; when the last sector of file is loaded in buffer, the handle is automatically closed and flag is true (<>0).
49 ; ----------------------------------;
50 FORTHWORD "READ" ; -- fl closed flag
51 ; ----------------------------------;
58 SUB &CurrentHdl,TOS ; -- fl if fl <>0 (if Z=0) handle is closed
60 ; ----------------------------------;
63 ;-----------------------------------------------------------------------
64 ; WRITE" (CREATE part) subroutines
65 ;-----------------------------------------------------------------------
67 ; parse all FAT sectors until free cluster is found
68 ; this NewCluster is marked as the end's one (-1)
71 ; input : CurFATsector
73 ; output: W = new FATsector, SD_BUF = [new FATsector], NewCluster
74 ; SectorL is unchanged, FATS are not updated.
75 ; S = 2 --> Disk FULL error
76 ; ----------------------------------;
77 SearchNewCluster ; <== CREATE file, WRITE_File
78 ; ----------------------------------;
79 MOV #2,S ; preset disk full return error
80 PUSH &CurFATsector ; last known free cluster sector
82 ADD Y,Y ; Y = bytes size of Cluster number (2 or 4)
83 ; ----------------------------------;
84 LoadFATsectorInBUF ; <== IncrementFATsector
85 ; ----------------------------------;
86 MOV @RSP,W ; W = FATsector
88 JZ OPW_Error ; FATsector = FATSize ===> abort disk full
89 CALL #ReadFAT1SectorW ;SWX
90 MOV #0,X ; init FAToffset
91 ; ----------------------------------;
92 SearchFreeClustInBUF ; <== SearchNextCluster
93 ; ----------------------------------;
94 CMP #2,Y ; FAT16 Cluster size ?
95 JZ ClusterLowWordTest ; yes
97 CMP #0,SD_BUF+2(X) ; cluster address hi word = 0 ?
98 JNZ SearchNextNewCluster ;
100 CMP #0,SD_BUF(X) ; Cluster address lo word = 0 ?
101 JZ GNC_FreeClusterFound ;
102 SearchNextNewCluster ;
103 ADD Y,X ; increment SD_BUF offset by size of Cluster address
105 JNE SearchFreeClustInBUF ; loopback while X < BytsPerSec
107 ADD #1,0(RSP) ; increment FATsector
108 JMP LoadFATsectorInBUF ; loopback
109 ; ----------------------------------;
110 GNC_FreeClusterFound ; Y = cluster number low word in SD_BUF = FATsector
111 ; ----------------------------------;
112 MOV #0,S ; clear error
113 MOV.B @RSP,W ; W = 0:FATsectorLo
114 MOV #-1,SD_BUF(X) ; mark NewCluster low word as end cluster (0xFFFF) in SD_BUF
115 CMP #2,Y ; Y = FAT16 size of Cluster number ?
116 JZ FAT16EntryToClusterNum ; yes
117 MOV #0FFFh,SD_BUF+2(X) ; no: mark NewCluster high word as end cluster (0x0FFF) in SD_BUF
118 ; ----------------------------------;
119 FAT32EntryToClusterNum ; convert FAT32 cluster address to cluster number
120 ; ----------------------------------;
121 RRA X ; X = FATOffset>>1, FAToffset is byte size
122 SWPB W ; W = FATsectorLo:0
123 ADD W,X ; X = FATsectorLo:FATOffset>>1
124 MOV.B 1(RSP),W ; W = FATsectorHi
125 RRA W ; W = FATsectorHi>>1
126 RRC X ; X = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
127 MOV W,&NewClusterH ; NewClusterH = FATsectorHi>>1
128 MOV X,&NewClusterL ; NewClusterL = FATsectorLo>>1:FAToffset>>2
129 JMP SearchNewClusterEnd ; max cluster = 7FFFFF ==> 1FFFFFFF sectors ==> 256 GB
130 ; ----------------------------------;
131 FAT16EntryToClusterNum ; convert FAT16 address of Cluster in cluster number
132 ; ----------------------------------;
133 RRA X ; X = Offset>>1, offset is word < 256
134 MOV.B X,&NewClusterL ; X = NewCluster numberLO (byte)
135 MOV.B W,&NewClusterL+1 ; W = NewCluster numberHI (byte)
136 MOV #0,&NewClusterH ;
137 ; ----------------------------------;
138 SearchNewClusterEnd ;
139 ; ----------------------------------;
140 MOV @RSP+,W ; W = FATsector
141 MOV W,&CurFATsector ; refresh CurrentFATsector
143 ; ----------------------------------;
146 ; update FATs with SD_BUF content.
147 ; input : FATsector, FAToffset, SD_BUF = [FATsector]
148 ; use : SWX registers
149 ; ----------------------------------; else update FATsector of the old cluster
151 ; ----------------------------------;
153 ADD &OrgFAT1,W ; update FAT#1
154 CALL #WriteSectorW ; SWX
156 ADD &OrgFAT2,W ; update FAT#2
157 MOV #WriteSectorW,PC ; then ret
158 ; ----------------------------------;
162 ; FAT16/32 format for date and time in a DIR entry
163 ; create time : offset 0Dh = 0 to 200 centiseconds, not used.
164 ; offset 0Eh = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
165 ; access time : offset 14h = always 0, not used as date
166 ; modified time : ofsset 16h = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
167 ; dates : offset 10, 12, 18 = 0byyyyyyymmmmddddd, with : y=year-1980, m=month, d=day
169 ; ----------------------------------; input:
170 GetYMDHMSforDIR ;X=date, W=TIME
171 ; ----------------------------------;
173 .IFNDEF RTC ; RTC_B or RTC_C select
174 ; ----------------------------------;
175 BIT.B #RTCHOLD,&RTCCTL1 ; rtc is running ?
178 BIT.B #RTCRDY,&RTCCTL1 ; rtc values are valid ?
180 MOV.B &RTCSEC,W ; yes
181 RRA.B W ; 2 seconds accuracy time
183 MOV.B #32,&MPY ; common MPY for minutes and months
188 MOV.B &RTCHOUR,&MPY ;
202 ; ----------------------------------;
205 ; when create filename, forbidden chars are skipped
206 ForbiddenChars ; 15 forbidden chars table + dot char
207 .byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
209 ; ----------------------------------;
211 ; ----------------------------------;
213 JL FillDIRentryName ; X < 4 : no need spaces to complete name entry
215 CALL #OPWC_CompleteWithSpaces; complete name entry
217 ; ----------------------------------;
219 ; ----------------------------------;
220 FillDIRentryName ;SWXY use
221 ; ----------------------------------;
222 MOV.B @T+,W ; W = char of pathname
223 MOV.B W,SD_BUF(Y) ; to DIRentry
224 ; CMP #0,W ; end of stringZ ?
225 ; JZ OPWC_CompleteWithSpaces ;
226 CMP T,&EndOfPath ; EOS < PTR ?
227 JLO OPWC_CompleteWithSpaces ; yes
228 ; ----------------------------------;
230 ; ----------------------------------;
232 MOV #15,IP ;2 forbidden chars count
233 MOV #ForbiddenChars,S ;2 here, S is free
236 JZ FillDIRentryName ;2 skip forbidden char
238 JNZ ForbiddenCharLoop ;2
240 ; ----------------------------------;
241 CMP.B @S,W ;1 46 (0x2E)
242 JZ OPWC_SkipDot ;2 skip '.'
243 ; ----------------------------------;
245 JL FillDIRentryName ; skip char =< SPACE char
246 ADD #1,Y ; increment DIRentry ptr
247 SUB #1,X ; decrement count of chars entry
248 JNZ FillDIRentryName ;
249 ; ----------------------------------;
250 OPWC_CompleteWithSpaces ; 0 to n spaces !
251 ; ----------------------------------;
254 ; ----------------------------------;
255 OPWC_CompleteWithSpaceloop ;
256 ; ----------------------------------;
257 MOV.B #' ',SD_BUF(Y) ; remplace dot by char space
258 ADD #1,Y ; increment DIRentry ptr in buffer
259 SUB #1,X ; dec countdown of chars space
260 JNZ OPWC_CompleteWithSpaceloop ;
263 ; ----------------------------------;
268 ; ======================================================================
269 ; WRITE" primitive as part of OpenPathName
270 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
271 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
272 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
273 ; output: nothing else abort on error
274 ; error 1 : PathNameNotFound
275 ; error 2 : NoSuchFile
276 ; error 4 : DirectoryFull
277 ; error 8 : AlreadyOpen
278 ; error 16 : NomoreHandle
279 ; ======================================================================
281 ; ----------------------------------;
283 CMP #2,W ; open_type = WRITE" ?
284 JNZ OPEN_QDEL ; no : goto next step
285 ; ----------------------------------;
286 ; 1 try to open ; done
287 ; ----------------------------------;
288 ; 2 select error "no such file" ;
289 ; ----------------------------------;
290 CMP #2,S ; "no such file" error ?
291 JZ OPEN_WRITE_CREATE ; yes
292 CMP #0,S ; no open file error ?
293 JZ OPEN_WRITE_APPEND ; yes
294 ; ----------------------------------;
296 ; ----------------------------------;
297 OPWC_InvalidPathname ; S = 1
298 OPWC_DiskFull ; S = 2
299 OPWC_DirectoryFull ; S = 4
300 OPWC_AlreadyOpen ; S = 8
301 OPWC_NomoreHandle ; S = 16
302 ; ----------------------------------;
303 OPW_Error ; set ECHO, type Pathname, type #error, type "< WriteError"; no return
306 .byte 12,"< WriteError",0 ;
307 .word BRAN,SD_ERROR ;
308 ; ----------------------------------;
311 ; ======================================================================
312 ; WRITE" (CREATE part) primitive as part of OpenPathName
313 ; input from open: S = NoSuchFile, W = open_type, SectorHL = DIRsectorHL,
314 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
315 ; output: nothing else abort on error:
316 ; error 1 : InvalidPathname
318 ; error 4 : DirectoryFull
319 ; error 8 : AlreadyOpen
320 ; error 16 : NomoreHandle
321 ; ======================================================================
323 ; ----------------------------------;
325 ; ----------------------------------;
326 ; 3 get free cluster ;
327 ; ----------------------------------; input: FATsector
328 CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer,NewCluster
329 MOV &NewClusterL,&ClusterL ;
330 MOV &NewClusterH,&ClusterH ;
331 CALL #UpdateFATsSectorW ;SWX update FATs with buffer
332 ; ----------------------------------;
333 CALL #ReadSector ; reload DIRsector
334 MOV &EntryOfst,Y ; reload entry offset (first free entry in DIR)
335 ; ----------------------------------;
336 ; 4 init DIRentryAttributes ;
337 ; ----------------------------------;
338 OPWC_SetEntryAttribute ; (cluster=DIRcluster!)
339 MOV.B #20h,SD_BUF+11(Y) ; file attribute = file
340 CALL #GetYMDHMSforDIR ;WX X=DATE, W=TIME
341 MOV #0,SD_BUF+12(Y) ; nt reserved = 0 and centiseconds are 0
342 MOV W,SD_BUF+14(Y) ; time of creation
343 MOV X,SD_BUF+16(Y) ; date of creation 20/08/2001
344 MOV X,SD_BUF+18(Y) ; date of access 20/08/2001
345 MOV &ClusterH,SD_BUF+20(Y) ; as first Cluster Hi
346 MOV &ClusterL,SD_BUF+26(Y) ; as first cluster LO
347 MOV #0,SD_BUF+28(Y) ; file lenghtLO = 0
348 MOV #0,SD_BUF+30(Y) ; file lenghtHI = 0
349 ; ----------------------------------;
350 ; 5 create DIRentryName ;
351 ; ----------------------------------;
352 MOV #1,S ; preset pathname error
353 MOV &Pathname,T ; here, pathname is "xxxxxxxx.yyy" format
354 ; CMP.B #0,0(T) ; forbidden null string
356 JZ OPWC_InvalidPathname ; write error 1
357 CMP.B #'.',0(T) ; forbidden "." in first
358 JZ OPWC_InvalidPathname ; write error 1
359 MOV #11,X ; X=countdown of chars entry
360 CALL #FillDIRentryName ;STWXY
361 ; ----------------------------------;
363 ; ----------------------------------;
364 CALL #WriteSector ;SWX update DIRsector
365 ; ----------------------------------;
366 ; 7 Get free handle ;
367 ; ----------------------------------;
369 CALL #GetFreeHandle ; output : S = handle error, CurCluster and CurSector are set
370 ; ----------------------------------;
371 CMP #0,S ; no error ?
372 JNZ OPWC_NomoreHandle ; ==> abort with error 16
374 ; ----------------------------------;
376 ;-----------------------------------------------------------------------
378 ;-----------------------------------------------------------------------
380 ; SectorL is unchanged
381 ; ----------------------------------;
382 OPWW_UpdateDirectory ; <== CloseHandleT
383 ; ----------------------------------; Input : current Handle
384 MOV HDLL_DIRsect(T),W ;
385 MOV HDLH_DIRsect(T),X ;
386 CALL #readSectorWX ;SWX buffer = DIRsector
387 CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
388 MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
389 MOV X,SD_BUF+18(Y) ; access date
390 MOV W,SD_BUF+22(Y) ; modified time
391 MOV X,SD_BUF+24(Y) ; modified date
392 OPWW_UpdateEntryFileSize ;
393 MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
394 MOV HDLH_CurSize(T),SD_BUF+30(Y);
395 MOV HDLL_DIRsect(T),W ;
396 MOV HDLH_DIRsect(T),X ;
397 MOV #WriteSectorWX,PC ;SWX then RET
398 ; ----------------------------------;
400 ; this subroutine is called by Write_File (bufferPtr=512) and CloseHandleT (0 =< BufferPtr =< 512)
401 ; ==================================;
402 WriteBuffer ;SWXY input: T = CurrentHDL
403 ; ==================================;
404 ADD &BufferPtr,HDLL_CurSize(T) ; update handle CurrentSizeL
405 ADDC #0,HDLH_CurSize(T) ;
406 ; ==================================;
408 ; ==================================;
410 MOV &SectorH,X ; High
411 MOV #WriteSectorWX,PC ; ...then RET
412 ; ----------------------------------;
416 ; write sequentially the buffer in the post incremented SectorHL.
417 ; The first time, SectorHL is initialized by WRITE".
418 ; All used registers must be initialized.
419 ; ==================================;
420 Write_File ; <== WRITE, SD_EMIT, TERM2SD"
421 ; ==================================;
422 MOV #BytsPerSec,&BufferPtr ; write always all the buffer
424 CALL #WriteBuffer ; write SD_BUF and update Handle informations only for DIRentry update
425 MOV #0,&BufferPtr ; reset buffer pointer
426 ; ----------------------------------;
427 PostIncrementSector ;
428 ; ----------------------------------;
429 ADD.B #1,HDLB_ClustOfst(T) ; increment current Cluster offset
430 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
431 JNZ Write_File_End ; no,
432 ; ----------------------------------;
433 GetNewCluster ; input : T=CurrentHdl
434 ; ----------------------------------;
435 MOV.B #0,HDLB_ClustOfst(T) ; reset handle ClusterOffset
436 CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
437 PUSH Y ; push current FAToffset
438 PUSH W ; push current FATsector
439 CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer, NewCluster
440 CMP @RSP,W ; current and new clusters are in same FATsector?
441 JZ LinkClusters ; yes
442 UpdateNewClusterFATs ;
443 CALL #UpdateFATsSectorW ;SWX no: UpdateFATsSectorW with buffer of new FATsector
444 MOV @RSP,W ; W = current FATsector
445 CALL #ReadFAT1SectorW ;SWX reload current FATsector in buffer to link clusters
447 MOV @RSP+,W ; W = current FATsector
448 MOV @RSP+,Y ; pop current FAToffset
449 MOV &NewClusterL,SD_BUF(Y) ; store new cluster to current cluster address in current FATsector buffer
450 CMP #1,&FATtype ; FAT16?
451 JZ UpdatePreviousClusterFATs ; yes
452 MOV &NewClusterH,SD_BUF+2(Y);
453 UpdatePreviousClusterFATs ;
454 CALL #UpdateFATsSectorW ;SWX update FATS with current FATsector buffer
455 UpdateHandleCurCluster ;
456 MOV &NewClusterL,HDLL_CurClust(T) ; update handle with new cluster
457 MOV &NewClusterH,HDLH_CurClust(T) ;
458 ; CALL #ComputeHDLcurrentSector ; set Cluster first Sector as next Sector to be written
459 ; MOV #OPWW_UpdateDirectory,PC ; update DIRentry to avoid cluster lost, then RET
461 MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
462 ; ----------------------------------;
465 ; sequentially write the entire SD_BUF in a file opened by WRITE"
466 ; ----------------------------------;
468 ; ----------------------------------;
471 ; ----------------------------------;
473 ;Z SD_EMIT c -- output char c to a SD_CARD file opened as write
474 ; ----------------------------------;
475 FORTHWORD "SD_EMIT" ;
476 ; ----------------------------------;
478 CMP #BytsPerSec,&BufferPtr ; 4 file buffer is full ?
480 CALL #Write_File ; BufferPtr = 0
483 MOV.B TOS,SD_BUF(Y) ; 3
484 ADD #1,&BufferPtr ; 4
487 ; ----------------------------------; 22~ for SD_EMIT, 22~ for EMIT
492 ; ======================================================================
493 ; WRITE" (APPEND part) primitive as part of OpenPathName
494 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
495 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
496 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
497 ; output: nothing else abort on error
499 ; ======================================================================
501 ; ----------------------------------;
503 ; ----------------------------------;
504 ; 1- open file ; done
505 ; ----------------------------------;
506 ; 2- compute missing Handle infos ;
507 ; ----------------------------------;
508 ; 2.1- Compute Sectors count ; Sectors = HDLL_CurSize/512
509 ; ----------------------------------;
510 MOV.B HDLL_CurSize+1(T),Y ;Y = 0:CurSizeLOHi
511 MOV.B HDLH_CurSize(T),X ;X = 0:CurSizeHILo
512 SWPB X ;X = CurSizeHIlo:0
513 ADD Y,X ;X = CurSizeHIlo:CurSizeLOhi
514 MOV.B HDLH_CurSize+1(T),Y ;Y:X = CurSize / 256
515 ; ----------------------------------;
516 ; 2.2 Compute Clusters Count ;
517 ; ----------------------------------;
518 MOV.B &SecPerClus,T ;3 T = DIVISOR = SecPerClus = 0:SPClo
520 MOV #0,W ;1 W = 0:REMlo = 0
523 RRA Y ;1 0>0:SEC_HI>C
527 RRA T ;1 0>SPChi:SPClo>C
528 JNC DIVSECPERSPC1 ;2 7~ loopback if carry clear
532 JGE DIVSECPERSPC2 ;2 4~ loopback Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
533 ; ----------------------------------;
534 MOV &CurrentHDL,T ;3 reload Handle ptr
535 ; ----------------------------------;
536 ; 2.3- Compute last Cluster ; X = Clusters numberLO, Y = Clusters numberHI
537 ; ----------------------------------;
538 ADD HDLL_FirstClus(T),X ;
539 ADDC HDLH_FirstClus(T),Y ;
540 MOV X,HDLL_CurClust(T) ; update handle
541 MOV Y,HDLH_CurClust(T) ;
542 ; ----------------------------------;
543 ; 2.4- Compute Sectors offset ;
544 ; ----------------------------------;
545 MOV.B W,HDLB_ClustOfst(T) ;3 update handle with W = REMlo = sectors offset in last cluster
546 ; ----------------------------------;
547 ; 3- load last sector in SD_BUF ;
548 ; ----------------------------------;
549 MOV HDLL_CurSize(T),W ; example : W = 1013
550 BIC #01FFh,HDLL_CurSize(T) ; substract 13 from HDLL_CurSize, because loaded in buffer
551 AND #01FFh,W ; W = 13
552 MOV W,&BufferPtr ; init Buffer Pointer with 13
553 CALL #LoadHDLcurrentSector ;SWX
554 mNEXT ; BufferPtr = first free byte offset
555 ; ----------------------------------;
558 ; ======================================================================
559 ; DEL" primitive as part of OpenPathName
560 ; All "DEL"eted clusters are freed
561 ; If next DIRentry in same sector is free, DIRentry is freed, else hidden.
562 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
563 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
564 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
565 ; output: nothing (no message if open error)
566 ; ======================================================================
570 ; CMP #4,W ; open_type = DEL"
572 ; ----------------------------------;
574 ; ----------------------------------;
575 ; 1- open file ; done
576 ; ----------------------------------;
577 CMP #0,S ; open file happy end ?
578 JNE DEL_END ; no: don't send message
579 ; ----------------------------------;
580 ; 2- Delete DIR entry ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
581 ; ----------------------------------;
582 SelectFreeEntry ; nothing to do: S = 0 ready for free entry!
583 ; ----------------------------------;
584 CMP #BytsPerSec-32,Y ; Entry >= last entry in DIRsector ?
585 JHS SelectHideEntry ; yes: next DIR entry is out of sector
586 CMP.B #0,SD_BUF+32(Y) ; no: next DIR entry in DIRsector is free?
587 JZ WriteDelEntry ; yes
588 ; ----------------------------------;
590 ; ----------------------------------;
592 ; ----------------------------------;
594 ; ----------------------------------;
596 CALL #WriteSector ;SWX write SectorHL=DIRsector
597 ; ----------------------------------;
598 ; 3- free all file clusters ; Cluster = FirstCluster
599 ; ----------------------------------;
600 ComputeClusterSectWofstY ;
601 CALL #ClusterToFAT1sectWofstY;WXY W = FATsector, Y=FAToffset
602 MOV W,&CurFATsector ; update CurrentFATsector
603 ; ----------------------------------;
605 ; ----------------------------------;
606 MOV W,T ; T = W = current FATsector memory
607 CALL #ReadFAT1SectorW ;SWX
608 ; ----------------------------------;
609 GetAndFreeClusterLo ;
610 ; ----------------------------------;
611 MOV SD_BUF(Y),W ; get [clusterLO]
612 MOV #0,SD_BUF(Y) ; free CLusterLO
614 CMP #1,&FATtype ; FAT16 ?
615 JZ ClusterLoTest ; yes
616 GetAndFreeClusterHi ;
617 MOV SD_BUF+2(Y),X ; get [clusterHI]
618 MOV #0,SD_BUF+2(Y) ; free CLusterHI
620 AND #00FFFh,X ; select 12 bits significant
621 CMP #00FFFh,X ; [ClusterHI] was = 0FFFh?
622 JNE SearchNextCluster2free ; no
624 CMP #-1,W ; [ClusterLO] was = FFFFh?
625 JZ EndOfFileClusters ; yes
626 ; ----------------------------------;
627 SearchNextCluster2free
628 ; ----------------------------------;
631 CALL #ClusterToFAT1sectWofstY;WXY
632 CMP W,T ; new FATsector = current FATsector memory ?
633 JZ GetAndFreeClusterLo ; yes loop back
634 PUSH W ; no: save new FATsector...
635 MOV T,W ; ...before update current FATsector
636 CALL #UpdateFATsSectorW ;SWX
637 MOV @RSP+,W ; restore new current FATsector
638 JMP LoadFAT1sector ; loop back with Y = FAToffset
639 ; ----------------------------------;
641 ; ----------------------------------;
642 MOV T,W ; T = W = current FATsector
643 CALL #UpdateFATsSectorW ;SWX
644 ; ----------------------------------;
646 ; ----------------------------------;
648 ; ----------------------------------;
651 ; ----------------------------------;
655 ; first TERATERM sends the command TERM2SD" file.ext" to FastForth which returns XOFF at the end of the line.
656 ; then when XON is sent below, TERATERM sends "file.ext" up to XOFF sent by TERM2SD" (slices of 512 bytes),
657 ; then TERATERM sends char ETX that closes the file on SD_CARD.
660 FORTHWORD "TERM2SD\34"
662 .word DELDQ ; DEL file if already exist
663 .word lit,2 ; -- open_type
664 .word HERE,COUNT ; -- open_type addr cnt
665 .word PARENOPEN ; reopen same filepath but as write
668 BIC #UCRXIFG,&TERM_IFG ; clean up UCRX buffer
669 ; ----------------------------------;
670 T2S_GetSliceLoop ; tranfert by slices of 512 bytes terminal input to file on SD_CARD via SD_BUF
671 ; ----------------------------------;
672 MOV #0,Y ;1 reset Y = BufferPtr
673 CALL #RXON ; use no registers
674 ; ----------------------------------;
676 ; ----------------------------------;
677 BIT #UCRXIFG,&TERM_IFG ;3 new char in TERMRXBUF ?
678 JZ T2S_FillBufferLoop ;2
679 MOV.B &TERM_RXBUF,X ;3
680 CMP.B #4,X ;1 EOT sent by TERATERM ?
684 CMP #BytsPerSec-1,Y ;2
685 JLO T2S_FillBufferLoop ;2 Y<511 21 cycles char loop
686 JZ T2S_XOFF ;2 Y=511 send XOFF after RX 511th char
687 ; ----------------------------------;
688 T2S_WriteFile ;2 Y>511
689 ; ----------------------------------;
690 CALL #Write_File ;TSWXY write all the buffer
691 JMP T2S_GetSliceLoop ;2
692 ; ----------------------------------;
693 T2S_XOFF ; 27 cycles between XON and XOFF
694 ; ----------------------------------;
695 CALL #RXOFF ;4 use no registers
696 JMP T2S_FillBufferLoop ;2 loop back to get 512th char
697 ; ----------------------------------;
699 ; ----------------------------------;
700 CALL #RXOFF ;4 use no registers
702 CALL #CloseHandleT ;4
705 ; ----------------------------------;