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/>.
20 ; used variables : BufferPtr, BufferLen
22 ;-----------------------------------------------------------------------
23 ; SD card OPEN, LOAD subroutines
24 ;-----------------------------------------------------------------------
26 ; ==================================;
27 ReadFAT1SectorW ;SWX (< 65536)
28 ; ==================================;
30 MOV #0,X ; FAT1_SectorHI = 0
31 JMP ReadSectorWX ;SWX read FAT1SectorW, W = 0
32 ; ----------------------------------;
34 .IFDEF SD_CARD_READ_WRITE
36 ; this subroutine is called by Write_File (bufferPtr=512) and CloseHandle (0 =< BufferPtr =< 512)
37 ; ==================================;
38 WriteSD_Buf ;SWX input: T = CurrentHDL
39 ; ==================================;
40 ADD &BufferPtr,HDLL_CurSize(T) ; update handle CurrentSizeL
41 ADDC #0,HDLH_CurSize(T) ;
42 ; ==================================;
44 ; ==================================;
47 JMP WriteSectorWX ; ...then RET
48 ; ----------------------------------;
52 ; rules for registers use
54 ; T = CurrentHdl, pathname
55 ; W = SectorL, (RTC) TIME
56 ; X = SectorH, (RTC) DATE
57 ; Y = BufferPtr, (DIR) DIREntryOfst
59 ; ==================================;
60 HDLcurClus2FATsecWofstY ;WXY Input: T=Handle, HDL_CurClustHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
61 ; ==================================;
62 MOV HDLL_CurClust(T),&ClusterL ;
63 MOV HDLH_CurClust(T),&ClusterH ;
64 ; ==================================;
65 ClusterHLtoFAT1sectWofstY ;WXY Input : ClusterHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
66 ; ==================================;limited to $10000 sectors ==> $800000 clusters ==> 32GB for 4k clusters
67 MOV.B &ClusterL+1,W ;3 W = ClusterLoHI
68 MOV.B &ClusterL,Y ;3 Y = ClusterLOlo
69 ; input : Cluster n, max = 7FFFFF, (SD_card up to 256 GB with 64k clusters)
70 ; ClusterLoLo*4 = displacement in 512 bytes sector ==> FAToffset
71 ; ClusterHiLo&ClusterLoHi +C << 1 = relative FATsector + orgFAT1 ==> FATsector
72 ; ----------------------------------;
73 MOV.B &ClusterH,X ;3 X = 0:ClusterHIlo
74 SWPB X ;1 X = ClusterHIlo:0
75 BIS X,W ;1 W = ClusterHIlo:ClusterLOhi
76 ; ----------------------------------;
77 SWPB Y ;1 Y = ClusterLOlo:0
78 ADD Y,Y ;1 Y = ClusterLOlo:0 << 1 (carry report for FATsector)
79 ADDC W,W ;1 FATsector = W = ClusterHIlo:ClusterLOhi<<1 + Carry
80 SWPB Y ;1 Y = 0:ClusterLOlo
81 ADD Y,Y ;1 FAToffset = Y = 0:ClusterLOlo<<2 for FAT32
83 ; ----------------------------------;
86 ; ==================================;
87 ClusterHLtoFrstSectorHL ; Input : ClusterHL, output: first SectorHL of ClusterHL
88 ; ==================================;
89 .IFDEF MPY ; general case
90 ; ----------------------------------;
91 MOV &ClusterL,&MPY32L ;3
92 MOV &ClusterH,&MPY32H ;3
93 MOV &SecPerClus,&OP2 ;5+3
96 ADD &OrgClusters,&SectorL ;5 OrgClusters = sector of virtual cluster 0, word size
97 ADDC #0,&SectorH ;3 32~
98 ; ----------------------------------;
99 .ELSEIF ; case of no hardware multiplier
100 ; ----------------------------------; Cluster24<<SecPerClus --> ClusFrstSect; SecPerClus = {1,2,4,8,16,32,64}
101 PUSHM #3,W ;5 PUSHM W,X,Y
102 MOV.B &SecPerClus,W ;3 SecPerClus(5-1) = multiplicator
103 MOV &ClusterL,X ;3 Cluster(16-1) --> MULTIPLICANDlo
104 MOV.B &ClusterH,Y ;3 Cluster(24-17) --> MULTIPLICANDhi
107 ADD X,X ;1 (RLA) shift one left MULTIPLICANDlo16
108 ADDC Y,Y ;1 (RLC) shift one left MULTIPLICANDhi8
110 RRA W ;1 shift one right multiplicator
111 JNC CCFS_LOOP ;2 C = 0 loop back
112 ADD &OrgClusters,X ;3 OrgClusters = sector of virtual_cluster_0, word size
114 MOV X,&SectorL ;3 low result
115 MOV Y,&SectorH ;3 high result
116 POPM #3,W ;5 POPM Y,X,W
117 ; ----------------------------------;32~ + 5~ by 2* shift
119 ; ----------------------------------;
121 ; ----------------------------------;
123 ; ==================================;
124 HDLCurClusPlsOfst2sectorHL ;SWX input: HDL (CurClust, ClustOfst) output: SectorHL
125 ; ==================================;
126 MOV HDLL_CurClust(T),&ClusterL ;
127 MOV HDLH_CurClust(T),&ClusterH ;
128 ; ==================================;
129 ClusterHL2sectorHL ;W input: ClusterHL, ClustOfst output: SectorHL
130 ; ==================================;
131 CALL #ClusterHLtoFrstSectorHL ;
132 MOV.B HDLB_ClustOfst(T),W ; byte to word conversion
136 ; ----------------------------------;
138 ; if first open_load token, save DefaultInputStream
139 ; if other open_load token, decrement token, save previous context
142 ; Input : DIREntryOfst, Cluster = DIREntryOfst(HDLL_FirstClus())
143 ; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
144 ; Output: Cluster = first Cluster of file, X = CurrentHdl
145 ; ==================================; input : Cluster, DIREntryOfst
146 GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
147 ; ==================================; output : T = new CurrentHdl
148 MOV #4,S ; prepare file already open error
150 MOV #0,X ; X = init previous handle as 0
151 ; ----------------------------------;
153 ; ----------------------------------;
154 CMP.B #0,HDLB_Token(T) ; free handle ?
155 JZ FreeHandleFound ; yes
156 ;AlreadyOpenTest ; no
157 CMP &ClusterH,HDLH_FirstClus(T);
158 JNE SearchNextHandle ;
159 CMP &ClusterL,HDLL_FirstClus(T);
160 JZ OPEN_Error ; error 4: Already Open abort ===>
162 MOV T,X ; handle is occupied, keep it in X as previous handle
163 ADD #HandleLenght,T ;
165 JNZ SearchHandleLoop ;
167 JMP OPEN_Error ; error 8 = no more handle error, abort ===>
168 ; ----------------------------------;
169 FreeHandleFound ; T = new handle, X = previous handle
170 ; ----------------------------------;
171 MOV #0,S ; prepare Happy End (no error)
173 MOV X,HDLW_PrevHDL(T) ; link to previous handle
174 ; ----------------------------------;
175 ;CheckCaseOfPreviousToken ;
176 ; ----------------------------------;
177 CMP #0,X ; existing previous handle?
179 ADD &TOIN,HDLW_BUFofst(X) ; in previous handle, add interpret offset to Buffer offset
180 ; ----------------------------------;
181 ;CheckCaseOfLoadFileToken ;
182 ; ----------------------------------;
183 CMP.B #0,W ; open_type is LOAD (-1) ?
184 JGE InitHandle ; W>=0, no
185 CMP.B #0,HDLB_Token(X) ; previous token is negative? (open_load type)
187 ADD.B HDLB_Token(X),W ; LOAD token = previous LOAD token -1
188 ; ----------------------------------;
190 ; ----------------------------------;
191 MOV.B W,HDLB_Token(T) ; marks handle as open type: <0=LOAD, 1=READ, 2=DEL, 4=WRITE, 8=APPEND
192 MOV.B #0,HDLB_ClustOfst(T) ; clear ClustOfst
193 MOV &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
194 MOV &SectorH,HDLH_DIRsect(T);
195 MOV &DIREntryOfst,Y ;
196 MOV Y,HDLW_DIRofst(T) ; init handle SD_BUF offset of DIR entry
197 MOV SD_BUF+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
198 MOV SD_BUF+20(Y),HDLH_FirstClus(T); = 0 if new DIRentry (create write file)
199 MOV SD_BUF+26(Y),HDLL_CurClust(T); init handle CurrentCluster
200 MOV SD_BUF+20(Y),HDLH_CurClust(T); = 0 if new DIRentry (create write file)
201 MOV SD_BUF+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
202 MOV SD_BUF+30(Y),HDLH_CurSize(T); = 0 if new DIRentry (create write file)
203 MOV #0,&BufferPtr ; reset BufferPtr all type of files
204 CMP.B #2,W ; del file request (2) ?
206 JGE HDLCurClusPlsOfst2sectorHL ; set ClusterHL and SectorHL for all WRITE requests
207 ; ----------------------------------;
208 MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD request
210 JZ ReplaceInputBuffer ; case of first loaded file
211 JL SaveAcceptContext ; case of other loaded file
212 JMP SetBufLenLoadCurSector ; case of READ file
213 ; ----------------------------------;
215 ; ----------------------------------;
216 MOV #SDIB_ORG,&CIB_ORG ; set SD Input Buffer as Current Input Buffer before return to QUIT
217 MOV #SD_ACCEPT,&PFAACCEPT ; redirect ACCEPT to SD_ACCEPT before return to QUIT
218 ; ----------------------------------;
219 SaveAcceptContext ; (see CloseHandle)
220 ; ----------------------------------;
221 MOV &SOURCE_LEN,HDLW_PrevLEN(T) ;
222 MOV &SOURCE_ORG,HDLW_PrevORG(T) ;
223 MOV &TOIN,HDLW_PrevTOIN(T) ;
224 JMP SetBufLenLoadCurSector ; then RET
225 ; ----------------------------------;
228 ; sequentially load in SD_BUF bytsPerSec bytes of a file opened as read or load
229 ; HDLL_CurSize leaves the not yet read size
230 ; All used registers must be initialized.
231 ; ==================================;
232 Read_File ; <== SD_ACCEPT, READ
233 ; ==================================;
235 MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
236 ; ----------------------------------;
237 CMP #bytsPerSec,&BufferLen ;
238 JNZ CloseHandle ; because this last and incomplete sector is already read
239 SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
240 SUBC #0,HDLH_CurSize(T) ;
241 ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
242 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
243 JNC SetBufLenLoadCurSector ; no
244 ; ----------------------------------;
245 ;SearchNextClusterInFAT1 ;
246 ; ----------------------------------;
247 MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
248 CALL #HDLcurClus2FATsecWofstY;WXY Output: FATsector W=FATsector, Y=FAToffset
249 CALL #ReadFAT1SectorW ;SWX (< 65536)
250 MOV #0,HDLH_CurClust(T) ; preset HDLH_CurClust(T)=0 for FAT16
251 MOV SD_BUF(Y),HDLL_CurClust(T) ;
252 MOV SD_BUF+2(Y),HDLH_CurClust(T); set HDLH_CurClust(T)=0 for FAT32
253 ; ==================================;
254 SetBufLenLoadCurSector ;WXY <== previous handle reLOAD with BufferPtr<>0
255 ; ==================================;
256 MOV #bytsPerSec,&BufferLen ; preset BufferLen
257 CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
258 JNZ LoadCurSectorHL ; yes
259 CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedBuffer)
260 JC TokenToCloseTest ; yes because all the file is already read
261 CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
262 JC LoadCurSectorHL ; yes
263 MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
264 ; ==================================;
266 ; ==================================;
267 CALL #HDLCurClusPlsOfst2sectorHL;SWX
268 ; ==================================;
270 ; ==================================;
272 MOV &SectorH,X ; High
273 JMP ReadSectorWX ; SWX then RET with W = 0, SR(Z) = 1
274 ; ----------------------------------;
277 ; ==================================;
278 CloseHandle ; <== CLOSE, TERM2SD", OPEN_DEL
279 ; ==================================;
281 CMP #0,T ; no handle?
283 ; ----------------------------------;
284 .IFDEF SD_CARD_READ_WRITE
285 ; ----------------------------------;
286 CMP.B #4,HDLB_Token(T) ; WRITE file ?
287 JL TokenToCloseTest ; no, case of DEL READ LOAD file
288 ;; ----------------------------------; optionnal
290 ;RemFillZero ;the remainder of sector
291 ; CMP #BytsPerSec,W ;2 buffer full ?
292 ; JZ UpdateWriteSector ;2 remainding of buffer is full filled with $FF
293 ; MOV.B #-1,SD_BUF(W) ;3
296 ; ----------------------------------;
297 ;UpdateWriteSector ; case of any WRITE file
298 ; ----------------------------------;
299 CALL #WriteSD_Buf ;SWX
300 ; ----------------------------------;
301 ;Load Update DirEntry ;SWXY
302 ; ----------------------------------;
303 MOV HDLL_DIRsect(T),W ;
304 MOV HDLH_DIRsect(T),X ;
305 CALL #ReadSectorWX ;SWX SD_buffer = DIRsector
306 MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
307 CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
308 MOV X,SD_BUF+18(Y) ; access date
309 MOV W,SD_BUF+22(Y) ; modified time
310 MOV X,SD_BUF+24(Y) ; modified date
311 MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
312 MOV HDLH_CurSize(T),SD_BUF+30(Y);
313 MOV HDLL_DIRsect(T),W ;
314 MOV HDLH_DIRsect(T),X ;
315 CALL #WriteSectorWX ;SWX
316 ; ----------------------------------;
318 ; ==================================;
319 TokenToCloseTest ; <== Read_File
320 ; ==================================;
321 CMP.B #-1,HDLB_Token(T) ;
322 JZ RestoreDefaultACCEPT ;
324 ; ----------------------------------;
325 ;CaseOfAnyReadWriteDelFileIsClosed ; token >= -1
326 ; ----------------------------------;
327 JMP CloseHandleRightNow ; then RET
328 ; ----------------------------------;
329 RestoreDefaultACCEPT ;
330 ; ----------------------------------;
331 MOV #TIB_ORG,&CIB_ORG ; restore TIB as Current Input Buffer and..
332 MOV #BODYACCEPT,&PFAACCEPT ; restore default ACCEPT for next line (next loop of QUIT)
333 ; ----------------------------------;
334 LoadFileToClose ; R-- SD_ACCEPT(SDA_InitSrcAddr)
335 ; ----------------------------------;
336 MOV #SDA_RetOfCloseHandle,0(RSP); R-- SD_ACCEPT(SDA_RetOfCloseHandle)
337 ; ----------------------------------;
338 ;RestorePreviousContext ; ready for the next QUIT loop
339 ; ----------------------------------;
340 MOV HDLW_PrevLEN(T),&SOURCE_LEN ;
341 MOV HDLW_PrevORG(T),&SOURCE_ORG ;
342 MOV HDLW_PrevTOIN(T),&TOIN ;
343 ; ----------------------------------;
344 CloseHandleRightNow ;
345 ; ----------------------------------;
346 MOV.B #0,HDLB_Token(T) ; release the handle
347 MOV @T,T ; T = previous handle
348 MOV T,&CurrentHdl ; becomes current handle
349 CMP #0,T ; no more handle ?
350 JZ HandleRet ; with SR(Z) = 1
351 ; ----------------------------------;
352 RestorePreviousLoadedBuffer ;
353 ; ----------------------------------;
354 MOV HDLW_BUFofst(T),&BufferPtr ; restore previous BufferPtr
355 CALL #SetBufLenLoadCurSector ; then reload previous buffer
356 BIC #Z,SR ; force SR(Z) = 0
357 ; ----------------------------------;
359 ; ----------------------------------;
360 MOV @RSP+,PC ; SR(Z) state is used by SD_ACCEPT(SDA_RetOfCloseHandle)
361 ; ----------------------------------;
363 ; ----------------------------------;
364 SDA_EOF_IP .word SDA_EndOfFile ; defines return address from ECHO|NOECHO to SD_ACCEPT
365 ; ----------------------------------;
366 SDA_RetOfCloseHandle ; -- SDIB_org SDIB_end SDIB_ptr R-- closed_handle Z = 1 if no more handle
367 ; ----------------------------------;
369 JZ EchoForDefaultAccept ;
371 EchoForDefaultAccept ;
373 ; ----------------------------------;
376 .IFDEF SD_CARD_READ_WRITE
378 ; ==================================;
379 HDLFrstClus2FATsecWofstY ;WXY Input: T=Handle, HDL_CurClustHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
380 ; ==================================;
381 MOV HDLL_FirstClus(T),&ClusterL ;
382 MOV HDLH_FirstClus(T),&ClusterH ;
383 JMP ClusterHLtoFAT1sectWofstY ;
384 ; ----------------------------------;
386 ;-----------------------------------------------------------------------
387 ; SD_READ_WRITE FORTH words
388 ;-----------------------------------------------------------------------
391 ; parse string until " is encountered, convert counted string in String
392 ; then parse string until char '0'.
393 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
394 ; char "\" as first one initializes rootDir as SearchDir.
395 ; if file found, if not already open and if free handle...
396 ; ...open the file as read and return the handle in CurrentHdl.
397 ; then load first sector in buffer, bufferLen and bufferPtr are ready for read
398 ; currentHdl keep handle that is flagged as "read".
400 ; to read sequentially next sectors use READ word. A flag is returned : true if file is closed.
401 ; the last sector so is in buffer.
403 ; if pathname is a directory, change current directory.
404 ; if an error is encountered, no handle is set, error message is displayed.
406 ; READ" acts also as CD dos command :
407 ; - READ" a:\misc\" set a:\misc as current directory
408 ; - READ" a:\" reset current directory to root
409 ; - READ" ..\" change to parent directory
411 ; to close all files type : WARM (or COLD, RESET)
413 ; ==================================;
414 FORTHWORDIMM "READ\34" ; immediate
415 ; ==================================;
417 MOV.B #1,W ; W = READ request
419 ; ----------------------------------;
421 ;Z DEL" pathame" -- immediate
422 ; ==================================;
423 FORTHWORDIMM "DEL\34" ; immediate
424 ; ==================================;
425 MOV.B #2,W ; W = DEL request
427 ; ----------------------------------;
429 ;Z WRITE" pathame" -- immediate
430 ; if file exist, free all clusters then switch handle to WRITE
431 ; if "no such file", open a write handle
432 ; ==================================;
433 FORTHWORDIMM "WRITE\34" ; immediate
434 ; ==================================;
436 MOV.B #4,W ; W = WRITE request
438 ; ----------------------------------;
440 ;Z APPEND" pathame" -- immediate
441 ; open the file designed by pathname.
442 ; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
443 ; ==================================;
444 FORTHWORDIMM "APPEND\34" ; immediate
445 ; ==================================;
446 MOV.B #8,W ; W = APPEND request
448 ; ----------------------------------;
451 ; close current handle
452 ; ==================================;
454 ; ==================================;
457 ; ----------------------------------;
459 .ENDIF ; SD_CARD_READ_WRITE
461 ;-----------------------------------------------------------------------
462 ; SD_CARD_LOADER FORTH word
463 ;-----------------------------------------------------------------------
465 ;Z LOAD" pathame" -- immediate
466 ; compile state : compile LOAD" pathname"
467 ; exec state : open a file from SD card via its pathname
468 ; see Open_File primitive for pathname conventions
469 ; the opened file becomes the new input stream for INTERPRET
470 ; this command is recursive, limited only by the count of free handles (up to 8)
471 ; LOAD" acts also as dos command "CD" :
472 ; - LOAD" \misc\" set a:\misc as current directory
473 ; - LOAD" \" reset current directory to root
474 ; - LOAD" ..\" change to parent directory
476 ; ==================================;
477 FORTHWORDIMM "LOAD\34" ; immediate
478 ; ==================================;
479 MOV.B #-1,W ; W = LOAD request
480 ; ----------------------------------;
482 ; ======================================================================
483 ; OPEN FILE primitive
484 ; ======================================================================
486 ; primitive for LOAD" READ" CREATE" WRITE" DEL"
487 ; store OpenType on TOS,
488 ; compile state : compile OpenType, compile SQUOTE and the string of provided pathname
489 ; exec state : open a file from SD card via its pathname
490 ; convert counted string found at HERE in a String then parse it
491 ; char "\" as first one initializes rootDir as SearchDir.
492 ; if file found, if not already open and if free handle...
493 ; ...open the file as read and return the handle in CurrentHdl.
494 ; if the pathname is a directory, change current directory, no handle is set.
495 ; if an error is encountered, no handle is set, an error message is displayed.
496 ; ==================================;
498 ; ==================================;
501 MOV W,TOS ; -- Open_type (-1=LOAD", 1=READ", 2=DEL", 4=WRITE", 8=APPEND")
504 ; ----------------------------------;
506 mDOCOL ; if compile state R-- LOAD"_return
507 .word lit,lit,COMMA,COMMA ; compile open_type as literal
508 .word SQUOTE ; compile string_exec + string
509 .word lit,ParenOpen,COMMA ; compile (OPEN)
511 ; ----------------------------------;
513 mDOCOL ; if exec state
514 .word lit,'"',WORDD,COUNT ; -- open_type addr cnt
517 ; ----------------------------------;
518 ParenOpen ; -- open_type addr cnt execution of OPEN_COMP: IP points to OPEN_COMP(EXIT),
519 ; ----------------------------------; case of OPEN_EXEC: IP points to INTERPRET(INTLOOP).
521 BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card module ?
522 JZ Q_SD_not_init ; yes
523 BIC #BUS_SD,&SD_SEL ; no, hide SIMO, SOMI & SCK pins (SD not initialized memory)
525 BIT #BUS_SD,&SD_SEL ; is SD init by SYS ?
526 JNZ OPEN_LetUsGo ; no --> with TOS = -1 does abort
527 MOV #NO_SD_CARD,PC ; S = 0 --> error 0
528 ; ----------------------------------;
530 ; ----------------------------------;
532 CMP #0,TOS ; cnt = 0 ?
533 JZ OPEN_Error ; yes: error 1 ===>
534 MOV @PSP+,rDOCON ; -- open_type cnt rDOCON = addr = pathname PTR
535 ADD rDOCON,TOS ; -- open_type EOS TOS = EOS (End Of String) = pathname end
536 .IFDEF SD_CARD_READ_WRITE ;
537 MOV TOS,&PathName_END ; for WRITE CREATE part
539 MOV &DIRClusterL,&ClusterL ; set DIR cluster
540 MOV &DIRClusterH,&ClusterH ;
541 ; ----------------------------------;
542 ;OPN_AntiSlashFirstTest ;
543 ; ----------------------------------;
544 CMP.B #'\\',0(rDOCON) ; "\" as first char ?
545 JNZ OPN_SearchInDIR ; no
546 ADD #1,rDOCON ; yes : skip '\' char
548 JMP OPN_AntiSlashFirstNext ;
549 ; ----------------------------------;
550 OPN_SearchInDIR ; <=== dir found in path
551 ; ----------------------------------;
552 MOV rDOCON,&PathName_PTR ; save Pathname ptr
553 ; ----------------------------------;
554 OPN_LoadDIRcluster ; <=== next DIR cluster loopback
555 ; ----------------------------------;
556 CALL #ClusterHLtoFrstSectorHL; output: first Sector of this cluster
557 MOV &SecPerClus,rDODOES ; set sectors count down
558 ; ----------------------------------;
559 OPN_LoadDIRsector ; <=== next DIR Sector loopback
560 ; ----------------------------------;
561 CALL #ReadSectorHL ;SWX,
562 MOV #2,S ; prepare error 2
563 ; ----------------------------------; W = 0 = DIREntryOfst
564 OPN_SearchDIRentry ; <=== next DIR_Entry loopback
565 ; ----------------------------------;
566 MOV W,&DIREntryOfst ; update DIREntryOfst
567 CMP.B #0,SD_BUF(W) ; free entry ?
568 JZ OPN_NoSuchFile ; NoSuchFile error = 2 ===>
569 MOV W,Y ; 1 W = DIREntryOfst, Y = Entry_name pointer
570 MOV #8,X ; count of chars in entry name
571 ; ----------------------------------;
573 ; ----------------------------------;
575 CMP.B T,SD_BUF(Y) ; compare Pathname with DirEntry1to8, char by char
576 JNZ OPN_CompareNameNext ;
579 JNZ OPN_CompareName ;
580 MOV.B @rDOCON+,T ; 9th char of Pathname should be '.'
581 JZ OPN_CompareNameDone ; if X = 0
582 ; ----------------------------------;
583 OPN_CompareNameNext ; remainder of 8 chars of DIR_entry name must be spaces
584 ; ----------------------------------;
585 CMP.B #32,SD_BUF(Y) ; parse DIR entry up to 8th chars
586 JNZ OPN_DIRentryMismatch ; if a char of DIR entry name <> space
589 JNZ OPN_CompareNameNext ;
590 ; ----------------------------------;
591 OPN_CompareNameDone ; T = "." or FirstNotEqualChar
592 ; ----------------------------------;
593 CMP.B #'\\',T ; FirstNotEqualChar of Pathname = "\" ?
595 ; ----------------------------------;
596 MOV #3,X ; to compare 3 char extension
597 CMP.B #'.',T ; FirstNotEqualChar of Pathname = dot ?
598 JNZ OPN_CompExtensionNext ; if not
599 ; ----------------------------------;
600 OPN_CompareExtension ;
601 ; ----------------------------------;
602 CMP.B @rDOCON+,SD_BUF(Y) ; compare Pathname_ext(char) with DirEntry9to11(char)
603 JNZ OPN_CompExtensionNext ;
606 JNZ OPN_CompareExtension ;
607 JZ OPN_CompExtensionDone ;
608 ; ----------------------------------;
609 OPN_CompExtensionNext ; remainder of 8 chars of DIR_entry extension must be spaces
610 ; ----------------------------------;
611 CMP.B #32,SD_BUF(Y) ; parse DIR entry up to 11th chars
612 JNZ OPN_DIRentryMismatch ; if a char of DIR entry extension <> space
615 JNZ OPN_CompExtensionNext ;
616 ; ----------------------------------;
617 OPN_CompExtensionDone ;
618 ; ----------------------------------;
619 CMP.B #'.',-2(rDOCON) ; LastCharEqual = dot ? (case of Pathname = "..\" which matches with first DIR entry = ".")
620 JZ OPN_DIRentryMismatch ; to compare with 2th DIR entry, the good one.
621 CMP TOS,rDOCON ; EOS reached ?
622 JC OPN_EntryFound ; yes
623 ; ----------------------------------;
624 OPN_DIRentryMismatch ;
625 ; ----------------------------------;
626 MOV &PathName_PTR,rDOCON ; reload PathName_PTR as it was at last OPN_SearchInDIR
627 ADD #32,W ; W = DIREntryOfst + DIRentrySize
628 CMP #512,W ; out of sector bound ?
629 JNZ OPN_SearchDIRentry ; no, loopback for search next DIR entry in same sector
630 ; ----------------------------------;
633 SUB #1,rDODOES ; count of Dir sectors reached ?
634 JNZ OPN_LoadDIRsector ; no, loopback to load next DIR sector in same cluster
635 ; ----------------------------------;
636 CALL #ClusterHLtoFAT1sectWofstY ; load FATsector in SD_Buffer, set Y = FAToffset
637 CMP #-1,0(Y) ; last DIR cluster ?
638 JNZ OPN_SetNextDIRcluster ;
640 .IFNDEF SD_CARD_READ_WRITE ;
641 JZ OPN_NoSuchFile ; yes, NoSuchFile error = 2 ===>
643 JNZ OPN_SetNextDIRcluster ; no
644 ;OPN_QcreateDIRentry ; -- open_type EOS
645 CMP #4,0(PSP) ; open type = WRITE" or APPEND" ?
646 JNC OPN_NoSuchFile ; no: NoSuchFile error = 2 ===>
647 ;OPN_AddDIRcluster ; yes
648 PUSH #OPN_LoadDIRcluster ; as RETurn of GetNewCluster: ===> loopback to load this new DIR cluster
649 ; ==================================;
650 GetNewCluster ; called by Write_File
651 ; ==================================;
652 PUSH Y ; push previous FAToffset
653 PUSH W ; push previous FATsector
654 CALL #SearchMarkNewClusterHL ;SWXY input: W = FATsector Y = FAToffset, output: ClusterHL, W = FATsector of New cluster
655 CMP @RSP,W ; previous and new clusters are in same FATsector?
656 JZ LinkClusters ; yes
657 ; ----------------------------------;
658 ;UpdateNewClusterFATs ;
659 ; ----------------------------------;
660 MOV @RSP,W ; W = previous FATsector
661 CALL #ReadFAT1SectorW ;SWX reload previous FATsector in buffer to link clusters
662 ; ----------------------------------;
664 ; ----------------------------------;
665 MOV @RSP+,W ; W = previous FATsector
666 MOV @RSP+,Y ; Y = previous FAToffset
667 MOV &ClusterL,SD_BUF(Y) ; store new cluster to current cluster address in previous FATsector buffer
668 MOV &ClusterH,SD_BUF+2(Y) ;
669 JMP SaveSectorWtoFATs ;SWXY update FATs from SD_BUF to W = previous FATsector, then RET
670 ; ==================================;
671 .ENDIF ; SD_CARD_READ_WRITE ;
672 ; ----------------------------------;
673 OPN_SetNextDIRcluster ;
674 ; ----------------------------------;
677 JMP OPN_LoadDIRcluster ; ===> loop back to load this new DIR cluster
678 ; ----------------------------------;
680 ; ----------------------------------;
681 OPN_EntryFound ; Y points on the file attribute (11th byte of entry)
682 ; ----------------------------------;
683 ; MOV W,&DIREntryOfst ;
684 MOV SD_BUF+14H(W),&ClusterH ; first clusterH of file
685 MOV SD_BUF+1Ah(W),&ClusterL ; first clusterL of file
686 BIT.B #10h,SD_BUF+0Bh(W) ; test if Directory or File
687 JZ OPN_FileFound ; is a file
688 ; ----------------------------------;
689 ;OPN_DIRfound ; entry is a DIRECTORY
690 ; ----------------------------------;
691 CMP #0,&ClusterH ; case of ".." entry, when parent directory is root
692 JNZ OPN_DIRfoundNext ;
693 CMP #0,&ClusterL ; case of ".." entry, when parent directory is root
694 JNZ OPN_DIRfoundNext ;
695 OPN_AntiSlashFirstNext
696 MOV #2,&ClusterL ; set clusterL as RootDIR cluster
698 CMP TOS,rDOCON ; EOS reached ?
699 JNC OPN_SearchInDIR ; no: (rDOCON points after "\") ==> loop back
700 ; ----------------------------------;
701 ;OPN_SetCurrentDIR ; -- open_type ptr PathName_PTR is set on name of this DIR
702 ; ----------------------------------;
703 MOV &ClusterL,&DIRClusterL ;
704 MOV &ClusterH,&DIRclusterH ;
705 MOV #0,0(PSP) ; -- open_type ptr set open_type = 0 = DIR
707 ; ----------------------------------;
708 OPN_FileFound ; -- open_type ptr PathName_PTR is set on name of file
709 ; ----------------------------------;
711 CALL #GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
712 ; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
713 OPN_NoSuchFile ; S = error 2
715 MOV #xdodoes,rDODOES ; restore rDODOES
716 MOV #xdocon,rDOCON ; restore rDODOES
717 MOV @PSP+,W ; -- ptr W = open_type
719 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
722 MOV @IP+,PC ; nothing else to do
723 ; ----------------------------------;
726 ; ======================================================================
727 ; LOAD" primitive as part of Open_File
728 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
729 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
730 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
731 ; output: nothing else abort on error
732 ; ======================================================================
734 ; ----------------------------------;
736 ; ----------------------------------;
737 .IFDEF SD_CARD_READ_WRITE ;
738 CMP.B #-1,W ; open_type = LOAD"
739 JNZ OPEN_1W ; next step
741 ; ----------------------------------; here W is free
743 ; ----------------------------------;
744 CMP #0,S ; open file happy end ?
746 MOV #NOECHO,PC ; return to QUIT5 then SD_ACCEPT
748 ; ----------------------------------;
750 ; ----------------------------------;
751 OPEN_Error ; S= error
752 ; ----------------------------------;
753 ; Error 1 : PathNameNotFound ; S = error 1
754 ; Error 2 : NoSuchFile ; S = error 2
755 ; Error 4 : alreadyOpen ; S = error 4
756 ; Error 8 : NomoreHandle ; S = error 8
757 ; ----------------------------------;
758 MOV #SD_CARD_FILE_ERROR,PC ;
759 ; ----------------------------------;
761 ; to enable bootstrap: BOOT
762 ; to disable bootstrap: NOBOOT
764 ; XBOOT [SYSRSTIV|USERSTIV] --
765 ; here we are after INIT_FORTH
766 ; performs bootstrap from SD_CARD\BOOT.4th file, ready to test SYSRSTIV|USERSYS value
767 XBOOT CALL &HARD_APP ; WARM first calls HARD_APP (which includes INIT_HARD_SD)
768 MOV #PSTACK-2,PSP ; preserve SYSRSTIV|USERSYS in TOS for BOOT.4TH tests
769 MOV #0,0(PSP) ; set TOS = 0 for the next of XBOOT
771 .word XSQUOTE ; -- SYSRSTIV|USERSYS addr u
772 .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
773 .word BRAN,QUIT4 ; to interpret this string, then loop back to QUIT1/QUIT2
774 ; ----------------------------------;
776 ; ==================================;
777 FORTHWORD "BOOT" ; to enable BOOT
778 ; ==================================;
779 MOV #XBOOT,&PUCNEXT ; inserts XBOOT in PUC chain.
782 ; ==================================;
783 FORTHWORD "NOBOOT" ; to disable BOOT
784 ; ==================================;
785 NOBOOT MOV #WARM,&PUCNEXT ; removes XBOOT from PUC chain.