+Lee Stewart Posted October 4, 2015 Author Share Posted October 4, 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. Aha! That gives me an idea! Be back with more, later. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 4, 2015 Share Posted October 4, 2015 It would do it in a loop until it sees ]data. That way, broken lines and multiple lines and blank lines would make no difference. You would have to check for special cases such as comments. The simplest way to do that is to do a BL WORD and convert directly to a number. If the conversion doesn't work then check for a comment. If not a comment then error. If an open bracket is detected then enter a state where you throw everything away (BL WORD in a loop) until you get a closed bracket. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 5, 2015 Author Share Posted October 5, 2015 (edited) It would do it in a loop until it sees ]data. That way, broken lines and multiple lines and blank lines would make no difference. You would have to check for special cases such as comments. The simplest way to do that is to do a BL WORD and convert directly to a number. If the conversion doesn't work then check for a comment. If not a comment then error. If an open bracket is detected then enter a state where you throw everything away (BL WORD in a loop) until you get a closed bracket. [Edit: See post #1212 for an updated DATA[ .] That's pretty much what I'm doing already—just was not handling the user hitting “Enter” or entering more than 80 characters before ]DATA closed the array. But, I think I have it, now. I will use QUERY when DATA[ detects a null. QUERY calls EXPECT with the TIB address and 80 characters as the maximum input. QUERY is what INTERPRET uses to get the next line from the terminal. Here is the code: : DATA[ ( -- addr count ) ( Input Stream: n1 ... nn) STATE @ IF COMPILE DATA[] 0 , THEN HERE 0 BEGIN IN @ IN_TMP ! BL WORD HERE 1+ C@ CASE 93 OF IN_TMP @ IN ! 1 ENDOF ( handle ]DATA ) 40 OF HERE C@ 1 = IF ( handle comment ) [COMPILE] ( 0 ELSE 1 0 ?ERROR THEN ENDOF 45 OF HERE 3 + C@ 62 = ( handle --> ) IF [COMPILE] --> ELSE [NUMBER] THEN 0 ENDOF 0 OF CR QUERY 0 ENDOF ( handle null [line end]) DROP [NUMBER] 0 1 ENDCASE UNTIL ; IMMEDIATE While loading blocks, the line above (in brown) that tests for null should not find a null before it finds ]DATA . A terminating null only occurs at the end of a block. So far, the above code is working for both terminal entry and block loading. ...lee Edited March 30, 2016 by Lee Stewart 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 6, 2015 Author Share Posted October 6, 2015 One minor, cosmetic tweak of the ‘ QUERY ’ line in the last post (also updated there): 0 OF CR QUERY 0 ENDOF ( handle null [line end]) CR will cause the next line in the input stream to actually appear on the next line as you would expect. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 6, 2015 Author Share Posted October 6, 2015 While porting @Vorticon’s Jetpac to fbForth, I discovered a bug in SSDT , which is the easiest way for a user to change the Sprite Pattern Descriptor Table in graphics mode to a different location from the the default 800h. The default, 800h, is coincident with the text Pattern Descriptor Table. I thought I had tested SSDT ; but, obviously, I did not! It is easy enough to change the SPDT in code, but it is not trivial. Besides, SSDT not only changes the user variable read by the constant, SPDTAB , but also changes VDP register #6 to the proper value and executes DELALL to initialize sprites. I have other changes to fbForth 2.0 that I want to make; but, I will probably release another build sooner than I intended because of this bug. Oh, well! ...lee 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2015 Author Share Posted October 12, 2015 I have fixed SSDT . I have also fixed BSAVE and BLOAD to save and load the vocabulary link fields of the FORTH and ASSEMBLER vocabularies. This leaves the remaining cartridge space as Bank Free Space ---- ---------- 0 168 bytes 1 58 bytes 2 147 bytes 3 30 bytes There are a few words I would like to add to the resident dictionary; but, as you can see, there is not much room without some improvement to the efficiency of my code. Finding more space would be a major undertaking, I'm afraid. It would probably be easier to go to a 64KiB cartridge. At that point, I think I might reorganize things a bit. My biggest challenge will likely be managing the resident dictionary itself. As it stands, the resident dictionary's linked lists are wholly contained in Bank 2, which has only 147 bytes left! Each additional word takes a minimum of 10 bytes for a word with a one-character name. Six- and seven-character names take 16 bytes each. I should be able to gain space by moving some code in Bank 2 to Banks 4+ with a 64KiB cartridge. One thing I will definitely try to do if/when I go to a 64KiB EPROM will be to organize the resident dictionary into linkable blocks to reduce the interpreter's search time through blocks of words the user doesn't care about. Words that can be organized into separate blocks are graphics primitives, file I/O, floating point library, 40/80-column editor and font editor. If a user does not need one or more of those blocks of words, the interpreter's search time can be significantly reduced. Of course, I must devise a creative way to manage the linked lists—we'll see. Back to the imminent build #3 of fbForth 2.0, I think I may add VLIST , which is practically the same as TurboForth's WORDS . VLIST is currently loadable from FBLOCKS and is used to list the words in the current dictionary. It occupies 124 bytes of dictionary space. If I include it, there is room for little else. There are a couple more words that won't take up much space, one of which is ELSEOF , which is very similar to Turboforth's DEFAULT: and is part of the CASE ... ENDCASE construct. I will discuss in a future post what ELSEOF does and why I chose not to implement DEFAULT: , though you can probably guess how to use ELSEOF . ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2015 Author Share Posted October 14, 2015 OK, here is my ELSEOF offering: : ELSEOF ( n -- ) COMPILE DUP [COMPILE] OF ; IMMEDIATE ELSEOF starts out the same as TurboForth's DEFAULT: , but still requires ENDOF to terminate the clause. To me, ELSEOF is more in the spirit of the rest of the CASE ... ENDCASE construct in Forth. DEFAULT: seems to me to mix the look and feel of the switch statement in C with that of the CASE .. ENDCASE in Forth. Just as with TurboForth's DEFAULT: , fbForth's ELSEOF ... ENDOF must immediately follow the last OF ... ENDOF clause. Also, as with DEFAULT: , any code following ELSEOF ... ENDOF and preceding ENDCASE will never execute because, if all of the OF ... ENDOF clauses fail, the ELSEOF ... ENDOF clause will always succeed. To lift @Willsy's example, the following all do exactly the same thing, i.e., any number passed to TEST other than 1, 2, or 3 will result in 999 being printed: : TEST CASE 1 OF 100 ENDOF 2 OF 200 ENDOF 3 OF 300 ENDOF 999 SWAP ( any other case——the old way and not very intuitive) ENDCASE . ( print result) ; : TEST CASE 1 OF 100 ENDOF 2 OF 200 ENDOF 3 OF 300 ENDOF DUP OF 999 ENDOF ( any other case——@Willsy's way before defining DEFAULT: and much better!) ENDCASE . ( print result) ; : TEST CASE 1 OF 100 ENDOF 2 OF 200 ENDOF 3 OF 300 ENDOF ELSEOF 999 ENDOF ( any other case——my new fbForth way) ENDCASE . ( print result) ; I will likely be including ELSEOF in the resident dictionary of the next build, which, hopefully, will be before the Faire. ...lee Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted October 15, 2015 Share Posted October 15, 2015 I like it. Perhaps something to incorporate in TF as well. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 16, 2015 Author Share Posted October 16, 2015 I like it. Perhaps something to incorporate in TF as well. You can add it yourself before any code that uses it. It only takes 20 bytes. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 16, 2015 Share Posted October 16, 2015 Yes that's a gem. I'll put it on the add list! Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted October 19, 2015 Share Posted October 19, 2015 Are there already tools that list blocks in fbForth to DV80 files? I could probably do something with 'sed' on the ?windows? box hosting my hdx drive, but wondered if there was already something out there... I saw the thread on using Intellij for editing forth files, which would imply moving the code to and from pc text files... I want to be able to commit any of my code to git in a reasonable manner, while actually using the TI for as much of the workflow as is reasonable. Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted October 19, 2015 Share Posted October 19, 2015 Also, COINCALL doesn't behave like I would expect. Is the cursor a sprite? do I need to disable it? I suspect this because I have repeating overlapping sprites with motion going on, and the collisions are almost never detected. But when I started printing out the flag from COINCALL, quite lazily with just a 'DUP .', then I started getting lots of collisions detected even through my intended sprites were not in collisions at the time. If I move the cursor by doing something like 32 8 * 23 + CURPOS ! then that issue goes away, but doing that seems really fishy. Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 19, 2015 Share Posted October 19, 2015 Also, COINCALL doesn't behave like I would expect. Is the cursor a sprite? do I need to disable it? I suspect this because I have repeating overlapping sprites with motion going on, and the collisions are almost never detected. But when I started printing out the flag from COINCALL, quite lazily with just a 'DUP .', then I started getting lots of collisions detected even through my intended sprites were not in collisions at the time. If I move the cursor by doing something like 32 8 * 23 + CURPOS ! then that issue goes away, but doing that seems really fishy. Post your code. Let's have a look and we'll get out sleuthing heads on! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 19, 2015 Author Share Posted October 19, 2015 Are there already tools that list blocks in fbForth to DV80 files? I could probably do something with 'sed' on the ?windows? box hosting my hdx drive, but wondered if there was already something out there... I saw the thread on using Intellij for editing forth files, which would imply moving the code to and from pc text files... I want to be able to commit any of my code to git in a reasonable manner, while actually using the TI for as much of the workflow as is reasonable. That is on the back burner. It would be simple enough to do. I would probably list them much the same as LIST does to the screen, with block numbers and line numbers. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 19, 2015 Author Share Posted October 19, 2015 Also, COINCALL doesn't behave like I would expect. Is the cursor a sprite? do I need to disable it? I suspect this because I have repeating overlapping sprites with motion going on, and the collisions are almost never detected. But when I started printing out the flag from COINCALL, quite lazily with just a 'DUP .', then I started getting lots of collisions detected even through my intended sprites were not in collisions at the time. If I move the cursor by doing something like 32 8 * 23 + CURPOS ! then that issue goes away, but doing that seems really fishy. The cursor is not a sprite. The flashing is handled by the code that implements KEY . The cursor is ASCII 30, so you should probably avoid using that character in a sprite. CURPOS is a user variable that holds the cursor position and has nothing to do with sprites. COINCALL does nothing more than report the state of the coincidence bit in the VDP status byte at >837B. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 19, 2015 Share Posted October 19, 2015 With regard to COINCALL if you have sprites off the screen that are on top of one another or transparent sprites on top of one another then you may get a hit if they have non-empty characters associated with them. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 19, 2015 Author Share Posted October 19, 2015 The E/A Manual says this about the coincidence bit: Set if two or more sprites have overlapping pixels, including sprites that are transparent and sprites that are off the bottom of the screen. The flag is cleared by reading the Status Register or by resetting VDP. Though transparent coincident sprites will, indeed, cause the setting of the coincidence bit, coincident sprites, completely off the bottom of the screen, will not. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 19, 2015 Author Share Posted October 19, 2015 Also, COINCALL doesn't behave like I would expect. Is the cursor a sprite? do I need to disable it? I suspect this because I have repeating overlapping sprites with motion going on, and the collisions are almost never detected. But when I started printing out the flag from COINCALL, quite lazily with just a 'DUP .', then I started getting lots of collisions detected even through my intended sprites were not in collisions at the time. If I move the cursor by doing something like 32 8 * 23 + CURPOS ! then that issue goes away, but doing that seems really fishy. Before working with sprites and after changing to the VDP mode of interest, sprites should be initialized with DELALL . ...lee Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted October 20, 2015 Share Posted October 20, 2015 Ok, I am performing GRAPHICS, then DELALL, then creating a driver sprite, and 7 rival sprites. This code currently, experiences coincidence immediately in the 'CONTROL' loop and terminates. But if I change block 5 word SHOWLIVES to end with "30 22 .at", then things loop around. I think I just spotted my error, block 4... Do loop end values are not inclusive, so I'm looping from 2 to 9 to create the enemie cars, which creates sprites 2 through 8. but then I set 9 in motion... which should probably be 8... ? ## BLOCK: 1 ( TITLE SCREEN ) : .AT ( X,Y -- ) SWAP 32 * + CURPOS ! ; : ALLCOLOR ( F,B -- ) DUP SCREEN 15 0 DO OVER OVER I COLOR LOOP DROP DROP ; : TITLE GRAPHICS 1 13 ALLCOLOR 5 7 .AT ." FORMULA-TI RACING" 9 8 .AT ." MATTHEW SPLETT" 10 11 .AT ." 1984,2015" 20 6 .AT ." PRESS FIRE TO BEGIN" ; : WAITFIRE BEGIN 1 JCRU 1 = UNTIL ; ( LOAD OTHER BLOCKS ) : LOADALL 7 2 DO I LOAD LOOP ; LOADALL ## BLOCK: 2 ( CAR PATTERNS) BASE->R HEX : RACECAR 03C7 CFFF CFCC 0B0B 68 SPCHAR 0B0B 0FCF CFFF C7C4 69 SPCHAR C0E3 F3FF F333 D0D0 6A SPCHAR D0D0 F0F3 F3FF E323 6B SPCHAR ; : CURBS FBF5 FBF5 FBF5 FBF5 6C CHAR DFAF DFAF DFAF DFAF 6D CHAR ; R->BASE ## BLOCK: 3 ( DRAW TRACK ) : DRAWTRACK CLS CURBS 1 15 ALLCOLOR 5 0 24 108 VCHAR 25 0 24 109 VCHAR ; ## BLOCK: 4 ( ADD SPRITES ) : SPRSETUP DELALL 2 MAGNIFY ; : DRIVER 121 160 13 104 1 SPRITE ; : RNDSPEED ( --n ) 10 RND 3 + ; : ENEMIES 9 2 DO 17 I 20 * + 9 I 3 + 104 I SPRITE 0 RNDSPEED I MOTION LOOP 9 #MOTION ; : GOCARS RANDOMIZE SPRSETUP RACECAR DRIVER ENEMIES ; ## BLOCK: 5 ( CONTROL LOOP ) 5 VARIABLE LIVES : SHOWLIVES 2 2 .AT LIVES @ . ; : CRASH -1 LIVES +! SHOWLIVES ; : CONTROL 0 JMODE ! 5 LIVES ! SHOWLIVES BEGIN COINCALL IF CRASH ENDIF LIVES @ 1 < UNTIL ; ## BLOCK: 6 ( LAUNCH GAME ) : DEVMODE 0 #MOTION TEXT ; : GAME TITLE WAITFIRE DRAWTRACK GOCARS CONTROL DEVMODE ; ." Enter GAME to begin." ( I wrote a little groovy/java code to create this block dump ) Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted October 20, 2015 Share Posted October 20, 2015 Ok, I've found that my sprite numbering is off... I've straightened that out... so now I have sprites 0 the driver, and 1 through 7 the cars. and I'm supposed to use 7 + 1 for the #MOTION... so that wasn't the problem... It is the CONTROL word in block 5 that is confusing me. COINCALL is just returning -1 all the time, which as a flag is true. Do I need to redefine characters 0 - 3 since I'm in '2 magnify' mode? Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted October 20, 2015 Share Posted October 20, 2015 That was it... DELALL sets all the sprites patterns to 0, but with my magnified sprites, some magic invisible sprites are tripping the COINCALL. So I defined character patterns 0 - 3, to all 0000s, and COINCALL behaved as I would expect. I still feel like that means I'm not initializing the unused sprites correctly... Now I read a little further in the Lee Stewart book, and it suggests I should move the sprite pattern table so it doesn't overlap with the normal pattern table in Graphics mode... Would that have saved me this issue? or would I still have to have made sure that sprite pattern 0 - 3 is all zeros? Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 20, 2015 Author Share Posted October 20, 2015 That was it... DELALL sets all the sprites patterns to 0, but with my magnified sprites, some magic invisible sprites are tripping the COINCALL. So I defined character patterns 0 - 3, to all 0000s, and COINCALL behaved as I would expect. I still feel like that means I'm not initializing the unused sprites correctly... Now I read a little further in the Lee Stewart book, and it suggests I should move the sprite pattern table so it doesn't overlap with the normal pattern table in Graphics mode... Would that have saved me this issue? or would I still have to have made sure that sprite pattern 0 - 3 is all zeros? Sprite patterns should not have anything to do with collision unless they are associated with a sprite. The only reason I can contrive for the behavior you see is not using a lower-numbered sprite. Anytime you define a sprite in fbForth, all lower-numbered sprites are checked for whether they have been marked as undefined with their y coordinates set to >D0. If that is the case their y coordinates are set to >C0 (192). The effect of this immediately after invoking GRAPHICS and DELALL , is that all previously undefined sprites will be defined as though by 0 192 0 0 0 SPRITE Their motion vectors will also each be 0. With the magnification factor set to 2, character patterns 0 – 3 are, indeed, associated with each of those previously undefined sprites. I checked the collision bit with overlapping, off-screen sprites and it was not set, contrary to the E/A Manual, so I am puzzled. It certainly could be a bug in fbForth. If we find any such bugs, they will not survive! ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 20, 2015 Author Share Posted October 20, 2015 Re sprite patterns, the default situation, as noted by @jedimatt42, is that the PDT and the SPDT are coincident. When the VDP mode is changed to Graphics, the PDT is first filled with 2KiB of >FF, after which the current font is loaded at the starting address of the PDT. The current font will be either 1KiB or 2KiB in length. The default font is 1KiB, with patterns for the first 32 characters (256 bytes for codes 0 – 31) filled with >FF. Obviously, if the font is just 1KiB, the upper 1KiB (pattern codes 128 – 255) will remain all >FFs. Furthermore, if you change the location of the SPDT, it is not initialized for you. It will contain whatever values happen to be at the new location. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 20, 2015 Author Share Posted October 20, 2015 Ok, I am performing GRAPHICS, then DELALL, then creating a driver sprite, and 7 rival sprites. This code currently, experiences coincidence immediately in the 'CONTROL' loop and terminates. But if I change block 5 word SHOWLIVES to end with "30 22 .at", then things loop around. I think I just spotted my error, block 4... Do loop end values are not inclusive, so I'm looping from 2 to 9 to create the enemie cars, which creates sprites 2 through 8. but then I set 9 in motion... which should probably be 8... ? ... Your code has no doubt changed, so I won't get too much into it, yet. Just a couple of comments. The conventional way to show stack effects in Forth is to separate stack entries with spaces, which would change : .AT ( X,Y -- ) SWAP 32 * + CURPOS ! ; to : .AT ( X Y -- ) SWAP 32 * + CURPOS ! ; Also, with Y on the top of the stack (rightmost item), your code should be : .AT ( X Y -- ) 32 * + CURPOS ! ; But, there is already a resident word with a more generalized form of this definition. It is actually written in ALC; but, here is the equivalent high-level Forth: : GOTOXY ( X Y -- ) SCRN_WIDTH @ * + SCRN_START @ + CURPOS ! ; Of course, it could be that your stack effects are backwards, in which case : .AT ( Y X -- ) SWAP 32 * + CURPOS ! ; could be written : .AT ( Y X -- ) SWAP GOTOXY ; ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 20, 2015 Author Share Posted October 20, 2015 Perhaps you know this: You can load successive blocks with --> as the last word on each block except, of course, the final block. That way, the blocks can start anywhere without needing to redefine a word like LOADALL . ...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.