1 ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FR5xxxSD_RW.asm
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 ; ======================================================================
12 ; ----------------------------------;
14 CMP #1,W ; open_type = READ" ?
15 JNZ OPEN_QWRITE ; no : goto next step
16 ; ----------------------------------;
18 ; ----------------------------------;
19 CMP #0,S ; open file happy end ?
22 ; ----------------------------------;
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).
29 ; ----------------------------------;
30 FORTHWORD "READ" ; -- fl closed flag
31 ; ----------------------------------;
38 SUB &CurrentHdl,TOS ; -- fl if fl <>0 (if Z=0) handle is closed
40 ; ----------------------------------;
43 ;-----------------------------------------------------------------------
44 ; WRITE" (CREATE part) subroutines
45 ;-----------------------------------------------------------------------
47 ; parse all FAT sectors until free cluster is found
48 ; this NewCluster is marked as the end's one (-1)
51 ; input : CurFATsector
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
62 ADD Y,Y ; Y = bytes size of Cluster number (2 or 4)
63 ; ----------------------------------;
64 LoadFATsectorInBUF ; <== IncrementFATsector
65 ; ----------------------------------;
66 MOV @RSP,W ; W = FATsector
68 JZ OPW_Error ; FATsector = FATSize ===> abort disk full
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
79 CMP #0,SD_BUF+2(X) ; cluster address hi word = 0 ?
80 JNZ SearchNextNewCluster ;
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
87 JNE SearchFreeClustInBUF ; loopback while X < BytsPerSec
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
125 ; ----------------------------------;
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
133 ; ----------------------------------;
135 ADD &OrgFAT1,W ; update FAT#1
137 CALL #WriteSectorWX ; write a logical sector
139 ADD &OrgFAT2,W ; update FAT#2
141 CALL #WriteSectorWX ; write a logical sector
142 ; ----------------------------------;
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
153 ; ----------------------------------; input:
154 GetYMDHMSforDIR ;X=date, W=TIME
155 ; ----------------------------------;
157 .IFNDEF RTC ; RTC_B or RTC_C select
158 ; ----------------------------------;
159 BIT.B #RTCHOLD,&RTCCTL1 ; rtc is running ?
162 BIT.B #RTCRDY,&RTCCTL1 ; rtc values are valid ?
164 MOV.B &RTCSEC,W ; yes
165 RRA.B W ; 2 seconds accuracy time
167 MOV.B #32,&MPY ; common MPY for minutes and months
172 MOV.B &RTCHOUR,&MPY ;
186 ; ----------------------------------;
189 ; when create filename, forbidden chars are skipped
190 ForbiddenChars ; 15 forbidden chars table + dot char
191 .byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
193 ; ----------------------------------;
195 ; ----------------------------------;
197 JL FillDIRentryName ; X < 4 : no need spaces to complete name entry
199 CALL #OPWC_CompleteWithSpaces; complete name entry
201 ; ----------------------------------;
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 ; ----------------------------------;
214 ; ----------------------------------;
216 MOV #15,IP ;2 forbidden chars count
217 MOV #ForbiddenChars,S ;2 here, S is free
220 JZ FillDIRentryName ;2 skip forbidden char
222 JNZ ForbiddenCharLoop ;2
224 ; ----------------------------------;
225 CMP.B @S,W ;1 46 (0x2E)
226 JZ OPWC_SkipDot ;2 skip '.'
227 ; ----------------------------------;
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 ; ----------------------------------;
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 ;
247 ; ----------------------------------;
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 ; ======================================================================
265 ; ----------------------------------;
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 ; ----------------------------------;
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
290 .byte 12,"< WriteError",0 ;
291 .word BRAN,ABORT_SD ; to insert S error as flag, no return
292 ; ----------------------------------;
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
302 ; error 4 : DirectoryFull
303 ; error 8 : AlreadyOpen
304 ; error 16 : NomoreHandle
305 ; ======================================================================
307 ; ----------------------------------;
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
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 ; ----------------------------------;
347 ; ----------------------------------;
348 CALL #WriteSector ;SWX update DIRsector
349 ; ----------------------------------;
350 ; 7 Get free handle ;
351 ; ----------------------------------;
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
358 ; ----------------------------------;
360 ;-----------------------------------------------------------------------
362 ;-----------------------------------------------------------------------
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 ; ----------------------------------;
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 ; ==================================;
392 ; ==================================;
394 MOV &SectorH,X ; High
395 MOV #WriteSectorWX,PC ; ...then RET
396 ; ----------------------------------;
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
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
431 CALL #ReadSectorWX ;SWX (< 65536)
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
447 MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
448 ; ----------------------------------;
451 ; sequentially write the entire SD_BUF in a file opened by WRITE"
452 ; ----------------------------------;
453 FORTHWORD "WRITE" ; in assembly : CALL &WRITE+2
454 ; ----------------------------------;
457 ; ----------------------------------;
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
467 ; ======================================================================
469 ; ----------------------------------;
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
488 MOV #0,W ;1 W = 0:REMlo = 0
491 RRA Y ;1 0>0:SEC_HI>C
495 RRA T ;1 0>SPChi:SPClo>C
496 JNC DIVSECPERSPC1 ;2 7~ loopback if carry clear
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 ; ----------------------------------;
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 ; ======================================================================
538 ; CMP #4,W ; open_type = DEL"
540 ; ----------------------------------;
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 ; ----------------------------------;
558 ; ----------------------------------;
560 ; ----------------------------------;
562 ; ----------------------------------;
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 ; ----------------------------------;
573 ; ----------------------------------;
574 MOV W,T ; T = W = current FATsector memory
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
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
590 AND #00FFFh,X ; select 12 bits significant
591 CMP #00FFFh,X ; [ClusterHI] was = 0FFFh?
592 JNE SearchNextCluster2free ; no
594 CMP #-1,W ; [ClusterLO] was = FFFFh?
595 JZ EndOfFileClusters ; yes
596 ; ----------------------------------;
597 SearchNextCluster2free
598 ; ----------------------------------;
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 ; ----------------------------------;
611 ; ----------------------------------;
612 MOV T,W ; T = W = current FATsector
613 CALL #UpdateFATsSectorW ;SWX
614 ; ----------------------------------;
616 ; ----------------------------------;
618 ; ----------------------------------;
621 ; ----------------------------------;
625 .IFNDEF TERMINAL_I2C ; if UART_TERMINAL
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.
631 FORTHWORD "TERM2SD\34"
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
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 ; ----------------------------------;
646 ; ----------------------------------;
647 BIT #RX_TERM,&TERM_IFG ;3 new char in TERMRXBUF ?
648 JZ T2S_FillBufferLoop ;2
649 MOV.B &TERM_RXBUF,X ;3
651 CMP.B #4,X ;1 EOT sent by TERATERM ?
652 JZ T2S_End_Of_File ;2 yes
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 ; ----------------------------------;
670 ; ----------------------------------;
671 CALL #RXOFF ;4 use no registers
673 CALL #CloseHandleT ;4
675 ; ----------------------------------;
677 .ELSE ; if I2C_TERMINAL
679 FORTHWORD "TERM2SD\34"
680 CALL #WAITCHAREND ; wait I2C_Master (re)START RX
681 BIC #WAKE_UP,&TERM_IFG ; clear UCSTTIFG before next test
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
688 ; ----------------------------------;
690 BIC #WAKE_UP,&TERM_IFG ; clear UCSTTIFG before next test
691 ; ----------------------------------;
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
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
713 .word LIT,0Ah,EMIT ; use Y reg
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 ; ----------------------------------;
719 ; ----------------------------------;
720 CMP #BytsPerSec,W ;2 buffer full ?
721 JNC T2S_FillBufferLoop ;2 no 21 cycles char loop
722 ; ----------------------------------;
724 ; ----------------------------------;
725 CALL #Write_File ;4 TSWXY write all the buffer
726 JMP T2S_ClearBuffer ;2
727 ; ----------------------------------;
729 ; ----------------------------------;
730 MOV @RSP+,IP ; before CloseHandleT
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 ; ----------------------------------;