OSDN Git Service

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