Jump to content
IGNORED

fbForth—TI Forth with File-based Block I/O [Post #1 UPDATED: 06/09/2023]


Lee Stewart

Recommended Posts

And, H-e-e-r-r-e-s the beta 4—I'm not sure why I didn't package a beta 3—I had a reason for calling this one beta 4, but now cannot recall. Did I tell you I was getting old?!

 

fbForth200-beta04.zip

fbForth200-beta04-MESS.zip

 

See post #670 above to see how to set up Classic99.ini, if you have never used fbForth 2.0.

 

I modified the exit from the 64-column editor to pop you into the VDP mode you left when you entered it. Let me know if you would like some other behavior. (Previously, it simply popped you into the 8-line text portion of the screen, with the block still visible.)

 

FBLOCKS is getting emptier and emptier! There's only one menu page, now. All the graphics mode words and graphics primitives are in the resident dictionary.

 

VMODE is a new word that I described somewhere above, I think. It requires you to put the mode # (0 – 6) on the stack before executing it. It does the same thing as executing one of the mode words such as TEXT80 or GRAPHICS2 , but now you can write code that can restore modes (which I did for the 64-column editor).

 

One other note: To initiate sprites, you should now execute DELALL , first, instead of " vaddr SSDT " (no quotes). Again, let me know what does not seem to work.

 

...lee

 

EDIT: MESS file above is flawed—will repost in a later entry.

Edited by Lee Stewart
Link to comment
Share on other sites

I don't know if you can use it at all -- it may take too much code (I didn't count the bytes, but, my line draw function worked. ;) I didn't have your test program (I went back and looked?), so I wrote my own and pasted your line draw in for a side-by-side comparison.

 

 

The three draw passes are set, unset, and XOR. You can see by the final interference pattern that your line draw is nicer, but I met my goal of being faster (not by as much as I expected though! Your lines are fast!!) I did manage to do it without needing any extra registers or changing workspace in the end - I had to shuffle some code anyway.

 

I wanted to try something different - rather than plotting pixels, this code actually works in address space, X coordinates are updated by shifting, and Y coordinates by adding. I think this is pretty close for the restrictions you had in place, but I'm going to see what I can do to speed it up without restrictions for my library (so if you can't use it, no worries!)

 

The biggest ugly with this code is that it has essentially two copies of itself, slightly tweaked - one for shallow lines and one for steep lines. It's pretty much a duplication of code but eliminates inline tests.

 

Just for fun anyway - thanks for the challenge! Included in the zip is the standalone code (note: it doesn't include a pixel function, so you might still need your dot function if it's called from Forth anyway, I don't have anything in here that would speed that up!), and the demo programs for Asm99. EA#3 load and program name is START.

 

LINEDRAW.zip

  • Like 2
Link to comment
Share on other sites

Lee,

 

Took it for a quick test-drive this morning. Looking good. :thumbsup: I managed to fankle this little ditty together:

 

 

: PRETTY ( -- )
    4 VMODE
    256 0 DO  0 0 I 191 LINE  4 +LOOP
    193 0 DO  0 0 255 I LINE  4 +LOOP ;

 

Sigh... Wish I could get hi-res into TF. :woozy:

  • Like 1
Link to comment
Share on other sites

I don't know if you can use it at all -- it may take too much code (I didn't count the bytes, but, my line draw function worked. ;) I didn't have your test program (I went back and looked?), ...

 

Sorry about that. | :) Here it is:

: SP2L ( SPLIT2 mode: draw lines from upper left to fill screen)
    SPLIT2 DTOG
    255 0 DO                           
        0 32 I 191 LINE
    LOOP
    31 190 DO
        0 32 255 I LINE
    -1 +LOOP ;

Here's another in full bitmap mode that requires you to type FCTN+4 (QUIT) to exit to text mode:

