P1 Blockfile System in EEProm for a Standalone Computer with Tachyon 5.7 Forth
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
Files
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.
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.
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...