; -*- coding: utf-8 -*-
; forthMSP430FR_SD_LOAD.asm
-;Z SD_ACCEPT addr addr len -- addr' len' get line to interpret from a SD Card file
-; no interrupt allowed
-; defered word ACCEPT is redirected here by the word LOAD"
-; "defered" word CIB is redirected to SDIB (PAD if RAM<2k) by the word LOAD"
-; sequentially move an input line ended by CRLF from SD_BUF to PAD
-; if end of SD_BUF is reached before CRLF, asks Read_HandledFile to refill buffer with next sector
-; then load the end of the line to PAD ptr.
-; when all LOAD"ed files are read, redirects defered word ACCEPT to default ACCEPT and restore interpret pointers.
-; see CloseHandleT.
+; Tested with MSP-EXP430FR5994 launchpad
+; Copyright (C) <2019> <J.M. THOORENS>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
; used variables : BufferPtr, BufferLen
; SD card OPEN, LOAD subroutines
;-----------------------------------------------------------------------
-; used variables : BufferPtr, BufferLen
-
; rules for registers use
; S = error
; T = CurrentHdl, pathname
; W = SectorL, (RTC) TIME
; X = SectorH, (RTC) DATE
-; Y = BufferPtr, (DIR) EntryOfst, FAToffset
+; Y = BufferPtr, (DIR) DIREntryOfst
-; ----------------------------------;
-HDLCurClusToFAT1sectWofstY ;WXY Input: T=currentHandle, Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
-; ----------------------------------;
+; ==================================;
+HDLcurClus2FATsecWofstY ;WXY Input: T=Handle, HDL_CurClustHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
+; ==================================;
MOV HDLL_CurClust(T),&ClusterL ;
MOV HDLH_CurClust(T),&ClusterH ;
-; ----------------------------------;
-ClusterToFAT1sectWofstY ;WXY Input : Cluster ; Output: W = FATsector, Y = FAToffset
-; ----------------------------------;
+; ==================================;
+ClusterHLtoFAT1sectWofstY ;WXY Input : ClusterHL Output: ClusterHL, FATsector, W = FATsector, Y = FAToffset
+; ==================================;
MOV.B &ClusterL+1,W ;3 W = ClusterLoHI
- MOV.B &ClusterL,Y ;3 Y = ClusterLoLo
- CMP #1,&FATtype ;3 FAT16?
- JZ CTF1S_end ;2 yes
-
+ MOV.B &ClusterL,Y ;3 Y = ClusterLOlo
; input : Cluster n, max = 7FFFFF (SDcard up to 256 GB)
; ClusterLoLo*4 = displacement in 512 bytes sector ==> FAToffset
; ClusterHiLo&ClusterLoHi +C << 1 = relative FATsector + orgFAT1 ==> FATsector
; ----------------------------------;
- MOV.B &ClusterH,X ; X = 0:ClusterHiLo
- SWPB X ; X = ClusterHiLo:0
- ADD X,W ; W = ClusterHiLo:ClusterLoHi
+ MOV.B &ClusterH,X ; X = 0:ClusterHIlo
+ SWPB X ; X = ClusterHIlo:0
+ BIS X,W ; W = ClusterHIlo:ClusterLOhi
; ----------------------------------;
- SWPB Y ; Y = ClusterLoLo:0
- ADD Y,Y ;1 Y = ClusterLoLo:0 << 1 + carry for FATsector
- ADDC W,W ; W = ClusterHiLo:ClusterLoHi << 1 = ClusterHiLo:ClusterL / 128
- SWPB Y
-CTF1S_end
- ADD Y,Y ; Y = 0:ClusterLoLo << 1
+ SWPB Y ; Y = ClusterLOlo:0
+ ADD Y,Y ;1 Y = ClusterLOlo:0 << 1 (+ carry for FATsector)
+ ADDC W,W ; FATsector = W = ClusterHIlo:ClusterLOhi<<1 + Carry
+ SWPB Y ; Y = 0:ClusterLOlo
+ ADD Y,Y ; FAToffset = Y = 0:ClusterLOlo << 1 for FAT16 and 0:ClusterLOlo<<2 for FAT32
MOV @RSP+,PC ;4
; ----------------------------------;
+; ==================================;
+ReadFAT1SectorW ;SWX (< 65536)
+; ==================================;
+ ADD &OrgFAT1,W ;
+ MOV #0,X ; FAT1_SectorHI = 0
+ JMP ReadSectorWX ;SWX read FAT1SectorW
+; ----------------------------------;
; use no registers
-; ----------------------------------; Input : Cluster, output: Sector = Cluster_first_sector
-ComputeClusFrstSect ; If Cluster = 1 ==> RootDirectory ==> SectorL = OrgRootDir
-; ----------------------------------; Output: SectorL of Cluster
- MOV #0,&SectorH ;
- MOV &OrgRootDir,&SectorL ;
- CMP.B #0,&ClusterH ; clusterH <> 0 ?
- JNE CCFS_AllOthers ; yes
- CMP #1,&ClusterL ; clusterHL = 1 ? (FAT16 specificity)
- JZ CCFS_RET ; yes, sectorL for FAT16 OrgRootDIR is done
-CCFS_AllOthers ;
-; ----------------------------------;
+; ==================================;
+ClusterHLtoFrstSectorHL ; Input : ClusterHL, output: first SectorHL of ClusterHL
+; ==================================;
.IFDEF MPY ; general case
; ----------------------------------;
MOV &ClusterL,&MPY32L ;3
; ----------------------------------;
-; ----------------------------------;
-ComputeHDLcurrentSector ; input: currentHandle, output: Cluster, Sector
-; ----------------------------------;
- MOV HDLL_CurClust(T),&ClusterL ;
- MOV HDLH_CurClust(T),&ClusterH ;
- CALL #ComputeClusFrstSect ;
- MOV.B HDLB_ClustOfst(T),W ;
- ADD W,&SectorL ;
- ADDC #0,&SectorH ;
- MOV @RSP+,PC ;
-; ----------------------------------;
-
-; ----------------------------------; input : X = countdown_of_spaces, Y = name pointer in buffer
-ParseEntryNameSpaces ;XY
-; ----------------------------------; output: Z flag, Y is set after the last space char
- CMP #0,X ;
- JZ PENSL_END ;
-; ----------------------------------;
-ParseEntryNameSpacesLoop ;
-; ----------------------------------;
- CMP.B #32,SD_BUF(Y) ; SPACE ?
- JNZ PENSL_END ; no: RET
- ADD #1,Y ;
- SUB #1,X ;
- JNZ ParseEntryNameSpacesLoop;
-PENSL_END ;
- MOV @RSP+,PC ;
-; ----------------------------------;
-
-
-; sequentially load in SD_BUF bytsPerSec bytes of a file opened as read or as load
-; if new bufferLen have a size <= BufferPtr, closes the file then RET.
-; if previous bufferLen had a size < bytsPerSec, closes the file and reloads previous LOADed file if exist.
-; HDLL_CurSize leaves the not yet read size
-; All used registers must be initialized.
; ==================================;
-Read_File ; <== SD_ACCEPT, READ
+HDLCurClusPlsOfst2sectorHL ;SWX input: HDL (CurClust, ClustOfst) output: SectorHL
; ==================================;
- MOV &CurrentHdl,T ;
- MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
-; ----------------------------------;
- CMP #bytsPerSec,&BufferLen ;
- JNZ CloseHandleT ; because this last and incomplete sector is already read
- SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
- SUBC #0,HDLH_CurSize(T) ;
- ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
- CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
- JNC SetBufLenAndLoadCurSector ; no
-; ----------------------------------;
-;SearchNextCluster ; yes
-; ----------------------------------;
- MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
- CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
- ADD &OrgFAT1,W ;
- MOV #0,X ;
- CALL #ReadSectorWX ;SWX (< 65536)
- MOV #0,HDLH_CurClust(T) ;
- MOV SD_BUF(Y),HDLL_CurClust(T) ;
- CMP #1,&FATtype ; FAT16?
- JZ SetBufLenAndLoadCurSector ;
- MOV SD_BUF+2(Y),HDLH_CurClust(T);
-; ==================================;
-SetBufLenAndLoadCurSector ;WXY <== previous handle reLOAD with BufferPtr<>0
-; ==================================;
- MOV #bytsPerSec,&BufferLen ; preset BufferLen
- CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
- JNZ LoadHDLcurrentSector ; yes
- CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedBuffer)
- JC CloseHandleT ; yes
- CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
- JC LoadHDLcurrentSector ; yes
- MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
-; ==================================;
-LoadHDLcurrentSector ; <=== OPEN_WRITE_APPEND
-; ==================================;
- CALL #ComputeHDLcurrentSector ; use no registers
+ MOV HDLL_CurClust(T),&ClusterL ;
+ MOV HDLH_CurClust(T),&ClusterH ;
; ==================================;
-ReadSector ;
+ClusterHL2sectorHL ;W input: ClusterHL, ClustOfst output: SectorHL
; ==================================;
- MOV &SectorL,W ; Low
- MOV &SectorH,X ; High
- JMP ReadSectorWX ; SWX then RET
+ CALL #ClusterHLtoFrstSectorHL ;
+ MOV.B HDLB_ClustOfst(T),W ; byte to word conversion
+ ADD W,&SectorL ;
+ ADDC #0,&SectorH ;
+ MOV @RSP+,PC ;
; ----------------------------------;
; if other open_load token, decrement token, save previous context
; OPEN subroutine
-; Input : EntryOfst, Cluster = EntryOfst(HDLL_FirstClus())
+; Input : DIREntryOfst, Cluster = DIREntryOfst(HDLL_FirstClus())
; init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus,HDLL_CurClust,HDLL_CurSize)
; Output: Cluster = first Cluster of file, X = CurrentHdl
-; ----------------------------------; input : Cluster, EntryOfst
+; ==================================; input : Cluster, DIREntryOfst
GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
-; ----------------------------------; output : T = new CurrentHdl
+; ==================================; output : T = new CurrentHdl
MOV #8,S ; prepare file already open error
MOV #FirstHandle,T ;
MOV #0,X ; X = init previous handle as 0
; ----------------------------------;
SearchHandleLoop ;
; ----------------------------------;
- CMP.B #0,HDLB_Token(T) ; free handle ?
- JZ FreeHandleFound ; yes
+ CMP.B #0,HDLB_Token(T) ; free handle ?
+ JZ FreeHandleFound ; yes
AlreadyOpenTest ; no
CMP &ClusterH,HDLH_FirstClus(T);
JNE SearchNextHandle ;
CMP &ClusterL,HDLL_FirstClus(T);
- JZ InitHandleRET ; error 8: Already Open abort ===>
+ JZ OPEN_Error ; error 8: Already Open abort ===>
SearchNextHandle ;
MOV T,X ; handle is occupied, keep it in X as previous handle
ADD #HandleLenght,T ;
CMP #HandleEnd,T ;
JNZ SearchHandleLoop ;
- ADD S,S ; 16 = no more handle error, abort ===>
-InitHandleRET ;
- MOV @RSP+,PC ;
+ ADD S,S ;
+ JMP OPEN_Error ; error 16 = no more handle error, abort ===>
; ----------------------------------;
FreeHandleFound ; T = new handle, X = previous handle
; ----------------------------------;
; ----------------------------------;
InitHandle ;
; ----------------------------------;
- MOV.B W,HDLB_Token(T) ; marks handle as open type: <0=LOAD, 1=READ, 2=WRITE, 4=DEL
+ MOV.B W,HDLB_Token(T) ; marks handle as open type: <0=LOAD, 1=READ, 2=DEL, 4=WRITE, 8=APPEND
MOV.B #0,HDLB_ClustOfst(T) ; clear ClustOfst
MOV &SectorL,HDLL_DIRsect(T); init handle DIRsectorL
- MOV &SectorH,HDLH_DIRsect(T);
- MOV &EntryOfst,Y ;
+ MOV &SectorH,HDLH_DIRsect(T);
+ MOV &DIREntryOfst,Y ;
MOV Y,HDLW_DIRofst(T) ; init handle SD_BUF offset of DIR entry
MOV SD_BUF+26(Y),HDLL_FirstClus(T); init handle firstcluster of file (to identify file)
- MOV SD_BUF+20(Y),HDLH_FirstClus(T)
- MOV SD_BUF+26(Y),HDLL_CurClust(T) ; init handle CurrentCluster
- MOV SD_BUF+20(Y),HDLH_CurClust(T)
+ MOV SD_BUF+20(Y),HDLH_FirstClus(T); = 0 if new DIRentry (create write file)
+ MOV SD_BUF+26(Y),HDLL_CurClust(T); init handle CurrentCluster
+ MOV SD_BUF+20(Y),HDLH_CurClust(T); = 0 if new DIRentry (create write file)
MOV SD_BUF+28(Y),HDLL_CurSize(T); init handle LOW currentSizeL
- MOV SD_BUF+30(Y),HDLH_CurSize(T);
+ MOV SD_BUF+30(Y),HDLH_CurSize(T); = 0 if new DIRentry (create write file)
MOV #0,&BufferPtr ; reset BufferPtr all type of files
- CMP.B #2,W ; is a WRITE file handle?
- JZ ComputeHDLcurrentSector ; = 2, is a WRITE file
- JGE InitHandleRET ; > 2, is a file to be deleted
- MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD file
+ CMP.B #2,W ; del file request (2) ?
+ JZ InitHandleRET ;
+ JGE HDLCurClusPlsOfst2sectorHL ; set ClusterHL and SectorHL for all WRITE requests
+; ----------------------------------;
+ MOV #0,HDLW_BUFofst(T) ; < 2, is a READ or a LOAD request
CMP.B #-1,W ;
JZ ReplaceInputBuffer ; case of first loaded file
JL SaveBufferContext ; case of other loaded file
- JMP SetBufLenAndLoadCurSector ; case of READ file
+ JMP SetBufLenLoadCurSector ; case of READ file
; ----------------------------------;
ReplaceInputBuffer ;
; ----------------------------------;
- MOV #SDIB_ORG,&CIB_ADR ; set SD Input Buffer as Current Input Buffer before return to QUIT
+ MOV #SDIB_ORG,&CIB_ORG ; set SD Input Buffer as Current Input Buffer before return to QUIT
MOV #SD_ACCEPT,&PFAACCEPT ; redirect ACCEPT to SD_ACCEPT before return to QUIT
; ----------------------------------;
-SaveBufferContext ; (see CloseHandleT)
+SaveBufferContext ; (see CloseHandle)
; ----------------------------------;
MOV &SOURCE_LEN,HDLW_PrevLEN(T) ; = CPL
SUB &TOIN,HDLW_PrevLEN(T) ; PREVLEN = CPL - >IN
MOV &SOURCE_ORG,HDLW_PrevORG(T) ; = CIB
ADD &TOIN,HDLW_PrevORG(T) ; PrevORG = CIB + >IN
- JMP SetBufLenAndLoadCurSector ; then RET
+ JMP SetBufLenLoadCurSector ; then RET
+; ----------------------------------;
+InitHandleRET ;
+; ----------------------------------;
+ MOV @RSP+,PC ;
; ----------------------------------;
+; sequentially load in SD_BUF bytsPerSec bytes of a file opened as read or as load
+; if new bufferLen have a size <= BufferPtr, closes the file then RET.
+; if previous bufferLen had a size < bytsPerSec, closes the file and reloads previous LOADed file if exist.
+; HDLL_CurSize leaves the not yet read size
+; All used registers must be initialized.
+; ==================================;
+Read_File ; <== SD_ACCEPT, READ
+; ==================================;
+ MOV &CurrentHdl,T ;
+ MOV #0,&BufferPtr ; reset BufferPtr (the buffer is already read)
; ----------------------------------;
-CloseHandleHere ;
+ CMP #bytsPerSec,&BufferLen ;
+ JNZ CloseHandle ; because this last and incomplete sector is already read
+ SUB #bytsPerSec,HDLL_CurSize(T) ; HDLL_CurSize is decremented of one sector lenght
+ SUBC #0,HDLH_CurSize(T) ;
+ ADD.B #1,HDLB_ClustOfst(T) ; current cluster offset is incremented
+ CMP.B &SecPerClus,HDLB_ClustOfst(T) ; Cluster Bound reached ?
+ JNC SetBufLenLoadCurSector ; no
+; ----------------------------------;
+;SearchNextClusterInFAT1 ;
+; ----------------------------------;
+ MOV.B #0,HDLB_ClustOfst(T) ; reset Current_Cluster sectors offset
+ CALL #HDLcurClus2FATsecWofstY;WXY Output: FATsector W=FATsector, Y=FAToffset
+ CALL #ReadFAT1SectorW ;SWX (< 65536)
+ MOV #0,HDLH_CurClust(T) ; preset HDLH_CurClust(T)=0 for FAT16
+ MOV SD_BUF(Y),HDLL_CurClust(T) ;
+ MOV SD_BUF+2(Y),HDLH_CurClust(T); set HDLH_CurClust(T)=0 for FAT32
+; ==================================;
+SetBufLenLoadCurSector ;WXY <== previous handle reLOAD with BufferPtr<>0
+; ==================================;
+ MOV #bytsPerSec,&BufferLen ; preset BufferLen
+ CMP #0,HDLH_CurSize(T) ; CurSize > 65535 ?
+ JNZ LoadCurSectorHL ; yes
+ CMP HDLL_CurSize(T),&BufferPtr ; BufferPtr >= CurSize ? (BufferPtr = 0 or see RestorePreviousLoadedBuffer)
+ JC CloseHandle ; yes
+ CMP #bytsPerSec,HDLL_CurSize(T) ; CurSize >= 512 ?
+ JC LoadCurSectorHL ; yes
+ MOV HDLL_CurSize(T),&BufferLen ; no: adjust BufferLen
+; ==================================;
+LoadCurSectorHL ;
+; ==================================;
+ CALL #HDLCurClusPlsOfst2sectorHL;SWX
+; ==================================;
+ReadSectorHL ;
+; ==================================;
+ MOV &SectorL,W ; Low
+ MOV &SectorH,X ; High
+ JMP ReadSectorWX ; SWX then RET
+; ----------------------------------;
+
+
+; ----------------------------------;
+CloseHandleT ;
; ----------------------------------;
MOV.B #0,HDLB_Token(T) ; release the handle
MOV @T,T ; T = previous handle
RestorePreviousLoadedBuffer ;
; ----------------------------------;
MOV HDLW_BUFofst(T),&BufferPtr ; restore previous BufferPtr
- CALL #SetBufLenAndLoadCurSector ; then reload previous buffer
- BIC #Z,SR ;
+ CALL #SetBufLenLoadCurSector ; then reload previous buffer
+ BIC #Z,SR ;
; ----------------------------------;
CloseHandleRet ;
MOV @RSP+,PC ; Z = 1 if no more handle
; ==================================;
-CloseHandleT ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
+CloseHandle ; <== CLOSE, Read_File, TERM2SD", OPEN_DEL
; ==================================;
MOV &CurrentHdl,T ;
CMP #0,T ; no handle?
JZ CloseHandleRet ; RET
; ----------------------------------;
.IFDEF SD_CARD_READ_WRITE
- CMP.B #2,HDLB_Token(T) ; opened as write (updated) file ?
- JNZ TestClosedToken ; no
- CALL #WriteBuffer ;SWXY
- CALL #OPWW_UpdateDirectory ;SWXY
+ CMP.B #4,HDLB_Token(T) ; WRITE file ?
+ JNZ TestClosedToken ; no, case of DEL READ LOAD file
+;; ----------------------------------; optionnal
+; MOV &BufferPtr,W ;
+;FullFillZero ;the remainder of sector
+; CMP #BytsPerSec,W ;2 buffer full ?
+; JZ CloseWriteHandle ;2 remainding of buffer is full filled with 0
+; MOV.B #0,SD_BUF(W) ;3
+; ADD #1,W ;1
+; JMP FullFillZero ;2
+;; ----------------------------------;
+WriteBeforeClose
+ CALL #WriteSD_Buf ;SWX
+CloseWriteHandle
+ CALL #LoadUpdateSaveDirEntry ;SWXY
.ENDIF ;
; ----------------------------------;
TestClosedToken ;
; ----------------------------------;
CaseOfAnyReadWriteDelFileIsClosed ; token >= 0
; ----------------------------------;
- JGE CloseHandleHere ; then RET
+ JGE CloseHandleT ; then RET
; ----------------------------------;
CaseOfAnyLoadedFileIsClosed ; -- org' len' R-- QUIT3 dst_ptr dst_len SD_ACCEPT
; ----------------------------------;
; ----------------------------------;
ReturnOfSD_ACCEPT ;
; ----------------------------------;
- ADD #6,RSP ; R-- QUIT4 empties return stack
+ ADD #6,RSP ; R-- QUIT3 empties return stack
MOV @RSP+,IP ; skip return to SD_ACCEPT
; ----------------------------------;
- CALL #CloseHandleHere ; Z = 1 if no more handle
+ CALL #CloseHandleT ; Z = 1 if no more handle
; ----------------------------------;
CheckFirstLoadedFileIsClosed ;
; ----------------------------------;
; ----------------------------------;
RestoreDefaultACCEPT ; if no more handle, first loaded file is closed...
; ----------------------------------;
- MOV #TIB_ORG,&CIB_ADR ; restore TIB as Current Input Buffer for next line (next QUIT)
+ MOV #TIB_ORG,&CIB_ORG ; restore TIB as Current Input Buffer for next line (next QUIT)
MOV #BODYACCEPT,&PFAACCEPT ; restore default ACCEPT for next line (next QUIT)
MOV #ECHO,PC ; -- org len if return to Terminal ACCEPT
; ----------------------------------;
+; ==================================; input : X = countdown_of_spaces, Y = DIRsector_buffer ptr
+ParseEntryNameSpaces ;XY
+; ==================================; output: Z flag, Y is set after the last space char
+ CMP #0,X ;
+ JZ PENSL_END ;
+; ----------------------------------;
+ParseEntryNameSpacesLoop ;
+; ----------------------------------;
+ CMP.B #32,SD_BUF(Y) ; SPACE ?
+ JNZ PENSL_END ; no: RET
+ ADD #1,Y ;
+ SUB #1,X ;
+ JNZ ParseEntryNameSpacesLoop;
+PENSL_END ;
+ MOV @RSP+,PC ;
+; ----------------------------------;
+
+
.IFDEF SD_CARD_READ_WRITE
;-----------------------------------------------------------------------
; if pathname is a directory, change current directory.
; if an error is encountered, no handle is set, error message is displayed.
-; READ" acts also as CD dos command :
+; READ" acts also as CD dos command :
; - READ" a:\misc\" set a:\misc as current directory
; - READ" a:\" reset current directory to root
; - READ" ..\" change to parent directory
; to close all files type : WARM (or COLD, RESET)
-; ----------------------------------;
+; ==================================;
FORTHWORDIMM "READ\34" ; immediate
-; ----------------------------------;
+; ==================================;
READDQ
- MOV.B #1,W ; W = OpenType
+ MOV.B #1,W ; W = READ request
JMP Open_File ;
; ----------------------------------;
-;Z WRITE" pathame" -- immediate
-; open or create the file designed by pathname.
-; an error occurs if the file is already opened.
-; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
-; compile state : compile WRITE" pathname"
-; exec state : open or create entry selected by pathname
+;Z DEL" pathame" -- immediate
+; ==================================;
+ FORTHWORDIMM "DEL\34" ; immediate
+; ==================================;
+DELDQ
+ MOV.B #2,W ; W = DEL request
+ JMP Open_File ;
; ----------------------------------;
+
+;Z WRITE" pathame" -- immediate
+; if file exist, free all clusters then switch handle to WRITE
+; if "no such file", open a write handle
+; ==================================;
FORTHWORDIMM "WRITE\34" ; immediate
-; ----------------------------------;
+; ==================================;
WRITEDQ
- MOV.B #2,W ; W = OpenType
+ MOV.B #4,W ; W = WRITE request
JMP Open_File ;
; ----------------------------------;
-
-;Z DEL" pathame" -- immediate
-; compile state : compile DEL" pathname"
-; exec state : DELETE entry selected by pathname
-
-; ----------------------------------;
- FORTHWORDIMM "DEL\34" ; immediate
-; ----------------------------------;
-DELDQ
- MOV.B #4,W ; W = OpenType
+;Z APPEND" pathame" -- immediate
+; open the file designed by pathname.
+; the last sector of the file is loaded in buffer, and bufferPtr leave the address of the first free byte.
+; ==================================;
+ FORTHWORDIMM "APPEND\34" ; immediate
+; ==================================;
+APPENDQ
+ MOV.B #8,W ; W = APPEND request
JMP Open_File ;
; ----------------------------------;
-
-;Z CLOSE --
+;Z CLOSE --
; close current handle
-; ----------------------------------;
+; ==================================;
FORTHWORD "CLOSE" ;
-; ----------------------------------;
- CALL #CloseHandleT ;
- MOV @IP+,PC ;
+; ==================================;
+ CALL #CloseHandle ;
+ MOV @IP+,PC ;
; ----------------------------------;
.ENDIF ; SD_CARD_READ_WRITE
;Z LOAD" pathame" -- immediate
; compile state : compile LOAD" pathname"
; exec state : open a file from SD card via its pathname
-; see Open_File primitive for pathname conventions
+; see Open_File primitive for pathname conventions
; the opened file becomes the new input stream for INTERPRET
; this command is recursive, limited only by the count of free handles (up to 8)
-; LOAD" acts also as dos command "CD" :
+; LOAD" acts also as dos command "CD" :
; - LOAD" \misc\" set a:\misc as current directory
; - LOAD" \" reset current directory to root
; - LOAD" ..\" change to parent directory
-; ----------------------------------;
+; ==================================;
FORTHWORDIMM "LOAD\34" ; immediate
+; ==================================;
+ MOV.B #-1,W ; W = LOAD request
; ----------------------------------;
- MOV.B #-1,W ; W = OpenType
-; ----------------------------------;
-
; ======================================================================
; OPEN FILE primitive
; ...open the file as read and return the handle in CurrentHdl.
; if the pathname is a directory, change current directory, no handle is set.
; if an error is encountered, no handle is set, an error message is displayed.
-; ----------------------------------;
+; ==================================;
Open_File ; --
-; ----------------------------------;
+; ==================================;
SUB #2,PSP ;
MOV TOS,0(PSP) ;
- MOV W,TOS ; -- Open_type (0=LOAD", 1=READ", 2=WRITE", 4=DEL")
+ MOV W,TOS ; -- Open_type (-1=LOAD", 1=READ", 2=DEL", 4=WRITE", 8=APPEND")
CMP #0,&STATE ;
JZ OPEN_EXEC ;
; ----------------------------------;
; ----------------------------------;
OPEN_EXEC ;
mDOCOL ; if exec state
- .word lit,'"',WORDD,COUNT ; -- open_type addr u
+ .word lit,'"',WORDD,COUNT ; -- open_type addr cnt
.word $+2 ;
MOV @RSP+,IP ;
; ----------------------------------;
-ParenOpen ; -- open_type HERE HERE as pathname ptr
+ParenOpen ; -- open_type addr cnt
; ----------------------------------;
MOV @PSP+,rDOCON ; rDOCON = addr = pathname PTR
ADD rDOCON,TOS ; TOS = EOS (End Of String) = pathname end
.IFDEF SD_CARD_READ_WRITE ;
- MOV TOS,&EndOfPath ; for WRITE CREATE part
+ MOV TOS,&PathName_END ; for WRITE CREATE part
.ENDIF
; ----------------------------------;
-OPN_PathName ;
+;OPN_PathName ;
; ----------------------------------;
+ MOV #2,&ClusterL ; set root DIR cluster
+ MOV #0,&ClusterH ;
MOV #1,S ; error 1
- MOV &DIRClusterL,&ClusterL ;
- MOV &DIRclusterH,&ClusterH ;
CMP rDOCON,TOS ; PTR = EOS ? (end of pathname ?)
- JZ OPN_NoPathName ; yes: error 1 ===>
+ JZ OPEN_Error ; yes: error 1 ===>
; ----------------------------------;
CMP.B #':',1(rDOCON) ; A: B: C: ... in pathname ?
JNZ OPN_AntiSlashStartTest ; no
ADD #2,rDOCON ; yes : skip drive because not used, only one SD_card
; ----------------------------------;
OPN_AntiSlashStartTest ;
- CMP.B #'\\',0(rDOCON) ; "\" as first char ?
+ CMP.B #'\\',0(rDOCON) ; "\" as first char ?
JNZ OPN_SearchDirSector ; no
ADD #1,rDOCON ; yes : skip '\' char
- MOV &FATtype,&ClusterL ; FATtype = 1 as FAT16 RootDIR, FATtype = 2 = FAT32RootDIR
- MOV #0,&ClusterH ;
; ----------------------------------;
-OPN_EndOfStringTest ; <=== dir found in path
+OPN_EndOfStringTest ;
; ----------------------------------;
CMP rDOCON,TOS ; PTR = EOS ? (end of pathname ?)
- JZ OPN_SetCurrentDIR ; yes
+ JZ OPN_SetCurrentDIR ; if pathname ptr = end of string
; ----------------------------------;
-OPN_SearchDirSector ;
+OPN_SearchDirSector ; <=== dir found in path
; ----------------------------------;
- MOV rDOCON,&Pathname ; save Pathname ptr
- CALL #ComputeClusFrstSect ; output: SectorHL
- MOV #32,rDODOES ; preset countdown for FAT16 RootDIR sectors
- CMP #2,&FATtype ; FAT32?
- JZ OPN_SetDirSectors ; yes
- CMP &ClusterL,&FATtype ; FAT16 AND RootDIR ?
- JZ OPN_LoadDIRsector ; yes
-OPN_SetDirSectors ;
- MOV &SecPerClus,rDODOES ;
+ MOV rDOCON,&PathName_PTR ; save Pathname ptr
+ CALL #ClusterHLtoFrstSectorHL; output: SectorHL
+ MOV &SecPerClus,rDODOES ; DIR sectors = one cluster sectors
; ----------------------------------;
OPN_LoadDIRsector ; <=== Dir Sector loopback
; ----------------------------------;
- CALL #ReadSector ;SWX
+ CALL #ReadSectorHL ;SWX
; ----------------------------------;
MOV #2,S ; prepare no such file error
MOV #0,W ; init entries count
MOV W,Y ; 1
RLAM #4,Y ; --> * 16
ADD Y,Y ; 1 --> * 2
- MOV Y,&EntryOfst ; EntryOfst points to first free entry
+ MOV Y,&DIREntryOfst ; DIREntryOfst
CMP.B #0,SD_BUF(Y) ; free entry ? (end of entries in DIR)
JZ OPN_NoSuchFile ; error 2 NoSuchFile, used by create ===>
MOV #8,X ; count of chars in entry name
ADD #1,rDOCON ; 9th char of Pathname is always a dot
; ----------------------------------;
OPN_FirstCharMismatch ;
+; ----------------------------------;
CMP.B #'.',-1(rDOCON) ; FirstNotEqualChar of Pathname = dot ?
JZ OPN_DotFound ;
; ----------------------------------;
-OPN_DotNotFound ;
+OPN_DotNotFound ;
; ----------------------------------;
- ADD #3,X ; for next cases not equal chars of entry until 11 must be spaces
+ ADD #3,X ; for next cases not equal chars of DIRentry until 11 must be spaces
CALL #ParseEntryNameSpaces ; for X + 3 chars
- JNZ OPN_DIRentryMismatch ; if a char entry <> space
+ JNZ OPN_DIRentryMismatch ; if a char entry <> space
CMP.B #'\\',-1(rDOCON) ; FirstNotEqualChar of Pathname = "\" ?
JZ OPN_EntryFound ;
CMP rDOCON,TOS ; EOS exceeded ?
; ----------------------------------;
OPN_DIRentryMismatch ;
; ----------------------------------;
- MOV &pathname,rDOCON ; reload Pathname
+ MOV &PathName_PTR,rDOCON ; reload PathName_PTR as it was at last OPN_SearchDirSector
ADD #1,W ; inc entry
- CMP #16,W ; 16 entry in a sector
+ CMP #16,W ; 16 entries in a sector
JNZ OPN_SearchDIRentry ; ===> loopback for search next DIR entry
; ----------------------------------;
ADD #1,&SectorL ;
JNZ OPN_LoadDIRsector ; ===> loopback for search next DIR sector
; ----------------------------------;
MOV #4,S ;
- JMP OPN_EndOfDIR ; error 4 ===>
+ JMP OPEN_Error ; ENd of DIR error 4 ===>
; ----------------------------------;
; ----------------------------------;
OPN_DotFound ; not equal chars of entry name until 8 must be spaces
; ----------------------------------;
CMP.B #'.',-2(rDOCON) ; LastCharEqual = dot ?
- JZ OPN_DIRentryMismatch ; case of first DIR entry = "." and Pathname = "..\"
+ JZ OPN_DIRentryMismatch ; case of first DIR entry = "." and Pathname = "..\"
CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,7}
JNZ OPN_DIRentryMismatch ; if a char entry <> space
MOV #3,X ;
JMP OPN_EntryFound ;
OPN_ExtNotEqualChar ;
CMP rDOCON,TOS ; EOS exceeded ?
- JC OPN_DIRentryMismatch ; no, loop back
+ JC OPN_DIRentryMismatch ; no, loop back
CMP.B #'\\',-1(rDOCON) ; FirstNotEqualChar = "\" ?
JNZ OPN_DIRentryMismatch ;
CALL #ParseEntryNameSpaces ; parse X spaces, X{0,...,3}
; ----------------------------------;
OPN_EntryFound ; Y points on the file attribute (11th byte of entry)
; ----------------------------------;
- MOV &EntryOfst,Y ; reload DIRentry
+ MOV &DIREntryOfst,Y ; reload DIRentry
MOV SD_BUF+26(Y),&ClusterL ; first clusterL of file
- MOV SD_BUF+20(Y),&ClusterH ; first clusterT of file, always 0 if FAT16
+ MOV SD_BUF+20(Y),&ClusterH ; first clusterH of file
OPN_EntryFoundNext
BIT.B #10h,SD_BUF+11(Y) ; test if Directory or File
- JZ OPN_FileFound ;
+ JZ OPN_FileFound ; is a file
; ----------------------------------;
OPN_DIRfound ; entry is a DIRECTORY
; ----------------------------------;
JNZ OPN_DIRfoundNext ;
CMP #0,&ClusterL ; case of ".." entry, when parent directory is root
JNZ OPN_DIRfoundNext ;
- MOV &FATtype,&ClusterL ; set cluster as RootDIR cluster
+ MOV #2,&ClusterL ; set cluster as RootDIR cluster
OPN_DIRfoundNext ;
- CMP rDOCON,TOS ; EOS exceeded ?
- JC OPN_EndOfStringTest ; no: (we presume that FirstNotEqualChar = "\") ==> loop back
+ CMP rDOCON,TOS ; EOS reached ?
+ JNZ OPN_SearchDirSector ; no: (we presume that FirstNotEqualChar = "\") ==> loop back
; ----------------------------------;
-OPN_SetCurrentDIR ; -- open_type ptr
+OPN_SetCurrentDIR ; -- open_type ptr PathName_PTR is set on name of this DIR
; ----------------------------------;
MOV &ClusterL,&DIRClusterL ;
MOV &ClusterH,&DIRclusterH ;
- MOV #0,0(PSP) ; -- open_type ptr open_type = 0
+ MOV #0,0(PSP) ; -- open_type ptr open_type = 0
JMP OPN_Dir
; ----------------------------------;
-OPN_FileFound ; -- open_type ptr
+OPN_FileFound ; -- open_type ptr PathName_PTR is set on name of file
; ----------------------------------;
- MOV @PSP,W ;
+ MOV @PSP,W ;
CALL #GetFreeHandle ;STWXY init handle(HDLL_DIRsect,HDLW_DIRofst,HDLL_FirstClus = HDLL_CurClust,HDLL_CurSize)
; ----------------------------------; output : T = CurrentHdl*, S = ReturnError, Y = DIRentry offset
-OPN_NomoreHandle ; S = error 16
-OPN_alreadyOpen ; S = error 8
-OPN_EndOfDIR ; S = error 4
OPN_NoSuchFile ; S = error 2
-OPN_NoPathName ; S = error 1
-OPN_Dir
+OPN_Dir ;
MOV #xdodoes,rDODOES ; restore rDODOES
MOV #xdocon,rDOCON ; restore rDODOES
MOV @PSP+,W ; -- ptr W = open_type
; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
; output: nothing else abort on error
; ======================================================================
-
+
; ----------------------------------;
OPEN_QDIR ;
; ----------------------------------;
; ----------------------------------;
.IFDEF SD_CARD_READ_WRITE ;
CMP.B #-1,W ; open_type = LOAD"
- JNZ OPEN_QREAD ; next step
+ JNZ OPEN_1W ; next step
.ENDIF ;
; ----------------------------------; here W is free
OPEN_LOAD ;
; ----------------------------------;
CMP #0,S ; open file happy end ?
JNZ OPEN_Error ; no
-OPEN_LOAD_END
- MOV @IP+,PC ;
+OPEN_LOAD_END ;
+ MOV #NOECHO,PC ;
+; MOV @IP+,PC ;
; ----------------------------------;
; ----------------------------------;
.word BRAN,ABORT_SD ; to insert S error as flag, no return
; ----------------------------------;
-
.IFDEF BOOTLOADER
+; to enable bootstrap: BOOT
+; to disable bootstrap: NOBOOT
+
+; XBOOT [SYSRSTIV|USERSTIV] --
+; here we are after INIT_FORTH
+; performs bootstrap from SD_CARD\BOOT.4th file, ready to test SYSRSTIV|USERSYS value
+XBOOT ; BIT #1,TOS ; USERSYS request ?
+ ; JNZ AbortBoot ;
+ ; CMP #0,TOS ; WARM request ?
+ ; JZ AbortBoot ; if yes
+ BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card socket ?
+ JZ BOOT_YES ; if yes
+AbortBoot MOV #WARM,PC ; goto WARM without return
+; ----------------------------------;
+BOOT_YES CALL &HARD_APP ; CALL HARD_APP (which includes INIT_HARD_SD)
+ MOV #PSTACK-2,PSP ; preserve SYSRSTIV|USERSYS in TOS for BOOT.4TH tests
+ MOV #0,0(PSP) ; set 0 for next SYS use
+ mDOCOL ;
+ .word XSQUOTE ; -- SYSRSTIV|USERSYS addr u
+ .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
+; .byte 22,"NOECHO LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
+ .word BRAN,QUIT4 ; to interpret this string, then loop back to QUIT
+; ----------------------------------;
- FORTHWORD "[PFA]"
-; [PFA] CFA -- [PFA] ; add source indirection to DEFERSTORE
- ADD #2,TOS
- MOV @TOS,TOS
+; ==================================;
+ FORTHWORD "BOOT" ; to enable BOOT
+; ==================================;
+ MOV #XBOOT,&PUCNEXT ; inserts XBOOT in PUC chain.
MOV @IP+,PC
-; to enable bootstrap: ' BOOT IS WARM
-; to disable bootstrap: ' BOOT [PFA] IS WARM
-
- FORTHWORD "BOOT"
-; BOOT RSTIV_MEM --
-; performs bootstrap from SD_CARD\BOOT.4th file
-BOOT MOV @PC+,X
-PFA_BOOT .word INI_HARD_SD ; X = INI_HARD_SD addr, 2(X) = [PFA_X] = previous INI_HARD_APP (INIT_TERM) addr , see forthMSP430FR_SD_INIT.asm
- CMP #2,TOS ; RSTIV_MEM <> WARM ?
- JC QSD_MEM ; yes
- MOV @RSP+,PC ; if RSTIV_MEM U< 2, return to BODYWARM
-QSD_MEM BIT.B #CD_SD,&SD_CDIN ; SD_memory in SD_Card socket ?
- JZ BOOT_YES ;
-NO_BOOT MOV 2(X),PC ; if no, goto previous INIT: INIT TERMINAL then ret to PFAWARM
-;---------------------------------------------------------------------------------
-; RESET 7: if RSTIV_MEM <> WARM, init TERM, init SD
-;---------------------------------------------------------------------------------
-BOOT_YES CALL X ; init TERM UC first then init SD card, TOS = RSTIV_MEM
-;---------------------------------------------------------------------------------
-; END OF RESET
-;---------------------------------------------------------------------------------
- MOV #PSTACK-2,PSP ;
- MOV #0,0(PSP) ; PUSH 0 on Stack
- MOV #0,&STATE ; )
- MOV #LSTACK,&LEAVEPTR ; > same as QUIT
- MOV #RSTACK,RSP ; )
- ASMtoFORTH ;
- .word XSQUOTE ; -- RSTIV_MEM addr u
- .byte 15,"LOAD\34 BOOT.4TH\34" ; LOAD" BOOT.4TH" issues error 2 if no such file...
- .word BRAN,QUIT4 ; to interpret this string
- .ENDIF
+; ==================================;
+ FORTHWORD "NOBOOT" ; to disable BOOT
+; ==================================;
+ MOV #WARM,&PUCNEXT ; removes XBOOT from PUC chain.
+ MOV @IP+,PC ;
+ .ENDIF