+Lee Stewart #826 Posted January 3 3 minutes ago, TheBF said: I posted an expansion of the code in the Assembly forum since if I confused you then I was making trouble. The PUSH, macro is for any register. So in this case I did not PUSH R4 into memory stack. I only "pushed" R0 R1 & R2. I see that, now—and, I am sure you explained it to me before. I just know that I will always need to relearn that fact any time I want to write or understand written Camel99 Forth Assembler code. ...lee Quote Share this post Link to post Share on other sites
+TheBF #827 Posted January 3 Yes it took me time when I bought HsForth to remember that BX was used this way. Now it's second nature. BTW how do you get Camel99 to print with the 99 sub-scripted? It looks nice. Quote Share this post Link to post Share on other sites
+Lee Stewart #828 Posted January 3 1 hour ago, TheBF said: BTW how do you get Camel99 to print with the 99 sub-scripted? It looks nice. That is the font, Georgia, available on the edit menu above. 🙂 ...lee 2 Quote Share this post Link to post Share on other sites
+TheBF #829 Posted January 5 Can you smell the burnt brain cells out there in web space? 🤬 I have spent way to much time trying different things to marry Forth WORDLISTS to SAM memory in an elegant way. I am sure it can be done but I struggle with keeping the mental map of all the pointers to pointers to pointer-pointers... One my challenges with Forth is that I not only want to write the program, I want to write the words that let somebody else write more programs simply. Double responsibility. The context required to maintain the connections between the Forth Interpreter and compiler and arbitrary blocks of code out there in the SAMS card seem way to bulky the way I was doing it. I made something that worked fine to load up and run the code. But letting each code page be found in the wordlist search order exceeded my grasp this time. I am missing something and it doesn't seem very elegant. Next Steps: One of my specifications is I want to be able to load existing library files into SAMS without changes. I might have to make all the compiling words deferred and have a Forth version and a SAMS version and vector them all with a single command. That would let : push the sams bank# onto the return stack and ; could compile code to revert back to the previous bank# before doing EXIT. So I have lots things that work but not to my liking including this which I will call CODEX1. It works like simplified Forth79 vocabularies where each CODEX only links back to Forth. You can only compile code into the active CODEX using words in the CODEX and/or in Forth. Not overly practical but you can load up lots of utilities. You have to manually activate each CODEX by name. Not very useful yet. Spoiler \ CODEX1: SAMS Memory Forth compiling Jan 4, 2021 B Fox \ A CODEX is named 4K page in SAMS memory that contains code. \ Each code page holds its own DP and CONTEXT at the end of the SAMS page. \ Each code page is like a small vocabulary that links back to Forth. \ NEEDS DUMP FROM DSK1.TOOLS NEEDS SAMSCARD FROM DSK1.SAMSFTH HERE HEX E000 CONSTANT CSEG \ "CODE SEG" window address CSEG FFC + CONSTANT PLINKS \ local memory pointers, end of each bank 4000 CSEG 0B RSHIFT + CONSTANT CREG \ compute CSEG SAMS register VARIABLE TOTAL-AMS VARIABLE BANK# VARIABLE PAGE# CREATE HOME 0 , 0 , \ place holder for Forth DP & CONTEXT : CODEX-RESET ( -- ) EF PAGE# ! TOTAL-AMS OFF ; CODEX-RESET : NEWPAGE ( - n) PAGE# 1+! PAGE# @ DUP FF > ABORT" No more CODE pages" ; : CMAP ( bank# -- ) \ ** bank# must be in low byte** DUP BANK# ! \ last used SAMS bank SAMSCARD 0SBO \ turn on the card ( bank#) CREG ! \ store bank# in SAMS register 0SBZ ; \ turn off card : AMS-HERE ( -- addr) PLINKS @ ; : DICTIONARY ( -- dp context) DP @ CONTEXT @ @ ; : RELINK ( dp context -- ) CONTEXT @ ! DP ! ; : ACTIVATE ( bank# -- ) CMAP PLINKS [email protected] RELINK ; : FAR: ( -- ) BANK# @ ACTIVATE ; : LOCAL: ( -- ) HOME [email protected] RELINK ; : END-LOCAL ( -- ) DICTIONARY HOME 2! ; : BANK-MEM ( -- n ) PLINKS [email protected] DROP CSEG - ; : END-SAMS ( -- ) DICTIONARY PLINKS 2! LOCAL: AMS-HERE EFFF > ABORT" SAMS page size exceeds 4K" BANK-MEM TOTAL-AMS +! ; : .SAMSCODE CR ." SAMS CODE: " TOTAL-AMS @ U. ; : CODEX: ( -- ) CREATE NEWPAGE >< DUP , CMAP CSEG CONTEXT @ @ PLINKS 2! \ init local memory pointers in SAMS DOES> @ ACTIVATE ; IMMEDIATE HERE SWAP - DECIMAL . .( bytes used) Demo code Spoiler \ CODEX1 tests CODEX-RESET \ define some named code pages CODEX: MISC CODEX: ASSEMBLER CODEX: FILES CODEX: GRAPHICS CODEX: TOOLS CODEX: SOUND \ END-LOCAL remembers where the Forth dictionary ends \ You must use it you add more code to Forth END-LOCAL MISC DECIMAL : STAR 42 EMIT ; : STARS 0 ?DO STAR LOOP ; : HI CR ." Hello world from SAMS memory!" ; INCLUDE DSK1.SOUND END-SAMS ASSEMBLER INCLUDE DSK1.ASM9900 END-SAMS GRAPHICS INCLUDE DSK1.GRAFIX INCLUDE DSK1.COLORS INCLUDE DSK1.DIRSPRIT INCLUDE DSK1.AUTOMOTION END-SAMS FILES INCLUDE DSK1.DIR INCLUDE DSK1.CATALOG INCLUDE DSK1.BLOCKS END-SAMS TOOLS INCLUDE DSK1.TOOLS INCLUDE DSK1.ELAPSE END-SAMS TEXT 17 7 VWTR DECIMAL .SAMSCODE 1 Quote Share this post Link to post Share on other sites
+TheBF #830 Posted January 6 Catching up with TI-BASIC I am reviewing everything for release V2.66 and I have never been happy with how I handled character definitions. I was also envious of BASIC's ability to handle character definition strings of arbitrary length. The secret to that feature is using a text string as the input parameter. It occurred to me that now I have all the pieces needed to make a "CALLCHAR" that works like TI-BASIC. I just had to put the pieces together. The pieces used are VDP memory manager in Forth style that lets you compile numbers into VDP memory sequentially as done in the Forth dictionary Forth's DIGIT? that converts an ascii char to a number with a conversion success flag (re-written in Assembler in V2.0) S" Forth word to define a string literal NEEDS VC, FROM DSK1.VDPMEM : >NIB ( char -- n) DIGIT? 0= ABORT" Bad char" ; : CALLCHAR ( addr len char --) BASE @ VP @ 2>R \ save radix & VDP mem pointer HEX 8* 800 + \ compute VDP address of char VP ! \ set VP pointer BOUNDS \ convert addr,len to addresses DO I [email protected] >NIB 4 LSHIFT \ convert left nibble & shift I 1+ [email protected] >NIB \ convert right nibble OR VC, \ OR them, compile into VDP RAM 2 +LOOP 2R> VP ! BASE ! \ restore VP and BASE ; EDIT: I forgot that I had to convert chars to nibbles and put them together. 2 Quote Share this post Link to post Share on other sites
+TheBF #831 Posted January 14 I was working on refining the operation of the ED99 editor. I never liked the fact that if you are copying records in SAMS memory and you only have one 4K window in memory, as I did, you have to copy the record out to RAM and then write the copy back to the new record. All this to avoid the the boundary where you want to move the last record of a page to the first record of a new page or vice versa. I recently read a presentation by Chuck Moore and he spoke about using the word BLOCK to deal with memory even when there are no disks on the system. For those who don't speak FORTH, BLOCK takes an integer argument and returns the address where you can get a "block" of disk space. This is traditionally 1K. There are typically a number of buffers and BLOCK has a enough smarts to manage the disk and memory like a virtual memory system. Wouldn't it be nice if SAMS memory could be accessed so simply? Well I took today to figure out a way. I decided to keep two 4K windows in LOW RAM. A BLOCK is 4K in size for simplicity. The code toggles back and forth between the two buffers as you request a SAMS "BLOCK". If the SAMS page is mapped into a buffer already, it just returns the buffer address. I also provide BUFF0 and BUFF1 to map in pass-thru memory for those cases where you just need regular memory for other stuff. This is not optimal code by any means but it seems to work. I will know for sure when I weave it into a new version of ED99. Spoiler \ BLOCK as a method to manage SAMS pages Jan 14 2021 Brian Fox \ NEEDS .S FROM DSK1.TOOLS HERE DECIMAL 24 USER 'R12 \ address of R12 in any Forth workspace HEX : SAMSCARD ( -- ) 1E00 'R12 ! ; \ select sams card \ using machine code so we don't need the CRU library HEX \ *set the CRU address in 'R12 before using these words* CODE 0SBO ( -- ) 1D00 , NEXT, ENDCODE CODE 0SBZ ( -- ) 1E00 , NEXT, ENDCODE CODE 1SBO ( -- ) 1D01 , NEXT, ENDCODE CODE 1SBZ ( -- ) 1E01 , NEXT, ENDCODE : SAMS-ON ( -- ) SAMSCARD 1SBO ; \ enable mapper : SAMS-OFF ( -- ) SAMSCARD 1SBZ ; \ disable mapper \ * SAMSINI sets card to "pass-through" condition : SAMSINI SAMSCARD \ select SAMS card 0SBO \ turn card on 0 \ register value stays on stack 4000 20 \ register address, # SAMS regs BOUNDS ( -- 4100 4000) DO DUP I ! \ I is reg. address I @ OVER <> ABORT" SAMSINI err" 0100 + \ next value 0101 for 1MB card, 0100 Classic99 2 +LOOP 0SBZ \ turn off card DROP ; : MAP ( block# buffer -- ) SWAP >< SWAP \ (fix this with code word) 0B RSHIFT \ divide by 2048 4000 + \ convert to SAMS register address SAMSCARD 0SBO \ enable SAMS card ! \ write block# to SAMS register 0SBZ ; \ turn off SAMS card \ ========================================== \ block manager uses handles 0 & 1 DECIMAL 256 CONSTANT HIGHBLK \ assumes 1Mb card (256*4K = 1Mb) VARIABLE USE \ BUFFER management arrays HEX CREATE BLK#S 0 , 0 , \ SAMS page in the buffer CREATE WINDOWS 2000 , 3000 , \ windows in Low CPU RAM : ]BLK# ( handle -- addr) CELLS BLK#S + ; : ]BUFFER ( handle -- buffer) CELLS WINDOWS + @ ; HEX : BUFF0 ( -- addr) 2000 02 OVER MAP ; \ map in pass-thru memory : BUFF1 ( -- addr) 3000 03 OVER MAP ; : BLOCK ( block# --- addr ) \ HIGHBLK OVER U> ABORT" SAMS page error" \ optional range test 0 ]BLK# @ OVER = IF DROP 2000 EXIT THEN \ mapped in 0? return buffer 1 ]BLK# @ OVER = IF DROP 3000 EXIT THEN \ mapped in 1? return buffer \ page is not already mapped... USE @ 1 XOR USE ! \ toggle to USE other buffer DUP USE @ ]BLK# ! \ record block# for this handle USE @ ]BUFFER TUCK MAP \ get the buffer address & map in SAMS page ; HERE SWAP - DECIMAL CR . .( bytes) 3 Quote Share this post Link to post Share on other sites
+TheBF #832 Posted January 15 SAMS BLOCK is even better in CODE I am always impressed with how Forth code maps so well onto 9900 Forth Assembler . (Gives me more ideas about a Machine Forth system that maps closer to 9900 than Chuck's ideas which were based on his F21 CPU.) Just did a timing test and it looks like this code is 9X faster than the Forth code version. \ block as SAMS manager HEX VARIABLE USE CREATE BLK#S 0 , 0 , \ SAMS page in the buffer CREATE WINDOWS 2000 , 3000 , \ windows in Low CPU RAM CODE BLOCK ( bank -- buffer) R0 BLK#S LI, \ handle 0 search R0 ** TOS CMP, EQ IF, TOS 2000 LI, NEXT, ENDIF, R0 INCT, \ handle 1 search R0 ** TOS CMP, EQ IF, TOS 3000 LI, NEXT, ENDIF, W 0001 LI, USE @@ W XOR, W USE @@ MOV, W W ADD, \ W holds offset TOS BLK#S (W) MOV, \ store the bank# WINDOWS (W) R1 MOV, \ get the window to use R1 0B SRL, \ divide by 2048 R1 4000 AI, \ convert to SAMS register address R12 1E00 LI, \ cru address of SAMS 0 SBO, \ SAMS card on TOS SWPB, \ swap bytes on bank value TOS R1 ** MOV, \ load bank into register 0 SBZ, \ SAMS card off WINDOWS (W) TOS MOV, \ return buffer on TOS NEXT, ENDCODE Edit: Did the SWPB too early in 1st version 2 1 Quote Share this post Link to post Share on other sites
+TheBF #833 Posted Monday at 05:22 AM I am really enjoying using the BLOCK code for SAMS management. I am making some major changes to ED99 and IT really has simplified everything. Here is my new definition for a temporary buffer: : HEAP ( -- addr) 2 BLOCK ; It's so seamless. It just swaps out the SAMS page that was last used and gives me a 4K block of pass thru memory. I have to use some 32bit intermediate math to compute a record but it's in the kernel so no worries. VARIABLE BLK : ]RECORD ( n -- addr) RECSIZE UM* 4K UM/MOD 1STBLK + DUP BLK ! BLOCK + ; 1STBLK is just an offset into the 255 available blocks computed from a variable that is the file# we are editing. I record the block in use in case I might need it but so far I have not, since the editor works mostly at the line level. I built a clipboard by doing the same thing but using a "1stblock" that is above the last block used for text. DECIMAL \ clipline returns the string at top of clipstack \ clip board uses blocks 161..193 : ]CLIP ( rec# -- addr) RECSIZE UM* 4K UM/MOD 161 + BLOCK + ; Since there are two 4K buffers copying a line of text to the clipboard is just: : LINE2CLIP ( line# -- ) ]RECORD CLIPLINE COPY-REC #CLIPS 1+! ; It seems to be coming together much easier now. I hope to have new version out this week. Working on adding the ability to mark text lines (with highlighting) and cutting them out to clipboard and pasting them back in. Old version can copy one line at a time or copy the entire file. 3 Quote Share this post Link to post Share on other sites
+TheBF #834 Posted Thursday at 10:09 PM I am working hard on getting a new release of ED99. It will have some new features like hi-lighting lines for copy/delete, 1000 lines per file and paste now can insert lines anywhere in a file. I have limited it to 5 files open at once to save some room in SAMS memory for future development. It is still record based and very wasteful of the memory. Wouldn't it be nice to be able to delete files that you no longer need? Tested it here on my TI-99. (It doesn't work on Classic99 of course but will be great for working on real iron) COM1_19200bps - TI-99 DELETE.mp4 2 Quote Share this post Link to post Share on other sites