: PATTERN ( GRAPHICS2 mode: draw lines from upper left to fill screen)
    GRAPHICS2 DTOG
    255 0 DO
        0 0 I 191 LINE
    LOOP
    -1 191 DO
        0 0 255 I LINE
    -1 +LOOP
    BEGIN PAUSE UNTIL TEXT ;  ( FCTN+4 to quit)

I will definitely have a look at your code. Thanks for your input! :) There's no particular reason in ALC to call DOT from LINE to plot the pixel, except that I was transliterating the Forth code and it is, after all, the Forth way to use lots of small functions. Of course, space is shrinking in that bank—I have 1098 bytes left.

 

...lee

 

EDIT: Corrected SP2L—the first DO was on the wrong line!

Edited by Lee Stewart
Link to comment
Share on other sites

Lee,

 

Took it for a quick test-drive this morning. Looking good. :thumbsup: I managed to fankle this little ditty together:

: PRETTY ( -- )
    4 VMODE
    256 0 DO  0 0 I 191 LINE  4 +LOOP
    193 0 DO  0 0 255 I LINE  4 +LOOP ;

Sigh... Wish I could get hi-res into TF. :woozy:

 

Yeah, you'd have to put the block buffers in RAM like fbForth (and TI Forth before it).

 

PRETTY is very nice! I wrote a similar word ( PATTERN ) that covers the full screen with single steps (see my last post).

 

...lee

Link to comment
Share on other sites

See post #670 above to see how to set up Classic99.ini, if you have never used fbForth 2.0.

To make it easier, if you rename the file to "fbForth200_3.bin, then Classic99 will autodetect the type (3.bin) for Cartridge->User->Open.

 

I like that split mode. :)

Link to comment
Share on other sites

... Just for fun anyway - thanks for the challenge! Included in the zip is the standalone code (note: it doesn't include a pixel function, so you might still need your dot function if it's called from Forth anyway, ...

 

Wow! Nice use of the X instruction! :-o I really must keep that closer to the front of my mind.

 

I do need to keep DOT for high-level Forth; but, I certainly don't need to call it from LINE , though I'm calling it via BL, not through high-level Forth. Obviously, the savings from your code that would help by my not calling DOT would be

  • handling DMODE only once per line vs. every pixel;
  • shifting per bitmap byte horizontally;
  • adding per pixel row vertically;
  • enabling interrupts only once per line instead of every pixel;
  • probably, more I didn't see!

Perhaps you know that DCOLOR (ALC: $DCOL) in fbForth has a value of -1 for no change. If you do, does that mean that setting the color to every pixel (byte?) is cheaper than the test? Also, DCOLOR contains both the FG and BG color of the bitmap byte containing our pixel, e.g., 10h = black on transparent.

 

Anyway, the time for my PATTERN is 36 seconds with DCOLOR = -1, i.e., no updates to color table, and 42 seconds with updates for 100,127 pixels drawn. Removing LIMI 0/LIMI 2 to once per line saves only 1 second for all those pixels drawn!

 

...lee

Link to comment
Share on other sites

To make it easier, if you rename the file to "fbForth200_3.bin, then Classic99 will autodetect the type (3.bin) for Cartridge->User->Open.

 

I like that split mode. :)

 

I will do that for the next go-round. Thanks.

 

Split mode gives you 8 text lines; but, split2 gives you more bitmap real estate with just 4 text lines, which is probably enough to type commands for testing. You just have to remember that the bitmap screen ends at dotrow 127 in split mode and starts at dotrow 32 in split2 mode.

 

...lee

Link to comment
Share on other sites

Wow! Nice use of the X instruction! :-o I really must keep that closer to the front of my mind.

 

I do need to keep DOT for high-level Forth; but, I certainly don't need to call it from LINE , though I'm calling it via BL, not through high-level Forth. Obviously, the savings from your code that would help by my not calling DOT would be

  • handling DMODE only once per line vs. every pixel;
  • shifting per bitmap byte horizontally;
  • adding per pixel row vertically;
  • enabling interrupts only once per line instead of every pixel;
  • probably, more I didn't see!
