1 ; -*- coding: utf-8 -*-
2 ; forthMSP430FR_SD_LOAD.asm
4 ; Tested with MSP-EXP430FR5994 launchpad
5 ; Copyright (C) <2019> <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 ; used variables : BufferPtr, BufferLen
23 ;-----------------------------------------------------------------------
24 ; SD card OPEN, LOAD subroutines
25 ;-----------------------------------------------------------------------
27 ; rules for registers use
29 ; T = CurrentHdl, pathname
30 ; W = SectorL, (RTC) TIME
31 ; X = SectorH, (RTC) DATE
32 ; Y = BufferPtr, (DIR) DIREntryOfst
35 ; ==================================;
36 HDLcurClus2FATsecWofstY ;WXY Input: T=Handle, HDL_CurClustHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
37 ; ==================================;
38 MOV HDLL_CurClust(T),&ClusterL ;
39 MOV HDLH_CurClust(T),&ClusterH ;
40 ; ==================================;
41 ClusterHLtoFAT1sectWofstY ;WXY Input : ClusterHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
42 ; ==================================;
43 MOV.B &ClusterL+1,W ;3 W = ClusterLoHI
44 MOV.B &ClusterL,Y ;3 Y = ClusterLOlo
45 ; input : Cluster n, max = 7FFFFF (SDcard up to 256 GB)
46 ; ClusterLoLo*4 = displacement in 512 bytes sector ==> FAToffset
47 ; ClusterHiLo&ClusterLoHi +C << 1 = relative FATsector + orgFAT1 ==> FATsector
48 ; ----------------------------------;
49 MOV.B &ClusterH,X ; X = 0:ClusterHIlo
50 SWPB X ; X = ClusterHIlo:0
51 BIS X,W ; W = ClusterHIlo:ClusterLOhi
52 ; ----------------------------------;
53 SWPB Y ; Y = ClusterLOlo:0
54 ADD Y,Y ;1 Y = ClusterLOlo:0 << 1 (+ carry for FATsector)
55 ADDC W,W ; FATsector = W = ClusterHIlo:ClusterLOhi<<1 + Carry
56 SWPB Y ; Y = 0:ClusterLOlo
57 ADD Y,Y ; FAToffset = Y = 0:ClusterLOlo << 1 for FAT16 and 0:ClusterLOlo<<2 for FAT32
59 ; ----------------------------------;
61 ; ==================================;
62 ReadFAT1SectorW ;SWX (< 65536)
63 ; ==================================;
65 MOV #0,X ; FAT1_SectorHI = 0
66 JMP ReadSectorWX ;SWX read FAT1SectorW
67 ; ----------------------------------;
70 ; ==================================;
71 ClusterHLtoFrstSectorHL ; Input : ClusterHL, output: first SectorHL of ClusterHL
72 ; ==================================;
73 .IFDEF MPY ; general case
74 ; ----------------------------------;
75 MOV &ClusterL,&MPY32L ;3
76 MOV &ClusterH,&MPY32H ;3
77 MOV &SecPerClus,&OP2 ;5+3
80 ADD &OrgClusters,&SectorL ;5 OrgClusters = sector of virtual cluster 0, word size
81 ADDC #0,&SectorH ;3 32~
82 ; ----------------------------------;
83 .ELSEIF ; case of no hardware multiplier
84 ; ----------------------------------; Cluster24<<SecPerClus --> ClusFrstSect; SecPerClus = {1,2,4,8,16,32,64}
85 PUSHM #3,W ;5 PUSHM W,X,Y
86 MOV.B &SecPerClus,W ;3 SecPerClus(5-1) = multiplicator
87 MOV &ClusterL,X ;3 Cluster(16-1) --> MULTIPLICANDlo
88 MOV.B &ClusterH,Y ;3 Cluster(24-17) --> MULTIPLICANDhi
91 ADD X,X ;1 (RLA) shift one left MULTIPLICANDlo16
92 ADDC Y,Y ;1 (RLC) shift one left MULTIPLICANDhi8
94 RRA W ;1 shift one right multiplicator
95 JNC CCFS_LOOP ;2 C = 0 loop back
96 CCFS_NEXT ; C = 1, it's done
97 ADD &OrgClusters,X ;3 OrgClusters = sector of virtual_cluster_0, word size
99 MOV X,&SectorL ;3 low result
100 MOV Y,&SectorH ;3 high result
101 POPM #3,W ;5 POPM Y,X,W
102 ; ----------------------------------;32~ + 5~ by 2* shift
104 ; ----------------------------------;
107 ; ----------------------------------;
111 ; ==================================;
112 HDLCurClusPlsOfst2sectorHL ;SWX input: HDL (CurClust, ClustOfst) output: SectorHL
113 ; ==================================;
114 MOV HDLL_CurClust(T),&ClusterL ;
115 MOV HDLH_CurClust(T),&ClusterH ;
116 ; ==================================;
117 ClusterHL2sectorHL ;W input: ClusterHL, ClustOfst output: SectorHL
118 ; ==================================;
119 CALL #ClusterHLtoFrstSectorHL ;
120 MOV.B HDLB_ClustOfst(T),W ; byte to word conversion
124 ; ----------------------------------;
127 ; if first open_load token, save DefaultInputStream
128 ; if other open_load token, decrement token, save previous context
131 ; Input : DIREntryOfst, Cluster = DIREntryOfst(HDLL_FirstClus())
132 ; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
133 ; Output: Cluster = first Cluster of file, X = CurrentHdl
134 ; ==================================; input : Cluster, DIREntryOfst
135 GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
136 ; ==================================; output : T = new CurrentHdl
137 MOV #8,S ; prepare file already open error
139 MOV #0,X ; X = init previous handle as 0
140 ; ----------------------------------;
142 ; ----------------------------------;
143 CMP.B #0,HDLB_Token(T) ; free handle ?
144 JZ FreeHandleFound ; yes
146 CMP &ClusterH,HDLH_FirstClus(T);
147 JNE SearchNextHandle ;
148 CMP &ClusterL,HDLL_FirstClus(T);
149 JZ OPEN_Error ; error 8: Already Open abort ===>
151 MOV T,X ; handle is occupied, keep it in X as previous handle
152 ADD #HandleLenght,T ;
154 JNZ SearchHandleLoop ;
156 JMP OPEN_Error ; error 16 = no more handle error, abort ===>
157 ; ----------------------------------;
158 FreeHandleFound ; T = new handle, X = previous handle
159 ; ----------------------------------;
160 MOV #0,S ; prepare Happy End (no error)
162 MOV X,HDLW_PrevHDL(T) ; link to previous handle
163 ; ----------------------------------;
164 CheckCaseOfPreviousToken ;
165 ; ----------------------------------;
166 CMP #0,X ; existing previous handle?
168 ADD &TOIN,HDLW_BUFofst(X) ; in previous handle, add interpret offset to Buffer offset
169 ; ----------------------------------;
170 CheckCaseOfLoadFileToken ;
171 ; ----------------------------------;
172 CMP.B #0,W ; open_type is LOAD (-1) ?
173 JGE InitHandle ; W>=0, no
174 CMP.B #0,HDLB_Token(X) ; previous token is negative? (open_load type)
176 ADD.B HDLB_Token(X),W ; LOAD token = previous LOAD token -1
177 ; ----------------------------------;
179 ; ----------------------------------;
180 MOV.B W,HDLB_Token(T) ; marks handle as open type: <0=LOAD, 1=READ, 2=DEL, 4=WRITE, 8=APPEND
181 MOV.B #0,HDLB_ClustOfst(T) ; clear ClustOfst
182 MOV &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
183 MOV &SectorH,HDLH_DIRsect(T);
184 MOV &DIREntryOfst,Y ;
185 MOV Y,HDLW_DIRofst(T) ; init handle SD_BUF offset of DIR entry
186 MOV SD_BUF+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
187 MOV SD_BUF+20(Y),HDLH_FirstClus(T); = 0 if new DIRentry (create write file)
188 MOV SD_BUF+26(Y),HDLL_CurClust(T); init handle CurrentCluster
189 MOV SD_BUF+20(Y),HDLH_CurClust(T); = 0 if new DIRentry (create write file)
190 MOV SD_BUF+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
191 MOV SD_BUF+30(Y),HDLH_CurSize(T); = 0 if new DIRentry (create write file)
192 MOV #0,&BufferPtr ; reset BufferPtr all type of files
193 CMP.B #2,W ; del file request (2) ?
195 JGE HDLCurClusPlsOfst2sectorHL ; set ClusterHL and SectorHL for all WRITE requests
196 ; ----------------------------------;
197 MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD request
199 JZ ReplaceInputBuffer ; case of first loaded file
200 JL SaveBufferContext ; case of other loaded file
201 JMP SetBufLenLoadCurSector ; case of READ file
202 ; ----------------------------------;
204 ; ----------------------------------;
205 MOV #SDIB_ORG,&CIB_ORG ; set SD Input Buffer as Current Input Buffer before return to QUIT
206 MOV #SD_ACCEPT,&PFAACCEPT ; redirect ACCEPT to SD_ACCEPT before return to QUIT
207 ; ----------------------------------;
208 SaveBufferContext ; (see CloseHandle)
209 ; ----------------------------------;
210 MOV &SOURCE_LEN,HDLW_PrevLEN(T) ; = CPL
211 SUB &TOIN,HDLW_PrevLEN(T) ; PREVLEN = CPL - >IN
212 MOV &SOURCE_ORG,HDLW_PrevORG(T) ; = CIB
213 ADD &TOIN,HDLW_PrevORG(T) ; PrevORG = CIB + >IN
214 JMP SetBufLenLoadCurSector ; then RET
215 ; ----------------------------------;
217 ; ----------------------------------;
219 ; ----------------------------------;
222 ; sequentially load in SD_BUF bytsPerSec bytes of a file opened as read or as load
223 ; if new bufferLen have a size <= BufferPtr, closes the file then RET.
224 ; if previous bufferLen had a size < bytsPerSec, closes the file and reloads previous LOADed file if exist.
225 ; HDLL_CurSize leaves the not yet read size
226 ; All used registers must be initialized.
227 ; ==================================;
228 Read_File ; <== SD_ACCEPT, READ
229 ; ==================================;
231 MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
232 ; ----------------------------------;
233 CMP #bytsPerSec,&BufferLen ;
234 JNZ CloseHandle ; because this last and incomplete sector is already read
235 SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
236 SUBC #0,HDLH_CurSize(T) ;
237 ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
238 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
239 JNC SetBufLenLoadCurSector ; no
240 ; ----------------------------------;
241 ;SearchNextClusterInFAT1 ;
242 ; ----------------------------------;
243 MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
244 CALL #HDLcurClus2FATsecWofstY;WXY Output: FATsector W=FATsector, Y=FAToffset
245 CALL #ReadFAT1SectorW ;SWX (< 65536)
246 MOV #0,HDLH_CurClust(T) ; preset HDLH_CurClust(T)=0 for FAT16
247 MOV SD_BUF(Y),HDLL_CurClust(T) ;
248 MOV SD_BUF+2(Y),HDLH_CurClust(T); set HDLH_CurClust(T)=0 for FAT32
249 ; ==================================;
250 SetBufLenLoadCurSector ;WXY <== previous handle reLOAD with BufferPtr<>0
251 ; ==================================;
252 MOV #bytsPerSec,&BufferLen ; preset BufferLen
253 CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
254 JNZ LoadCurSectorHL ; yes
255 CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedBuffer)
257 CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
258 JC LoadCurSectorHL ; yes
259 MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
260 ; ==================================;
262 ; ==================================;
263 CALL #HDLCurClusPlsOfst2sectorHL;SWX
264 ; ==================================;
266 ; ==================================;
268 MOV &SectorH,X ; High
269 JMP ReadSectorWX ; SWX then RET
270 ; ----------------------------------;
273 ; ----------------------------------;
275 ; ----------------------------------;
276 MOV.B #0,HDLB_Token(T) ; release the handle
277 MOV @T,T ; T = previous handle
278 MOV T,&CurrentHdl ; becomes current handle
280 JZ CloseHandleRet ; if no more handle
281 ; ----------------------------------;
282 RestorePreviousLoadedBuffer ;
283 ; ----------------------------------;
284 MOV HDLW_BUFofst(T),&BufferPtr ; restore previous BufferPtr
285 CALL #SetBufLenLoadCurSector ; then reload previous buffer
287 ; ----------------------------------;
289 MOV @RSP+,PC ; Z = 1 if no more handle
290 ; ----------------------------------;
293 ; ==================================;
294 CloseHandle ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
295 ; ==================================;
297 CMP #0,T ; no handle?
298 JZ CloseHandleRet ; RET
299 ; ----------------------------------;
300 .IFDEF SD_CARD_READ_WRITE
301 CMP.B #4,HDLB_Token(T) ; WRITE file ?
302 JNZ TestClosedToken ; no, case of DEL READ LOAD file
303 ;; ----------------------------------; optionnal
305 ;FullFillZero ;the remainder of sector
306 ; CMP #BytsPerSec,W ;2 buffer full ?
307 ; JZ CloseWriteHandle ;2 remainding of buffer is full filled with 0
308 ; MOV.B #0,SD_BUF(W) ;3
310 ; JMP FullFillZero ;2
311 ;; ----------------------------------;
313 CALL #WriteSD_Buf ;SWX
315 CALL #LoadUpdateSaveDirEntry ;SWXY
317 ; ----------------------------------;
319 ; ----------------------------------;
320 CMP.B #0,HDLB_Token(T) ;
321 ; ----------------------------------;
322 CaseOfAnyReadWriteDelFileIsClosed ; token >= 0
323 ; ----------------------------------;
324 JGE CloseHandleT ; then RET
325 ; ----------------------------------;
326 CaseOfAnyLoadedFileIsClosed ; -- org' len' R-- QUIT3 dst_ptr dst_len SD_ACCEPT
327 ; ----------------------------------;
328 RestoreSD_ACCEPTContext ;
329 ; ----------------------------------;
330 MOV HDLW_PrevLEN(T),TOS ;
331 MOV HDLW_PrevORG(T),0(PSP) ; -- org len
332 ; ----------------------------------;
334 ; ----------------------------------;
335 ADD #6,RSP ; R-- QUIT3 empties return stack
336 MOV @RSP+,IP ; skip return to SD_ACCEPT
337 ; ----------------------------------;
338 CALL #CloseHandleT ; Z = 1 if no more handle
339 ; ----------------------------------;
340 CheckFirstLoadedFileIsClosed ;
341 ; ----------------------------------;
342 JZ RestoreDefaultACCEPT ;
343 MOV #NOECHO,PC ; -- org len if return to SD_ACCEPT
344 ; ----------------------------------;
345 RestoreDefaultACCEPT ; if no more handle, first loaded file is closed...
346 ; ----------------------------------;
347 MOV #TIB_ORG,&CIB_ORG ; restore TIB as Current Input Buffer for next line (next QUIT)
348 MOV #BODYACCEPT,&PFAACCEPT ; restore default ACCEPT for next line (next QUIT)
349 MOV #ECHO,PC ; -- org len if return to Terminal ACCEPT
350 ; ----------------------------------;
353 ; ==================================; input : X = countdown_of_spaces, Y = DIRsector_buffer ptr
354 ParseEntryNameSpaces ;XY
355 ; ==================================; output: Z flag, Y is set after the last space char
358 ; ----------------------------------;
359 ParseEntryNameSpacesLoop ;
360 ; ----------------------------------;
361 CMP.B #32,SD_BUF(Y) ; SPACE ?
362 JNZ PENSL_END ; no: RET
365 JNZ ParseEntryNameSpacesLoop;
368 ; ----------------------------------;
371 .IFDEF SD_CARD_READ_WRITE
373 ;-----------------------------------------------------------------------
374 ; SD_READ_WRITE FORTH words
375 ;-----------------------------------------------------------------------
378 ; parse string until " is encountered, convert counted string in String
379 ; then parse string until char '0'.
380 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
381 ; char "\" as first one initializes rootDir as SearchDir.
382 ; if file found, if not already open and if free handle...
383 ; ...open the file as read and return the handle in CurrentHdl.
384 ; then load first sector in buffer, bufferLen and bufferPtr are ready for read
385 ; currentHdl keep handle that is flagged as "read".
387 ; to read sequentially next sectors use READ word. A flag is returned : true if file is closed.
388 ; the last sector so is in buffer.
390 ; if pathname is a directory, change current directory.
391 ; if an error is encountered, no handle is set, error message is displayed.
393 ; READ" acts also as CD dos command :
394 ; - READ" a:\misc\" set a:\misc as current directory
395 ; - READ" a:\" reset current directory to root
396 ; - READ" ..\" change to parent directory
398 ; to close all files type : WARM (or COLD, RESET)
400 ; ==================================;
401 FORTHWORDIMM "READ\34" ; immediate
402 ; ==================================;
404 MOV.B #1,W ; W = READ request
406 ; ----------------------------------;
408 ;Z DEL" pathame" -- immediate
409 ; ==================================;
410 FORTHWORDIMM "DEL\34" ; immediate
411 ; ==================================;
413 MOV.B #2,W ; W = DEL request
415 ; ----------------------------------;
417 ;Z WRITE" pathame" -- immediate
418 ; if file exist, free all clusters then switch handle to WRITE
419 ; if "no such file", open a write handle
420 ; ==================================;
421 FORTHWORDIMM "WRITE\34" ; immediate
422 ; ==================================;
424 MOV.B #4,W ; W = WRITE request
426 ; ----------------------------------;
428 ;Z APPEND" pathame" -- immediate
429 ; open the file designed by pathname.
430 ; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
431 ; ==================================;
432 FORTHWORDIMM "APPEND\34" ; immediate
433 ; ==================================;
435 MOV.B #8,W ; W = APPEND request
437 ; ----------------------------------;
440 ; close current handle
441 ; ==================================;
443 ; ==================================;
446 ; ----------------------------------;
448 .ENDIF ; SD_CARD_READ_WRITE
450 ;-----------------------------------------------------------------------
451 ; SD_CARD_LOADER FORTH word
452 ;-----------------------------------------------------------------------
454 ;Z LOAD" pathame" -- immediate
455 ; compile state : compile LOAD" pathname"
456 ; exec state : open a file from SD card via its pathname
457 ; see Open_File primitive for pathname conventions
458 ; the opened file becomes the new input stream for INTERPRET
459 ; this command is recursive, limited only by the count of free handles (up to 8)
460 ; LOAD" acts also as dos command "CD" :
461 ; - LOAD" \misc\" set a:\misc as current directory
462 ; - LOAD" \" reset current directory to root
463 ; - LOAD" ..\" change to parent directory
465 ; ==================================;
466 FORTHWORDIMM "LOAD\34" ; immediate
467 ; ==================================;
468 MOV.B #-1,W ; W = LOAD request
469 ; ----------------------------------;
471 ; ======================================================================
472 ; OPEN FILE primitive
473 ; ======================================================================
475 ; primitive for LOAD" READ" CREATE" WRITE" DEL"
476 ; store OpenType on TOS,
477 ; compile state : compile OpenType, compile SQUOTE and the string of provided pathname
478 ; exec state : open a file from SD card via its pathname
479 ; convert counted string found at HERE in a String then parse it
480 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
481 ; char "\" as first one initializes rootDir as SearchDir.
482 ; if file found, if not already open and if free handle...
483 ; ...open the file as read and return the handle in CurrentHdl.
484 ; if the pathname is a directory, change current directory, no handle is set.
485 ; if an error is encountered, no handle is set, an error message is displayed.
486 ; ==================================;
488 ; ==================================;
491 MOV W,TOS ; -- Open_type (-1=LOAD", 1=READ", 2=DEL", 4=WRITE", 8=APPEND")
494 ; ----------------------------------;
496 mDOCOL ; if compile state R-- LOAD"_return
497 .word lit,lit,COMMA,COMMA ; compile open_type as literal
498 .word SQUOTE ; compile string_exec + string
499 .word lit,ParenOpen,COMMA ; compile (OPEN)
501 ; ----------------------------------;
503 mDOCOL ; if exec state
504 .word lit,'"',WORDD,COUNT ; -- open_type addr cnt
507 ; ----------------------------------;
508 ParenOpen ; -- open_type addr cnt
509 ; ----------------------------------;
510 MOV @PSP+,rDOCON ; rDOCON = addr = pathname PTR
511 ADD rDOCON,TOS ; TOS = EOS (End Of String) = pathname end
512 .IFDEF SD_CARD_READ_WRITE ;
513 MOV TOS,&PathName_END ; for WRITE CREATE part
515 ; ----------------------------------;
517 ; ----------------------------------;
518 MOV #2,&ClusterL ; set root DIR cluster
521 CMP rDOCON,TOS ; PTR = EOS ? (end of pathname ?)
522 JZ OPEN_Error ; yes: error 1 ===>
523 ; ----------------------------------;
524 CMP.B #':',1(rDOCON) ; A: B: C: ... in pathname ?
525 JNZ OPN_AntiSlashStartTest ; no
526 ADD #2,rDOCON ; yes : skip drive because not used, only one SD_card
527 ; ----------------------------------;
528 OPN_AntiSlashStartTest ;
529 CMP.B #'\\',0(rDOCON) ; "\" as first char ?
530 JNZ OPN_SearchDirSector ; no
531 ADD #1,rDOCON ; yes : skip '\' char
532 ; ----------------------------------;
533 OPN_EndOfStringTest ;
534 ; ----------------------------------;
535 CMP rDOCON,TOS ; PTR = EOS ? (end of pathname ?)
536 JZ OPN_SetCurrentDIR ; if pathname ptr = end of string
537 ; ----------------------------------;
538 OPN_SearchDirSector ; <=== dir found in path
539 ; ----------------------------------;
540 MOV rDOCON,&PathName_PTR ; save Pathname ptr
541 CALL #ClusterHLtoFrstSectorHL; output: SectorHL
542 MOV &SecPerClus,rDODOES ; DIR sectors = one cluster sectors
543 ; ----------------------------------;
544 OPN_LoadDIRsector ; <=== Dir Sector loopback
545 ; ----------------------------------;
546 CALL #ReadSectorHL ;SWX
547 ; ----------------------------------;
548 MOV #2,S ; prepare no such file error
549 MOV #0,W ; init entries count
550 ; ----------------------------------;
551 OPN_SearchDIRentry ; <=== DIR Entry loopback
552 ; ----------------------------------;
556 MOV Y,&DIREntryOfst ; DIREntryOfst
557 CMP.B #0,SD_BUF(Y) ; free entry ? (end of entries in DIR)
558 JZ OPN_NoSuchFile ; error 2 NoSuchFile, used by create ===>
559 MOV #8,X ; count of chars in entry name
560 ; ----------------------------------;
561 OPN_CompareName8chars ;
562 ; ----------------------------------;
563 CMP.B @rDOCON+,SD_BUF(Y) ; compare Pathname(char) with DirEntry(char)
564 JNZ OPN_FirstCharMismatch ;
567 JNZ OPN_CompareName8chars ; loopback if chars 1 to 7 of string and DirEntry are equal
568 ADD #1,rDOCON ; 9th char of Pathname is always a dot
569 ; ----------------------------------;
570 OPN_FirstCharMismatch ;
571 ; ----------------------------------;
572 CMP.B #'.',-1(rDOCON) ; FirstNotEqualChar of Pathname = dot ?
574 ; ----------------------------------;
576 ; ----------------------------------;
577 ADD #3,X ; for next cases not equal chars of DIRentry until 11 must be spaces
578 CALL #ParseEntryNameSpaces ; for X + 3 chars
579 JNZ OPN_DIRentryMismatch ; if a char entry <> space
580 CMP.B #'\\',-1(rDOCON) ; FirstNotEqualChar of Pathname = "\" ?
582 CMP rDOCON,TOS ; EOS exceeded ?
583 JNC OPN_EntryFound ; yes
584 ; ----------------------------------;
585 OPN_DIRentryMismatch ;
586 ; ----------------------------------;
587 MOV &PathName_PTR,rDOCON ; reload PathName_PTR as it was at last OPN_SearchDirSector
589 CMP #16,W ; 16 entries in a sector
590 JNZ OPN_SearchDIRentry ; ===> loopback for search next DIR entry
591 ; ----------------------------------;
594 SUB #1,rDODOES ; dec count of Dir sectors
595 JNZ OPN_LoadDIRsector ; ===> loopback for search next DIR sector
596 ; ----------------------------------;
598 JMP OPEN_Error ; ENd of DIR error 4 ===>
599 ; ----------------------------------;
601 ; ----------------------------------;
602 OPN_DotFound ; not equal chars of entry name until 8 must be spaces
603 ; ----------------------------------;
604 CMP.B #'.',-2(rDOCON) ; LastCharEqual = dot ?
605 JZ OPN_DIRentryMismatch ; case of first DIR entry = "." and Pathname = "..\"
606 CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,7}
607 JNZ OPN_DIRentryMismatch ; if a char entry <> space
609 ; ----------------------------------;
610 OPN_CompareExt3chars ;
611 ; ----------------------------------;
612 CMP.B @rDOCON+,SD_BUF(Y) ; compare string(char) with DirEntry(char)
613 JNZ OPN_ExtNotEqualChar ;
616 JNZ OPN_CompareExt3chars ; nothing to do if chars equal
618 OPN_ExtNotEqualChar ;
619 CMP rDOCON,TOS ; EOS exceeded ?
620 JC OPN_DIRentryMismatch ; no, loop back
621 CMP.B #'\\',-1(rDOCON) ; FirstNotEqualChar = "\" ?
622 JNZ OPN_DIRentryMismatch ;
623 CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,3}
624 JNZ OPN_DIRentryMismatch ; if a char entry <> space, loop back
625 ; ----------------------------------;
626 OPN_EntryFound ; Y points on the file attribute (11th byte of entry)
627 ; ----------------------------------;
628 MOV &DIREntryOfst,Y ; reload DIRentry
629 MOV SD_BUF+26(Y),&ClusterL ; first clusterL of file
630 MOV SD_BUF+20(Y),&ClusterH ; first clusterH of file
632 BIT.B #10h,SD_BUF+11(Y) ; test if Directory or File
633 JZ OPN_FileFound ; is a file
634 ; ----------------------------------;
635 OPN_DIRfound ; entry is a DIRECTORY
636 ; ----------------------------------;
637 CMP #0,&ClusterH ; case of ".." entry, when parent directory is root
638 JNZ OPN_DIRfoundNext ;
639 CMP #0,&ClusterL ; case of ".." entry, when parent directory is root
640 JNZ OPN_DIRfoundNext ;
641 MOV #2,&ClusterL ; set cluster as RootDIR cluster
643 CMP rDOCON,TOS ; EOS reached ?
644 JNZ OPN_SearchDirSector ; no: (we presume that FirstNotEqualChar = "\") ==> loop back
645 ; ----------------------------------;
646 OPN_SetCurrentDIR ; -- open_type ptr PathName_PTR is set on name of this DIR
647 ; ----------------------------------;
648 MOV &ClusterL,&DIRClusterL ;
649 MOV &ClusterH,&DIRclusterH ;
650 MOV #0,0(PSP) ; -- open_type ptr open_type = 0
652 ; ----------------------------------;
653 OPN_FileFound ; -- open_type ptr PathName_PTR is set on name of file
654 ; ----------------------------------;
656 CALL #GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
657 ; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
658 OPN_NoSuchFile ; S = error 2
660 MOV #xdodoes,rDODOES ; restore rDODOES
661 MOV #xdocon,rDOCON ; restore rDODOES
662 MOV @PSP+,W ; -- ptr W = open_type
664 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
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 ; ======================================================================
675 ; ----------------------------------;
677 ; ----------------------------------;
679 JZ OPEN_LOAD_END ; nothing to do
680 ; ----------------------------------;
682 ; ----------------------------------;
683 .IFDEF SD_CARD_READ_WRITE ;
684 CMP.B #-1,W ; open_type = LOAD"
685 JNZ OPEN_1W ; next step
687 ; ----------------------------------; here W is free
689 ; ----------------------------------;
690 CMP #0,S ; open file happy end ?
695 ; ----------------------------------;
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
708 .word XSQUOTE ; don't use S register
709 .byte 11,"< OpenError" ;
710 .word BRAN,ABORT_SD ; to insert S error as flag, no return
711 ; ----------------------------------;
714 ; to enable bootstrap: BOOT
715 ; to disable bootstrap: NOBOOT
717 ; XBOOT [SYSRSTIV|USERSTIV] --
718 ; here we are after INIT_FORTH
719 ; performs bootstrap from SD_CARD\BOOT.4th file, ready to test SYSRSTIV|USERSYS value
720 XBOOT ; BIT #1,TOS ; USERSYS request ?
722 ; CMP #0,TOS ; WARM request ?
723 ; JZ AbortBoot ; if yes
724 BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card socket ?
726 AbortBoot MOV #WARM,PC ; goto WARM without return
727 ; ----------------------------------;
728 BOOT_YES CALL &HARD_APP ; CALL HARD_APP (which includes INIT_HARD_SD)
729 MOV #PSTACK-2,PSP ; preserve SYSRSTIV|USERSYS in TOS for BOOT.4TH tests
730 MOV #0,0(PSP) ; set 0 for next SYS use
732 .word XSQUOTE ; -- SYSRSTIV|USERSYS addr u
733 .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
734 ; .byte 22,"NOECHO LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
735 .word BRAN,QUIT4 ; to interpret this string, then loop back to QUIT
736 ; ----------------------------------;
738 ; ==================================;
739 FORTHWORD "BOOT" ; to enable BOOT
740 ; ==================================;
741 MOV #XBOOT,&PUCNEXT ; inserts XBOOT in PUC chain.
744 ; ==================================;
745 FORTHWORD "NOBOOT" ; to disable BOOT
746 ; ==================================;
747 MOV #WARM,&PUCNEXT ; removes XBOOT from PUC chain.