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 CCFS_NEXT ; C = 1, it's done
113 ADD &OrgClusters,X ;3 OrgClusters = sector of virtual_cluster_0, word size
115 MOV X,&SectorL ;3 low result
116 MOV Y,&SectorH ;3 high result
117 POPM #3,W ;5 POPM Y,X,W
118 ; ----------------------------------;32~ + 5~ by 2* shift
120 ; ----------------------------------;
123 ; ----------------------------------;
125 ; ==================================;
126 HDLCurClusPlsOfst2sectorHL ;SWX input: HDL (CurClust, ClustOfst) output: SectorHL
127 ; ==================================;
128 MOV HDLL_CurClust(T),&ClusterL ;
129 MOV HDLH_CurClust(T),&ClusterH ;
130 ; ==================================;
131 ClusterHL2sectorHL ;W input: ClusterHL, ClustOfst output: SectorHL
132 ; ==================================;
133 CALL #ClusterHLtoFrstSectorHL ;
134 MOV.B HDLB_ClustOfst(T),W ; byte to word conversion
138 ; ----------------------------------;
140 ; if first open_load token, save DefaultInputStream
141 ; if other open_load token, decrement token, save previous context
144 ; Input : DIREntryOfst, Cluster = DIREntryOfst(HDLL_FirstClus())
145 ; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
146 ; Output: Cluster = first Cluster of file, X = CurrentHdl
147 ; ==================================; input : Cluster, DIREntryOfst
148 GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
149 ; ==================================; output : T = new CurrentHdl
150 MOV #4,S ; prepare file already open error
152 MOV #0,X ; X = init previous handle as 0
153 ; ----------------------------------;
155 ; ----------------------------------;
156 CMP.B #0,HDLB_Token(T) ; free handle ?
157 JZ FreeHandleFound ; yes
159 CMP &ClusterH,HDLH_FirstClus(T);
160 JNE SearchNextHandle ;
161 CMP &ClusterL,HDLL_FirstClus(T);
162 JZ OPEN_Error ; error 4: Already Open abort ===>
164 MOV T,X ; handle is occupied, keep it in X as previous handle
165 ADD #HandleLenght,T ;
167 JNZ SearchHandleLoop ;
169 JMP OPEN_Error ; error 8 = no more handle error, abort ===>
170 ; ----------------------------------;
171 FreeHandleFound ; T = new handle, X = previous handle
172 ; ----------------------------------;
173 MOV #0,S ; prepare Happy End (no error)
175 MOV X,HDLW_PrevHDL(T) ; link to previous handle
176 ; ----------------------------------;
177 CheckCaseOfPreviousToken ;
178 ; ----------------------------------;
179 CMP #0,X ; existing previous handle?
181 ADD &TOIN,HDLW_BUFofst(X) ; in previous handle, add interpret offset to Buffer offset
182 ; ----------------------------------;
183 CheckCaseOfLoadFileToken ;
184 ; ----------------------------------;
185 CMP.B #0,W ; open_type is LOAD (-1) ?
186 JGE InitHandle ; W>=0, no
187 CMP.B #0,HDLB_Token(X) ; previous token is negative? (open_load type)
189 ADD.B HDLB_Token(X),W ; LOAD token = previous LOAD token -1
190 ; ----------------------------------;
192 ; ----------------------------------;
193 MOV.B W,HDLB_Token(T) ; marks handle as open type: <0=LOAD, 1=READ, 2=DEL, 4=WRITE, 8=APPEND
194 MOV.B #0,HDLB_ClustOfst(T) ; clear ClustOfst
195 MOV &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
196 MOV &SectorH,HDLH_DIRsect(T);
197 MOV &DIREntryOfst,Y ;
198 MOV Y,HDLW_DIRofst(T) ; init handle SD_BUF offset of DIR entry
199 MOV SD_BUF+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
200 MOV SD_BUF+20(Y),HDLH_FirstClus(T); = 0 if new DIRentry (create write file)
201 MOV SD_BUF+26(Y),HDLL_CurClust(T); init handle CurrentCluster
202 MOV SD_BUF+20(Y),HDLH_CurClust(T); = 0 if new DIRentry (create write file)
203 MOV SD_BUF+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
204 MOV SD_BUF+30(Y),HDLH_CurSize(T); = 0 if new DIRentry (create write file)
205 MOV #0,&BufferPtr ; reset BufferPtr all type of files
206 CMP.B #2,W ; del file request (2) ?
208 JGE HDLCurClusPlsOfst2sectorHL ; set ClusterHL and SectorHL for all WRITE requests
209 ; ----------------------------------;
210 MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD request
212 JZ ReplaceInputBuffer ; case of first loaded file
213 JL SaveBufferContext ; case of other loaded file
214 JMP SetBufLenLoadCurSector ; case of READ file
215 ; ----------------------------------;
217 ; ----------------------------------;
218 MOV #SDIB_ORG,&CIB_ORG ; set SD Input Buffer as Current Input Buffer before return to QUIT
219 MOV #SD_ACCEPT,&PFAACCEPT ; redirect ACCEPT to SD_ACCEPT before return to QUIT
220 ; ----------------------------------;
221 SaveBufferContext ; (see CloseHandle)
222 ; ----------------------------------;
223 MOV &SOURCE_LEN,HDLW_PrevLEN(T) ; = CPL
224 SUB &TOIN,HDLW_PrevLEN(T) ; PREVLEN = CPL - >IN
225 MOV &SOURCE_ORG,HDLW_PrevORG(T) ; = CIB
226 ADD &TOIN,HDLW_PrevORG(T) ; PrevORG = CIB + >IN
227 JMP SetBufLenLoadCurSector ; then RET
228 ; ----------------------------------;
230 ; ----------------------------------;
232 ; ----------------------------------;
235 ; sequentially load in SD_BUF bytsPerSec bytes of a file opened as read or as load
236 ; if new bufferLen have a size <= BufferPtr, closes the file then RET.
237 ; if previous bufferLen had a size < bytsPerSec, closes the file and reloads previous LOADed file if exist.
238 ; HDLL_CurSize leaves the not yet read size
239 ; All used registers must be initialized.
240 ; ==================================;
241 Read_File ; <== SD_ACCEPT, READ
242 ; ==================================;
244 MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
245 ; ----------------------------------;
246 CMP #bytsPerSec,&BufferLen ;
247 JNZ CloseHandle ; because this last and incomplete sector is already read
248 SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
249 SUBC #0,HDLH_CurSize(T) ;
250 ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
251 CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
252 JNC SetBufLenLoadCurSector ; no
253 ; ----------------------------------;
254 ;SearchNextClusterInFAT1 ;
255 ; ----------------------------------;
256 MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
257 CALL #HDLcurClus2FATsecWofstY;WXY Output: FATsector W=FATsector, Y=FAToffset
258 CALL #ReadFAT1SectorW ;SWX (< 65536)
259 MOV #0,HDLH_CurClust(T) ; preset HDLH_CurClust(T)=0 for FAT16
260 MOV SD_BUF(Y),HDLL_CurClust(T) ;
261 MOV SD_BUF+2(Y),HDLH_CurClust(T); set HDLH_CurClust(T)=0 for FAT32
262 ; ==================================;
263 SetBufLenLoadCurSector ;WXY <== previous handle reLOAD with BufferPtr<>0
264 ; ==================================;
265 MOV #bytsPerSec,&BufferLen ; preset BufferLen
266 CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
267 JNZ LoadCurSectorHL ; yes
268 CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedBuffer)
270 CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
271 JC LoadCurSectorHL ; yes
272 MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
273 ; ==================================;
275 ; ==================================;
276 CALL #HDLCurClusPlsOfst2sectorHL;SWX
277 ; ==================================;
279 ; ==================================;
281 MOV &SectorH,X ; High
282 JMP ReadSectorWX ; SWX then RET with W = 0
283 ; ----------------------------------;
286 ; ==================================;
287 CloseHandle ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
288 ; ==================================;
290 CMP #0,T ; no handle?
291 JZ CloseHandleRet ; RET
292 ; ----------------------------------;
293 .IFDEF SD_CARD_READ_WRITE
294 CMP.B #4,HDLB_Token(T) ; WRITE file ?
295 JL TestClosedToken ; no, case of DEL READ LOAD file
296 ;; ----------------------------------; optionnal
298 ;RemFillZero ;the remainder of sector
299 ; CMP #BytsPerSec,W ;2 buffer full ?
300 ; JZ UpdateWriteSector ;2 remainding of buffer is full filled with 0
301 ; MOV.B #0,SD_BUF(W) ;3
304 ;; ----------------------------------;
306 CALL #WriteSD_Buf ;SWX
307 ; ----------------------------------;
308 ;Load Update Save DirEntry ;SWXY
309 ; ----------------------------------;
310 MOV HDLL_DIRsect(T),W ;
311 MOV HDLH_DIRsect(T),X ;
312 CALL #ReadSectorWX ;SWX SD_buffer = DIRsector
313 MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
314 CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
315 MOV X,SD_BUF+18(Y) ; access date
316 MOV W,SD_BUF+22(Y) ; modified time
317 MOV X,SD_BUF+24(Y) ; modified date
318 MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
319 MOV HDLH_CurSize(T),SD_BUF+30(Y);
320 MOV HDLL_DIRsect(T),W ;
321 MOV HDLH_DIRsect(T),X ;
322 CALL #WriteSectorWX ;SWX
323 ; ----------------------------------;
325 ; ----------------------------------;
327 ; ----------------------------------;
328 CMP.B #0,HDLB_Token(T) ;
329 ; ----------------------------------;
330 CaseOfAnyReadWriteDelFileIsClosed ; token >= 0
331 ; ----------------------------------;
332 JGE CloseHandleT ; then RET
333 ; ----------------------------------;
334 CaseOfAnyLoadedFileIsClosed ; -- org' len' R-- QUIT3 dst_ptr dst_len SD_ACCEPT
335 ; ----------------------------------;
336 RestoreSD_ACCEPTContext ;
337 ; ----------------------------------;
338 MOV HDLW_PrevLEN(T),TOS ;
339 MOV HDLW_PrevORG(T),0(PSP) ; -- org len
340 ; ----------------------------------;
342 ; ----------------------------------;
343 ADD #6,RSP ; R-- QUIT3 empties return stack
344 MOV @RSP+,IP ; skip return to SD_ACCEPT
345 ; ----------------------------------;
346 PUSH #CheckFirstLoadedFile ; defines the RETurn of CloseHandleT
347 ; ----------------------------------;
349 ; ----------------------------------;
350 MOV.B #0,HDLB_Token(T) ; release the handle
351 MOV @T,T ; T = previous handle
352 MOV T,&CurrentHdl ; becomes current handle
354 JZ CloseHandleRet ; if no more handle
355 ; ----------------------------------;
356 RestorePreviousLoadedBuffer ;
357 ; ----------------------------------;
358 MOV HDLW_BUFofst(T),&BufferPtr ; restore previous BufferPtr
359 CALL #SetBufLenLoadCurSector ; then reload previous buffer
361 ; ----------------------------------;
363 MOV @RSP+,PC ; Z = 1 if no more handle, then RET
364 ; ----------------------------------;
365 CheckFirstLoadedFile ;
366 ; ----------------------------------;
367 JZ RestoreDefaultACCEPT ;
368 MOV #NOECHO,PC ; -- org len if return to SD_ACCEPT
369 ; ----------------------------------;
370 RestoreDefaultACCEPT ; if no more handle, first loaded file is closed...
371 ; ----------------------------------;
372 MOV #TIB_ORG,&CIB_ORG ; restore TIB as Current Input Buffer for next line (next QUIT)
373 MOV #BODYACCEPT,&PFAACCEPT ; restore default ACCEPT for next line (next QUIT)
374 MOV #ECHO,PC ; -- org len if return to Terminal ACCEPT
375 ; ----------------------------------;
377 .IFDEF SD_CARD_READ_WRITE
379 ; ==================================;
380 HDLFrstClus2FATsecWofstY ;WXY Input: T=Handle, HDL_CurClustHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
381 ; ==================================;
382 MOV HDLL_FirstClus(T),&ClusterL ;
383 MOV HDLH_FirstClus(T),&ClusterH ;
384 JMP ClusterHLtoFAT1sectWofstY ;
385 ; ----------------------------------;
387 ;-----------------------------------------------------------------------
388 ; SD_READ_WRITE FORTH words
389 ;-----------------------------------------------------------------------
392 ; parse string until " is encountered, convert counted string in String
393 ; then parse string until char '0'.
394 ; media identifiers "A:", "B:" ... are ignored (only one SD_Card),
395 ; char "\" as first one initializes rootDir as SearchDir.
396 ; if file found, if not already open and if free handle...
397 ; ...open the file as read and return the handle in CurrentHdl.
398 ; then load first sector in buffer, bufferLen and bufferPtr are ready for read
399 ; currentHdl keep handle that is flagged as "read".
401 ; to read sequentially next sectors use READ word. A flag is returned : true if file is closed.
402 ; the last sector so is in buffer.
404 ; if pathname is a directory, change current directory.
405 ; if an error is encountered, no handle is set, error message is displayed.
407 ; READ" acts also as CD dos command :
408 ; - READ" a:\misc\" set a:\misc as current directory
409 ; - READ" a:\" reset current directory to root
410 ; - READ" ..\" change to parent directory
412 ; to close all files type : WARM (or COLD, RESET)
414 ; ==================================;
415 FORTHWORDIMM "READ\34" ; immediate
416 ; ==================================;
418 MOV.B #1,W ; W = READ request
420 ; ----------------------------------;
422 ;Z DEL" pathame" -- immediate
423 ; ==================================;
424 FORTHWORDIMM "DEL\34" ; immediate
425 ; ==================================;
427 MOV.B #2,W ; W = DEL request
429 ; ----------------------------------;
431 ;Z WRITE" pathame" -- immediate
432 ; if file exist, free all clusters then switch handle to WRITE
433 ; if "no such file", open a write handle
434 ; ==================================;
435 FORTHWORDIMM "WRITE\34" ; immediate
436 ; ==================================;
438 MOV.B #4,W ; W = WRITE request
440 ; ----------------------------------;
442 ;Z APPEND" pathame" -- immediate
443 ; open the file designed by pathname.
444 ; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
445 ; ==================================;
446 FORTHWORDIMM "APPEND\34" ; immediate
447 ; ==================================;
449 MOV.B #8,W ; W = APPEND request
451 ; ----------------------------------;
454 ; close current handle
455 ; ==================================;
457 ; ==================================;
460 ; ----------------------------------;
462 .ENDIF ; SD_CARD_READ_WRITE
464 ;-----------------------------------------------------------------------
465 ; SD_CARD_LOADER FORTH word
466 ;-----------------------------------------------------------------------
468 ;Z LOAD" pathame" -- immediate
469 ; compile state : compile LOAD" pathname"
470 ; exec state : open a file from SD card via its pathname
471 ; see Open_File primitive for pathname conventions
472 ; the opened file becomes the new input stream for INTERPRET
473 ; this command is recursive, limited only by the count of free handles (up to 8)
474 ; LOAD" acts also as dos command "CD" :
475 ; - LOAD" \misc\" set a:\misc as current directory
476 ; - LOAD" \" reset current directory to root
477 ; - LOAD" ..\" change to parent directory
479 ; ==================================;
480 FORTHWORDIMM "LOAD\34" ; immediate
481 ; ==================================;
482 MOV.B #-1,W ; W = LOAD request
483 ; ----------------------------------;
485 ; ======================================================================
486 ; OPEN FILE primitive
487 ; ======================================================================
489 ; primitive for LOAD" READ" CREATE" WRITE" DEL"
490 ; store OpenType on TOS,
491 ; compile state : compile OpenType, compile SQUOTE and the string of provided pathname
492 ; exec state : open a file from SD card via its pathname
493 ; convert counted string found at HERE in a String then parse it
494 ; char "\" as first one initializes rootDir as SearchDir.
495 ; if file found, if not already open and if free handle...
496 ; ...open the file as read and return the handle in CurrentHdl.
497 ; if the pathname is a directory, change current directory, no handle is set.
498 ; if an error is encountered, no handle is set, an error message is displayed.
499 ; ==================================;
501 ; ==================================;
504 MOV W,TOS ; -- Open_type (-1=LOAD", 1=READ", 2=DEL", 4=WRITE", 8=APPEND")
507 ; ----------------------------------;
509 mDOCOL ; if compile state R-- LOAD"_return
510 .word lit,lit,COMMA,COMMA ; compile open_type as literal
511 .word SQUOTE ; compile string_exec + string
512 .word lit,ParenOpen,COMMA ; compile (OPEN)
514 ; ----------------------------------;
516 mDOCOL ; if exec state
517 .word lit,'"',WORDD,COUNT ; -- open_type addr cnt
520 ; ----------------------------------;
521 ParenOpen ; -- open_type addr cnt
522 ; ----------------------------------;
525 BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card module ?
526 JZ Q_SD_not_init ; yes
527 BIC #BUS_SD,&SD_SEL ; no, hide SIMO, SOMI & SCK pins (SD not initialized memory)
529 BIT #BUS_SD,&SD_SEL ; is SD init by SYS ?
530 JNZ OPEN_LetUsGo ; no --> with TOS = -1 does abort
531 MOV #NO_SD_CARD,PC ; S = 0 --> error 0
532 ; ----------------------------------;
534 ; ----------------------------------;
536 CMP #0,TOS ; cnt = 0 ?
537 JZ OPEN_Error ; yes: error 1 ===>
538 MOV @PSP+,rDOCON ; -- open_type cnt rDOCON = addr = pathname PTR
539 ADD rDOCON,TOS ; -- open_type EOS TOS = EOS (End Of String) = pathname end
540 .IFDEF SD_CARD_READ_WRITE ;
541 MOV TOS,&PathName_END ; for WRITE CREATE part
543 MOV &DIRClusterL,&ClusterL ; set DIR cluster
544 MOV &DIRClusterH,&ClusterH ;
545 ; ----------------------------------;
546 OPN_AntiSlashFirstTest ;
547 ; ----------------------------------;
548 CMP.B #'\\',0(rDOCON) ; "\" as first char ?
549 JNZ OPN_SearchInDIR ; no
550 ADD #1,rDOCON ; yes : skip '\' char
552 JMP OPN_AntiSlashFirstNext ;
553 ; ----------------------------------;
554 OPN_SearchInDIR ; <=== dir found in path
555 ; ----------------------------------;
556 MOV rDOCON,&PathName_PTR ; save Pathname ptr
557 ; ----------------------------------;
558 OPN_LoadDIRcluster ; <=== next DIR cluster loopback
559 ; ----------------------------------;
560 CALL #ClusterHLtoFrstSectorHL; output: first Sector of this cluster
561 MOV &SecPerClus,rDODOES ; set sectors count down
562 ; ----------------------------------;
563 OPN_LoadDIRsector ; <=== next DIR Sector loopback
564 ; ----------------------------------;
565 CALL #ReadSectorHL ;SWX,
566 MOV #2,S ; prepare error 2
567 ; ----------------------------------; W = 0 = DIREntryOfst
568 OPN_SearchDIRentry ; <=== next DIR_Entry loopback
569 ; ----------------------------------;
570 MOV W,&DIREntryOfst ; update DIREntryOfst
571 CMP.B #0,SD_BUF(W) ; free entry ?
572 JZ OPN_NoSuchFile ; NoSuchFile error = 2 ===>
573 MOV W,Y ; 1 W = DIREntryOfst, Y = Entry_name pointer
574 MOV #8,X ; count of chars in entry name
575 ; ----------------------------------;
577 ; ----------------------------------;
579 CMP.B T,SD_BUF(Y) ; compare Pathname with DirEntry1to8, char by char
580 JNZ OPN_CompareNameNext ;
583 JNZ OPN_CompareName ;
584 MOV.B @rDOCON+,T ; 9th char of Pathname should be '.'
585 JZ OPN_CompareNameDone ; if X = 0
586 ; ----------------------------------;
587 OPN_CompareNameNext ; remainder of 8 chars of DIR_entry name must be spaces
588 ; ----------------------------------;
589 CMP.B #32,SD_BUF(Y) ; parse DIR entry up to 8th chars
590 JNZ OPN_DIRentryMismatch ; if a char of DIR entry name <> space
593 JNZ OPN_CompareNameNext ;
594 ; ----------------------------------;
595 OPN_CompareNameDone ; T = "." or FirstNotEqualChar
596 ; ----------------------------------;
597 CMP.B #'\\',T ; FirstNotEqualChar of Pathname = "\" ?
599 ; ----------------------------------;
600 MOV #3,X ; to compare 3 char extension
601 CMP.B #'.',T ; FirstNotEqualChar of Pathname = dot ?
602 JNZ OPN_CompExtensionNext ; if not
603 ; ----------------------------------;
604 OPN_CompareExtension ;
605 ; ----------------------------------;
606 CMP.B @rDOCON+,SD_BUF(Y) ; compare Pathname_ext(char) with DirEntry9to11(char)
607 JNZ OPN_CompExtensionNext ;
610 JNZ OPN_CompareExtension ;
611 JZ OPN_CompExtensionDone ;
612 ; ----------------------------------;
613 OPN_CompExtensionNext ; remainder of 8 chars of DIR_entry extension must be spaces
614 ; ----------------------------------;
615 CMP.B #32,SD_BUF(Y) ; parse DIR entry up to 11th chars
616 JNZ OPN_DIRentryMismatch ; if a char of DIR entry extension <> space
619 JNZ OPN_CompExtensionNext ;
620 ; ----------------------------------;
621 OPN_CompExtensionDone ;
622 ; ----------------------------------;
623 CMP.B #'.',-2(rDOCON) ; LastCharEqual = dot ? (case of Pathname = "..\" which matches with first DIR entry = ".")
624 JZ OPN_DIRentryMismatch ; to compare with 2th DIR entry, the good one.
625 CMP TOS,rDOCON ; EOS reached ?
626 JC OPN_EntryFound ; yes
627 ; ----------------------------------;
628 OPN_DIRentryMismatch ;
629 ; ----------------------------------;
630 MOV &PathName_PTR,rDOCON ; reload PathName_PTR as it was at last OPN_SearchInDIR
631 ADD #32,W ; W = DIREntryOfst + DIRentrySize
632 CMP #512,W ; out of sector bound ?
633 JNZ OPN_SearchDIRentry ; no, loopback for search next DIR entry in same sector
634 ; ----------------------------------;
637 SUB #1,rDODOES ; count of Dir sectors reached ?
638 JNZ OPN_LoadDIRsector ; no, loopback to load next DIR sector in same cluster
639 ; ----------------------------------;
640 CALL #ClusterHLtoFAT1sectWofstY ; load FATsector in SD_Buffer, set Y = FAToffset
641 CMP #-1,0(Y) ; last DIR cluster ?
642 JNZ OPN_SetNextDIRcluster ;
644 .IFNDEF SD_CARD_READ_WRITE ;
645 JZ OPN_NoSuchFile ; yes, NoSuchFile error = 2 ===>
647 JNZ OPN_SetNextDIRcluster ; no
648 OPN_QcreateDIRentry ; -- open_type EOS
649 CMP #4,0(PSP) ; open type = WRITE" or APPEND" ?
650 JNC OPN_NoSuchFile ; no: NoSuchFile error = 2 ===>
651 OPN_AddDIRcluster ; yes
652 PUSH #OPN_LoadDIRcluster ; as RETurn of GetNewCluster: ===> loopback to load this new DIR cluster
653 ; ==================================;
654 GetNewCluster ; called by Write_File
655 ; ==================================;
656 PUSH Y ; push previous FAToffset
657 PUSH W ; push previous FATsector
658 CALL #SearchMarkNewClusterHL ;SWXY input: W = FATsector Y = FAToffset, output: ClusterHL, W = FATsector of New cluster
659 CMP @RSP,W ; previous and new clusters are in same FATsector?
660 JZ LinkClusters ; yes
661 ; ----------------------------------;
662 UpdateNewClusterFATs ;
663 ; ----------------------------------;
664 MOV @RSP,W ; W = previous FATsector
665 CALL #ReadFAT1SectorW ;SWX reload previous FATsector in buffer to link clusters
666 ; ----------------------------------;
668 ; ----------------------------------;
669 MOV @RSP+,W ; W = previous FATsector
670 MOV @RSP+,Y ; Y = previous FAToffset
671 MOV &ClusterL,SD_BUF(Y) ; store new cluster to current cluster address in previous FATsector buffer
672 MOV &ClusterH,SD_BUF+2(Y) ;
673 JMP SaveSectorWtoFATs ;SWXY update FATs from SD_BUF to W = previous FATsector, then RET
674 ; ==================================;
675 .ENDIF ; SD_CARD_READ_WRITE ;
676 ; ----------------------------------;
677 OPN_SetNextDIRcluster ;
678 ; ----------------------------------;
681 JMP OPN_LoadDIRcluster ; ===> loop back to load this new DIR cluster
682 ; ----------------------------------;
684 ; ----------------------------------;
685 OPN_EntryFound ; Y points on the file attribute (11th byte of entry)
686 ; ----------------------------------;
687 ; MOV W,&DIREntryOfst ;
688 MOV SD_BUF+14H(W),&ClusterH ; first clusterH of file
689 MOV SD_BUF+1Ah(W),&ClusterL ; first clusterL of file
691 BIT.B #10h,SD_BUF+0Bh(W) ; test if Directory or File
692 JZ OPN_FileFound ; is a file
693 ; ----------------------------------;
694 OPN_DIRfound ; entry is a DIRECTORY
695 ; ----------------------------------;
696 CMP #0,&ClusterH ; case of ".." entry, when parent directory is root
697 JNZ OPN_DIRfoundNext ;
698 CMP #0,&ClusterL ; case of ".." entry, when parent directory is root
699 JNZ OPN_DIRfoundNext ;
700 OPN_AntiSlashFirstNext
701 MOV #2,&ClusterL ; set clusterL as RootDIR cluster
703 CMP TOS,rDOCON ; EOS reached ?
704 JNC OPN_SearchInDIR ; no: (rDOCON points after "\") ==> loop back
705 ; ----------------------------------;
706 OPN_SetCurrentDIR ; -- open_type ptr PathName_PTR is set on name of this DIR
707 ; ----------------------------------;
708 MOV &ClusterL,&DIRClusterL ;
709 MOV &ClusterH,&DIRclusterH ;
710 MOV #0,0(PSP) ; -- open_type ptr set open_type = 0 = DIR
712 ; ----------------------------------;
713 OPN_FileFound ; -- open_type ptr PathName_PTR is set on name of file
714 ; ----------------------------------;
716 CALL #GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
717 ; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
718 OPN_NoSuchFile ; S = error 2
720 MOV #xdodoes,rDODOES ; restore rDODOES
721 MOV #xdocon,rDOCON ; restore rDODOES
722 MOV @PSP+,W ; -- ptr W = open_type
724 ; ----------------------------------; then go to selected OpenType subroutine (OpenType = W register)
727 ; ======================================================================
728 ; LOAD" primitive as part of Open_File
729 ; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
730 ; Buffer = [DIRsector], ClusterHL = FirstClusterHL
731 ; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
732 ; output: nothing else abort on error
733 ; ======================================================================
735 ; ----------------------------------;
737 ; ----------------------------------;
739 JNZ OPEN_QLOAD ; nothing else to do
741 ; ----------------------------------;
743 ; ----------------------------------;
744 .IFDEF SD_CARD_READ_WRITE ;
745 CMP.B #-1,W ; open_type = LOAD"
746 JNZ OPEN_1W ; next step
748 ; ----------------------------------; here W is free
750 ; ----------------------------------;
751 CMP #0,S ; open file happy end ?
756 ; ----------------------------------;
758 ; ----------------------------------;
759 OPEN_Error ; S= error
760 ; ----------------------------------;
761 ; Error 1 : PathNameNotFound ; S = error 1
762 ; Error 2 : NoSuchFile ; S = error 2
763 ; Error 4 : alreadyOpen ; S = error 4
764 ; Error 8 : NomoreHandle ; S = error 8
765 ; ----------------------------------;
766 MOV #SD_CARD_FILE_ERROR,PC ;
767 ; ----------------------------------;
770 ; to enable bootstrap: BOOT
771 ; to disable bootstrap: NOBOOT
773 ; XBOOT [SYSRSTIV|USERSTIV] --
774 ; here we are after INIT_FORTH
775 ; performs bootstrap from SD_CARD\BOOT.4th file, ready to test SYSRSTIV|USERSYS value
776 XBOOT CALL &HARD_APP ; WARM first calls HARD_APP (which includes INIT_HARD_SD)
777 MOV #PSTACK-2,PSP ; preserve SYSRSTIV|USERSYS in TOS for BOOT.4TH tests
778 MOV #0,0(PSP) ; set TOS = 0 for the next of XBOOT
780 .word XSQUOTE ; -- SYSRSTIV|USERSYS addr u
781 .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
782 .word BRAN,QUIT4 ; to interpret this string, then loop back to QUIT1/QUIT2
783 ; ----------------------------------;
785 ; ==================================;
786 FORTHWORD "BOOT" ; to enable BOOT
787 ; ==================================;
788 MOV #XBOOT,&PUCNEXT ; inserts XBOOT in PUC chain.
791 ; ==================================;
792 FORTHWORD "NOBOOT" ; to disable BOOT
793 ; ==================================;
794 NOBOOT MOV #WARM,&PUCNEXT ; removes XBOOT from PUC chain.