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 BUFFER 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 ?
51 ; ----------------------------------;
57 SUB &CurrentHdl,TOS ; -- fl if fl <>0 (if Z=0) handle is closed
59 ; ----------------------------------;
62 ;-----------------------------------------------------------------------
63 ; WRITE" (CREATE part) subroutines
64 ;-----------------------------------------------------------------------
66 ; parse all FAT sectors until free cluster is found
67 ; this NewCluster is marked as the end's one (-1)
70 ; input : CurFATsector
72 ; output: W = new FATsector, BUFFER = [new FATsector], NewCluster
73 ; SectorL is unchanged, FATS are not updated.
74 ; S = 2 --> Disk FULL error
75 ; ----------------------------------;
76 SearchNewCluster ; <== CREATE file, WRITE_File
77 ; ----------------------------------;
78 MOV #2,S ; preset disk full return error
79 PUSH &CurFATsector ; last known free cluster sector
81 ADD Y,Y ; Y = bytes size of Cluster number (2 or 4)
82 ; ----------------------------------;
83 LoadFATsectorInBUF ; <== IncrementFATsector
84 ; ----------------------------------;
85 MOV @RSP,W ; W = FATsector
87 JZ OPW_Error ; FATsector = FATSize ===> abort disk full
88 CALL #ReadFAT1SectorW ;SWX
89 MOV #0,X ; init FAToffset
90 ; ----------------------------------;
91 SearchFreeClustInBUF ; <== SearchNextCluster
92 ; ----------------------------------;
93 CMP #2,Y ; FAT16 Cluster size ?
94 JZ ClusterLowWordTest ; yes
96 CMP #0,BUFFER+2(X) ; cluster address hi word = 0 ?
97 JNZ SearchNextNewCluster ;
99 CMP #0,BUFFER(X) ; Cluster address lo word = 0 ?
100 JZ GNC_FreeClusterFound ;
101 SearchNextNewCluster ;
102 ADD Y,X ; increment BUFFER offset by size of Cluster address
104 JNE SearchFreeClustInBUF ; loopback while X < BytsPerSec
106 ADD #1,0(RSP) ; increment FATsector
107 JMP LoadFATsectorInBUF ; loopback
108 ; ----------------------------------;
109 GNC_FreeClusterFound ; Y = cluster number low word in BUFFER = FATsector
110 ; ----------------------------------;
111 MOV #0,S ; clear error
112 MOV.B @RSP,W ; W = 0:FATsectorLo
113 MOV #-1,BUFFER(X) ; mark NewCluster low word as end cluster (0xFFFF) in BUFFER
114 CMP #2,Y ; Y = FAT16 size of Cluster number ?
115 JZ FAT16EntryToClusterNum ; yes
116 MOV #0FFFh,BUFFER+2(X) ; no: mark NewCluster high word as end cluster (0x0FFF) in BUFFER
117 ; ----------------------------------;
118 FAT32EntryToClusterNum ; convert FAT32 cluster address to cluster number
119 ; ----------------------------------;
120 RRA X ; X = FATOffset>>1, FAToffset is byte size
121 SWPB W ; W = FATsectorLo:0
122 ADD W,X ; X = FATsectorLo:FATOffset>>1
123 MOV.B 1(RSP),W ; W = FATsectorHi
124 RRA W ; W = FATsectorHi>>1
125 RRC X ; X = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
126 MOV W,&NewClusterH ; NewClusterH = FATsectorHi>>1
127 MOV X,&NewClusterL ; NewClusterL = FATsectorLo>>1:FAToffset>>2
128 JMP SearchNewClusterEnd ; max cluster = 7FFFFF ==> 1FFFFFFF sectors ==> 256 GB
129 ; ----------------------------------;
130 FAT16EntryToClusterNum ; convert FAT16 address of Cluster in cluster number
131 ; ----------------------------------;
132 RRA X ; X = Offset>>1, offset is word < 256
133 MOV.B X,&NewClusterL ; X = NewCluster numberLO (byte)
134 MOV.B W,&NewClusterL+1 ; W = NewCluster numberHI (byte)
135 MOV #0,&NewClusterH ;
136 ; ----------------------------------;
137 SearchNewClusterEnd ;
138 ; ----------------------------------;
139 MOV @RSP+,W ; W = FATsector
140 MOV W,&CurFATsector ; refresh CurrentFATsector
142 ; ----------------------------------;
145 ; update FATs with BUFFER content.
146 ; input : FATsector, FAToffset, BUFFER = [FATsector]
147 ; use : SWX registers
148 ; ----------------------------------; else update FATsector of the old cluster
150 ; ----------------------------------;
152 ADD &OrgFAT1,W ; update FAT#1
153 CALL #WriteSectorW ; SWX
155 ADD &OrgFAT2,W ; update FAT#2
156 MOV #WriteSectorW,PC ; then ret
157 ; ----------------------------------;
161 ; FAT16/32 format for date and time in a DIR entry
162 ; create time : offset 0Dh = 0 to 200 centiseconds, not used.
163 ; offset 0Eh = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
164 ; access time : offset 14h = always 0, not used as date
165 ; modified time : ofsset 16h = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
166 ; dates : offset 10, 12, 18 = 0byyyyyyymmmmddddd, with : y=year-1980, m=month, d=day
168 ; ----------------------------------; input:
169 GetYMDHMSforDIR ;X=date, W=TIME
170 ; ----------------------------------;
172 .IFNDEF RTC ; RTC_B or RTC_C select
173 ; ----------------------------------;
174 BIT.B #RTCHOLD,&RTCCTL1 ; rtc is running ?
177 BIT.B #RTCRDY,&RTCCTL1 ; rtc values are valid ?
179 MOV.B &RTCSEC,W ; yes
180 RRA.B W ; 2 seconds accuracy time
182 MOV.B #32,&MPY ; common MPY for minutes and months
187 MOV.B &RTCHOUR,&MPY ;
201 ; ----------------------------------;
204 ; when create filename, forbidden chars are skipped
205 ForbiddenChars ; 15 forbidden chars + dot char table
206 ; " * + , / : ; < = > ? [ \ ] | .
207 .byte 34,42,43,44,47,58,59,60,61,62,63,91,92,93,124,46
211 ; ----------------------------------;
213 ; ----------------------------------;
215 JL FillDIRentryName ; X < 4 : no need spaces to complete name entry
217 CALL #OPWC_CompleteWithSpaces; complete name entry
219 ; ----------------------------------;
221 ; ----------------------------------;
222 FillDIRentryName ;SWXY use
223 ; ----------------------------------;
224 MOV.B @T+,W ; W = char of pathname
225 MOV.B W,BUFFER(Y) ; to DIRentry
226 CMP #0,W ; end of stringZ ?
227 JZ OPWC_CompleteWithSpaces ;
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 #32,BUFFER(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,BUFFER+11(Y) ; file attribute = file
340 CALL #GetYMDHMSforDIR ;WX X=DATE, W=TIME
341 MOV #0,BUFFER+12(Y) ; nt reserved = 0 and centiseconds are 0
342 MOV W,BUFFER+14(Y) ; time of creation
343 MOV X,BUFFER+16(Y) ; date of creation 20/08/2001
344 MOV X,BUFFER+18(Y) ; date of access 20/08/2001
345 MOV &ClusterH,BUFFER+20(Y) ; as first Cluster Hi
346 MOV &ClusterL,BUFFER+26(Y) ; as first cluster LO
347 MOV #0,BUFFER+28(Y) ; file lenghtLO = 0
348 MOV #0,BUFFER+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
355 JZ OPWC_InvalidPathname ; write error 1
356 CMP.B #'.',0(T) ; forbidden "." in first
357 JZ OPWC_InvalidPathname ; write error 1
358 MOV #11,X ; X=countdown of chars entry
359 CALL #FillDIRentryName ;STWXY
360 ; ----------------------------------;
362 ; ----------------------------------;
363 CALL #WriteSector ;SWX update DIRsector
364 ; ----------------------------------;
365 ; 7 Get free handle ;
366 ; ----------------------------------;
368 CALL #GetFreeHandle ; output : S = handle error, CurCluster and CurSector are set
369 ; ----------------------------------;
370 CMP #0,S ; no error ?
371 JNZ OPWC_NomoreHandle ; ==> abort with error 16
373 ; ----------------------------------;
375 ;-----------------------------------------------------------------------
377 ;-----------------------------------------------------------------------
379 ; SectorL is unchanged
380 ; ----------------------------------;
381 OPWW_UpdateDirectory ; <== CloseHandleT
382 ; ----------------------------------; Input : current Handle
383 MOV HDLL_DIRsect(T),W ;
384 MOV HDLH_DIRsect(T),X ;
385 CALL #readSectorWX ;SWX buffer = DIRsector
386 CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
387 MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
388 MOV X,BUFFER+18(Y) ; access date
389 MOV W,BUFFER+22(Y) ; modified time
390 MOV X,BUFFER+24(Y) ; modified date
391 OPWW_UpdateEntryFileSize ;
392 MOV HDLL_CurSize(T),BUFFER+28(Y); save new filesize
393 MOV HDLH_CurSize(T),BUFFER+30(Y);
394 MOV HDLL_DIRsect(T),W ;
395 MOV HDLH_DIRsect(T),X ;
396 MOV #WriteSectorWX,PC ;SWX then RET
397 ; ----------------------------------;
399 ; this subroutine is called by Write_File and CloseHandleT
400 ; ==================================;
401 WriteBuffer ;SWXY input: T = CurrentHDL
402 ; ==================================;
403 ADD &BufferPtr,HDLL_CurSize(T) ; update handle CurrentSizeL
404 ADDC #0,HDLH_CurSize(T) ;
405 ; ==================================;
407 ; ==================================;
409 MOV &SectorH,X ; High
410 MOV #WriteSectorWX,PC ; ...then RET
411 ; ----------------------------------;
415 ; write sequentially the buffer in the post incremented SectorHL.
416 ; The first time, SectorHL is initialized by WRITE".
417 ; All used registers must be initialized.
418 ; ==================================;
419 Write_File ; <== WRITE, SD_EMIT, TERM2SD"
420 ; ==================================;
421 MOV #BytsPerSec,&BufferPtr ; write always all the buffer
423 CALL #WriteBuffer ; write BUFFER and update Handle informations only for DIRentry update
424 MOV #0,&BufferPtr ; reset buffer pointer
425 ; ----------------------------------;
426 PostIncrementSector ;
427 ; ----------------------------------;
428 ADD.B #1,HDLB_ClustOfst(T) ; increment current Cluster offset
429 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
430 JNZ Write_File_End ; no,
431 ; ----------------------------------;
432 GetNewCluster ; input : T=CurrentHdl
433 ; ----------------------------------;
434 MOV.B #0,HDLB_ClustOfst(T) ; reset handle ClusterOffset
435 CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
436 PUSH Y ; push current FAToffset
437 PUSH W ; push current FATsector
438 CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer, NewCluster
439 CMP @RSP,W ; current and new clusters are in same FATsector?
440 JZ LinkClusters ; yes
441 UpdateNewClusterFATs ;
442 CALL #UpdateFATsSectorW ;SWX no: UpdateFATsSectorW with buffer of new FATsector
443 MOV @RSP,W ; W = current FATsector
444 CALL #ReadFAT1SectorW ;SWX reload current FATsector in buffer to link clusters
446 MOV @RSP+,W ; W = current FATsector
447 MOV @RSP+,Y ; pop current FAToffset
448 MOV &NewClusterL,BUFFER(Y) ; store new cluster to current cluster address in current FATsector buffer
449 CMP #1,&FATtype ; FAT16?
450 JZ UpdatePreviousClusterFATs ; yes
451 MOV &NewClusterH,BUFFER+2(Y);
452 UpdatePreviousClusterFATs ;
453 CALL #UpdateFATsSectorW ;SWX update FATS with current FATsector buffer
454 UpdateHandleCurCluster ;
455 MOV &NewClusterL,HDLL_CurClust(T) ; update handle with new cluster
456 MOV &NewClusterH,HDLH_CurClust(T) ;
457 ; CALL #ComputeHDLcurrentSector ; set Cluster first Sector as next Sector to be written
458 ; MOV #OPWW_UpdateDirectory,PC ; update DIRentry to avoid cluster lost, then RET
460 MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
461 ; ----------------------------------;
464 ; sequentially write the BUFFER in a file opened by WRITE"
465 ; ----------------------------------;
467 ; ----------------------------------;
470 ; ----------------------------------;
472 ;Z SD_EMIT c -- output char c to a SD_CARD file opened as write
473 ; ----------------------------------;
474 FORTHWORD "SD_EMIT" ;
475 ; ----------------------------------;
477 CMP #BytsPerSec,&BufferPtr ; 4 file buffer is full ?
479 CALL #Write_File ; BufferPtr = 0
482 MOV.B TOS,BUFFER(Y) ; 3
483 ADD #1,&BufferPtr ; 4
486 ; ----------------------------------; 19~ for SD_EMIT, 22~ for EMIT
491 ; ======================================================================
492 ; WRITE" (APPEND part) primitive as part of OpenPathName
493 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
494 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
495 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl, BufferPtr=HDLW_BufOfst=0
496 ; output: nothing else abort on error
498 ; ======================================================================
500 ; ----------------------------------;
502 ; ----------------------------------;
503 ; 1- open file ; done
504 ; ----------------------------------;
505 ; 2- compute missing Handle infos ;
506 ; ----------------------------------;
507 ; 2.1- Compute Sectors count ; Sectors = HDLL_CurSize/512
508 ; ----------------------------------;
509 MOV.B HDLL_CurSize+1(T),Y ;Y = 0:CurSizeLOHi
510 MOV.B HDLH_CurSize(T),X ;X = 0:CurSizeHILo
511 SWPB X ;X = CurSizeHIlo:0
512 ADD Y,X ;X = CurSizeHIlo:CurSizeLOhi
513 MOV.B HDLH_CurSize+1(T),Y ;Y:X = CurSize / 256
514 ; RRA Y ;Y = Sectors number_High
515 ; RRC X ;X = Sectors number_Low
516 ; ----------------------------------;
517 ; 2.2 Compute Clusters Count ;
518 ; ----------------------------------;
519 MOV.B &SecPerClus,T ;3 T = DIVISOR = SecPerClus = 0:SPClo
521 MOV #0,W ;1 W = 0:REMlo = 0
523 ; RRA T ;1 0>0:SPClo>C preshift one right DIVISOR
525 RRA Y ;1 0>0:SEC_HI>C
529 RRA T ;1 0>SPChi:SPClo>C
530 JNC DIVSECPERSPC1 ;2 7~ loopback if carry clear
534 ; JNZ DIVSECPERSPC2 ;2 4~ loopback Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
535 JGE DIVSECPERSPC2 ;2 4~ loopback Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
536 ; ----------------------------------;
537 MOV &CurrentHDL,T ;3 reload Handle ptr
538 ; ----------------------------------;
539 ; 2.3- Compute last Cluster ; X = Clusters numberLO, Y = Clusters numberHI
540 ; ----------------------------------;
541 ADD HDLL_FirstClus(T),X ;
542 ADDC HDLH_FirstClus(T),Y ;
543 MOV X,HDLL_CurClust(T) ; update handle
544 MOV Y,HDLH_CurClust(T) ;
545 ; ----------------------------------;
546 ; 2.4- Compute Sectors offset ;
547 ; ----------------------------------;
548 MOV.B W,HDLB_ClustOfst(T) ;3 update handle with W = REMlo = sectors offset in last cluster
549 ; ----------------------------------;
550 ; 3- load last sector in BUFFER ;
551 ; ----------------------------------;
552 MOV HDLL_CurSize(T),W ; example : W = 1013
553 BIC #01FFh,HDLL_CurSize(T) ; substract 13 from HDLL_CurSize, because loaded in buffer
554 AND #01FFh,W ; W = 13
555 MOV W,&BufferPtr ; init Buffer Pointer with 13
556 CALL #LoadHDLcurrentSector ;SWX
557 mNEXT ; BufferPtr = first free byte offset
558 ; ----------------------------------;
561 ; ======================================================================
562 ; DEL" primitive as part of OpenPathName
563 ; All "DEL"eted clusters are freed
564 ; If next DIRentry in same sector is free, DIRentry is freed, else hidden.
565 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
566 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
567 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl, BufferPtr=HDLW_BufOfst=0
568 ; output: nothing (no message if open error)
569 ; ======================================================================
573 ; CMP #4,W ; open_type = DEL"
575 ; ----------------------------------;
577 ; ----------------------------------;
578 ; 1- open file ; done
579 ; ----------------------------------;
580 CMP #0,S ; open file happy end ?
581 JNE OPND_END ; no: don't send message
582 ; ----------------------------------;
583 ; 2- Delete DIR entry ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
584 ; ----------------------------------;
585 SelectFreeEntry ; nothing to do: S = 0 ready for free entry!
586 ; ----------------------------------;
587 CMP #BytsPerSec-32,Y ; Entry >= last entry in DIRsector ?
588 JHS SelectHideEntry ; yes: next DIR entry is out of sector
589 CMP.B #0,BUFFER+32(Y) ; no: next DIR entry in DIRsector is free?
590 JZ WriteDelEntry ; yes
591 ; ----------------------------------;
593 ; ----------------------------------;
595 ; ----------------------------------;
597 ; ----------------------------------;
599 CALL #WriteSector ;SWX write SectorHL=DIRsector
600 ; ----------------------------------;
601 ; 3- free all file clusters ; Cluster = FirstCluster
602 ; ----------------------------------;
603 ComputeClusterSectWofstY ;
604 CALL #ClusterToFAT1sectWofstY;WXY W = FATsector, Y=FAToffset
605 MOV W,&CurFATsector ; update CurrentFATsector
606 ; ----------------------------------;
608 ; ----------------------------------;
609 MOV W,T ; T = W = current FATsector memory
610 CALL #ReadFAT1SectorW ;SWX
611 ; ----------------------------------;
612 GetAndFreeClusterLo ;
613 ; ----------------------------------;
614 MOV BUFFER(Y),W ; get [clusterLO]
615 MOV #0,BUFFER(Y) ; free CLusterLO
617 CMP #1,&FATtype ; FAT16 ?
618 JZ ClusterLoTest ; yes
619 GetAndFreeClusterHi ;
620 MOV BUFFER+2(Y),X ; get [clusterHI]
621 MOV #0,BUFFER+2(Y) ; free CLusterHI
623 AND #00FFFh,X ; select 12 bits significant
624 CMP #00FFFh,X ; [ClusterHI] was = 0FFFh?
625 JNE SearchNextCluster2free ; no
627 CMP #-1,W ; [ClusterLO] was = FFFFh?
628 JZ EndOfFileClusters ; yes
629 ; ----------------------------------;
630 SearchNextCluster2free
631 ; ----------------------------------;
634 CALL #ClusterToFAT1sectWofstY;WXY
635 CMP W,T ; new FATsector = current FATsector memory ?
636 JZ GetAndFreeClusterLo ; yes loop back
637 PUSH W ; no: save new FATsector...
638 MOV T,W ; ...before update current FATsector
639 CALL #UpdateFATsSectorW ;SWX
640 MOV @RSP+,W ; restore new current FATsector
641 JMP LoadFAT1sector ; loop back with Y = FAToffset
642 ; ----------------------------------;
644 ; ----------------------------------;
645 MOV T,W ; T = W = current FATsector
646 CALL #UpdateFATsSectorW ;SWX
647 ; ----------------------------------;
649 ; ----------------------------------;
651 ; ----------------------------------;
653 ; ----------------------------------;
658 ; first TERATERM sends the command TERM2SD" file.ext" to FastForth which returns XOFF at the end of the line.
659 ; then when XON is sent below, TERATERM sends "file.ext" by slices of 512 bytes,
660 ; until it sends char ETX that closes the file on SD_CARD.
662 FORTHWORD "TERM2SD\34"
664 .word DELDQ ; DEL file if already exist
667 ADD #2,RSP ; pop IP of OPEN
669 MOV #2,0(PSP) ; -- open_type HERE open_type = open as write
670 MOV #TERM2SD,IP ; IP = ParenOpen return address
671 MOV #PARENOPEN,PC ; open_type HERE -- open as write the file whose HERE is the c-addr of pathname
673 FORTHtoASM ; T = CurrentHdl
674 BIC #UCRXIFG,&TERMIFG ; clean up RX buffer
675 ; ----------------------------------;
676 T2S_GetSliceLoop ; tranfert by slices of 512 bytes terminal input to file on SD_CARD via BUFFER
677 ; ----------------------------------;
678 MOV #0,Y ;1 reset Y = BufferPtr
679 CALL #RXON ; use no registers
680 ; ----------------------------------;
682 ; ----------------------------------;
683 BIT #UCRXIFG,&TERMIFG ;3 new char in TERMRXBUF ?
684 JZ T2S_FillBufferLoop ;2
685 MOV.B &TERMRXBUF,X ;3
686 CMP.B #4,X ;1 ETX sent by TERATERM ?
690 CMP #BytsPerSec-1,Y ;2
691 JLO T2S_FillBufferLoop ;2 Y<511 21 cycles char loop
692 JZ T2S_XOFF ;2 Y=511 send XOFF after RX 511th char
693 ; ----------------------------------;
694 T2S_WriteFile ;2 Y>511
695 ; ----------------------------------;
696 CALL #Write_File ;TSWXY write all the buffer
697 JMP T2S_GetSliceLoop ;2
698 ; ----------------------------------;
699 T2S_XOFF ; 27 cycles between XON and XOFF
700 ; ----------------------------------;
701 CALL #RXOFF ;4 use no registers
702 JMP T2S_FillBufferLoop ;2 loop back to get 512th char
703 ; ----------------------------------;
705 ; ----------------------------------;
706 CALL #RXOFF ;4 use no registers
708 CALL #CloseHandleT ;4
711 ; ----------------------------------;