Perhaps you know that DCOLOR (ALC: $DCOL) in fbForth has a value of -1 for no change. If you do, does that mean that setting the color to every pixel (byte?) is cheaper than the test? Also, DCOLOR contains both the FG and BG color of the bitmap byte containing our pixel, e.g., 10h = black on transparent.

 

Anyway, the time for my PATTERN is 36 seconds with DCOLOR = -1, i.e., no updates to color table, and 42 seconds with updates for 100,127 pixels drawn. Removing LIMI 0/LIMI 2 to once per line saves only 1 second for all those pixels drawn!

 

...lee

 

I do enable interrupts per pixel, just like yours did (my own testing also suggested it wasn't a huge difference in speed, which makes sense as a line can finish in less than a vblank so most lines aren't interrupted anyway), but I did not realize that $DCOL has a -1 value (that's useful!) That would probably require a test-and-jump in the pixel function. The test would be faster than writing the color, so it's worth adding.

 

As coded, it does set foreground and background (the byte is copied verbatim).

 

My main goal was to avoid address calculation for every pixel, by working in address space instead of coordinates, and it does seem to have helped. I'm not sure if anyone did it that was before, but it was a new idea to me. ;) Ultimately, though, the fewer extra instructions in the inner loop, the better! X is nice for simplifying the loop, but separate functions for each of the four possible slopes would be faster still (only slightly, though, X only adds 8 cycles).

 

Thanks for looking at it though!

Link to comment
Share on other sites

... writing the color, ...

 

Regarding your trick in justline.a99 for going from writing a byte to the PDT to writing a byte to the color table, it will only work if they are at 2000h and 0000h, respectively. If they are the other way round (possible), the trick won't work. What will work is to OR 4000h the first time (as you did with SOCB) and XOR 2000h (without first correcting the address) the second time:

 

Also, what is the fastest "do nothing" instruction to insert between VDP accesses that will give the VDP enough time to settle for accelerated consoles et al.?—I'm not doing that in DOT and I probably should.

 

...lee

Link to comment
Share on other sites

@Tursi...

 

Your comment about "BL @RTNEXT" prompted me to check my code. All instances of that statement are, in fact, supposed to be "B @RTNEXT". I explained it to myself in my trampoline code, used it correctly a few times, then had a brain fart when I got around to writing the graphics primitives. Thanks! :)

 

...lee

Link to comment
Share on other sites

Regarding your trick in justline.a99 for going from writing a byte to the PDT to writing a byte to the color table, it will only work if they are at 2000h and 0000h, respectively. If they are the other way round (possible), the trick won't work. What will work is to OR 4000h the first time (as you did with SOCB) and XOR 2000h (without first correcting the address) the second time:

 

Also, what is the fastest "do nothing" instruction to insert between VDP accesses that will give the VDP enough time to settle for accelerated consoles et al.?—I'm not doing that in DOT and I probably should.

 

...lee

