OSDN Git Service

modified word # ; refreshed source folders
[fast-forth/master.git] / forthMSP430FR_SD_RW.asm
1 ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FR5xxxSD_RW.asm
3
4 ; and only for FR5xxx and FR6xxx with RTC_B or RTC_C hardware if you want write file with date and time.
5
6 ; Tested with MSP-EXP430FR5969 launchpad
7 ; Copyright (C) <2015>  <J.M. THOORENS>
8 ;
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.
13 ;
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.
18 ;
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/>.
21
22
23
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 ; ======================================================================
31
32 ; ----------------------------------;
33 OPEN_QREAD                          ;
34     CMP     #1,W                    ; open_type = READ" ?
35     JNZ     OPEN_QWRITE             ; no : goto next step
36 ; ----------------------------------;
37 OPEN_READ                           ;
38 ; ----------------------------------;
39     CMP     #0,S                    ; open file happy end ?
40     JNZ     OPEN_Error              ; no
41     mNEXT                           ;
42 ; ----------------------------------;
43
44 ;Z READ            -- f
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).
48
49 ; ----------------------------------;
50     FORTHWORD "READ"                ; -- fl     closed ?
51 ; ----------------------------------;
52 READ
53     SUB     #2,PSP                  ;
54     MOV     TOS,0(PSP)              ;
55     MOV     &CurrentHdl,TOS         ;
56     CALL    #Read_File              ;SWX
57     SUB     &CurrentHdl,TOS         ; -- fl     if fl <>0 (if Z=0) handle is closed
58     mNEXT                           ;
59 ; ----------------------------------;
60
61
62 ;-----------------------------------------------------------------------
63 ; WRITE" (CREATE part) subroutines
64 ;-----------------------------------------------------------------------
65
66 ; parse all FAT sectors until free cluster is found 
67 ; this NewCluster is marked as the end's one (-1)
68
69
70 ; input : CurFATsector
71 ; use SWX registers
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
80     MOV     &FATtype,Y              ;
81     ADD     Y,Y                     ;  Y = bytes size of Cluster number (2 or 4)
82 ; ----------------------------------;
83 LoadFATsectorInBUF                  ; <== IncrementFATsector
84 ; ----------------------------------;
85     MOV     @RSP,W                  ; W = FATsector
86     CMP     W,&FATSize              ;
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
95 ClusterHighWordTest                 ;
96     CMP     #0,BUFFER+2(X)          ; cluster address hi word = 0 ?
97     JNZ     SearchNextNewCluster    ;
98 ClusterLowWordTest                  ;
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
103     CMP     #BytsPerSec,X           ;
104     JNE     SearchFreeClustInBUF    ; loopback while X < BytsPerSec
105 IncrementFATsector                  ;
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
141     RET                             ;
142 ; ----------------------------------;
143
144
145 ; update FATs with BUFFER content.
146 ; input : FATsector, FAToffset, BUFFER = [FATsector]
147 ; use : SWX registers
148 ; ----------------------------------; else update FATsector of the old cluster
149 UpdateFATsSectorW                   ;
150 ; ----------------------------------;
151     PUSH    W                       ;
152     ADD     &OrgFAT1,W              ; update FAT#1
153     CALL    #WriteSectorW           ; SWX
154     MOV     @RSP+,W                 ;
155     ADD     &OrgFAT2,W              ; update FAT#2
156     MOV     #WriteSectorW,PC        ; then ret
157 ; ----------------------------------;
158
159
160
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
167
168 ; ----------------------------------; input:
169 GetYMDHMSforDIR                     ;X=date, W=TIME
170 ; ----------------------------------;
171     .IFDEF    LF_XTAL               ;
172     .IFNDEF   RTC                   ; RTC_B or RTC_C select
173 ; ----------------------------------;
174     BIT.B   #RTCHOLD,&RTCCTL1       ; rtc is running ?
175     JNZ     SD_RW_RET               ; no
176 WaitRTC                             ; yes
177     BIT.B   #RTCRDY,&RTCCTL1        ; rtc values are valid ?
178     JZ      WaitRTC                 ; no
179     MOV.B   &RTCSEC,W               ; yes
180     RRA.B   W                       ; 2 seconds accuracy time
181     MOV.B   &RTCDAY,X               ;
182     MOV.B   #32,&MPY                ; common MPY for minutes and months
183     MOV.B   &RTCMIN,&OP2            ;
184     ADD     &RES0,W                 ;
185     MOV.B   &RTCMON,&OP2            ;
186     ADD     &RES0,X                 ;
187     MOV.B   &RTCHOUR,&MPY           ;
188     MOV     #2048,&OP2              ;
189     ADD     &RES0,W                 ;
190     MOV     &RTCYEAR,&MPY           ;
191     SUB     #1980,&MPY              ;
192     MOV     #512,&OP2               ;
193     ADD     &RES0,X                 ;
194     .ELSEIF
195     MOV     #0,X                    ; X=DATE 
196     MOV     #0,W                    ; W=TIME
197     .ENDIF
198     .ENDIF
199 SD_RW_RET                           ;
200     RET                             ;
201 ; ----------------------------------;
202
203
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
208
209
210
211 ; ----------------------------------;
212 OPWC_SkipDot                        ;
213 ; ----------------------------------;
214     CMP     #4,X                    ;
215     JL      FillDIRentryName        ; X < 4 : no need spaces to complete name entry
216     SUB     #3,X                    ;
217     CALL    #OPWC_CompleteWithSpaces; complete name entry 
218     MOV     #3,X                    ; 
219 ; ----------------------------------;
220
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 ; ----------------------------------;
229 SkipForbiddenChars                  ;
230 ; ----------------------------------;
231     PUSH    IP                      ;3
232     MOV     #15,IP                  ;2 forbidden chars count
233     MOV     #ForbiddenChars,S       ;2 here, S is free
234 ForbiddenCharLoop                   ;
235     CMP.B   @S+,W                   ;2
236     JZ      FillDIRentryName        ;2 skip forbidden char
237     SUB     #1,IP                   ;1
238     JNZ     ForbiddenCharLoop       ;2
239     MOV     @RSP+,IP                ;2
240 ; ----------------------------------;
241     CMP.B   @S,W                    ;1 46 (0x2E)
242     JZ      OPWC_SkipDot            ;2 skip '.'
243 ; ----------------------------------;
244     SUB     #33,W                   ;
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 ; ----------------------------------;
252     CMP     #0,X                    ; 
253     JZ      OPWC_CWS_End            ;
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  ;
261 OPWC_CWS_End                        ;
262     RET                             ;
263 ; ----------------------------------;
264
265
266
267
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 ; ======================================================================
280
281 ; ----------------------------------;
282 OPEN_QWRITE                         ;
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 ; ----------------------------------;
295 ; Write errors                      ;
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
304     mDOCOL                          ;
305     .word   XSQUOTE                 ;
306     .byte   12,"< WriteError",0     ;
307     .word   BRAN,SD_ERROR           ;
308 ; ----------------------------------;
309
310
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
317 ; error 2  : DiskFull       
318 ; error 4  : DirectoryFull  
319 ; error 8  : AlreadyOpen    
320 ; error 16 : NomoreHandle   
321 ; ======================================================================
322
323 ; ----------------------------------;
324 OPEN_WRITE_CREATE                   ;
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 ; ----------------------------------;
361 ; 6 save DIRsector                  ;
362 ; ----------------------------------;
363     CALL    #WriteSector            ;SWX update DIRsector
364 ; ----------------------------------;
365 ; 7 Get free handle                 ;
366 ; ----------------------------------;
367     MOV     #2,W                    ;
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
372     mNEXT                           ; --
373 ; ----------------------------------;
374
375 ;-----------------------------------------------------------------------
376 ; WRITE" subroutines
377 ;-----------------------------------------------------------------------
378
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 ; ----------------------------------;
398
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 ; ==================================;
406 WriteSector                         ;SWX
407 ; ==================================;
408     MOV     &SectorL,W              ; Low
409     MOV     &SectorH,X              ; High
410     MOV     #WriteSectorWX,PC       ; ...then RET
411 ; ----------------------------------;
412
413
414
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
422     MOV     &CurrentHdl,T           ;
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
445 LinkClusters                        ;
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
459 Write_File_End
460     MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
461 ; ----------------------------------;
462
463 ;Z WRITE            -- 
464 ; sequentially write the BUFFER in a file opened by WRITE"
465 ; ----------------------------------;
466     FORTHWORD "WRITE"               ;
467 ; ----------------------------------;
468     CALL    #Write_File             ;
469     mNEXT                           ;
470 ; ----------------------------------;
471
472 ;Z SD_EMIT  c --    output char c to a SD_CARD file opened as write
473 ; ----------------------------------;
474     FORTHWORD "SD_EMIT"             ;
475 ; ----------------------------------;
476 SD_EMIT                             ;
477     CMP     #BytsPerSec,&BufferPtr  ; 4 file buffer is full ?
478     JLO     SD_EmitNext             ; 2
479     CALL    #Write_File             ;   BufferPtr = 0
480 SD_EmitNext                         ;
481     MOV     &BufferPtr,Y            ; Y 
482     MOV.B   TOS,BUFFER(Y)           ; 3
483     ADD     #1,&BufferPtr           ; 4
484     MOV     @PSP+,TOS               ; 2
485     mNEXT                           ; 4
486 ; ----------------------------------; 19~ for SD_EMIT, 22~ for EMIT
487
488
489
490
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
497 ; error 2  : DiskFull       
498 ; ======================================================================
499
500 ; ----------------------------------;
501 OPEN_WRITE_APPEND                   ;
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
520 DIVSECPERSPC                        ;
521     MOV #0,W                        ;1 W = 0:REMlo = 0
522     MOV #8,S                        ;1 S = CNT
523 ;    RRA T                           ;1 0>0:SPClo>C   preshift one right DIVISOR
524 DIVSECPERSPC1                       ;
525     RRA Y                           ;1 0>0:SEC_HI>C
526     RRC X                           ;1 C>SEC_LO>C
527     RRC.B W                         ;1 C>REMlo>C
528     SUB #1,S                        ;1 CNT-1
529     RRA T                           ;1 0>SPChi:SPClo>C
530     JNC DIVSECPERSPC1               ;2 7~ loopback if carry clear
531 DIVSECPERSPC2                       ;
532     RRA W                           ;1 0>0:REMlo>C
533     SUB #1,S                        ;1 CNT-1
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 ; ----------------------------------;
559
560
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 ; ======================================================================
570
571
572 OPEN_QDEL                           ;
573 ;    CMP     #4,W                    ;   open_type = DEL"
574 ;    JNZ     OPEN_8W                 ;
575 ; ----------------------------------;
576 OPEN_DEL                            ;
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 ; ----------------------------------;
592 SelectHideEntry                     ;       no
593 ; ----------------------------------;
594     MOV.B   #0E5h,S                 ;
595 ; ----------------------------------;
596 WriteDelEntry
597 ; ----------------------------------;
598     MOV.B   S,BUFFER(Y)             ; 
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 ; ----------------------------------;
607 LoadFAT1sector
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
616 ClusterTestSelect                   ;
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
622 ClusterHiTest
623     AND     #00FFFh,X               ; select 12 bits significant
624     CMP     #00FFFh,X               ; [ClusterHI] was = 0FFFh?
625     JNE     SearchNextCluster2free  ; no
626 ClusterLoTest                  
627     CMP     #-1,W                   ; [ClusterLO] was = FFFFh?
628     JZ      EndOfFileClusters       ; yes 
629 ; ----------------------------------;
630 SearchNextCluster2free
631 ; ----------------------------------;
632     MOV     W,&ClusterL             ;
633     MOV     X,&ClusterH             ;
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 ; ----------------------------------;
643 EndOfFileClusters                   ;
644 ; ----------------------------------;
645     MOV     T,W                     ; T = W = current FATsector
646     CALL    #UpdateFATsSectorW      ;SWX
647 ; ----------------------------------;
648 ; 3- Close Handle                   ;
649 ; ----------------------------------;
650     CALL    #CloseHandleT           ;
651 ; ----------------------------------;
652 OPND_End                            ;
653 ; ----------------------------------;
654     mNEXT
655
656
657
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.
661
662     FORTHWORD "TERM2SD\34"
663     mDOCOL
664     .word   DELDQ                   ;   DEL file if already exist
665     .word   HERE                    ;
666     FORTHtoASM                      ;
667     ADD     #2,RSP                  ; pop IP of OPEN
668     SUB     #2,PSP                  ;
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
672 TERM2SD                             ;
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 ; ----------------------------------;
681 T2S_FillBufferLoop                  ;
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 ?
687     JZ      T2S_END                 ;2 yes
688     MOV.B   X,BUFFER(Y)             ;3
689     ADD     #1,Y                    ;1
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 ; ----------------------------------;
704 T2S_END                             ;
705 ; ----------------------------------;
706     CALL    #RXOFF                  ;4  use no registers
707     MOV     Y,&BufferPtr            ;3
708     CALL    #CloseHandleT           ;4
709     MOV     @RSP+,IP                ;2
710     mNEXT                           ;4
711 ; ----------------------------------;
712