Shop OBEX P1 Docs P2 Docs Learn Events
P1 Blockfile System in EEProm for a Standalone Computer with Tachyon 5.7 Forth — Parallax Forums

P1 Blockfile System in EEProm for a Standalone Computer with Tachyon 5.7 Forth

Christof Eb.Christof Eb. Posts: 1,106
edited 2021-07-24 16:08 in Propeller 1

P1 has 32 kBytes of Hub Ram, which amount you could call "restricted". Yet there is something like "Forth" which can act as an interactive operation system.
"Memory sizes (of Minicomputers around 1970) ranged from 16 to 64 Kbytes, although the latter were considered large. ... On this hardware, Moore’s Forth systems offered an integrated development toolkit including interactive access to an assembler, editor and the high-level Forth language, combined with a multitasking, multiuser operating environment supporting 64 users without visible degradation, all resident without run-time overlays." https://www.forth.com/resources/forth-programming-language/

Peter Jakacki's Tachyon Forth brings Forth to P1. See: https://docs.google.com/document/d/1HuBe1ULFxHfmmJ9OOBhRPEQu_RZZlKEUsPTkz3E_80Q/edit#heading=h.qztyefmek7t0
I like to recommend Tera Term as a terminal program. It can send the contents of the cut-buffer with ALT-V.

This Forth V5.7 has also a full blown FAT32 File System on board. - Unfortunately this FAT File System needs about 6.3kBytes of RAM. So if you upload the full Tachyon 5.7 to P1 you will only have 1.3kB of free memory. So lets simplify things.

Here is the suggestion of a blockfile system in the upper 32kB of the boot eeprom. These 32kB are 32 blocks of 1024Bytes of memory. A description of a blockfile system can be found here: https://www.forth.com/wp-content/uploads/2018/01/Starting-FORTH.pdf

"12 block" will read block number 12 into a ram buffer.
"update flush" will write it back into eeprom, after its content has been changed.

So with this type of file system you have to know, where the information is. No file names. You can upload the following into your Tachyon 5.7 and do "backup".

\ blockfileE.fth for TACHYON 5.7 for P1 by CWE
\ block file system in upper 32kB of eeprom

\ 1024 bytes blockBuf 

IFDEF TOOLS
 htck \ get adress of first byte in data section
 \ FORGET TOOLS
 FORGET EASYFILE
 org \ free data memory
}

IFDEF MY-EXTEND
 updated0  \ get adress of first byte data section
 FORGET MY-EXTEND
 org
}

module MY-EXTEND PRINT" BLOCKFILE and others CWE " ;

\ $7C00 := blockBuf0 \ only 1 buffer
BUFFERS := blockBuf0
byte updated0 
byte updated1

0 updated0 C!
0 updated1 C!

word actBlock0 
word actBlock1
word blockPoint0 
word blockPoint1
word eAdr0 
word eAdr1
word fkey
byte actLine byte actPos

\ the console cog0 uses buffer0, all others use 1
: blockBuf blockBuf0 COGID IF 1024 + THEN ;
: updated updated0 COGID IF 1 + THEN ;
: actBlock actBlock0 COGID IF 2 + THEN ;
: blockPoint blockPoint0 COGID IF 2 + THEN ;
: eAdr eAdr0 COGID IF 2 + THEN ;

: update \ mark block as modified
    1 updated C! ;

: flush \ write block back to eeprom if updated
    updated C@ IF
        actBlock W@ 
        1024 * $8000 + DUP eAdr W! \ adress of block in eeprom 
        blockBuf SWAP 1024 ESAVE ( ram eeprom cnt -- )
        0 updated C!
    THEN
;

: block ( blocknumber -- bufferadress ) \ read block from eeprom into blockbuffer
    \ flush 
    DUP actBlock W!
    1024 * $8000 + DUP eAdr W! \ adress of block in eeprom 
    blockBuf 1024 ELOAD ( eeprom ram cnt -- )
    0 updated C!
    blockBuf 
;

--- Read in the next character in the buffer as part of the console input stream
\ byte lastbyte ,

: BGET ( -- ch )
    blockBuf blockPoint W@ + C@ DUP 128 <> \ € for end
    blockPoint W@ 1024 < AND IF
        \ valid char
        blockPoint W@ 1+ 64 MOD 0= IF DROP 13 THEN
        blockPoint W++      
    ELSE
        DROP 13
        fkey W@ ukey W! \ switch back to console
    THEN
;    

--- Redirect the console input to read the file sequentially
: block> ukey W@ fkey W! ' BGET ukey W! ;

: load ( blocknumber -- ) \ compile block
    block DROP
    0 blockPoint W!
    block>
