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 @PSP+,X ; X = src
27 MOV &DDP,Y ; Y = dst = HERE
28 MOV.B TOS,W ; W = count
30 MOV.B W,0(Y) ; count at HERE
36 ; rules for registers use
38 ; T = CurrentHdl, pathname
39 ; W = SectorL, (RTC) TIME
40 ; X = SectorH, (RTC) DATE
41 ; Y = BufferPtr, (DIR) EntryOfst, FAToffset
44 ; ----------------------------------;
45 HDLCurClusToFAT1sectWofstY ;WXY Input: HDL_CurCluster, Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
46 ; ----------------------------------;
47 MOV HDLL_CurClust(T),&ClusterL ;
48 MOV HDLH_CurClust(T),&ClusterH ;
49 ; ----------------------------------;
50 ClusterToFAT1sectWofstY ;WXY Input : Cluster ; Output: W = FATsector, Y = FAToffset
51 ; ----------------------------------;
52 MOV.B &ClusterL+1,W ;3 W = ClusterLoHI
53 MOV.B &ClusterL,Y ;3 Y = ClusterLoLo
54 CMP #2,&FATtype ;3 FAT32?
55 JZ ClusterToFAT32sector ;2 yes
56 ADD Y,Y ;1 Y = ClusterLoLo << 1
61 ; input : Cluster n, max = 7FFFFF ==> SDcard up to 256 GB
62 ; ClusterLoLo*4 = displacement in 512 bytes sector ==> FAToffset
63 ; ClusterHiLo&ClusterLoHi +C << 1 = relative FATsector + orgFAT1 ==> FATsector
64 ; ----------------------------------;
65 ClusterToFAT32sector ; Input : Cluster ; Output: W=FATsector, Y=FAToffset
66 ; ----------------------------------;
67 MOV.B &ClusterH,X ; X = 0:ClusterHiLo
68 SWPB X ; X = ClusterHiLo:0
69 ADD X,W ; W = ClusterHiLo:ClusterLoHi
70 ; ----------------------------------;
71 SWPB Y ; Y = ClusterLoLo:0
72 ADD Y,Y ;1 Y = ClusterLoLo:0 * 2 + carry for FATsector
73 ADDC W,W ; W = ClusterHiLo:ClusterLoHi * 2 = ClusterHiLo:ClusterL / 128
75 ADD Y,Y ; Y = 0:ClusterLoLo * 4
77 ; ----------------------------------;
81 ; ----------------------------------; Input : Cluster
82 ComputeClusFrstSect ; If Cluster = 1 ==> RootDirectory ==> SectorL = OrgRootDir
83 ; ----------------------------------; Output: SectorL of Cluster
85 MOV &OrgRootDir,&SectorL ;
86 CMP #1,&ClusterL ; clusterL = 1 ? (FAT16 specificity)
87 JNE CCFS_AllOtherCLuster ; no
88 CMP.B #0,&ClusterH ; clusterT = 0 ?
89 JZ OpenSubRET ; yes, sectorL for FAT16 OrgRootDIR is done
90 CCFS_AllOtherCLuster ;
91 MOV &OrgClusters,&RES0 ; OrgClusters = sector of virtual cluster 0, word size
93 MOV &ClusterL,&MAC32L ;3
94 MOV &ClusterH,&MAC32H ;3
95 MOV &SecPerClus,&OP2 ;
99 ; ----------------------------------;
101 ; ----------------------------------;
102 ComputeHDLcurrentSector ;
103 ; ----------------------------------;
104 MOV HDLL_CurClust(T),&ClusterL;
105 MOV HDLH_CurClust(T),&ClusterH;
106 CALL #ComputeClusFrstSect ;
107 MOV.B HDLB_ClustOfst(T),W ;
111 ; ----------------------------------;
116 ; ----------------------------------; input : X = countdown_of_spaces, Y = name pointer in buffer
117 ParseEntryNameSpaces ;XY
118 ; ----------------------------------; output: Z flag, Y is set after the last space char
121 ; ----------------------------------; input : X = countdown_of_spaces, Y = name pointer in buffer
122 ParseEntryNameSpacesLoop ; here X must be > 0
123 ; ----------------------------------; output: Z flag, Y is set after the last space char
124 CMP.B #32,BUFFER(Y) ; SPACE ?
125 JNZ OpenSubRET ; no: RET
128 JNZ ParseEntryNameSpacesLoop;
130 ; ----------------------------------;
133 ; sequentially load in BUFFER bytsPerSec bytes of a file opened as read or as load
134 ; if previous bufferLen had a size < bytsPerSec, closes the file.
135 ; if new bufferLen have a size <= BufferPtr, closes the file.
136 ; reload previous LOADed file if exist.
137 ; HDLL_CurSize leaves the not yet read size
138 ; All used registers must be initialized.
139 ; ==================================;
140 Read_File ; <== SD_ACCEPT, READ
141 ; ==================================;
143 MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
144 CMP #bytsPerSec,&BufferLen ;
145 JNZ CloseHandleT ; because this last and incomplete sector is already read
146 SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
147 SUBC #0,HDLH_CurSize(T) ;
148 ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
149 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
150 JLO SetBufLenAndLoadCurSector ; no
151 ; ----------------------------------;
152 ;SearchNextCluster ; yes
153 ; ----------------------------------;
154 MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
155 CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
156 CALL #ReadFAT1SectorW ;SWX (< 65536)
157 MOV #0,HDLH_CurClust(T) ;
158 MOV BUFFER(Y),HDLL_CurClust(T) ;
159 CMP #1,&FATtype ; FAT16?
160 JZ SetBufLenAndLoadCurSector ;
161 MOV BUFFER+2(Y),HDLH_CurClust(T);
162 ; ==================================;
163 SetBufLenAndLoadCurSector ;WXY <== previous handle reLOAD
164 ; ==================================;
166 ; ----------------------------------;
167 MOV #bytsPerSec,&BufferLen ; preset BufferLen
168 CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
169 JNZ LoadHDLcurrentSector ; yes
170 CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedFileContext)
171 JHS CloseHandleT ; yes
172 CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
173 JHS LoadHDLcurrentSector ; yes
174 MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
175 ; ==================================;
176 LoadHDLcurrentSector ; <=== OPEN_WRITE_APPEND
177 ; ==================================;
178 CALL #ComputeHDLcurrentSector ; use no registers
179 ; ==================================;
181 ; ==================================;
183 MOV &SectorH,X ; High
184 JMP ReadSectorWX ; then RET
185 ; ----------------------------------;
188 ; if first open_load token, save DefaultInputStream
189 ; if other open_load token, decrement token, save previous context
192 ; Input : EntryOfst, Cluster = EntryOfst(HDLL_FirstClus())
193 ; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
194 ; Output: Cluster = first Cluster of file, X = CurrentHdl
195 ; ----------------------------------; input : Cluster, EntryOfst
196 GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
197 ; ----------------------------------; output : T = new CurrentHdl
198 MOV #8,S ; prepare file already open error
200 MOV #0,X ; X = previous handle, init = 0
201 ; ----------------------------------;
203 ; ----------------------------------;
204 CMP.B #0,HDLB_Token(T) ; free handle ?
205 JZ FreeHandleFound ; yes
207 CMP &ClusterH,HDLH_FirstClus(T);
208 JNE SearchNextHandle ;
209 CMP &ClusterL,HDLL_FirstClus(T);
210 JZ InitHandleRET ; error 8: Already Open abort ===>
212 MOV T,X ; handle is occupied, keep it in X as previous handle
213 ADD #HandleLenght,T ;
215 JNZ SearchHandleLoop ;
216 ; ----------------------------------;
217 ADD S,S ; 16 = no more handle error, abort ===>
220 ; ----------------------------------;
221 FreeHandleFound ; T = new handle, X = previous handle
222 ; ----------------------------------;
223 MOV #0,S ; prepare HappyEnd
225 MOV X,HDLW_PrevHDL(T) ; link to previous handle
226 ; ----------------------------------;
227 CheckCaseOfLoadFileToken ;
228 ; ----------------------------------;
229 CMP.B #0,W ; open_type is LOAD?
230 JGE InitHandle ; W>0, no
231 CMP.B #0,X ; existing previous handle?
233 CMP.B #0,HDLB_Token(X) ; previous token is negative? (open_load type)
235 ADD.B HDLB_Token(X),W ; LOAD token = previous LOAD token -1
236 ; ----------------------------------;
238 ; ----------------------------------;
239 MOV.B W,HDLB_Token(T) ; marks handle as open type
240 MOV.B #0,HDLB_ClustOfst(T) ; clear ClustOfst
241 MOV &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
242 MOV &SectorH,HDLH_DIRsect(T);
244 MOV Y,HDLW_DIRofst(T) ; init handle BUFFER offset of DIR entry
245 MOV BUFFER+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
246 MOV BUFFER+20(Y),HDLH_FirstClus(T)
247 MOV BUFFER+26(Y),HDLL_CurClust(T) ; init handle CurrentCluster
248 MOV BUFFER+20(Y),HDLH_CurClust(T)
249 MOV BUFFER+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
250 MOV BUFFER+30(Y),HDLH_CurSize(T);
251 MOV #0,&BufferPtr ; reset BufferPtr all type of files
252 CMP.B #2,W ; is a WRITE file handle?
253 JZ ComputeHDLcurrentSector ; = 2, is a WRITE file
254 JGE InitHandleRET ; > 2, is a file to be deleted
255 MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD file
256 ; ----------------------------------;
258 ; ----------------------------------;
259 CMP.B #-1,W ; is the first loaded file?
260 JZ FirstLoadFileHandle ; = -1, is the first LOADed file
261 JGE SetBufLenAndLoadCurSector ; > -1, is a READ file
262 ADD &TOIN,HDLW_BUFofst(X) ; < -1, is not the first LOADed file: in previous handle, add interpret offset to Buffer offset
263 JMP SetBufLenAndLoadCurSector ; thus, the return to this previous LOADed file will be on next char after current LOAD" cmd.
264 ; ----------------------------------;
265 FirstLoadFileHandle ;
266 ; ----------------------------------;
267 MOV &SOURCE_LEN,&SAVEtsLEN ;
268 SUB &TOIN,&SAVEtsLEN ; save remaining lenght
269 MOV &SOURCE_ADR,&SAVEtsPTR ;
270 ADD &TOIN,&SAVEtsPTR ; save new input org address
271 MOV #SD_ACCEPT,&ACCEPT+2 ; redirect ACCEPT to SD_ACCEPT
272 MOV &SOURCE_LEN,&TOIN ; to quit interpret (same as BACKSLASH)
273 JMP SetBufLenAndLoadCurSector ;
274 ;; ----------------------------------;
275 ;FirstLoadFileHandle ;
276 ;; ----------------------------------;
277 ; SUB &TOIN,&SOURCE_LEN ;
278 ; ADD &TOIN,&SOURCE_ADR ;
279 ; MOV #SD_ACCEPT,&ACCEPT+2 ; redirect ACCEPT to SD_ACCEPT
280 ; MOV &SOURCE_LEN,&TOIN ; to quit interpret (same as BACKSLASH)
281 ; JMP SetBufLenAndLoadCurSector ;
282 ; ----------------------------------;
286 ; If closed token = -1, restore DefaultInputStream
287 ; if closed token < -1, restore previous context
288 ; ==================================;
289 CloseHandleT ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
290 ; ==================================;
292 MOV #0,&BufferLen ; to inform the user that file is closed
293 CMP #0,T ; no handle?
294 JZ InitHandleRET ; RET
295 ; ----------------------------------;
296 .IFDEF SD_CARD_READ_WRITE
297 CMP.B #2,HDLB_Token(T) ; updated file ?
298 JNZ CloseHandleHere ; no
299 CALL #WriteBuffer ;SWXY
300 CALL #OPWW_UpdateDirectory ;SWXY
302 ; ----------------------------------;
304 ; ----------------------------------;
305 MOV.B HDLB_Token(T),W ; to test W=token below
306 MOV.B #0,HDLB_Token(T) ; close handle
307 ; ----------------------------------;
308 MOV @T,T ; T = previous handle
309 MOV T,&CurrentHdl ; becomes current handle
310 ; ----------------------------------;
311 CheckCaseOfClosedLoadedFile ;
312 ; ----------------------------------;
314 JZ LastFileLoadClosed ; W=0, this closed LOADed file had not a paren
315 JGE InitHandleRET ; W>0, for READ, WRITE, DEL files
316 ; ----------------------------------;
317 RestorePreviousLoadedFileContext ; W<0, this closed LOADed file had a paren
318 ; ----------------------------------;
319 MOV HDLW_BUFofst(T),&BufferPtr ; restore BufferPtr saved by SD_ACCEPT before interpreting LOAD cmd line
320 JMP SetBufLenAndLoadCurSector ;
321 ; ----------------------------------;
323 ; ----------------------------------;
324 RestoreDefaultInputStream ; it was the first LOADed filre
325 MOV &SAVEtsLEN,TOS ; restore lenght
326 MOV &SAVEtsPTR,2(PSP) ; restore pointer for interpret
327 MOV #PARENACCEPT,&ACCEPT+2 ; restore (ACCEPT)
328 JMP InitHandleRET ; RET
329 ; ----------------------------------;
330 ;RestoreDefaultInputStream ; it was the first LOADed filre
331 ; MOV &SOURCE_LEN,TOS ; restore lenght
332 ; MOV &SOURCE_ADR,2(PSP) ; restore pointer for interpret
333 ; MOV #0,&TOIN ; reset interpret ptr
334 ; MOV #PARENACCEPT,&ACCEPT+2 ; restore (ACCEPT)
335 ; JMP InitHandleRET ; RET
336 ; ----------------------------------;
339 .IFDEF SD_CARD_READ_WRITE
341 ;-----------------------------------------------------------------------
342 ; SD_READ_WRITE FORTH words
343 ;-----------------------------------------------------------------------
346 ; parse string until " is encountered, convert counted string in StringZ
347 ; then parse stringZ until char '0'.
348 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
349 ; char "\" as first one initializes rootDir as SearchDir.
350 ; if file found, if not already open and if free handle...
351 ; ...open the file as read and return the handle in CurrentHdl.
352 ; then load first sector in buffer, bufferLen and bufferPtr are ready for read
353 ; currentHdl keep handle that is flagged as "read".
355 ; to read sequentially next sectors use READ word. A flag is returned : true if file is closed.
356 ; the last sector so is in buffer.
358 ; if pathname is a directory, change current directory.
359 ; if an error is encountered, no handle is set, error message is displayed.
361 ; READ" acts also as CD dos command :
362 ; - READ" a:\misc\" set a:\misc as current directory
363 ; - READ" a:\" reset current directory to root
364 ; - READ" ..\" change to parent directory
366 ; to close all files type : WARM (or COLD, RESET)
368 ; ----------------------------------;
369 FORTHWORDIMM "READ\34" ; immediate
370 ; ----------------------------------;
372 MOV.B #1,W ; W = OpenType
374 ; ----------------------------------;
376 ;Z WRITE" pathame" -- immediate
377 ; open or create the file designed by pathname.
378 ; an error occurs if the file is already opened.
379 ; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
380 ; compile state : compile WRITE" pathname"
381 ; exec state : open or create entry selected by pathname
382 ; ----------------------------------;
383 FORTHWORDIMM "WRITE\34" ; immediate
384 ; ----------------------------------;
386 MOV.B #2,W ; W = OpenType
388 ; ----------------------------------;
391 ;Z DEL" pathame" -- immediate
392 ; compile state : compile DEL" pathname"
393 ; exec state : DELETE entry selected by pathname
395 ; ----------------------------------;
396 FORTHWORDIMM "DEL\34" ; immediate
397 ; ----------------------------------;
399 MOV.B #4,W ; W = OpenType
401 ; ----------------------------------;
404 .ENDIF ; SD_CARD_READ_WRITE
406 ;-----------------------------------------------------------------------
407 ; SD_CARD_LOADER FORTH word
408 ;-----------------------------------------------------------------------
411 ; close current handle
412 ; ----------------------------------;
414 ; ----------------------------------;
417 ; ----------------------------------;
419 ;Z LOAD" pathame" -- immediate
420 ; compile state : compile LOAD" pathname"
421 ; exec state : open a file from SD card via its pathname
422 ; see Open_File primitive for pathname conventions
423 ; the opened file becomes the new input stream for INTERPRET
424 ; this command is recursive, limited only by the count of free handles (up to 8)
426 ; LOAD" acts also as dos command "CD" :
427 ; - LOAD" \misc\" set a:\misc as current directory
428 ; - LOAD" \" reset current directory to root
429 ; - LOAD" ..\" change to parent directory
431 ; ----------------------------------;
432 FORTHWORDIMM "LOAD\34" ; immediate
433 ; ----------------------------------;
434 MOV.B #-1,W ; W = OpenType
435 ; ----------------------------------;
438 ; ======================================================================
439 ; OPEN FILE primitive
440 ; ======================================================================
442 ; primitive for LOAD" READ" CREATE" WRITE" DEL"
443 ; store OpenType on TOS,
444 ; compile state : compile OpenType, compile SQUOTE and the string of provided pathname
445 ; exec state : open a file from SD card via its pathname
446 ; convert counted string found at HERE in a StringZ then parse it
447 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
448 ; char "\" as first one initializes rootDir as SearchDir.
449 ; if file found, if not already open and if free handle...
450 ; ...open the file as read and return the handle in CurrentHdl.
451 ; if the pathname is a directory, change current directory, no handle is set.
452 ; if an error is encountered, no handle is set, an error message is displayed.
454 ; ----------------------------------;
456 ; ----------------------------------;
459 MOV W,TOS ; -- Open_type (0=LOAD", 1=READ", 2=WRITE", 4=DEL")
463 mDOCOL ; if compile state
464 .word lit,lit,COMMA,COMMA ; compile open_type as literal
465 .word SQUOTE ; compile string_exec + string
466 .word lit,SQUOTE2HERE,COMMA ; compile move in-line string to a counted string at HERE
467 .word lit,ParenOpen,COMMA ; compile (OPEN)
471 mDOCOL ; if exec state
472 .word lit,34,WORDD ; -- open_type HERE
475 ; ----------------------------------;
476 ParenOpen ; open_type HERE --
477 ; ----------------------------------;
478 SUB #2,PSP ; make room for DIRsector
479 ; ----------------------------------;
480 OPN_CountedToStringZ ;
481 ; ----------------------------------;
482 MOV.B @TOS+,Y ; Y=count, TOS = HERE+1
483 ADD TOS,Y ; Y = end of counted string
484 MOV.B #0,0(Y) ; open_type address_of_stringZ --
485 ; ----------------------------------;
487 ; ----------------------------------;
489 MOV &DIRClusterL,&ClusterL ;
490 MOV &DIRclusterH,&ClusterH ;
491 CMP.B #0,0(TOS) ; first char = 0 ?
492 JZ OPN_NoPathName ; error 1 ===>
493 CMP.B #':',1(TOS) ; A: B: C: ... in pathname ?
494 JNZ OPN_AntiSlashStartTest ; no
495 ADD #2,TOS ; yes : skip drive because not used, only one SD_card
496 OPN_AntiSlashStartTest ;
497 CMP.B #5Ch,0(TOS) ; "\" as first char ?
498 JNZ OPN_SearchDirSector ; no
499 ADD #1,TOS ; yes : skip '\' char
500 MOV &FATtype,&ClusterL ; FATtype = 1 as FAT16 RootDIR, FATtype = 2 = FAT32RootDIR
502 ; ----------------------------------;
503 OPN_EndOfDIRstringZtest ; <=== dir found in path
504 ; ----------------------------------;
505 CMP.B #0,0(TOS) ; End of pathname ?
506 JZ OPN_SetCurrentDIR ; yes
507 ; ----------------------------------;
508 OPN_SearchDirSector ;
509 ; ----------------------------------;
510 MOV TOS,&Pathname ; save name addr
511 CALL #ComputeClusFrstSect ; output: SectorHL
512 MOV #32,0(PSP) ; preset countdown for FAT16 RootDIR sectors
513 CMP #2,&FATtype ; FAT32?
514 JZ OPN_SetDirSectors ; yes
515 CMP &ClusterL,&FATtype ; FAT16 AND RootDIR ?
516 JZ OPN_LoadSectorDir ; yes
518 MOV &SecPerClus,0(PSP) ;
519 ; ----------------------------------;
520 OPN_LoadSectorDir ; <=== Dir Sector loopback
521 ; ----------------------------------;
522 CALL #ReadSector ;SWX
523 ; ----------------------------------;
524 MOV #2,S ; prepare no such file error
525 MOV #0,W ; init entries count
526 ; ----------------------------------;
527 OPN_SearchEntryInSector ; <=== DIR Entry loopback
528 ; ----------------------------------;
530 .word 0E58h ; 5 RLAM #4,Y --> * 16
532 MOV Y,&EntryOfst ; EntryOfst points to first free entry
533 CMP.B #0,BUFFER(Y) ; free entry ? (end of entries in DIR)
534 JZ OPN_NoSuchFile ; error 2 NoSuchFile, used by create ===>
535 MOV #8,X ; count of chars in entry name
536 OPN_CompareName8chars ;
537 CMP.B @TOS+,BUFFER(Y) ; compare Pathname(char) with DirEntry(char)
538 JNZ OPN_FirstCharMismatch ;
541 JNZ OPN_CompareName8chars ; loopback if chars 1 to 7 of stringZ and DirEntry are equal
542 ADD #1,TOS ; 9th char of Pathname is always a dot
543 ; ----------------------------------;
544 OPN_FirstCharMismatch ;
545 CMP.B #'.',-1(TOS) ; FirstNotEqualChar of Pathname = dot ?
547 ; ----------------------------------;
549 ; ----------------------------------;
550 ADD #3,X ; for next cases not equal chars of entry until 11 must be spaces
551 CALL #ParseEntryNameSpaces ; for X + 3 chars
552 JNZ OPN_EntryMismatch ; if a char entry <> space
554 CMP.B #5Ch,-1(TOS) ; FirstNotEqualChar of Pathname = "\" ?
556 OPN_EndOfStringZtest ;
557 CMP.B #0,-1(TOS) ; FirstNotEqualChar of Pathname = 0 ?
559 ; ----------------------------------;
561 ; ----------------------------------;
562 MOV &pathname,TOS ; reload Pathname
564 CMP #16,W ; 16 entry in a sector
565 JNZ OPN_SearchEntryInSector ; ===> loopback for search same sector next entry
566 ; ----------------------------------;
569 SUB #1,0(PSP) ; dec count of Dir sectors
570 JNZ OPN_LoadSectorDir ; ===> loopback for next DIR sector
571 ; ----------------------------------;
573 JMP OPN_EndOfDIR ; error 4 ===>
574 ; ----------------------------------;
576 ; ----------------------------------;
577 OPN_DotFound ; not equal chars of entry name until 8 must be spaces
578 ; ----------------------------------;
579 CMP.B #'.',-2(TOS) ; LastCharEqual = dot ?
580 JZ OPN_EntryMismatch ; case of first DIR entry = "." and Pathname = "..\"
581 CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,7}
582 JNZ OPN_EntryMismatch ; if a char entry <> space
584 OPN_CompareExtChars ;
585 CMP.B @TOS+,BUFFER(Y) ; compare stringZ(char) with DirEntry(char)
586 JNZ OPN_ExtNotEqualChar ;
589 JNZ OPN_CompareExtChars ; nothing to do if chars equal
591 OPN_ExtNotEqualChar ;
593 JNZ OPN_EntryMismatch ;
594 CMP.B #5Ch,-1(TOS) ; FirstNotEqualChar = "\" ?
595 JNZ OPN_EntryMismatch ;
596 CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,3}
597 JNZ OPN_EntryMismatch ; if a char entry <> space
598 ; ----------------------------------;
599 OPN_EntryFound ; Y points on the file attribute (11th byte of entry)
600 ; ----------------------------------;
601 MOV &EntryOfst,Y ; reload DIRentry
602 MOV BUFFER+26(Y),&ClusterL ; first clusterL of file
603 MOV BUFFER+20(Y),&ClusterH ; first clusterT of file, always 0 if FAT16
605 BIT.B #10h,BUFFER+11(Y) ; test if Directory or File
607 ; ----------------------------------;
608 OPN_DIRfound ; entry is a DIRECTORY
609 ; ----------------------------------;
610 CMP #0,&ClusterH ; case of ".." entry, when parent directory is root
611 JNZ OPN_DIRfoundNext ;
612 CMP #0,&ClusterL ; case of ".." entry, when parent directory is root
613 JNZ OPN_DIRfoundNext ;
614 MOV &FATtype,&ClusterL ; set cluster as RootDIR cluster
616 CMP.B #0,-1(TOS) ; FirstNotEqualChar = 0 ?
617 JNZ OPN_EndOfDIRstringZtest ; no : FirstNotEqualChar = "\"
618 ; ----------------------------------;
619 OPN_SetCurrentDIR ; -- open_type DIRsector ptr
620 ; ----------------------------------;
621 MOV &ClusterL,&DIRClusterL ;
622 MOV &ClusterH,&DIRclusterH ;
627 ; ----------------------------------;
628 OPN_FileFound ; -- open_type DIRsector ptr
629 ; ----------------------------------;
631 CALL #GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
632 ; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
633 OPN_NomoreHandle ; S = error 16
634 OPN_alreadyOpen ; S = error 8
635 OPN_EndOfDIR ; S = error 4
636 OPN_NoSuchFile ; S = error 2
637 OPN_NoPathName ; S = error 1
638 ADD #2,PSP ; -- open_type ptr
639 MOV @PSP+,W ; -- ptr W = open_type
641 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
644 ; ======================================================================
645 ; LOAD" primitive as part of Open_File
646 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
647 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
648 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
649 ; output: nothing else abort on error
650 ; ======================================================================
652 ; ----------------------------------;
653 .IFDEF SD_CARD_READ_WRITE ;
654 CMP.B #-1,W ; open_type = LOAD"
655 JNZ OPEN_QREAD ; next step
657 ; ----------------------------------; here W is free
659 ; ----------------------------------;
660 CMP #0,S ; open file happy end ?
662 ; ----------------------------------;
663 MOV #NEXT,&YEMIT ; set NOECHO, as does TERATERM before sending a file to the target.
664 ; ----------------------------------;
666 ; ----------------------------------;
670 ; ----------------------------------;
671 OPEN_Error ; S= error
672 ; ----------------------------------;
673 ; Error 1 : PathNameNotFound ; S = error 1
674 ; Error 2 : NoSuchFile ; S = error 2
675 ; Error 4 : DIRisFull ; S = error 4
676 ; Error 8 : alreadyOpen ; S = error 8
677 ; Error 16 : NomoreHandle ; S = error 16
678 ; ----------------------------------;
679 mDOCOL ; set ECHO, type Pathname, type #error, type "< OpenError"; no return
681 .byte 11,"< OpenError" ;
684 .word HERE,COUNT,TYPE,SPACE ;
685 .word BRAN,SD_QABORTYES ; to insert S error as flag, no return
686 ; ----------------------------------;