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 ; ----------------------------------;
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, SD_BUF = [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,SD_BUF+2(X) ; cluster address hi word = 0 ?
97 JNZ SearchNextNewCluster ;
99 CMP #0,SD_BUF(X) ; Cluster address lo word = 0 ?
100 JZ GNC_FreeClusterFound ;
101 SearchNextNewCluster ;
102 ADD Y,X ; increment SD_BUF 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 SD_BUF = FATsector
110 ; ----------------------------------;
111 MOV #0,S ; clear error
112 MOV.B @RSP,W ; W = 0:FATsectorLo
113 MOV #-1,SD_BUF(X) ; mark NewCluster low word as end cluster (0xFFFF) in SD_BUF
114 CMP #2,Y ; Y = FAT16 size of Cluster number ?
115 JZ FAT16EntryToClusterNum ; yes
116 MOV #0FFFh,SD_BUF+2(X) ; no: mark NewCluster high word as end cluster (0x0FFF) in SD_BUF
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 SD_BUF content.
146 ; input : FATsector, FAToffset, SD_BUF = [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 table + dot char
206 .byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
208 ; ----------------------------------;
210 ; ----------------------------------;
212 JL FillDIRentryName ; X < 4 : no need spaces to complete name entry
214 CALL #OPWC_CompleteWithSpaces; complete name entry
216 ; ----------------------------------;
218 ; ----------------------------------;
219 FillDIRentryName ;SWXY use
220 ; ----------------------------------;
221 MOV.B @T+,W ; W = char of pathname
222 MOV.B W,SD_BUF(Y) ; to DIRentry
223 ; CMP #0,W ; end of stringZ ?
224 ; JZ OPWC_CompleteWithSpaces ;
225 CMP T,&EndOfPath ; EOS < PTR ?
226 JLO OPWC_CompleteWithSpaces ; yes
227 ; ----------------------------------;
229 ; ----------------------------------;
231 MOV #15,IP ;2 forbidden chars count
232 MOV #ForbiddenChars,S ;2 here, S is free
235 JZ FillDIRentryName ;2 skip forbidden char
237 JNZ ForbiddenCharLoop ;2
239 ; ----------------------------------;
240 CMP.B @S,W ;1 46 (0x2E)
241 JZ OPWC_SkipDot ;2 skip '.'
242 ; ----------------------------------;
244 JL FillDIRentryName ; skip char =< SPACE char
245 ADD #1,Y ; increment DIRentry ptr
246 SUB #1,X ; decrement count of chars entry
247 JNZ FillDIRentryName ;
248 ; ----------------------------------;
249 OPWC_CompleteWithSpaces ; 0 to n spaces !
250 ; ----------------------------------;
253 ; ----------------------------------;
254 OPWC_CompleteWithSpaceloop ;
255 ; ----------------------------------;
256 MOV.B #' ',SD_BUF(Y) ; remplace dot by char space
257 ADD #1,Y ; increment DIRentry ptr in buffer
258 SUB #1,X ; dec countdown of chars space
259 JNZ OPWC_CompleteWithSpaceloop ;
262 ; ----------------------------------;
267 ; ======================================================================
268 ; WRITE" primitive as part of OpenPathName
269 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
270 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
271 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
272 ; output: nothing else abort on error
273 ; error 1 : PathNameNotFound
274 ; error 2 : NoSuchFile
275 ; error 4 : DirectoryFull
276 ; error 8 : AlreadyOpen
277 ; error 16 : NomoreHandle
278 ; ======================================================================
280 ; ----------------------------------;
282 CMP #2,W ; open_type = WRITE" ?
283 JNZ OPEN_QDEL ; no : goto next step
284 ; ----------------------------------;
285 ; 1 try to open ; done
286 ; ----------------------------------;
287 ; 2 select error "no such file" ;
288 ; ----------------------------------;
289 CMP #2,S ; "no such file" error ?
290 JZ OPEN_WRITE_CREATE ; yes
291 CMP #0,S ; no open file error ?
292 JZ OPEN_WRITE_APPEND ; yes
293 ; ----------------------------------;
295 ; ----------------------------------;
296 OPWC_InvalidPathname ; S = 1
297 OPWC_DiskFull ; S = 2
298 OPWC_DirectoryFull ; S = 4
299 OPWC_AlreadyOpen ; S = 8
300 OPWC_NomoreHandle ; S = 16
301 ; ----------------------------------;
302 OPW_Error ; set ECHO, type Pathname, type #error, type "< WriteError"; no return
305 .byte 12,"< WriteError",0 ;
306 .word BRAN,SD_ERROR ;
307 ; ----------------------------------;
310 ; ======================================================================
311 ; WRITE" (CREATE part) primitive as part of OpenPathName
312 ; input from open: S = NoSuchFile, W = open_type, SectorHL = DIRsectorHL,
313 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
314 ; output: nothing else abort on error:
315 ; error 1 : InvalidPathname
317 ; error 4 : DirectoryFull
318 ; error 8 : AlreadyOpen
319 ; error 16 : NomoreHandle
320 ; ======================================================================
322 ; ----------------------------------;
324 ; ----------------------------------;
325 ; 3 get free cluster ;
326 ; ----------------------------------; input: FATsector
327 CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer,NewCluster
328 MOV &NewClusterL,&ClusterL ;
329 MOV &NewClusterH,&ClusterH ;
330 CALL #UpdateFATsSectorW ;SWX update FATs with buffer
331 ; ----------------------------------;
332 CALL #ReadSector ; reload DIRsector
333 MOV &EntryOfst,Y ; reload entry offset (first free entry in DIR)
334 ; ----------------------------------;
335 ; 4 init DIRentryAttributes ;
336 ; ----------------------------------;
337 OPWC_SetEntryAttribute ; (cluster=DIRcluster!)
338 MOV.B #20h,SD_BUF+11(Y) ; file attribute = file
339 CALL #GetYMDHMSforDIR ;WX X=DATE, W=TIME
340 MOV #0,SD_BUF+12(Y) ; nt reserved = 0 and centiseconds are 0
341 MOV W,SD_BUF+14(Y) ; time of creation
342 MOV X,SD_BUF+16(Y) ; date of creation 20/08/2001
343 MOV X,SD_BUF+18(Y) ; date of access 20/08/2001
344 MOV &ClusterH,SD_BUF+20(Y) ; as first Cluster Hi
345 MOV &ClusterL,SD_BUF+26(Y) ; as first cluster LO
346 MOV #0,SD_BUF+28(Y) ; file lenghtLO = 0
347 MOV #0,SD_BUF+30(Y) ; file lenghtHI = 0
348 ; ----------------------------------;
349 ; 5 create DIRentryName ;
350 ; ----------------------------------;
351 MOV #1,S ; preset pathname error
352 MOV &Pathname,T ; here, pathname is "xxxxxxxx.yyy" format
353 ; 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,SD_BUF+18(Y) ; access date
389 MOV W,SD_BUF+22(Y) ; modified time
390 MOV X,SD_BUF+24(Y) ; modified date
391 OPWW_UpdateEntryFileSize ;
392 MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
393 MOV HDLH_CurSize(T),SD_BUF+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 (bufferPtr=512) and CloseHandleT (0 =< BufferPtr =< 512)
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 SD_BUF 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,SD_BUF(Y) ; store new cluster to current cluster address in current FATsector buffer
449 CMP #1,&FATtype ; FAT16?
450 JZ UpdatePreviousClusterFATs ; yes
451 MOV &NewClusterH,SD_BUF+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 entire SD_BUF 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,SD_BUF(Y) ; 3
483 ADD #1,&BufferPtr ; 4
486 ; ----------------------------------; 22~ 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 SD_BUF ;
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,SD_BUF+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 SD_BUF(Y),W ; get [clusterLO]
615 MOV #0,SD_BUF(Y) ; free CLusterLO
617 CMP #1,&FATtype ; FAT16 ?
618 JZ ClusterLoTest ; yes
619 GetAndFreeClusterHi ;
620 MOV SD_BUF+2(Y),X ; get [clusterHI]
621 MOV #0,SD_BUF+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.
663 FORTHWORD "TERM2SD\34"
665 .word DELDQ ; DEL filepath if already exist
666 .word lit,2 ; -- open_type
667 .word HERE,COUNT ; -- open_type addr cnt
668 .word PARENOPEN ; reopen same filepath but as write
671 BIC #UCRXIFG,&TERM_IFG ; clean up RX buffer
672 ; ----------------------------------;
673 T2S_GetSliceLoop ; tranfert by slices of 512 bytes terminal input to file on SD_CARD via SD_BUF
674 ; ----------------------------------;
675 MOV #0,Y ;1 reset Y = BufferPtr
676 CALL #RXON ; use no registers
677 ; ----------------------------------;
679 ; ----------------------------------;
680 BIT #UCRXIFG,&TERM_IFG ;3 new char in TERMRXBUF ?
681 JZ T2S_FillBufferLoop ;2
682 MOV.B &TERM_RXBUF,X ;3
683 CMP.B #4,X ;1 EOT sent by TERATERM ?
687 CMP #BytsPerSec-1,Y ;2
688 JLO T2S_FillBufferLoop ;2 Y<511 21 cycles char loop
689 JZ T2S_XOFF ;2 Y=511 send XOFF after RX 511th char
690 ; ----------------------------------;
691 T2S_WriteFile ;2 Y>511
692 ; ----------------------------------;
693 CALL #Write_File ;TSWXY write all the buffer
694 JMP T2S_GetSliceLoop ;2
695 ; ----------------------------------;
696 T2S_XOFF ; 27 cycles between XON and XOFF
697 ; ----------------------------------;
698 CALL #RXOFF ;4 use no registers
699 JMP T2S_FillBufferLoop ;2 loop back to get 512th char
700 ; ----------------------------------;
702 ; ----------------------------------;
703 CALL #RXOFF ;4 use no registers
705 CALL #CloseHandleT ;4
708 ; ----------------------------------;