;

: --> \ load next block too
    actBlock W@ 1+ block DROP
    0 blockPoint W! 
    \ block>
;

: wipe ( -- ) \ wipes the block with blanks
1024 FOR
    32 I blockBuf + C! 
NEXT ;

: listBuf \ list the actual block
    CR ." Block: " actBlock W@ . CR
    16 FOR
        I actLine C@ = IF green PEN ELSE white PEN THEN
        I . SPACE
        I 10 < IF SPACE THEN
        64 FOR
            J 64 * blockBuf + I + C@ 
            DUP 32 > IF EMIT ELSE DROP SPACE THEN
        NEXT
        CR
    NEXT
;

: list ( blocknumber -- ) \ list a block
    block DROP 0 actLine C! 0 actPos C! listBuf
;

: uf update flush ;
: l listBuf ;

: >line ( stringadress linenumber -- ) \ put string into line of blockBuf
    64 * blockBuf + $! ;

: getBuf \ get Block Buffer from keyboard
    ." Euro=128 for End" CR
    wipe
    0 blockPoint W!
    BEGIN
        WKEY DUP 10 <> IF 
            DUP 128 = IF DROP CR l EXIT THEN
            DUP EMIT 
            DUP 13 <> IF DUP blockBuf blockPoint W@ + C! THEN
            13 = IF 
                blockPoint W@ %1111.1111.1100.0000 AND 64 + blockPoint W!
            ELSE
                blockPoint W++
            THEN
        ELSE DROP THEN
    blockPoint W@ 1024 = UNTIL
    CR l
;

\ use block for data storage

: putBuf$ ( str line endpos -- ) \ put string into blockBuf rigth adjusted
    SWAP 64 * + blockBuf + \ last position ( str endadr )
    OVER LEN$ - 
    DUP 1- 32 SWAP C! \ put a blank before it
    $! ;

: putBuf# ( number line endpos ) \ put number into blockBuf 
    ROT NUM>STR -ROT putBuf$ ;

: getNum ( line endpos -- number ) \ get number from blockBuf right adjusted
    SWAP 64 * + blockBuf + \ last position 
    BEGIN \ search startpos 
        1- 
        DUP C@ 
        DUP 45 <  SWAP 57 > OR UNTIL 
    1+ STR>NUM
;

.STATS

Blocks can contain readable text. With "12 list" you load a block into ram and get a listing on the screen, which is organised as 16 lines of 64 chars. With "16 load" you can compile the text. If the last line of this screen has "-->" in it, the next block will be compiled too.

With "16 list getBuf" and after sending the contents "update flush" you can upload single screens. getBuf ends, when it receives code 128, which is €.

So now you can upload and list block files and you can compile them. What about an editor?

( Block 16 Block Editor CWE ) FORGET MYTOOL module MYTOOL
: copy ( sourceblock destinationblock -- ) ( copy block )
    SWAP block DROP actBlock W! update flush ;
: .Line CR ( print act line ) ."    "
    64 FOR I actPos C@ = IF green PEN 94 EMIT white PEN THEN   
        blockBuf actLine C@ 64 * + I +  C@ EMIT   NEXT ;
: t ( linenumber -- ) ( set active line number )
    DUP actLine C! 0 actPos C! l .Line ;
: cRight actPos DUP C@ 1+ 63 MIN SWAP C! ;
: cLeft actPos DUP C@ 1- 0 MAXS SWAP C! ;
: lUp actLine DUP C@ 1- 0 MAXS SWAP C! ;
: lDown actLine DUP C@ 1+ 15 MIN SWAP C! 0 actPos C! ;
: cDel  actPos C@ 0 > IF blockBuf actLine C@ 64 * + DUP 
        actPos C@ + DUP 1- 63 actPos C@ - CMOVE 
        actPos C--   63 + 32 SWAP C!   THEN ; 
--> €




( Block 17 Block Editor CWE )        
: cIns ( char -- ) actPos C@ 63 < IF   
    blockBuf actLine C@ 64 * + 
    actPos C@ + DUP DUP 1+ 63 actPos C@ - <CMOVE   
    C!   actPos C++   THEN ;
: lDel ( Active Line delete )
    actLine C@ 0 > IF   blockBuf actLine C@ 1+ 64 * + 
        DUP 64 - 15 actLine C@ - 64 * CMOVE 
        64 FOR
            32   blockBuf 959 + I +   C!   NEXT   THEN ;
--> €           









