1 ; -*- coding: utf-8 -*-
2 ; DTCforthMSP430FRxxxxSD_LOAD.asm
4 ; Tested with MSP-EXP430FR5969 launchpad
5 ; Copyright (C) <2017> <J.M. THOORENS>
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.
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.
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/>.
21 ;-----------------------------------------------------------------------
22 ; SD card OPEN, LOAD subroutines
23 ;-----------------------------------------------------------------------
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
28 MOV &DDP,Y ; Y = dst = HERE
31 ADD #1,W ; W = count+1
34 ; rules for registers use
36 ; T = CurrentHdl, pathname
37 ; W = SectorL, (RTC) TIME
38 ; X = SectorH, (RTC) DATE
39 ; Y = BufferPtr, (DIR) EntryOfst, FAToffset
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?
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
68 ADD Y,Y ; Y = 0:ClusterLoLo << 1
70 ; ----------------------------------;
74 ; ----------------------------------; Input : Cluster, output: Sector = Cluster_first_sector
75 ComputeClusFrstSect ; If Cluster = 1 ==> RootDirectory ==> SectorL = OrgRootDir
76 ; ----------------------------------; Output: SectorL of Cluster
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
84 ; ----------------------------------;
85 .IFDEF MPY ; general case
86 ; ----------------------------------;
87 MOV &ClusterL,&MPY32L ;3
88 MOV &ClusterH,&MPY32H ;3
89 MOV &SecPerClus,&OP2 ;5+3
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
102 ; JC CCFS_NEXT ;2 case of SecPerClus=1
105 ADD X,X ;1 (RLA) shift one left MULTIPLICANDlo16
106 ADDC Y,Y ;1 (RLC) shift one left MULTIPLICANDhi8
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
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
118 ; ----------------------------------;
121 ; ----------------------------------;
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 ;
134 ; ----------------------------------;
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
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
151 JNZ ParseEntryNameSpacesLoop;
154 ; ----------------------------------;
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 ; ==================================;
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 ; ==================================;
203 ; ==================================;
205 MOV &SectorH,X ; High
206 JMP ReadSectorWX ; then RET
207 ; ----------------------------------;
210 ; if first open_load token, save DefaultInputStream
211 ; if other open_load token, decrement token, save previous context
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
222 MOV #0,X ; X = init previous handle as 0
223 ; ----------------------------------;
225 ; ----------------------------------;
226 CMP.B #0,HDLB_Token(T) ; free handle ?
227 JZ FreeHandleFound ; yes
229 CMP &ClusterH,HDLH_FirstClus(T);
230 JNE SearchNextHandle ;
231 CMP &ClusterL,HDLL_FirstClus(T);
232 JZ InitHandleRET ; error 8: Already Open abort ===>
234 MOV T,X ; handle is occupied, keep it in X as previous handle
235 ADD #HandleLenght,T ;
237 JNZ SearchHandleLoop ;
238 ADD S,S ; 16 = no more handle error, abort ===>
241 ; ----------------------------------;
242 FreeHandleFound ; T = new handle, X = previous handle
243 ; ----------------------------------;
244 MOV #0,S ; prepare Happy End (no error)
246 MOV X,HDLW_PrevHDL(T) ; link to previous handle
247 ; ----------------------------------;
248 CheckCaseOfLoadFileToken ;
249 ; ----------------------------------;
250 CMP.B #0,X ; existing previous handle?
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)
257 ADD.B HDLB_Token(X),W ; LOAD token = previous LOAD token -1
258 ; ----------------------------------;
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);
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
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 ; ----------------------------------;
288 MOV W,&SAVEtsLEN ;3 save remaining lenght
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 ; ----------------------------------;
298 JMP SetBufLenAndLoadCurSector ;
299 ; ----------------------------------;
302 ; ==================================;
303 CloseHandleT ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
304 ; ==================================;
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
315 ; ----------------------------------;
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 ; ----------------------------------;
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
353 MOV @X,IP ;2 restore IP as it was when load" file" open
356 ; ----------------------------------;
359 .IFDEF SD_CARD_READ_WRITE
361 ;-----------------------------------------------------------------------
362 ; SD_READ_WRITE FORTH words
363 ;-----------------------------------------------------------------------
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".
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.
378 ; if pathname is a directory, change current directory.
379 ; if an error is encountered, no handle is set, error message is displayed.
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
386 ; to close all files type : WARM (or COLD, RESET)
388 ; ----------------------------------;
389 FORTHWORDIMM "READ\34" ; immediate
390 ; ----------------------------------;
392 MOV.B #1,W ; W = OpenType
394 ; ----------------------------------;
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 ; ----------------------------------;
406 MOV.B #2,W ; W = OpenType
408 ; ----------------------------------;
411 ;Z DEL" pathame" -- immediate
412 ; compile state : compile DEL" pathname"
413 ; exec state : DELETE entry selected by pathname
415 ; ----------------------------------;
416 FORTHWORDIMM "DEL\34" ; immediate
417 ; ----------------------------------;
419 MOV.B #4,W ; W = OpenType
421 ; ----------------------------------;
425 ; close current handle
426 ; ----------------------------------;
428 ; ----------------------------------;
431 ; ----------------------------------;
433 .ENDIF ; SD_CARD_READ_WRITE
435 ;-----------------------------------------------------------------------
436 ; SD_CARD_LOADER FORTH word
437 ;-----------------------------------------------------------------------
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
450 ; ----------------------------------;
451 FORTHWORDIMM "LOAD\34" ; immediate
452 ; ----------------------------------;
453 MOV.B #-1,W ; W = OpenType
454 ; ----------------------------------;
457 ; ======================================================================
458 ; OPEN FILE primitive
459 ; ======================================================================
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 ; ----------------------------------;
474 ; ----------------------------------;
477 MOV W,TOS ; -- Open_type (0=LOAD", 1=READ", 2=WRITE", 4=DEL")
481 mDOCOL ; if compile state
482 .word lit,lit,COMMA,COMMA ; compile open_type as literal
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)
492 mDOCOL ; if exec state
493 .word lit,34,WORDD ; -- open_type HERE
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 ; ----------------------------------;
506 ; ----------------------------------;
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
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
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 ; ----------------------------------;
549 .word 0E58h ; 5 RLAM #4,Y --> * 16
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 ;
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 ?
566 ; ----------------------------------;
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
573 CMP.B #5Ch,-1(TOS) ; FirstNotEqualChar of Pathname = "\" ?
575 OPN_EndOfStringZtest ;
576 CMP.B #0,-1(TOS) ; FirstNotEqualChar of Pathname = 0 ?
578 ; ----------------------------------;
580 ; ----------------------------------;
581 MOV &pathname,TOS ; reload Pathname
583 CMP #16,W ; 16 entry in a sector
584 JNZ OPN_SearchEntryInSector ; ===> loopback for search same sector next entry
585 ; ----------------------------------;
588 SUB #1,rDODOES ; dec count of Dir sectors
589 JNZ OPN_LoadSectorDir ; ===> loopback for next DIR sector
590 ; ----------------------------------;
592 JMP OPN_EndOfDIR ; error 4 ===>
593 ; ----------------------------------;
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
603 OPN_CompareExtChars ;
604 CMP.B @TOS+,BUFFER(Y) ; compare stringZ(char) with DirEntry(char)
605 JNZ OPN_ExtNotEqualChar ;
608 JNZ OPN_CompareExtChars ; nothing to do if chars equal
610 OPN_ExtNotEqualChar ;
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
624 BIT.B #10h,BUFFER+11(Y) ; test if Directory or File
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
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
644 ; ----------------------------------;
645 OPN_FileFound ; -- open_type ptr
646 ; ----------------------------------;
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
656 MOV #xdodoes,rDODOES ; restore rDODOES
657 MOV @PSP+,W ; -- ptr W = open_type
659 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
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 ; ======================================================================
670 ; ----------------------------------;
672 ; ----------------------------------;
674 JZ OPEN_LOAD_END ; nothing to do
675 ; ----------------------------------;
677 ; ----------------------------------;
678 .IFDEF SD_CARD_READ_WRITE ;
679 CMP.B #-1,W ; open_type = LOAD"
680 JNZ OPEN_QREAD ; next step
682 ; ----------------------------------; here W is free
684 ; ----------------------------------;
685 CMP #0,S ; open file happy end ?
687 MOV #INTLOOP,IP ; return to sender (QUIT) to get new line.
690 ; ----------------------------------;
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
703 .byte 11,"< OpenError" ;
706 .word HERE,COUNT,TYPE,SPACE ;
707 .word BRAN,SD_QABORTYES ; to insert S error as flag, no return
708 ; ----------------------------------;