+Lee Stewart Posted July 24, 2015 Author Share Posted July 24, 2015 My high-level Forth definition of SCROLL in post #993 above is abysmally slow! I will rewrite it in fbForth Assembler post haste—stay tuned. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 25, 2015 Author Share Posted July 25, 2015 Here is my fbForth Assembler version of doScroll , which is now called by SCROLL defined below it: HEX ASM: doScroll ( -- ) ( 0=left 2=right 4=up 6=down) sINC @() R4 MOV, WRAP @() R7 MOV, sNXTRC @() 834A @() MOV, ( move to FAC for speed) sSRCCH @() 834C @() MOV, ( source address to FAC+2 for speed) sDSTCH @() 834E @() MOV, ( dest address to FAC+4 for speed) sOUTCTR @() R6 MOV, ( sOUTCTR @ 0 DO ) 0 LIMI, ( necessary because fbForth's VSBR and VSBW do not disable interrupts) BEGIN, 834C @() R2 MOV, ( source address to R2 for inner loop) 834E @() R3 MOV, ( dest address to R3 for inner loop) R7 R7 MOV, ( wrapping? ) NE IF, R3 R0 MOV, 36F6 @() BLWP, ( VSBR--read wrap char from sDSTCH) R1 sWRCH @() MOV, ( save wrap char to MSB) THEN, sINCTR @() R5 MOV, ( sINCTR @ 0 DO ) BEGIN, R2 R0 MOV, ( get ready to read sSRCCH) 36F6 @() BLWP, ( VSBR--read char from sSRCCH) R3 R0 MOV, ( get ready to write sDSTCH) 36EE @() BLWP, ( VSBW--write char to sDSTCH) R4 R2 A, ( inc/dec sSRCCH) R4 R3 A, ( inc/dec sDSTCH) R5 DEC, EQ UNTIL, ( LOOP ) R3 R0 MOV, ( wrap char dest) sWRCH @() R1 MOV, 36EE @() BLWP, ( VSBW--write wrap/blank char to sDSTCH) 834A @() 834C @() A, ( next-round src address) 834A @() 834E @() A, ( next-round dst address) R6 DEC, EQ UNTIL, ( LOOP ) 2 LIMI, ( allow interrupts again) ;ASM : SCROLL ( dir -- ) ( 0=left 2=right 4=up 6=down) SCRDIR doScroll ; DECIMAL It is a good bit faster than the high-level version. I cheated a little bit, however. You will notice that the calls to VSBR and VSBW are calling 36F6h and 36EEh directly. That is because I happen to know where they are since I wrote it. It could change in future releases of the cartridge, so it can't be relied on. But for now, it works. It is still slower than TurboForth's SCROLL because it is not making as much use of scratchpad RAM as TurboForth and a couple of words that doScroll depends on are not written in ALC. I may include it in a future release of fbForth; but, I might need to go to a 64Kib cartridge to do it because the current 32KiB ROM is almost too tight. Here is the fbForth-assembled version of doScroll : ASM: doScroll ( -- ) C120 , sINC , C1E0 , WRAP , C820 , sNXTRC , 834A , C820 , sSRCCH , 834C , C820 , sDSTCH , 834E , C1A0 , sOUTCTR , 0300 , 0000 , C0A0 , 834C , C0E0 , 834E , C1C7 , 1305 , C003 , 0420 , 36F6 , C801 , sWRCH , C160 , sINCTR , C002 , 0420 , 36F6 , C003 , 0420 , 36EE , A084 , A0C4 , 0605 , 16F6 , C003 , C060 , sWRCH , 0420 , 36EE , A820 , 834A , 834C , A820 , 834A , 834E , 0606 , 16DC , 0300 , 0002 , ;ASM ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 25, 2015 Author Share Posted July 25, 2015 (edited) Here is my port to fbForth 2.0 of @Willsy's DarkStar that led to the last several posts in this thread:: DarkStar_fbForth2.zip Both files need to be in DSK1—DARKSTAR is the game and DKSTRCHR is the font file loaded by it. Be careful if you are using the same DSK1 for TurboForth because the TurboForth DarkStar blocks file has the same name (DARKSTAR)!! To start the game, make DSK1.DARKSTAR the current blocks file and load block #1: USEBFL DSK1.DARKSTAR 1 LOAD To get back to the default font after the game, type the following: 0 SCRFNT ! FNT ...lee Edited September 24, 2015 by Lee Stewart 2 Quote Link to comment Share on other sites More sharing options...
Omega-TI Posted July 27, 2015 Share Posted July 27, 2015 Here is my port to fbForth 2.0 of @Willsy's DarkStar that led to the last several posts in this thread:: This is the only game I have for my new fbForth cartridge, and it's a neat one too! ." Thanks!" Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 27, 2015 Author Share Posted July 27, 2015 <snip> This is the only game I have for my new fbForth cartridge, and it's a neat one too! ." Thanks!" In a few minutes, I will post a compiled version that will load faster. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 27, 2015 Author Share Posted July 27, 2015 Sorry—I got sidetracked! Here is an updated DARKSTAR with a compiled version in blocks #31 – #38: DarkStar_fbForth2_x2.zip To load the compiled version type 30 LOAD If your DKSTRCHR font file is not on DSK1, you can change the “DSK1” on line #1 of block #30 to load it from DSK2, DSK3, or .... ...lee 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 22, 2015 Author Share Posted September 22, 2015 The code below is my port to fbForth of @Willsy’s TurboForth DATA[ and ]DATA . I will be including this code in the next release of FBLOCKS instead of the code in post #963 because a programmer can simply use DATA[ ... ]DATA for both integers and bytes by doubling up for bytes. Note, too, that it can be used in word definitions as well as on the command line. Anyway, here it is: ( The words below do NOT require a count of the cells that follow it. ) ( They are much faster than INTERPRET with a list of numbers because they ) ( don't waste a dictionary search getting to the number conversion routine ) ( for each and every number! ) ( These words may be executed or compiled into definitions. ) : DATA[] ( -- addr #cells ) R 2+ R @ DUP 2 * 2+ R> + >R ; : DATA[ ( -- addr count ) ( Input Stream: n1 ... nn) STATE @ IF COMPILE DATA[] 0 , THEN HERE ( start address of list) 0 ( start counter) BEGIN IN @ ( get IN before reading next word) BL WORD ( get next token to HERE) HERE 1+ C@ ( get address of first character) 93 = ( is it ‘]’?) IF ( yes; we are at the end of the list) IN ! ( restore IN so INTERPRET reads last word we just read) 1 ( last time through loop [flag for UNTIL] ) ELSE DROP ( DROP IN value; we don't need it) HERE NUMBER ( convert to a double [32-bit] number) DROP ( make it a single [16-bit] number) , ( compile number into dictionary) 1+ ( increment counter) 0 ( once more through loop [flag for UNTIL] ) THEN UNTIL ( get next number in input stream) ; IMMEDIATE : ]DATA ( Interpreting: -- ) ( Compiling: addr count -- ) ( Executing: -- addr count ) STATE @ ( compiling?) IF ( yes) SWAP 2- ! ( store count in location before addr) THEN ; IMMEDIATE ...lee 1 Quote Link to comment Share on other sites More sharing options...
Willsy Posted September 23, 2015 Share Posted September 23, 2015 Nice Usage information is available here, which will now apply equally to both fbForth and TurboForth. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 23, 2015 Author Share Posted September 23, 2015 Here are the fbForth Assembler and code versions of DATA[] for fbForth: ( fbForth Assembler version of DATA[]--- ) ASM: DATA[] ( -- addr #cells ) IP *+ R1 MOV, ( get #cells in r1) SP DECT, ( make space on the stack) IP SP ** MOV, ( push the address of the data) SP DECT, ( make space on the stack ) R1 SP ** MOV, ( move #cells to stack ) R1 1 SLA, ( convert to bytes) R1 IP A, ( adjust Forth PC to jump over the data) ;ASM ( Code version of DATA[]--- ) HEX CODE DATA[] ( -- addr #cells ) C07D , 0649 , C64D , 0649 , C641 , 0A11 , A341 , NEXT, DECIMAL ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 23, 2015 Author Share Posted September 23, 2015 As it stands, there cannot be any code, including comments, between DATA[ and ]DATA . This means that you cannot easily set up a larger array of data than will fit in one Forth block. It is quite simple to do it for a VARIABLE array with the cell count in the first location (see below); but, to define an array-containing word, which pushes its cell-count and address of its first datum to the stack, is well nigh impossible. It will not be easy; but, I will try to work out a better definition of DATA[ to allow for comments and other words that may be needed for multi-block arrays, notably --> for loading successive blocks into the array. I might add that @Willsy’s DATA[ for TurboForth does not suffer this problem. Here is how to set up a multi-block VARIABLE array: ( First block) 0 VARIABLE MYARRAY DATA[ num(1) num(2) ... num(x) ]DATA SWAP DROP ( drop address; keep count) --> ( load next block) ( Middle blocks) DATA[ num(x+1) num(x+2) ... num(x+x) ]DATA SWAP DROP + ( drop address; add count to previous count) --> ( load next block) ... ( Last block) DATA[ num(x+1) num(x+2) ... num(x+x) ]DATA SWAP DROP + ( drop address; add count to previous count) MYARRAY ! ( store total cell-count in first cell of MYARRAY) ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted September 23, 2015 Share Posted September 23, 2015 Easiest way is to add an extra mode to the interpreter. Use state=2 as special data compiling mode. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 23, 2015 Author Share Posted September 23, 2015 Easiest way is to add an extra mode to the interpreter. Use state=2 as special data compiling mode. Well, there are two problems for me with that, viz., (1) I would need to release another build of the cartridge binary (not quite ready to do that); (2) I am trying to avoid the interpreter for large arrays of numbers because the interpreter searches the dictionary (466 words in the resident dictionary) for each and every number before it attempts number conversion. Small arrays are fine; but, I would like to make it convenient for very large arrays. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted September 23, 2015 Share Posted September 23, 2015 Ah! But in your interpreter, you would say: state @ 2 = if bl word number abort" Not a legal number" , else \ states 0 and 1 .... .... .... then So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def. You'd still need to update the cart though Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 23, 2015 Author Share Posted September 23, 2015 (edited) Ah! But in your interpreter, you would say: state @ 2 = if bl word number abort" Not a legal number" , else \ states 0 and 1 .... then So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def. You'd still need to update the cart though Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. It is not that simple in fbForth. I could certainly do something like that, I suppose; but, currently, the only words that set STATE are [ and ] . [ sets it to 0 for execute mode and ] sets it to C0h for compile mode. C0h is the sum of the value of the precedence bit (40h) and the terminator bit (80h) present in the length byte of immediate words in fbForth and TI Forth. ...lee Edited September 24, 2015 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted September 24, 2015 Share Posted September 24, 2015 Lee, would you mind not using that blue font by any chance? It really makes reading your messagea very hard... Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 24, 2015 Author Share Posted September 24, 2015 Lee, would you mind not using that blue font by any chance? It really makes reading your messagea very hard... We must be using different skins. Which are you using so I can see what different colors might work better? ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 24, 2015 Author Share Posted September 24, 2015 Yeah, I'll bet you are using the “Deflection” theme. I will change a few of the last posts to teal. Though a bit of a hassle, you can read that objectionable blue color (with “Deflection”) by selecting the text with your mouse. That temporarily turns it to white. “Deflection” appears to be the only skin with that problem. It would be nice if the skin software were smarter to avoid those kinds of clashes! 'Tis a pitty, really, because blue is such a pleasant color to the eyes on a white or light gray background. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 27, 2015 Author Share Posted September 27, 2015 Ah! But in your interpreter, you would say: state @ 2 = if bl word number abort" Not a legal number" , else \ states 0 and 1 .... .... .... then So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def. You'd still need to update the cart though Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. Actually, it looks like your code only has 2 states, executing (0) and compiling (1). You control compiling numbers with the variable, coding, at >A068. And—the dictionary is searched before number strings are converted to numbers. Anyway, I finally have a definition for DATA[ that will allow comments and --> between DATA[ and ]DATA . Any other words will throw an error. This will allow large arrays that span several blocks. I will post it later today. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted September 27, 2015 Share Posted September 27, 2015 Yes. I have a third state but it's not implemented via state. Like you say it's at a068 (called 'coding') IIRC. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 27, 2015 Author Share Posted September 27, 2015 (edited) Here is the updated code for DATA[ and ]DATA : [Edit: See post #1212 for an updated DATA[ .] ( The words below do NOT require a count of the cells that follow it. ) ( They are much faster than INTERPRET with a list of numbers because they ) ( don't waste a dictionary search getting to the number conversion routine ) ( for each and every number! Also, multi-block arrays may now be ) ( implemented because DATA[ now allows comments and --> [load next block] ) ( before ]DATA ) ( These words may be executed or compiled into definitions. ) ( Load only one of the following versions of DATA[] ) ( High-level Forth definition of DATA[]--- ) : DATA[] ( -- addr #cells ) R 2+ R @ DUP 2 * 2+ R> + >R ; ( fbForth Assembler version of DATA[]--- ) ASM: DATA[] ( -- addr #cells ) IP *+ R1 MOV, ( get #cells in r1) SP DECT, ( make space on the stack) IP SP ** MOV, ( push the address of the data) SP DECT, ( make space on the stack ) R1 SP ** MOV, ( move #cells to stack ) R1 1 SLA, ( convert to bytes) R1 IP A, ( adjust Forth PC to jump over the data) ;ASM ( Code version of DATA[]--- ) HEX CODE DATA[] ( -- addr #cells ) C07D , 0649 , C64D , 0649 , C641 , 0A11 , A341 , NEXT, DECIMAL ( The following version of DATA[ allows comments and --> between DATA[ and ]DATA ) 0 VARIABLE IN_TMP ( [NUMBER] expects packed string of number to convert at HERE) : [NUMBER] ( cnt -- cnt+1 ) HERE NUMBER ( convert to a double [32-bit] number) DROP ( make it a single [16-bit] number) , ( compile number into dictionary) 1+ ( increment counter) ; : DATA[ ( -- addr count ) ( Input Stream: n1 ... nn) STATE @ IF COMPILE DATA[] 0 , THEN HERE ( start address of list) 0 ( start counter) BEGIN IN @ IN_TMP ! ( get IN before reading next word) BL WORD ( get next token to HERE) HERE 1+ C@ ( get first character) CASE ( check first character) 93 ( ‘]’) OF IN_TMP @ IN ! ( restore IN to INTERPRET last word) 1 ( last time through loop [flag for UNTIL] ) ENDOF 40 ( ‘(’) OF HERE C@ 1 = ( comment) IF [COMPILE] ( 0 ( once more through loop [flag for UNTIL] ) ELSE 1 0 ?ERROR THEN ENDOF 45 ( ‘-’) OF HERE 3 + C@ 62 ( ‘>’) = ( ‘-->’) IF ( load next block) [COMPILE] --> ELSE ( convert and compile negative number) [NUMBER] ( convert and compile number at HERE; inc count) THEN 0 ( once more through loop [flag for UNTIL] ) ENDOF DROP ( drop unmatched code) [NUMBER] ( convert and compile number at HERE; inc count) 0 ( once more through loop [flag for UNTIL] ) 1 ( give ENDCASE something to consume) ENDCASE UNTIL ( get next number in input stream) ; IMMEDIATE : ]DATA ( Interpreting: -- ) ( Compiling: addr count -- ) ( Executing: -- addr count ) STATE @ ( compiling?) IF ( yes) SWAP 2- ! ( store count in location before addr) THEN ; IMMEDIATE I am sure DATA[ can be coded more efficiently; but, the above, at least, works pretty well, if I do say so myself! ...lee EDIT: I removed the inadvertent inclusion of the previous version of DATA[ . Edited March 30, 2016 by Lee Stewart 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 1, 2015 Author Share Posted October 1, 2015 Here is fbForth code for DCHAR and SPDCHAR to use DATA[ ... ]DATA as DCHAR does in TurboForth: ( Helper routine for DCHAR and SPDCHAR ) : [DCHAR] ( addr cnt chr# ptbase-- ) SWAP 8 * + ( VRAM destination address) SWAP -DUP ( get cnt to top of stack) IF ( continue only if cnt non-zero) 2 * ( adjust cnt to bytes) VMBW ( copy from addr to VRAM) THEN ; ( Equivalent to CALL CHAR in BASIC. Similar to CHAR , but uses) ( array of numbers instead of stack for pattern definition. ) ( Used to define one or more characters starting at chr# ) ( pattern address. Moves cnt cells from addr to chr# pattern ) ( address in VDP memory. ) : DCHAR ( addr cnt chr# -- ) PDT ( VRAM base address of pattern table) [DCHAR] ; ( copy cnt pattern cells from addr to VRAM) ( Same as DCHAR, but for sprite pattern definitions because ) ( SPDTAB does not always start at same VRAM address as PDT. ) : SPDCHAR ( addr cnt chr# -- ) SPDTAB ( VRAM base address of sprite pattern table) [DCHAR] ; ( copy cnt pattern cells from addr to VRAM) As indicated above, it was necessary to write two words ( DCHAR and SPDCHAR ) because the text and sprite pattern tables are not necessarily the same. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 3, 2015 Author Share Posted October 3, 2015 I just ran into a snag with my definition of DATA[ (see post #1020). It crashes with multi-line input from the terminal, i.e., when the terminating ]DATA is not on the same line with DATA[ . It works just fine loading from a blocks file. The problem appears to be the terminating null, which terminates input from the terminal. DATA[ attempts to convert the null to a number and fails, of course—aborting with an error message. If I tell DATA[ to ignore the null, the system hangs because (I think) the interpreter tries to read past the terminating null in the TIB (Terminal Input Buffer)—not a good thing. I haven't yet figured out how to keep DATA[ in control after the end of the input line. The key may be to define a word that mimics the functionality of --> , except for the block-loading part, because that works for multi-block DATA[ ... ]DATA arrays. If anyone has any suggestions, I am all ears! ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 3, 2015 Share Posted October 3, 2015 Can it move >IN (our whatever the FIG equivalent is) back to point to the null? Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 3, 2015 Share Posted October 3, 2015 I think maybe DATA[ should execute EXPECT and get its own data from the keyboard (when not loading a block) into a buffer and process it itself. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 4, 2015 Author Share Posted October 4, 2015 Can it move >IN (our whatever the FIG equivalent is) back to point to the null? IN—Yeah, that's easy enough, but I'm not sure what to do after that. I actually move IN in for ]DATA , ( and --> . ...lee 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.