Yes, that's true, but the code that I was reading to get an understanding of the requirements made assumptions of those addresses too. It's rare that an application will vary the locations of those tables, though.. does Forth do so?? (Putting the pattern table at >0000 lets you skip adding anything for pattern draws, meaning the extra work is only needed when color is in place, that's the order I usually use ;) ).

 

The XOR trick is cute though! I like that.

 

Anything is enough time, even an invalid instruction (fastest at 6 cycles) is enough, as for the most part we're right on the edge anyway. If you have valid work that you can interleave like I did, that's best (cause you have to do it anyway!), otherwise a jump which is NOT taken is fastest at 8 cycles and 1 memory access (a jump which IS taken is second fastest at 10 cycles and 1 memory access). So, NOP (JMP $) is the quickest, safest no-side-effect instruction.

Link to comment
Share on other sites

Yes, that's true, but the code that I was reading to get an understanding of the requirements made assumptions of those addresses too. It's rare that an application will vary the locations of those tables, though.. does Forth do so?? (Putting the pattern table at >0000 lets you skip adding anything for pattern draws, meaning the extra work is only needed when color is in place, that's the order I usually use ;) ).

 

The XOR trick is cute though! I like that.

 

Anything is enough time, even an invalid instruction (fastest at 6 cycles) is enough, as for the most part we're right on the edge anyway. If you have valid work that you can interleave like I did, that's best (cause you have to do it anyway!), otherwise a jump which is NOT taken is fastest at 8 cycles and 1 memory access (a jump which IS taken is second fastest at 10 cycles and 1 memory access). So, NOP (JMP $) is the quickest, safest no-side-effect instruction.

 

fbForth allows setting the two tables the other way; but, I am actually discouraging it by making it a whole lot harder to do than can be done in TI Forth and fbForth 1.0

 

Thanks for the NOP info. That's what I usually use, but wasn't sure there might be a faster solution. What do you mean by invalid instruction?

 

...lee

Link to comment
Share on other sites

An invalid instruction is any opcode that does not decode to a valid CPU instruction. They take 6 cycles for the 9900 to ignore. But, it's not a good idea to rely on them, as systems using other CPUs may behave unexpectedly if they encounter them.

Link to comment
Share on other sites

My, my—I just recovered 142 bytes from bank 1 by eliminating a good bit of the startup code I can now effect by calling TEXT (which is now part of the resident dictionary) in BOOT ! It's a small amount of room, but I now have 1230 bytes left in bank 1. Maybe a Bresenham ellipse and ....

 

...lee

 

 

EDIT: misspelled "ellipse"— :mad:

Edited by Lee Stewart
Link to comment
Share on other sites

Beta 4 has a problem with JKBD , the keyboard version of the joystick routine. I have fixed it, but need to do some yard work before I post it.

 

There also seems to be a problem with the BIN file in MESS. First, however, I must repackage the RPK because what I posted is wrong. I will fix that later, as well. Perhaps someone can tell what's going wrong with the BIN in MESS before I can.

 

...lee

Link to comment
Share on other sites

Here are the new betas:

fbForth200-beta04a.zip

fbForth200-beta04a-MESS.zip

 

Currently, the MESS RPK is not working for me. At first, I was only having trouble in the 3 bitmap modes. I could get in and out of them; but, there was nothing but the backgrounds. I am wondering if it is a VDP register issue with the TMS9938 (EVPC mode). Now, however, I cannot get past a blue screen at the very beginning. Unless someone can give me some insight sooner, I will work on that at an unspecified time down the road. I need to ensure I have the latest release before I start complaining.

 

...lee

Link to comment
Share on other sites

Lee, how far exactly do you get? I got inside FORTH and was able to type MENU, getting this list (Description ... Load block) and "Type <block> LOAD to load." I'm using ti99_4ev, and this is now running in 40 col mode.

 

Before I did something stupid :dunce: (not remembering what :ponder:), I got that far, as well. The problem was with the 3 bitmap modes ( entered by executing GRAPHICS2 , SPLIT or SPLIT2 ). Executing those words put me into the respective modes; however, all I got were background colors, so I could not see text in split or split2 modes, nor could I see any dots plotted with DOT or LINE . The foreground colors were missing—hence, my VDP-register question. I could get back to the other modes by blindly typing TEXT , TEXT80 or GRAPHICS , so everything else appeared to be functional.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

I tried it with the standard TI-99/4A in MESS, and when doing GRAPHICS2, I also get a gray screen with no contents. The v9938 implementation may have still have some issues, but the TMS9928 code is pretty well tested.

 

I get this output from the 9938:

 

(Starting Forth, typing GRAPHICS2, then blindly TEXT)

 

 

v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 70 to R#2
v9938: Write 0e to R#3
v9938: Write 39 to R#4
v9938: Write 86 to R#5
v9938: Write 38 to R#6
v9938: Write f7 to R#7
v9938: Write 00 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 02 to R#14
v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 00 to R#2
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 00 to R#6
v9938: Write 08 to R#8
v9938: Write 02 to R#9
v9938: Write f7 to R#12
v9938: Write 00 to R#14
...
v9938: Write 30 to R#1
v9938: mode = TEXT 1
v9938: Write 02 to R#0
v9938: mode = UNKNOWN
v9938: Write 06 to R#2
v9938: Write 7f to R#3
v9938: Write 3f to R#4
v9938: Write 36 to R#5
v9938: Write 07 to R#6
v9938: Write fe to R#7
v9938: Write 60 to R#1
v9938: mode = GRAPHIC 2
...
v9938: Write 30 to R#1
v9938: mode = UNKNOWN
v9938: Write 00 to R#0
v9938: mode = TEXT 1
v9938: Write 00 to R#2
v9938: Write 0e to R#3
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 01 to R#6
v9938: Write 4f to R#7
V9938: Read c4 from S#0
v9938: Write 70 to R#1
v9938: mode = TEXT 1
Link to comment
Share on other sites

 

I tried it with the standard TI-99/4A in MESS, and when doing GRAPHICS2, I also get a gray screen with no contents. The v9938 implementation may have still have some issues, but the TMS9928 code is pretty well tested.

 

I get this output from the 9938:

 

(Starting Forth, typing GRAPHICS2, then blindly TEXT)

 

 

 

v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 70 to R#2
v9938: Write 0e to R#3
v9938: Write 39 to R#4
v9938: Write 86 to R#5
v9938: Write 38 to R#6
v9938: Write f7 to R#7
v9938: Write 00 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 02 to R#14
v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 00 to R#2
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 00 to R#6
v9938: Write 08 to R#8
v9938: Write 02 to R#9
v9938: Write f7 to R#12
v9938: Write 00 to R#14
...
v9938: Write 30 to R#1
v9938: mode = TEXT 1
v9938: Write 02 to R#0
v9938: mode = UNKNOWN
v9938: Write 06 to R#2
v9938: Write 7f to R#3
v9938: Write 3f to R#4
v9938: Write 36 to R#5
v9938: Write 07 to R#6
v9938: Write fe to R#7
v9938: Write 60 to R#1
v9938: mode = GRAPHIC 2
...
v9938: Write 30 to R#1
v9938: mode = UNKNOWN
v9938: Write 00 to R#0
v9938: mode = TEXT 1
v9938: Write 00 to R#2
v9938: Write 0e to R#3
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 01 to R#6
v9938: Write 4f to R#7
V9938: Read c4 from S#0
v9938: Write 70 to R#1
v9938: mode = TEXT 1

 

 

 

Actually, you should get a gray screen with nothing on it when you execute GRAPHICS2 . It's when you get into split or split2 modes that you should see white text on the blue part of the screen. For graphics2 (full bitmap), try entering the following in text mode, i.e., before trying to get into graphics2 mode:

: TEST GRAPHICS2 0 0 255 191 LINE ;

TEST 

You should get a black line from the upper left to the lower right. You can then type TEXT , TEXT80 , or GRAPHICS to get to a mode where you can see what you are typing.

 

Also, I will take a closer look at your output above. Thanks for the info.

 

...lee

Link to comment
Share on other sites

Ah, OK, got it. With the TMS9928 in SPLIT(2), there is a ok:0 with cursor, but not with the v9938.

 

I tried it again; here is the new log:

 

 

v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 70 to R#2
v9938: Write 0e to R#3
v9938: Write 39 to R#4
v9938: Write 86 to R#5
v9938: Write 38 to R#6
v9938: Write f7 to R#7
v9938: Write 00 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 02 to R#14
v9938: Write 20 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 00 to R#2
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 00 to R#6
v9938: Write 08 to R#8
v9938: Write 02 to R#9
v9938: Write f7 to R#12
v9938: Write 00 to R#14
v9938: Write 60 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 00 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 60 to R#1
v9938: mode = GRAPHIC 1
v9938: Write 30 to R#1
v9938: mode = TEXT 1
v9938: Write 01 to R#6
v9938: Write 4f to R#7
v9938: Write 70 to R#1
v9938: mode = TEXT 1

 

SPLIT

 

 

v9938: Write 30 to R#1
v9938: mode = TEXT 1
v9938: Write 02 to R#0
v9938: mode = UNKNOWN
v9938: Write 06 to R#2
v9938: Write 7f to R#3
v9938: Write 3f to R#4
v9938: Write 36 to R#5
v9938: Write 07 to R#6
v9938: Write fe to R#7
v9938: Write 60 to R#1
v9938: mode = GRAPHIC 2

 

TEXT:

 

 

v9938: Write 30 to R#1
v9938: mode = UNKNOWN
v9938: Write 00 to R#0
v9938: mode = TEXT 1
v9938: Write 00 to R#2
v9938: Write 0e to R#3
v9938: Write 01 to R#4
v9938: Write 06 to R#5
v9938: Write 01 to R#6
v9938: Write 4f to R#7
v9938: Write 70 to R#1
v9938: mode = TEXT 1
Link to comment
Share on other sites

 

Ah, OK, got it. With the TMS9928 in SPLIT(2), there is a ok:0 with cursor, but not with the v9938.

 

I tried it again; here is the new log:

...

 

H-m-m-m—It's ignoring the left bit of VR00. I suppose that is OK because the 9938 will never be in 4KB mode for VRAM. However, the left 2 bits of R4 are lopped off as well and I don't know what that means. Perhaps, the 9938 VDP register settings are incompatible with the 9918A settings for bitmap mode. If so, I need to actually try to detect the 9938. My reason for doing anything with the 9938 at all was 80-column text mode, which works fine. Any ideas the bitmap settings (BTW, graphics2, split and split2 all use bitmap mode)?

 

...lee

Link to comment
Share on other sites

The v9938 manual says:

 

R0: 0 | DG | IE2 | IE1 | 0 | 0 | 1 | 0

R1: 0 | BL | IE0 | 0 | 0 | 0 | SI | MAG

 

The 9938 does not have a 4/16K flag. But I guess it just ignores the flag.

 

If you want to detect the v9938 you just have to read status register 4. Its contents can only be FF or FE. The 9928 has only one status register (so it ignores the status register pointer setting), and that register is highly unlikely to have that value (in particular when you don't have sprites on the screen).

 

[Edit: Isn't "Return to Pirate's Isle" another example of a Graphics2 application? Just tried it with ti99_4ev, and it works.]

Edited by mizapf
Link to comment
Share on other sites

The v9938 manual says:

 

R0: 0 | DG | IE2 | IE1 | 0 | 0 | 1 | 0

R1: 0 | BL | IE0 | 0 | 0 | 0 | SI | MAG

 

The 9938 does not have a 4/16K flag. But I guess it just ignores the flag.

 

If you want to detect the v9938 you just have to read status register 4. Its contents can only be FF or FE. The 9928 has only one status register (so it ignores the status register pointer setting), and that register is highly unlikely to have that value (in particular when you don't have sprites on the screen).

 

[Edit: Isn't "Return to Pirate's Isle" another example of a Graphics2 application? Just tried it with ti99_4ev, and it works.]

 

Oh, my, did I just get thrown a curve by the TI programmers of TI Forth!!! :-o VR04 is set at FFh (left 2 bits are ignored, so it's really 3Fh), which for the 9918A translates to 800*3Fh=3800h for 16KB rollover; but, for the 9938, it is 1F800h, which is in the 9938's address space!—so I changed it to 07h, which computes to 3800h without any games. For the 9938 I cannot test it yet. If you would be so kind, Michael, here it is (only the RPK is different):

 

fbForth200-beta04b-MESS.zip

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...