OSDN Git Service

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