+Lee Stewart Posted October 4, 2013 Author Share Posted October 4, 2013 Almost there! The blocks file I/O works—phew! Now I need to work my way through the graphics mode changes I made to the system blocks file, FBLOCKS. I may need to put the Sprite Attribute Table back where it was for bitmap mode. I'm hoping the bugs are elsewhere. I guess it'll be a few days for that. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 6, 2013 Author Share Posted October 6, 2013 I should be able to post fbForth v0.92 later today! The Sprite Attribute Table is right where I want it for bitmap mode! It's amazing that one bug I found had not shown up before in TI Forth—it was a disaster just waiting to happen. The SAT was never explicitly initialized and, when I moved it, it happened to be filled with FFh; whereas before, it happened to be filled with 0. This is significant because the cursor for the 64-column editor is a sprite and the left nybble (early clock) of the fourth byte is apparently left alone by the word SPRITE . With Fh in the left nybble, the cursor was screwed up. Right now, I am initializing SAT with 0; but, I may change the definition of SPRITE to zero that nybble. Any suggestions? ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 6, 2013 Author Share Posted October 6, 2013 ... the left nybble (early clock) of the fourth byte is apparently left alone by the word SPRITE . With Fh in the left nybble, the cursor was screwed up. Right now, I am initializing SAT with 0; but, I may change the definition of SPRITE to zero that nybble. Any suggestions? ...lee H-m-m-m—SPRITE calls SPRCOL , which goes out of its way to preserve that left nybble; so, I really do need to initialize the SAT with 0s. I suppose I could also create a word ( SPRCLK ? ) to toggle or set the early clock bit. Does anyone know whether the other three bits of the early-clock nybble mean anything? The E/A Manual is silent on that score. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 6, 2013 Author Share Posted October 6, 2013 OK—Here 'tis—at long last! fbForth092.zip I will probably update the notes with a little more detail before I embark on the manual. Let me know what does not work. ...lee 1 Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 6, 2013 Share Posted October 6, 2013 Lee Have downloaded it. Will take it out for a spin tomorrow and report back! Mark Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 7, 2013 Author Share Posted October 7, 2013 Lee Have downloaded it. Will take it out for a spin tomorrow and report back! Mark Thank you, Sir! ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 7, 2013 Author Share Posted October 7, 2013 Lee Have downloaded it. Will take it out for a spin tomorrow and report back! Mark Here is an updated set of notes—probably more than you care to know: fbForth092Readme.txt <---This replaces the ReadMe file of the same name included in the ZIP file in post #329 above. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2013 Author Share Posted October 12, 2013 I've started work on the fbForth manual. Right now, I'm following my TI Forth Instruction Manual "2nd Edition 2013" pretty closely, modifying it for fbForth as I go. Perhaps I'll have it done by Faire time. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2013 Author Share Posted October 14, 2013 As I'm working my way through the fbForth manual, I'm picking up a few minor (so far) errors I made in my 2nd edition of the TI Forth manual. In the process, I also noticed a bug in TI Forth I don't believe was ever reported. It is in SMOVE on TI Forth system screen/block #39, line 11, where " OVER OVER " should be removed. If the clause they are in is ever executed, there will be 2 extra numbers on the stack when SMOVE is finished. I will eventually post this information in the TI Forth Instruction Manual in PDF Format (edited & expanded) thread; but, right now, I'm focusing on getting the fbForth manual finished. The reason I bring this up here is that, in fbForth, I am replacing SCOPY and SMOVE with CPYBLK (pretty much lifted from @Willsy's TurboForth) and, in writing that part of the fbForth manual, I realized that SMOVE had been written to make copying a range of blocks to an overlapping range a safe process regardless of whether the destination starting block was higher or lower than the source starting block. It's safe to write from high to low, but not the other way round unless you reverse the writing order to start with the end block, which is exactly what SMOVE does. I was going to do the same with CPYBLK ; but, it would result in a lot more code in fbForth because I would have to compare the source and destination blocks file names to see whether they were the same before proceeding with the overlap tests. I'm not sure it's worth the effort. If I were to make CPYBLK overlap safe, it would probably behoove me to make MOVE , CMOVE and VMOVE also overlap safe to maintain consistency. I'm inclined to just inform the user that copying to a range that overlaps the source is not safe when copying to a higher location. Anybody care? ...lee 1 Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2013 Share Posted October 14, 2013 He he! I wanted to exactly the same thing in CPYBLK in TF (CPYBLK is just loaded in from disk when needed) but I never got around to writing the logic for it. If you *do* do it, can I lift the logic? Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2013 Share Posted October 14, 2013 To answer your question: If it's possible to do it within the constraints that you have, or have you set yourself (is your CPYBLK loaded in from disk when needed like mine?) then you should do it. A caveat in the manual is okay, but, what if they *do* want to copy some blocks with an overlapping range? They are basically stuffed - well, stuffed in the sense that they can't use CPYBLK and will need to invent their own routine to do it, which may be beyond the abilities or desires of the user... Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2013 Author Share Posted October 14, 2013 He he! I wanted to exactly the same thing in CPYBLK in TF (CPYBLK is just loaded in from disk when needed) but I never got around to writing the logic for it. If you *do* do it, can I lift the logic? Mais oui! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2013 Author Share Posted October 14, 2013 To answer your question: If it's possible to do it within the constraints that you have, or have you set yourself (is your CPYBLK loaded in from disk when needed like mine?) then you should do it. A caveat in the manual is okay, but, what if they *do* want to copy some blocks with an overlapping range? They are basically stuffed - well, stuffed in the sense that they can't use CPYBLK and will need to invent their own routine to do it, which may be beyond the abilities or desires of the user... You don't make it easy! Logic to do it is easy enough. I am sure, as is my wont, that I will use much more code than is necessary to accomplish the task. H-m-m-m—I suppose I could write a word that would require the source starting address, destination starting address, copy count; determine overlap and copy direction; and leave a flag. The stack signature would be "( src dst cnt — flag )". A value of 1 for flag would indicate a need to change the direction of the copy. I could then use that word in all four copy operations. Of course, MOVE would require me to double the count for the test word because its copy unit is 2 bytes. I will post my code as I go to get suggestions for making it more compact. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2013 Author Share Posted October 14, 2013 OK, first, I'll post my existing code for the copy operations. Please pay no attention to the text coloring in the code blocks. I'm using the "none" format in the AA editor's "Code" option, which, at least, does not remove spaces; but, it is still doing some irritating formatting. Here is the TMS9900 ALC for CMOVE , MOVE and VMOVE : * {SP = R9 : stack pointer } * {NEXT = R15: pointer to next instruction fetch routine} * *** CMOVE *** move cnt bytes from src RAM to dst RAM * ( src dst cnt --- ) * DATA BF007 L1015 DATA >8543,>4D4F,>56C5 CMOVE DATA $+2 MOV *SP+,R1 MOV *SP+,R2 MOV *SP+,R3 MOV R1,R1 JEQ CMOVE2 CMOVE1 MOVB *R3+,*R2+ DEC R1 JNE CMOVE1 CMOVE2 B *NEXT * * *** MOVE *** move cnt cells from src RAM to dst RAM * ( src dst cnt --- ) * DATA L1015 A1000 DATA >844D,>4F56,>45A0 MOVE DATA $+2 MOV *SP+,R1 MOV *SP+,R2 MOV *SP+,R3 MOV R1,R1 JEQ MOVE2 MOVE1 MOV *R3+,*R2+ DEC R1 JNE MOVE1 MOVE2 B *NEXT * * *** VMOVE *** move multiple bytes from one VDP location to another * ( vsrc vdst cnt --- ) * DATA S1004 S1004X DATA >8556,>4D4F,>56C5 VMOVE DATA $+2 MOV *SP+,R1 pop cnt to R1 MOV *SP+,R3 pop vdst to R3 ORI R3,>4000 prepare for VDP write MOV *SP+,R2 pop vsrc to R2 * ** copy cnt bytes from vsrc to vdst * {MAINWS = address of fbForth's workspace and, hence, the address of it's R0} * VMVMOR MOVB @MAINWS+5,@VDPWA write LSB of VDP read address MOVB R2,@VDPWA write MSB of VDP read address INC R2 next VDP read address MOVB @VDPRD,R0 read VDP byte MOVB @MAINWS+7,@VDPWA write LSB of VDP write address MOVB R3,@VDPWA write MSB of VDP write address INC R3 next VDP write address MOVB R0,@VDPWD write VDP byte DEC R1 decrement count JNE VMVMOR repeat if not done B *NEXT Here is the high-level fbForth code for CPYBLK : ( CPYBLK definition...) DECIMAL 0 VARIABLE SFL 0 VARIABLE DFL ( pointers to source and destination filename strings) : GNUM BL WORD HERE NUMBER DROP ; ( get number from terminal) ( GBFL gets HERE to stack; stores filename at HERE; establishes new HERE; store string address in variable pass on stack) : GBFL ( addrvar -- ) HERE 0 BFLNAM SWAP ! ; : CPYBLK ( should we FLUSH before we start?) HERE ( save address where we'll copy current blocks filename; maybe use R) BPB BPOFF @ + 9 + ( get address of blocks filename's char-count byte) DUP VSBR 1+ ( get count byte and increment it for copy count) HERE SWAP DUP =CELLS ALLOT VMBR ( get current blocks name to HERE and move HERE past it) GNUM >R GNUM 1+ >R ( move start & end block #s to return stack) SFL GBFL ( get source filename to HERE and store address, moving HERE) GNUM ( get destination start block to stack) DFL GBFL ( get destination filename to HERE and store address, moving HERE) R> R> ( get the end & start block #s from return stack for loop) DO DUP ( DUP destination block #) SFL @ (UB) ( open source blocks file) I BLOCK ( load next block) 2- ! ( decrement block address and store destination block #) DFL @ (UB) ( open destination blocks file) UPDATE FLUSH ( write block to destination blocks file) 1+ ( increment destination block #) LOOP ( continue loop) DROP ( DROP excess block #) DUP ( DUP old HERE) (UB) ( restore original blocks file to 'current' status) DP ! ( restore dictionary pointer) ; Now, for how TI Forth does an overlap-safe range copy ( SMOVE )— Remember that TI Forth is doing disk-sector I/O. In the code below, OFFSET , MINUS and, perhaps, R merit explanation: OFFSET is a Forth screen offset to disk drives not relevant in fbForth. It is usually 0, which means that screen copying is relative to drive 0 (DSK1). MINUS is the same as TurboForth's NEGATE , i.e., 4 MINUS replaces 4 on the stack with -4. R copies the top of the return stack (without destroying it) to the parameter stack. It is equivalent to TurboForth's R@ . 0 CONSTANT AD ( +1|-1 added to get next screen) : SCOPY ( src dst --- ) ( copy a single screen) OFFSET @ + SWAP BLOCK 2- ! UPDATE FLUSH ; : SMOVE ( src dst cnt --- ) ( copy a range of screens) >R ( cnt to return stack) OVER OVER ( dup src & dst) - DUP ( src-dst & dup it) 0< SWAP R MINUS > + 2 = ( only overlapping low to high need to copy in reverse direction) IF ( we're going from the top down) SWAP R + 1- SWAP R + 1- ( get highest src & dst screens) -1 ' AD ! ( we're decrementing the next screens) ELSE ( we're going from the bottom up) 1 ' AD ! ( we're incrementing the next screens) ENDIF R> 0 DO ( cnt from return stack so we're doing " cnt 0 DO ") SCOPY ( do the block copy from src to dst) AD + SWAP AD + SWAP ( get next src & dst screens) LOOP DROP DROP ( drop the leftover src & dst) ; ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 15, 2013 Author Share Posted October 15, 2013 Well—I ran into trouble trying to make CMOVE , MOVE and VMOVE overlap-safe. I tried to BL to another routine to pop the stack and set up the copy. It worked fine from the terminal line (my typing it in); but, it failed miserably when embedded in another word—at least, a word defined in the kernel. I don't know who out there can help me with this problem except for @Willsy, but here is the code snippet from the kernel: *** determine parameters for CMOVE , MOVE and VMOVE * ...pop cnt src dst and set up direction of copy * R0 will contain 0 or 1 depending on byte or word move * pass values in R1--R4 to the copy routines * MVPMS MOV *SP+,TEMP1 pop count (cnt) MOV *SP+,TEMP2 pop destination (dst) MOV *SP+,TEMP3 pop source (src) LI TEMP4,1 assume positive direction C TEMP2,TEMP3 dst > src? JLE MVPMS1 no...return to caller MOV TEMP2,TEMP5 yes...check for overlap and adjust if necessary S TEMP3,TEMP5 get positive difference C TEMP1,TEMP5 cnt > difference JLE MVPMS1 no...return to caller LI TEMP4,-1 change direction of copy MVPMS2 A TEMP1,TEMP2 add cnt to dst DEC TEMP2 adjust to highest dst location A TEMP1,TEMP3 add cnt to src DEC TEMP3 adjust to highest src location DEC TEMP0 this will result in 0 only if it came in as 1 JEQ MVPMS2 if not word copy, repeat this dance MVPMS1 B *LINK * *** CMOVE *** move cnt bytes from src RAM to dst RAM * ( src dst cnt --- ) * DATA BF007 <---LABEL field for interpreter L1015 DATA >8543,>4D4F,>56C5 <---NAME field for interpreter CMOVE DATA $+2 <---PARAMETER field for interpreter (points to code field) CLR TEMP0 tell MVPMS this is a byte copy <---CODE field for interpreter BL @MVPMS get parms MOV TEMP1,TEMP1 check for cnt = 0 JEQ CMOVE2 nothing to copy; we're outta here CMOVE1 MOVB *TEMP3,*TEMP2 copy a byte A TEMP4,TEMP2 next dst A TEMP4,TEMP3 next src DEC TEMP1 JNE CMOVE1 CMOVE2 B *NEXT The code from MVPMS to MVPMS1 is the helper ALC. It is not part of the threaded code. It is called by CMOVE , which is my first test on my way to including MOVE and VMOVE . The fbForth workspace registers are as follows: TEMP0 – TEMP7 are R0 – R7 SP = R9 and is the stack pointer LINK = R11 NEXT = R15 I suspect that all of the words in the kernel that invoke CMOVE fail; but, I don't know this for a fact. All I know is that as soon as I replace the self-contained word for CMOVE with the above code, the system goes off into the weeds when it comes up. Below is FILL , one of the words that uses CMOVE followed by its high-level text equivalent: *** FILL *** DATA L109F L10A0 DATA >8446,>494C,>4CA0 FILL DATA DOCOL,SWAP,TOR,OVER,CSTORE,DUP,ONEP DATA FROMR,ONEM,CMOVE,SEMIS * : FILL ( addr cnt b --- ) SWAP >R OVER C! DUP 1+ R> 1- CMOVE ; I am guessing that somehow LINK (R11) is getting trashed; but, I can't see how. At this point, I don't see it as worth the trouble to track it down; but, I just might. Upon startup, COLD references it twice. Other words in the kernel that use it are WORD , ID. , FILL and BLOAD . ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 15, 2013 Author Share Posted October 15, 2013 Hoo-Boy—it was fortuitous I chose FILL as an example of a kernel word using CMOVE . If you look at the code for FILL and play computer with it, you can see that FILL actually relies on the overlap-UNsafe behavior of CMOVE ! It puts the fill character into the first byte of the range and calls CMOVE with address address+1 count-1 CMOVE to finish the copy. CMOVE dutifully copies into the next byte what was just copied into the previous byte until it gets to the end of the range. I suppose this behavior could be part of the reason for the failure reported in my last post, and I still may try to track it down; but, I should probably abandon the effort to make CMOVE , MOVE and VMOVE overlap safe because of this side effect. I will, however, pursue it with CPYBLK . I just need to devise a clever way to check for the equality of two strings. ...lee Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 15, 2013 Share Posted October 15, 2013 How much user RAM will be available with fbForth on a 48K system? I ran into significant memory constraints with Core War using TI Forth. One of the advantages of Turbo Forth is that one has access to the entire RAM expansion for a program. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 15, 2013 Author Share Posted October 15, 2013 How much user RAM will be available with fbForth on a 48K system? I ran into significant memory constraints with Core War using TI Forth. One of the advantages of Turbo Forth is that one has access to the entire RAM expansion for a program. It's a very similar problem with fbForth as with TI Forth until I hoist the code into a cartridge, which won't be easy, but is my plan if I live long enough! fbForth 0.92 has 16066 bytes in high memory between HERE and the bottom of the stack, with the minimal system loaded. There is a 682-byte segment in low memory from the end of the fbForth block buffers and utilities to the bottom of the return stack. You need to be careful encroaching on the return stack. All of the system synonyms and some other basic stuff are part of the resident dictionary, now. There is a 9338-byte chunk of VRAM free and the capability of 3 open files (including the blocks file) in all text/graphics modes except for bitmap mode. Bitmap mode has VRAM pretty much stuffed with the capability of having 1 open file besides the blocks file. You can have more files than 3 open at once in non-bitmap modes, but each additional file grabs 518 bytes of upper VRAM—just check 8370h for the highest VRAM location (byte) available. I plan to take a look at the graphics primitives sometime to see if I can condense them. They grab quite a lot of space when they are loaded. One thing that I won't be able to change with a cartridge is the buffer space in low RAM reserved for block buffers. Each block takes 1028 bytes and there are 5 for a total of 5140 bytes. This number is actually user-controllable in both fbForth and TI Forth with the user variable, LIMIT$. You can subtract as many multiples of 1028 from the contents of LIMIT$ as you want, as long as you leave some space. I don't think I would go lower than 2 buffers. More is better with disk systems. Once your program code is loaded, however, you could co-opt all of the Forth buffer space in low RAM, as long as you don't need any more blocks from disk. Your first disk access for a Forth block after running your program, however, will grab the buffer space back that exists between FIRST and LIMIT . FIRST and LIMIT are constants that put on the stack the contents of FIRST$ and LIMIT$ , respectively. ...lee Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 16, 2013 Share Posted October 16, 2013 Yes, the graphics primitives definitely take up a lot of space. A cartridge version would be excellent, particularly since TI Forth supports bitmap graphics, my favorite mode Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 16, 2013 Author Share Posted October 16, 2013 I coded a string comparison word, SCMP , to compare 2 strings and leave a flag for the result of the comparison: -1, first string is less; 0, the strings are exactly equal; +1, second string is less. I only needed to discover whether the strings are equivalent for CPYBLK ; but, I figured I might as well make it more useful. SCMP requires two string addresses on the stack. The byte-count of the string must be in the first byte. It takes up 98 bytes of dictionary space. I suppose I could call it STRCMP as in C; but, that might be misleading because it's a little different from its C cousin. With that name, it would consume an even 100 bytes. But, I digress. Here's the code for anyone who wants to help me make it more compact (@Willsy? @Vorticon? ): * : SCMP ( straddr1 straddr2 --- -1|0|+1 ) OVER C@ OVER C@ OVER OVER - >R ( dup addresses, get strlens and dup; take diff and push to return stack MIN 1+ 0 SWAP 1 DO ( get min strlen; increment for limit; 0 flag start; swap with limit; start at 1 DROP ( drop 0 flag) OVER I + C@ ( get next char of str1) OVER I + C@ - ( get next char of str2 and take diff) DUP IF LEAVE THEN ( dup it and leave loop if not equal) LOOP R> OVER 0= ( pop cnt diff from return stack; copy loop result; see if 0 IF ( it's 0, so OR with cnt diff for final answer) OR ELSE ( it's not 0, so drop cnt diff ) DROP THEN SWAP DROP SWAP DROP ( get rid of leftover str1 and str2 pointers, leaving only comparison flag) ; * ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 16, 2013 Share Posted October 16, 2013 I had multiple cracks at it, but I couldn't improve on 98 bytes. However, upon trying your code, on TF, the output doesn't match the stack signature. In the event that the strings are not equal, I get the *difference* between the characters. Tested thus: : str1 ( --addr) s" hello" drop 1- ; : str2 ( --addr) s" hellO" drop 1- ; : SCMP ( straddr1 straddr2 --- -1|0|+1 ) OVER C@ OVER C@ OVER OVER - >R MIN 1+ 0 SWAP 1 DO DROP OVER I + C@ OVER I + C@ - DUP IF LEAVE THEN LOOP R> OVER 0= IF OR ELSE DROP THEN SWAP DROP SWAP DROP ; str1 str2 SCMP . If you have COUNT defined as a system word you may be able to tidy the start of the definition up. COUNT is: : COUNT ( addr -- addr+1 len) DUP 1+ SWAP C@ ; Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 16, 2013 Share Posted October 16, 2013 Have no idea why it's double spaced. When I preview the post, it shows my code as double spaced. POS. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 16, 2013 Author Share Posted October 16, 2013 I had multiple cracks at it, but I couldn't improve on 98 bytes. However, upon trying your code, on TF, the output doesn't match the stack signature. In the event that the strings are not equal, I get the *difference* between the characters. Tested thus: ... Yeah, I didn't check it as thoroughly as I thought. Maybe I should just indicate the stack signature this way: ( straddr1 straddr2 --- f<0|f=0|f>0 ). That is, however, not so neat and smacks of expediency, doesn't it?—but, it is shorter than the alternative. If you have COUNT defined as a system word you may be able to tidy the start of the definition up. ... It is. I'll have a look. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 16, 2013 Author Share Posted October 16, 2013 Have no idea why it's double spaced. When I preview the post, it shows my code as double spaced. POS. Did you choose "None" as the code type? ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 16, 2013 Share Posted October 16, 2013 (edited) Yeah, I didn't check it as thoroughly as I thought. Maybe I should just indicate the stack signature this way: ( straddr1 straddr2 --- f<0|f=0|f>0 ). That is, however, not so neat and smacks of expediency, doesn't it?—but, it is shorter than the alternative. You want to add SGN at the end to get the sign of the value, ala TI BASIC. Not sure if fbForth has that as a built-in word. TF doesn't. I define it as follows: : SGN ( n -- -1|0|+1) dup 0< SWAP 0> - ; Edited October 16, 2013 by Willsy 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.