OSDN Git Service

raz
[fast-forth/master.git] / forthMSP430FR_SD_LOAD.asm
1 ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FRxxxxSD_LOAD.asm
3
4 ; Tested with MSP-EXP430FR5969 launchpad
5 ; Copyright (C) <2017>  <J.M. THOORENS>
6 ;
7 ; This program is free software: you can redistribute it and/or modify
8 ; it under the terms of the GNU General Public License as published by
9 ; the Free Software Foundation, either version 3 of the License, or
10 ; (at your option) any later version.
11 ;
12 ; This program is distributed in the hope that it will be useful,
13 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ; GNU General Public License for more details.
16 ;
17 ; You should have received a copy of the GNU General Public License
18 ; along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21 ;-----------------------------------------------------------------------
22 ; SD card OPEN, LOAD subroutines
23 ;-----------------------------------------------------------------------
24
25 ;Z S">HERE  addr u -- HERE            move in-line string to a counted string at HERE
26 SQUOTE2HERE MOV     @PSP+,X     ; X = src
27             MOV     &DDP,Y      ; Y = dst = HERE
28             MOV.B   TOS,W       ; W = count
29             MOV     Y,TOS       ; -- HERE
30             MOV.B   W,0(Y)      ; count at HERE
31             ADD     #1,Y        ; inc dst
32             MOV #MOVEDOWN,PC    ;
33
34
35
36 ; rules for registers use
37 ; S = error
38 ; T = CurrentHdl, pathname
39 ; W = SectorL, (RTC) TIME
40 ; X = SectorH, (RTC) DATE
41 ; Y = BufferPtr, (DIR) EntryOfst, FAToffset
42
43
44 ; ----------------------------------;
45 HDLCurClusToFAT1sectWofstY          ;WXY Input: HDL_CurCluster, Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
46 ; ----------------------------------;
47     MOV HDLL_CurClust(T),&ClusterL  ;
48     MOV HDLH_CurClust(T),&ClusterH  ;
49 ; ----------------------------------;
50 ClusterToFAT1sectWofstY             ;WXY Input : Cluster ; Output: W = FATsector, Y = FAToffset
51 ; ----------------------------------;
52     MOV.B   &ClusterL+1,W           ;3 W = ClusterLoHI
53     MOV.B   &ClusterL,Y             ;3 Y = ClusterLoLo
54     CMP     #2,&FATtype             ;3 FAT32?
55     JZ      ClusterToFAT32sector    ;2 yes
56     ADD     Y,Y                     ;1 Y = ClusterLoLo << 1
57 OpenSubRET
58     RET
59
60
61 ; input : Cluster n, max = 7FFFFF ==> SDcard up to 256 GB
62 ; ClusterLoLo*4 = displacement in 512 bytes sector   ==> FAToffset
63 ; ClusterHiLo&ClusterLoHi +C  << 1 = relative FATsector + orgFAT1       ==> FATsector
64 ; ----------------------------------;
65 ClusterToFAT32sector                ; Input : Cluster ; Output: W=FATsector, Y=FAToffset
66 ; ----------------------------------;
67     MOV.B   &ClusterH,X             ;  X = 0:ClusterHiLo
68     SWPB    X                       ;  X = ClusterHiLo:0
69     ADD     X,W                     ;  W = ClusterHiLo:ClusterLoHi  
70 ; ----------------------------------;
71     SWPB    Y                       ;  Y = ClusterLoLo:0
72     ADD     Y,Y                     ;1 Y = ClusterLoLo:0 * 2 + carry for FATsector
73     ADDC    W,W                     ;  W = ClusterHiLo:ClusterLoHi * 2 = ClusterHiLo:ClusterL / 128
74     SWPB    Y
75     ADD     Y,Y                     ;  Y = 0:ClusterLoLo * 4
76     RET                             ;4
77 ; ----------------------------------;
78
79
80 ; use no registers
81 ; ----------------------------------; Input : Cluster
82 ComputeClusFrstSect                 ; If Cluster = 1 ==> RootDirectory ==> SectorL = OrgRootDir
83 ; ----------------------------------; Output: SectorL of Cluster
84     MOV     #0,&SectorH             ;
85     MOV     &OrgRootDir,&SectorL    ;
86     CMP     #1,&ClusterL            ; clusterL = 1 ? (FAT16 specificity)
87     JNE     CCFS_AllOtherCLuster    ; no
88     CMP.B   #0,&ClusterH            ;     clusterT = 0 ?
89     JZ      OpenSubRET              ; yes, sectorL for FAT16 OrgRootDIR is done
90 CCFS_AllOtherCLuster                ;
91     MOV     &OrgClusters,&RES0      ; OrgClusters = sector of virtual cluster 0, word size
92     MOV     #0,&RES1                ;
93     MOV     &ClusterL,&MAC32L       ;3
94     MOV     &ClusterH,&MAC32H       ;3
95     MOV     &SecPerClus,&OP2        ;
96     MOV     &RES0,&SectorL          ;
97     MOV     &RES1,&SectorH          ;
98     RET                             ; 
99 ; ----------------------------------;
100
101 ; ----------------------------------;
102 ComputeHDLcurrentSector            ;
103 ; ----------------------------------;
104     MOV   HDLL_CurClust(T),&ClusterL;
105     MOV   HDLH_CurClust(T),&ClusterH;
106     CALL  #ComputeClusFrstSect      ;
107     MOV.B   HDLB_ClustOfst(T),W     ;
108     ADD     W,&SectorL              ;
109     ADDC    #0,&SectorH             ;
110     RET                             ;
111 ; ----------------------------------;
112
113
114
115
116 ; ----------------------------------; input : X = countdown_of_spaces, Y = name pointer in buffer
117 ParseEntryNameSpaces                ;XY
118 ; ----------------------------------; output: Z flag, Y is set after the last space char
119     CMP     #0,X                    ; 
120     JZ      OpenSubRET              ;
121 ; ----------------------------------; input : X = countdown_of_spaces, Y = name pointer in buffer
122 ParseEntryNameSpacesLoop            ; here X must be > 0
123 ; ----------------------------------; output: Z flag, Y is set after the last space char
124     CMP.B   #32,BUFFER(Y)           ; SPACE ? 
125     JNZ     OpenSubRET              ; no: RET
126     ADD     #1,Y                    ;
127     SUB     #1,X                    ;
128     JNZ     ParseEntryNameSpacesLoop;
129     RET                             ; 
130 ; ----------------------------------; 
131
132
133 ; sequentially load in BUFFER bytsPerSec bytes of a file opened as read or as load
134 ; if previous bufferLen had a size < bytsPerSec, closes the file.
135 ; if new bufferLen have a size <= BufferPtr, closes the file.
136 ; reload previous LOADed file if exist.
137 ; HDLL_CurSize leaves the not yet read size 
138 ; All used registers must be initialized. 
139 ; ==================================;
140 Read_File                           ; <== SD_ACCEPT, READ
141 ; ==================================;
142     MOV     &CurrentHdl,T           ;
143     MOV     #0,&BufferPtr           ; reset BufferPtr (the buffer is already read)
144     CMP     #bytsPerSec,&BufferLen  ;
145     JNZ     CloseHandleT            ; because this last and incomplete sector is already read
146     SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
147     SUBC    #0,HDLH_CurSize(T)      ;
148     ADD.B   #1,HDLB_ClustOfst(T)    ; current cluster offset is incremented
149     CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
150     JLO SetBufLenAndLoadCurSector   ; no
151 ; ----------------------------------;
152 ;SearchNextCluster                  ; yes
153 ; ----------------------------------;
154     MOV.B   #0,HDLB_ClustOfst(T)    ; reset Current_Cluster sectors offset
155     CALL #HDLCurClusToFAT1sectWofstY;WXY  Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
156     CALL    #ReadFAT1SectorW        ;SWX (< 65536)
157     MOV     #0,HDLH_CurClust(T)     ;
158     MOV BUFFER(Y),HDLL_CurClust(T)  ;
159     CMP     #1,&FATtype             ; FAT16?
160     JZ SetBufLenAndLoadCurSector    ;
161     MOV BUFFER+2(Y),HDLH_CurClust(T);
162 ; ==================================;
163 SetBufLenAndLoadCurSector           ;WXY <== previous handle reLOAD
164 ; ==================================;
165 ;ComputeBufferLen                   ;
166 ; ----------------------------------;
167     MOV     #bytsPerSec,&BufferLen  ; preset BufferLen
168     CMP     #0,HDLH_CurSize(T)      ; CurSize > 65535 ?
169     JNZ     LoadHDLcurrentSector    ; yes
170     CMP HDLL_CurSize(T),&BufferPtr  ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedFileContext)
171     JHS      CloseHandleT           ; yes
172     CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
173     JHS     LoadHDLcurrentSector    ; yes
174     MOV HDLL_CurSize(T),&BufferLen  ; no: adjust BufferLen
175 ; ==================================;
176 LoadHDLcurrentSector                ; <=== OPEN_WRITE_APPEND
177 ; ==================================;
178     CALL #ComputeHDLcurrentSector   ; use no registers
179 ; ==================================;
180 ReadSector                          ;
181 ; ==================================;
182     MOV     &SectorL,W              ; Low
183     MOV     &SectorH,X              ; High
184     JMP     ReadSectorWX            ; then RET
185 ; ----------------------------------;
186
187
188 ; if first open_load token, save DefaultInputStream
189 ; if other open_load token, decrement token, save previous context
190
191 ; OPEN subroutine
192 ; Input : EntryOfst, Cluster = EntryOfst(HDLL_FirstClus())
193 ; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
194 ; Output: Cluster = first Cluster of file, X = CurrentHdl
195 ; ----------------------------------; input : Cluster, EntryOfst
196 GetFreeHandle                       ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
197 ; ----------------------------------; output : T = new CurrentHdl
198     MOV     #8,S                    ; prepare file already open error
199     MOV     #FirstHandle,T          ;
200     MOV     #0,X                    ; X = previous handle,  init = 0
201 ; ----------------------------------;
202 SearchHandleLoop                    ;
203 ; ----------------------------------;
204     CMP.B   #0,HDLB_Token(T)        ; free handle ?
205     JZ      FreeHandleFound         ; yes
206 AlreadyOpenTest                     ; no
207     CMP     &ClusterH,HDLH_FirstClus(T);
208     JNE     SearchNextHandle        ;
209     CMP     &ClusterL,HDLL_FirstClus(T);
210     JZ      InitHandleRET           ; error 8: Already Open abort ===> 
211 SearchNextHandle                    ;
212     MOV     T,X                     ; handle is occupied, keep it in X as previous handle
213     ADD     #HandleLenght,T         ;
214     CMP     #HandleEnd,T            ;
215     JNZ     SearchHandleLoop        ;
216 ; ----------------------------------;
217     ADD     S,S                     ; 16 = no more handle error, abort ===>
218 InitHandleRET                       ;
219     RET                             ;
220 ; ----------------------------------;
221 FreeHandleFound                     ; T = new handle, X = previous handle
222 ; ----------------------------------;
223     MOV     #0,S                    ; prepare HappyEnd
224     MOV     T,&CurrentHdl           ;
225     MOV     X,HDLW_PrevHDL(T)       ; link to previous handle
226 ; ----------------------------------;
227 CheckCaseOfLoadFileToken            ;
228 ; ----------------------------------;
229     CMP.B   #0,W                    ; open_type is LOAD?
230     JGE     InitHandle              ; W>0, no
231     CMP.B   #0,X                    ; existing previous handle?
232     JZ      InitHandle              ; no
233     CMP.B   #0,HDLB_Token(X)        ; previous token is negative? (open_load type)
234     JGE     InitHandle              ; no
235     ADD.B   HDLB_Token(X),W         ; LOAD token = previous LOAD token -1
236 ; ----------------------------------;
237 InitHandle                          ;
238 ; ----------------------------------;
239     MOV.B   W,HDLB_Token(T)         ; marks handle as open type
240     MOV.B   #0,HDLB_ClustOfst(T)    ; clear ClustOfst
241     MOV     &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
242     MOV     &SectorH,HDLH_DIRsect(T); 
243     MOV     &EntryOfst,Y            ;
244     MOV     Y,HDLW_DIRofst(T)       ; init handle BUFFER offset of DIR entry
245     MOV BUFFER+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
246     MOV BUFFER+20(Y),HDLH_FirstClus(T)
247     MOV BUFFER+26(Y),HDLL_CurClust(T)  ; init handle CurrentCluster
248     MOV BUFFER+20(Y),HDLH_CurClust(T) 
249     MOV BUFFER+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
250     MOV BUFFER+30(Y),HDLH_CurSize(T);
251     MOV     #0,&BufferPtr           ; reset BufferPtr all type of files
252     CMP.B   #2,W                    ; is a WRITE file handle?
253     JZ      ComputeHDLcurrentSector ; = 2, is a WRITE file
254     JGE     InitHandleRET           ; > 2, is a file to be deleted
255     MOV     #0,HDLW_BUFofst(T)      ; < 2, is a READ or a LOAD file
256 ; ----------------------------------;
257 HandleComplements                   ;
258 ; ----------------------------------;
259     CMP.B   #-1,W                   ; is the first loaded file?
260     JZ  FirstLoadFileHandle         ; = -1, is the first LOADed file
261     JGE SetBufLenAndLoadCurSector   ; > -1, is a READ file
262     ADD     &TOIN,HDLW_BUFofst(X)   ; < -1, is not the first LOADed file: in previous handle, add interpret offset to Buffer offset
263     JMP SetBufLenAndLoadCurSector   ; thus, the return to this previous LOADed file will be on next char after current LOAD" cmd.
264 ; ----------------------------------;
265 FirstLoadFileHandle                 ;
266 ; ----------------------------------;
267     MOV     &SOURCE_LEN,&SAVEtsLEN  ;
268     SUB     &TOIN,&SAVEtsLEN        ; save remaining lenght  
269     MOV     &SOURCE_ADR,&SAVEtsPTR  ; 
270     ADD     &TOIN,&SAVEtsPTR        ; save new input org address
271     MOV     #SD_ACCEPT,&ACCEPT+2    ; redirect ACCEPT to SD_ACCEPT
272     MOV     &SOURCE_LEN,&TOIN       ; to quit interpret (same as BACKSLASH)
273     JMP SetBufLenAndLoadCurSector   ;
274 ;; ----------------------------------;
275 ;FirstLoadFileHandle                 ; 
276 ;; ----------------------------------;
277 ;    SUB     &TOIN,&SOURCE_LEN       ;
278 ;    ADD     &TOIN,&SOURCE_ADR       ;
279 ;    MOV     #SD_ACCEPT,&ACCEPT+2    ; redirect ACCEPT to SD_ACCEPT
280 ;    MOV     &SOURCE_LEN,&TOIN       ; to quit interpret (same as BACKSLASH)
281 ;    JMP SetBufLenAndLoadCurSector   ;
282 ; ----------------------------------;
283
284
285
286 ; If closed token = -1, restore DefaultInputStream
287 ; if closed token < -1, restore previous context
288 ; ==================================;
289 CloseHandleT                        ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
290 ; ==================================;
291     MOV     &CurrentHdl,T           ;
292     MOV     #0,&BufferLen           ; to inform the user that file is closed
293     CMP     #0,T                    ; no handle?
294     JZ      InitHandleRET           ; RET
295 ; ----------------------------------;
296     .IFDEF SD_CARD_READ_WRITE
297     CMP.B   #2,HDLB_Token(T)        ; updated file ?
298     JNZ     CloseHandleHere         ; no
299     CALL    #WriteBuffer            ;SWXY
300     CALL    #OPWW_UpdateDirectory   ;SWXY 
301     .ENDIF
302 ; ----------------------------------;
303 CloseHandleHere                     ;
304 ; ----------------------------------;
305     MOV.B   HDLB_Token(T),W         ; to test W=token below
306     MOV.B   #0,HDLB_Token(T)        ; close handle
307 ; ----------------------------------;
308     MOV     @T,T                    ; T = previous handle
309     MOV     T,&CurrentHdl           ; becomes current handle
310 ; ----------------------------------;
311 CheckCaseOfClosedLoadedFile         ;
312 ; ----------------------------------;
313     ADD.B   #1,W                    ;
314     JZ      LastFileLoadClosed      ; W=0, this closed LOADed file had not a paren
315     JGE     InitHandleRET           ; W>0, for READ, WRITE, DEL files
316 ; ----------------------------------;
317 RestorePreviousLoadedFileContext    ; W<0, this closed LOADed file had a paren
318 ; ----------------------------------;
319     MOV HDLW_BUFofst(T),&BufferPtr  ; restore BufferPtr saved by SD_ACCEPT before interpreting LOAD cmd line 
320     JMP SetBufLenAndLoadCurSector   ;
321 ; ----------------------------------;
322 LastFileLoadClosed                  ;
323 ; ----------------------------------;
324 RestoreDefaultInputStream           ; it was the first LOADed filre
325     MOV     &SAVEtsLEN,TOS          ; restore lenght
326     MOV     &SAVEtsPTR,2(PSP)       ; restore pointer for interpret
327     MOV     #PARENACCEPT,&ACCEPT+2  ; restore (ACCEPT)
328     JMP     InitHandleRET           ; RET
329 ; ----------------------------------;
330 ;RestoreDefaultInputStream           ; it was the first LOADed filre
331 ;    MOV     &SOURCE_LEN,TOS         ; restore lenght
332 ;    MOV     &SOURCE_ADR,2(PSP)      ; restore pointer for interpret
333 ;    MOV     #0,&TOIN                ; reset interpret ptr
334 ;    MOV     #PARENACCEPT,&ACCEPT+2  ; restore (ACCEPT)
335 ;    JMP     InitHandleRET           ; RET
336 ; ----------------------------------;
337
338
339     .IFDEF SD_CARD_READ_WRITE
340
341 ;-----------------------------------------------------------------------
342 ; SD_READ_WRITE FORTH words
343 ;-----------------------------------------------------------------------
344
345 ;Z READ"         --
346 ; parse string until " is encountered, convert counted string in StringZ
347 ; then parse stringZ until char '0'.
348 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
349 ; char "\" as first one initializes rootDir as SearchDir.
350 ; if file found, if not already open and if free handle...
351 ; ...open the file as read and return the handle in CurrentHdl.
352 ; then load first sector in buffer, bufferLen and bufferPtr are ready for read
353 ; currentHdl keep handle that is flagged as "read".
354
355 ; to read sequentially next sectors use READ word. A flag is returned : true if file is closed.
356 ; the last sector so is in buffer.
357
358 ; if pathname is a directory, change current directory.
359 ; if an error is encountered, no handle is set, error message is displayed.
360
361 ; READ" acts also as CD dos command : 
362 ;     - READ" a:\misc\" set a:\misc as current directory
363 ;     - READ" a:\" reset current directory to root
364 ;     - READ" ..\" change to parent directory
365
366 ; to close all files type : WARM (or COLD, RESET)
367
368 ; ----------------------------------;
369     FORTHWORDIMM "READ\34"          ; immediate
370 ; ----------------------------------;
371 READDQ
372     MOV.B   #1,W                    ; W = OpenType
373     JMP     Open_File               ;
374 ; ----------------------------------;
375
376 ;Z WRITE" pathame"   --       immediate
377 ; open or create the file designed by pathname.
378 ; an error occurs if the file is already opened.
379 ; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
380 ; compile state : compile WRITE" pathname"
381 ; exec state : open or create entry selected by pathname
382 ; ----------------------------------;
383     FORTHWORDIMM "WRITE\34"         ; immediate
384 ; ----------------------------------;
385 WRITEDQ
386     MOV.B   #2,W                    ; W = OpenType
387     JMP     Open_File               ;
388 ; ----------------------------------;
389
390
391 ;Z DEL" pathame"   --       immediate
392 ; compile state : compile DEL" pathname"
393 ; exec state : DELETE entry selected by pathname
394
395 ; ----------------------------------;
396     FORTHWORDIMM "DEL\34"           ; immediate
397 ; ----------------------------------;
398 DELDQ
399     MOV.B   #4,W                    ; W = OpenType
400     JMP     Open_File               ;
401 ; ----------------------------------;
402
403
404     .ENDIF ; SD_CARD_READ_WRITE
405
406 ;-----------------------------------------------------------------------
407 ; SD_CARD_LOADER FORTH word
408 ;-----------------------------------------------------------------------
409
410 ;Z CLOSE      --     
411 ; close current handle
412 ; ----------------------------------;
413     FORTHWORD "CLOSE"               ;
414 ; ----------------------------------;
415     CALL    #CloseHandleT           ;
416     mNEXT                           ;
417 ; ----------------------------------;
418
419 ;Z LOAD" pathame"   --       immediate
420 ; compile state : compile LOAD" pathname"
421 ; exec state : open a file from SD card via its pathname
422 ; see Open_File primitive for pathname conventions 
423 ; the opened file becomes the new input stream for INTERPRET
424 ; this command is recursive, limited only by the count of free handles (up to 8)
425
426 ; LOAD" acts also as dos command "CD" : 
427 ;     - LOAD" \misc\" set a:\misc as current directory
428 ;     - LOAD" \" reset current directory to root
429 ;     - LOAD" ..\" change to parent directory
430
431 ; ----------------------------------;
432     FORTHWORDIMM "LOAD\34"          ; immediate
433 ; ----------------------------------;
434     MOV.B   #-1,W                   ; W = OpenType
435 ; ----------------------------------;
436
437
438 ; ======================================================================
439 ; OPEN FILE primitive
440 ; ======================================================================
441 ; Open_File               --
442 ; primitive for LOAD" READ" CREATE" WRITE" DEL"
443 ; store OpenType on TOS,
444 ; compile state : compile OpenType, compile SQUOTE and the string of provided pathname
445 ; exec state :  open a file from SD card via its pathname
446 ;               convert counted string found at HERE in a StringZ then parse it
447 ;                   media identifiers "A:", "B:" ... are ignored (only one SD_Card),
448 ;                   char "\" as first one initializes rootDir as SearchDir.
449 ;               if file found, if not already open and if free handle...
450 ;                   ...open the file as read and return the handle in CurrentHdl.
451 ;               if the pathname is a directory, change current directory, no handle is set.
452 ;               if an error is encountered, no handle is set, an error message is displayed.
453
454 ; ----------------------------------;
455 Open_File                           ; --
456 ; ----------------------------------;
457     SUB     #2,PSP                  ;
458     MOV     TOS,0(PSP)              ;
459     MOV     W,TOS                   ; -- Open_type (0=LOAD", 1=READ", 2=WRITE", 4=DEL")
460     CMP     #0,&STATE               ;
461     JZ      OPEN_EXEC               ;
462 OPEN_COMP                           ;
463     mDOCOL                          ; if compile state
464     .word   lit,lit,COMMA,COMMA     ; compile open_type as literal
465     .word   SQUOTE                  ; compile string_exec + string
466     .word   lit,SQUOTE2HERE,COMMA   ; compile move in-line string to a counted string at HERE 
467     .word   lit,ParenOpen,COMMA     ; compile (OPEN)
468     .word   EXIT    
469
470 OPEN_EXEC                           ;
471     mDOCOL                          ; if exec state
472     .word   lit,34,WORDD            ; -- open_type HERE
473     FORTHtoASM                      ;
474     MOV     @RSP+,IP                ;
475 ; ----------------------------------;
476 ParenOpen                           ; open_type HERE --
477 ; ----------------------------------;
478     SUB     #2,PSP                  ; make room for DIRsector
479 ; ----------------------------------;
480 OPN_CountedToStringZ                ;
481 ; ----------------------------------;
482     MOV.B   @TOS+,Y                 ; Y=count, TOS = HERE+1
483     ADD     TOS,Y                   ; Y = end of counted string      
484     MOV.B   #0,0(Y)                 ; open_type address_of_stringZ --
485 ; ----------------------------------;
486 OPN_PathName                        ;
487 ; ----------------------------------;
488     MOV     #1,S                    ; error 1
489     MOV     &DIRClusterL,&ClusterL  ;
490     MOV     &DIRclusterH,&ClusterH  ;
491     CMP.B   #0,0(TOS)               ; first char = 0 ? 
492     JZ      OPN_NoPathName          ; error 1 ===>
493     CMP.B   #':',1(TOS)             ; A: B: C: ... in pathname ?
494     JNZ     OPN_AntiSlashStartTest  ; no
495     ADD     #2,TOS                  ; yes : skip drive because not used, only one SD_card
496 OPN_AntiSlashStartTest              ;
497     CMP.B   #5Ch,0(TOS)             ; "\" as first char ?
498     JNZ     OPN_SearchDirSector     ; no
499     ADD     #1,TOS                  ; yes : skip '\' char
500     MOV     &FATtype,&ClusterL      ;       FATtype = 1 as FAT16 RootDIR, FATtype = 2 = FAT32RootDIR
501     MOV     #0,&ClusterH            ;
502 ; ----------------------------------;
503 OPN_EndOfDIRstringZtest             ; <=== dir found in path
504 ; ----------------------------------;
505     CMP.B   #0,0(TOS)               ;   End of pathname ?
506     JZ      OPN_SetCurrentDIR       ; yes
507 ; ----------------------------------;
508 OPN_SearchDirSector                 ;
509 ; ----------------------------------;
510     MOV     TOS,&Pathname           ; save name addr
511     CALL    #ComputeClusFrstSect    ; output: SectorHL
512     MOV     #32,0(PSP)              ; preset countdown for FAT16 RootDIR sectors
513     CMP     #2,&FATtype             ; FAT32?
514     JZ      OPN_SetDirSectors       ; yes
515     CMP     &ClusterL,&FATtype      ; FAT16 AND RootDIR ?
516     JZ      OPN_LoadSectorDir       ; yes
517 OPN_SetDirSectors                   ;
518     MOV     &SecPerClus,0(PSP)      ;
519 ; ----------------------------------;
520 OPN_LoadSectorDir                   ; <=== Dir Sector loopback
521 ; ----------------------------------;
522     CALL    #ReadSector             ;SWX
523 ; ----------------------------------;
524     MOV     #2,S                    ; prepare no such file error
525     MOV     #0,W                    ; init entries count
526 ; ----------------------------------;
527 OPN_SearchEntryInSector             ; <=== DIR Entry loopback
528 ; ----------------------------------;
529     MOV     W,Y                     ; 1
530     .word   0E58h                   ; 5 RLAM #4,Y --> * 16
531     ADD     Y,Y                     ; 1           --> * 2
532     MOV     Y,&EntryOfst            ; EntryOfst points to first free entry
533     CMP.B   #0,BUFFER(Y)            ; free entry ? (end of entries in DIR)
534     JZ      OPN_NoSuchFile          ; error 2 NoSuchFile, used by create ===>
535     MOV     #8,X                    ; count of chars in entry name
536 OPN_CompareName8chars               ;
537     CMP.B   @TOS+,BUFFER(Y)         ; compare Pathname(char) with DirEntry(char)
538     JNZ     OPN_FirstCharMismatch   ;
539     ADD     #1,Y                    ;
540     SUB     #1,X                    ;
541     JNZ     OPN_CompareName8chars   ; loopback if chars 1 to 7 of stringZ and DirEntry are equal
542     ADD     #1,TOS                  ; 9th char of Pathname is always a dot
543 ; ----------------------------------;
544 OPN_FirstCharMismatch               ;
545     CMP.B   #'.',-1(TOS)            ; FirstNotEqualChar of Pathname = dot ?
546     JZ      OPN_DotFound            ;
547 ; ----------------------------------;
548 OPN_DotNotFound                     ; 
549 ; ----------------------------------;
550     ADD     #3,X                    ; for next cases not equal chars of entry until 11 must be spaces
551     CALL #ParseEntryNameSpaces      ; for X + 3 chars
552     JNZ     OPN_EntryMismatch       ; if a char entry <> space  
553 OPN_AntiSlashTest                   ;
554     CMP.B   #5Ch,-1(TOS)            ; FirstNotEqualChar of Pathname = "\" ?
555     JZ      OPN_EntryFound          ;
556 OPN_EndOfStringZtest                ;
557     CMP.B   #0,-1(TOS)              ; FirstNotEqualChar of Pathname =  0  ?
558     JZ      OPN_EntryFound          ;
559 ; ----------------------------------;
560 OPN_EntryMismatch                   ;
561 ; ----------------------------------;
562     MOV     &pathname,TOS           ; reload Pathname
563     ADD     #1,W                    ; inc entry
564     CMP     #16,W                   ; 16 entry in a sector
565     JNZ     OPN_SearchEntryInSector ; ===> loopback for search same sector next entry
566 ; ----------------------------------;
567     ADD     #1,&SectorL             ;
568     ADDC    #0,&SectorH             ;
569     SUB     #1,0(PSP)               ; dec count of Dir sectors
570     JNZ     OPN_LoadSectorDir       ; ===> loopback for next DIR sector
571 ; ----------------------------------;
572     MOV     #4,S                    ;
573     JMP     OPN_EndOfDIR            ; error 4 ===> 
574 ; ----------------------------------;
575
576 ; ----------------------------------;
577 OPN_DotFound                        ; not equal chars of entry name until 8 must be spaces
578 ; ----------------------------------;
579     CMP.B   #'.',-2(TOS)            ; LastCharEqual = dot ?
580     JZ      OPN_EntryMismatch       ; case of first DIR entry = "." and Pathname = "..\" 
581     CALL    #ParseEntryNameSpaces   ; parse X spaces, X{0,...,7}
582     JNZ     OPN_EntryMismatch       ; if a char entry <> space
583     MOV     #3,X                    ;
584 OPN_CompareExtChars                 ;
585     CMP.B   @TOS+,BUFFER(Y)         ; compare stringZ(char) with DirEntry(char)
586     JNZ     OPN_ExtNotEqualChar     ;
587     ADD     #1,Y                    ;
588     SUB     #1,X                    ;
589     JNZ     OPN_CompareExtChars     ; nothing to do if chars equal
590     JMP     OPN_EntryFound          ;
591 OPN_ExtNotEqualChar                 ;
592     CMP.B   #0,-1(TOS)              ;
593     JNZ     OPN_EntryMismatch       ;     
594     CMP.B   #5Ch,-1(TOS)            ; FirstNotEqualChar = "\" ?
595     JNZ     OPN_EntryMismatch       ;
596     CALL    #ParseEntryNameSpaces   ; parse X spaces, X{0,...,3}
597     JNZ     OPN_EntryMismatch       ; if a char entry <> space
598 ; ----------------------------------;
599 OPN_EntryFound                      ; Y points on the file attribute (11th byte of entry)
600 ; ----------------------------------;
601     MOV     &EntryOfst,Y            ; reload DIRentry
602     MOV     BUFFER+26(Y),&ClusterL  ; first clusterL of file
603     MOV     BUFFER+20(Y),&ClusterH  ; first clusterT of file, always 0 if FAT16
604 OPN_EntryFoundNext
605     BIT.B   #10h,BUFFER+11(Y)       ; test if Directory or File
606     JZ      OPN_FileFound           ;
607 ; ----------------------------------;
608 OPN_DIRfound                        ; entry is a DIRECTORY
609 ; ----------------------------------;
610     CMP     #0,&ClusterH            ; case of ".." entry, when parent directory is root
611     JNZ     OPN_DIRfoundNext        ;
612     CMP     #0,&ClusterL            ; case of ".." entry, when parent directory is root
613     JNZ     OPN_DIRfoundNext        ;
614     MOV     &FATtype,&ClusterL      ; set cluster as RootDIR cluster
615 OPN_DIRfoundNext                    ;
616     CMP.B   #0,-1(TOS)              ; FirstNotEqualChar =  0  ?
617     JNZ     OPN_EndOfDIRstringZtest ; no : FirstNotEqualChar = "\"
618 ; ----------------------------------;
619 OPN_SetCurrentDIR                   ; -- open_type DIRsector ptr
620 ; ----------------------------------;
621     MOV     &ClusterL,&DIRClusterL  ;
622     MOV     &ClusterH,&DIRclusterH  ;
623     ADD     #4,PSP                  ; -- ptr
624     MOV     @PSP+,TOS               ; --
625     MOV     @RSP+,IP                ;
626     mNEXT                           ; happy end
627 ; ----------------------------------;
628 OPN_FileFound                       ; -- open_type DIRsector ptr
629 ; ----------------------------------;
630     MOV     2(PSP),W                
631     CALL    #GetFreeHandle          ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
632 ; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
633 OPN_NomoreHandle                    ; S = error 16
634 OPN_alreadyOpen                     ; S = error 8
635 OPN_EndOfDIR                        ; S = error 4
636 OPN_NoSuchFile                      ; S = error 2
637 OPN_NoPathName                      ; S = error 1
638     ADD     #2,PSP                  ; -- open_type ptr
639     MOV     @PSP+,W                 ; -- ptr            W = open_type
640     MOV     @PSP+,TOS               ; --
641 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
642
643
644 ; ======================================================================
645 ; LOAD" primitive as part of Open_File
646 ; input from open:  S = OpenError, W = open_type, SectorHL = DIRsectorHL,
647 ;                   Buffer = [DIRsector], ClusterHL = FirstClusterHL
648 ;       from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
649 ; output: nothing else abort on error
650 ; ======================================================================
651     
652 ; ----------------------------------;
653     .IFDEF SD_CARD_READ_WRITE       ;
654     CMP.B   #-1,W                   ; open_type = LOAD"
655     JNZ     OPEN_QREAD              ; next step
656     .ENDIF                          ;
657 ; ----------------------------------; here W is free
658 OPEN_LOAD                           ;
659 ; ----------------------------------;
660     CMP     #0,S                    ; open file happy end ?
661     JNZ     OPEN_Error              ; no
662 ; ----------------------------------;
663     MOV     #NEXT,&YEMIT            ; set NOECHO, as does TERATERM before sending a file to the target. 
664 ; ----------------------------------;
665     mNEXT
666 ; ----------------------------------;
667
668
669
670 ; ----------------------------------;
671 OPEN_Error                          ; S= error
672 ; ----------------------------------;
673 ; Error 1  : PathNameNotFound       ; S = error 1
674 ; Error 2  : NoSuchFile             ; S = error 2
675 ; Error 4  : DIRisFull              ; S = error 4
676 ; Error 8  : alreadyOpen            ; S = error 8
677 ; Error 16 : NomoreHandle           ; S = error 16
678 ; ----------------------------------;
679     mDOCOL                          ; set ECHO, type Pathname, type #error, type "< OpenError"; no return
680     .word   XSQUOTE                 ;
681     .byte   11,"< OpenError"        ;
682 SD_ERROR
683     .word   ECHO                    ;
684     .word   HERE,COUNT,TYPE,SPACE   ;
685     .word   BRAN,SD_QABORTYES       ; to insert S error as flag, no return
686 ; ----------------------------------;
687
688
689
690
691
692
693