( Block 18 Block Editor CWE )
: lIns ( Line insert )
    actLine C@ 14 < IF   blockBuf actLine C@ 64 * + 
        DUP 64 + 15 actLine C@ - 64 * <CMOVE 
        64 FOR
            32   blockBuf actLine C@ 64 * + I +   C! 
        NEXT   THEN ;
: curUpStart ( cursor to beginning of the line 1 lines up )
    27 EMIT 91 EMIT 49 EMIT 70 EMIT ;
byte inkey
: doKey inkey C@ SWITCH
    4 CASE cRight BREAK    19 CASE cLeft BREAK
    5 CASE lUp l BREAK    13 CASE lDown l BREAK
    8 CASE cDel BREAK    24 CASE lDel l BREAK
    25 CASE lIns l BREAK    32 128 CASES inkey C@ cIns BREAK
; --> €




( Block 19 Block Editor CWE )
: w CR blue PEN ( This is the Editor after x list )
    ." ^d cRight; ^s cLeft; ^e up; CR down; ^c End; " CR
    ." ^x lineDel ^y lineInsert; " CR white PEN
    BEGIN WKEY DUP inkey C! doKey   curUpStart .Line 
    3 = UNTIL l ;
: .index ( Print 1st line of all blocks )
    32 FOR I block DROP CR I . ."  " blockBuf 63 CTYPE NEXT ;
: lan ( list without numbers ) CR 
    16 FOR CR blockBuf I 64 * + 63 CTYPE NEXT CR ;
€

So you can "16 load" to compile it. This can be seen as an overlay, because you can "FORGET MYTOOL" to free the ram (about 900 bytes) again. With "16 list 4 t w" you start the editor on line 4. End it with CRTL-c.
Of course this little editor is less convenient as a PC-based one but it can be quite handy, if you use such block files as a parameter file for your P1 running to control something.

Perhaps you can see, that the blockfile variables are doubled. The idea is to have these separate for one second cog, which should be able to work with it in parallel to the console terminal.

In the following example a blinker is running in cog3, which can be forced by #paraFlag<>0 to read a new #pause value from block 4.

( Block 3 Blinktest )
( Reads Parameter in Block 4 )
byte #paraFlag   1 #paraFlag C!  
long #pause     100 #pause ! 
: rdPause ( reads parameter from block 4 )
    #paraFlag C@ 0 <> IF
        0 #paraFlag C! 
        4 block DROP   1 8 getNum #pause ! THEN ;
: doBlink BEGIN 
    rdPause 0 HIGH #pause @ ms 0 LOW #pause @ ms AGAIN ;
' doBlink 3 RUN
€


( Block 4 Parameter for doBlink )
     500
€

( The forum software seems to put blank lines and bold into the code. Of course be sure not to exceed 16 lines per block. And the very important ":" at line beginning is snatched... )

Have fun, Christof

Comments

  • @"Christof Eb." said:
    ... So with this type of file system you have to know, where the information is. No file names.

    I've been thinking, of what practical use that would be to the user who stores his files on the SD card and uses them not only within the Tachyon environment ? Isn't that FAT32 file system needed for an exchange of data with the SD card ?

  • Yes, Maciek, if you want to use a SD Card with filenames, you can or have to use FAT32 with TACHYON. The downside is, that you cannot do too much other things with P1 then, because so much RAM is used by the FAT driver.

    The block file system is one of the examples of Forth, where a SIMPLE but clever approach lets you achieve much of what you could achieve with a much more complicated way. I think it is a very good example of the https://en.wikipedia.org/wiki/Pareto_principle

    Perhaps I will try to write a version for a blockfile system for a SD-card too to have more room. As the 64kB eeprom is already there at the project board, the 32 blocks come for free on hardware side.

  • MJBMJB Posts: 1,235

    Fantastic Christof,

    s.o. not only using Tachyon, but also extending and then SHARING his ideas and work with us others here.

    About SD-Card FS.

    Originally Peter had this in two files SD & EasyFile, then Peter combined it.

    You should still be able to just leave the FAT32 stuff out and just use the SD / Buffer handlich etc. vitual memory level
    and build your BlockFS on top of this.
    Using 2 512 byte SD blocks per 1kb block.

  • @MJB said:
    Fantastic Christof,

    s.o. not only using Tachyon, but also extending and then SHARING his ideas and work with us others here.

    Hi MJB,
    if this refers to most of my other posts in the last months: Well, I am very frustrated about several decisions Parallax has made regarding P2 after all this waiting for x years. And sometimes I do have the impression, that they do not have the needs or possibilities of non professional makers in mind, so sometimes I see it as my ugly job to write something. - Sorry. - I used to share some years ago, but some things seem to be lost...

Sign In or Register to comment.