Jump to content
IGNORED

Floating-point math and bitmap mode


Recommended Posts

Hi all! In a TI-99 assembly, I am using both floating-point math functions and bitmap mode together, and the problem is that the math functions of XMLLNK/GPLLNK like to use low VDP memory for some of its work, a region I am using to store the screen bitmap. In the screenshot attached, you will notice a block of stray pixels on the right side of the screen, 28 bytes starting at VDP >03C0. Floating-point math was also stacking a couple of numbers at VDP >0008, which I was able to move elsewhere by changing the address in VSPTR (>836E), but I have not discovered a way to move the operations that use VDP >03C0.  I first initialize the bitmap, color map, and pattern descriptor table, so at the beginning, that region is all zeroes. When stepping through the first pass of the main loop, a step-over of the first floating-point branch is precisely when the data appears in that location.

 

It happens in emulation as well.  Editor/Assembler code LISS1 is also attached.

 

Any ideas?

lissajous.jpg

LISS1

  • Like 1
Link to comment
Share on other sites

3 hours ago, theincrediblepeep said:

Hi all! In a TI-99 assembly, I am using both floating-point math functions and bitmap mode together, and the problem is that the math functions of XMLLNK/GPLLNK like to use low VDP memory for some of its work, a region I am using to store the screen bitmap. In the screenshot attached, you will notice a block of stray pixels on the right side of the screen, 28 bytes starting at VDP >03C0. Floating-point math was also stacking a couple of numbers at VDP >0008, which I was able to move elsewhere by changing the address in VSPTR (>836E), but I have not discovered a way to move the operations that use VDP >03C0.  I first initialize the bitmap, color map, and pattern descriptor table, so at the beginning, that region is all zeroes. When stepping through the first pass of the main loop, a step-over of the first floating-point branch is precisely when the data appears in that location.

 

It happens in emulation as well.  Editor/Assembler code LISS1 is also attached.

 

Any ideas?

lissajous.jpg

LISS1 3.63 kB · 4 downloads

I am not familiar with floating point routines, didn't know they used some VDP. But I can think of a workaround.


Since floating point clobbers your pattern table entries at >3C0 - 3DF, (patterns 120-123) you can prevent those from appearing in the screen image table. The downside is you would not be able to graph or show anything in that spot.
 

Nice looking Lissajous!

  • Like 1
Link to comment
Share on other sites

6 hours ago, theincrediblepeep said:

In the screenshot attached, you will notice a block of stray pixels on the right side of the screen, 28 bytes starting at VDP >03C0. Floating-point math was also stacking a couple of numbers at VDP >0008, which I was able to move elsewhere by changing the address in VSPTR (>836E), but I have not discovered a way to move the operations that use VDP >03C0.

 

2 hours ago, FarmerPotato said:

Since floating point clobbers your pattern table entries at >3C0 - 3DF, (patterns 120-123)

 

I am pretty sure there is no way to move the VDP Rollout Area (>03C0 – >03DF). I believe it is only the GPL transcendental functions that use this area, which you will need to save/restore around the functions that use it. I think the E/A manual says which ones, but not sure. 

 

...lee

  • Like 3
Link to comment
Share on other sites

2 hours ago, Lee Stewart said:

I am pretty sure there is no way to move the VDP Rollout Area (>03C0 – >03DF). I believe it is only the GPL transcendental functions that use this area, which you will need to save/restore around the functions that use it. I think the E/A manual says which ones, but not sure. 

        ...lee

 

The GPLLNK routine (>14) that converts a floating point number to a string also uses the VDP Rollout Area.

 

...lee

  • Like 2
Link to comment
Share on other sites

2 hours ago, Lee Stewart said:

I am pretty sure there is no way to move the VDP Rollout Area (>03C0 – >03DF). I believe it is only the GPL transcendental functions that use this area, which you will need to save/restore around the functions that use it. I think the E/A manual says which ones, but not sure. 

        ...lee

 

Unfortunately, I could not find any mention in the E/A manual of the use of the VDP Rollout Area. It is mentioned in the TI GPL Programmer’s Guide, but not explicitly which routines use it. I just know from my GPLLNK experience with TI Forth and fbForth 1.0 that I needed to deal with saving/restoring those 32 bytes when using many GPLLNK floating point routines in bitmap mode. I have found other references to the VDP Rollout Area but not exactly which routines were involved.  To my knowledge, none of the XMLLNK floating point routines use it.

 

With fbForth 2.0, I avoided the problem altogether by replacing the entire GPLLNK/XMLLNK library of floating point routines with a port of the Geneve MDOS L10 Floating Point Library to cartridge ROM, improving the CNS routine, along the way, to output a 3-digit power of ten for scientific notation, when desired—but, I digress ...

 

...lee

  • Like 9
Link to comment
Share on other sites

Wow. You have a lot of good stuff hidden inside FbForth.

For lazy people like me I would probably try to write up some tables and try to do the transcendentals with integer math. :) 

Not sure what the graphic results would look like, but there are no floating point pixels positions so it might work. (?)

  • Like 2
  • Thanks 2
Link to comment
Share on other sites

This came up when developing The Missing Link. With Extended BASIC it is actually worse because V0370 to V03DE are used by XB, plus if you are using subprograms, the name goes to the crunch buffer at >0820 (if I remember right).

The solution was to give up 8 pixels on each side of the bitmapped screen, which now becomes 240 pixels wide. Remember that bitmapped mode is really just a fancy graphics mode. You can put the same character at each edge of the screen and set the pattern for that character to a blank.

Since it gives you a full width screen, I think Lee's approach is best. Save the VDP bytes in that area, do the routine, then restore the bytes. That part of the screen will flash briefly. A clever programmer could probably use a sprite to hide it.

 

Edited by senior_falcon
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

1 hour ago, TheBF said:

Wow. You have a lot of good stuff hidden inside fbForth.

For lazy people like me I would probably try to write up some tables and try to do the transcendentals with integer math. :) 

Not sure what the graphic results would look like, but there are no floating point pixels positions so it might work. (?)

 

Indeed. A lot depends, however, on why you might be using floating point operations in your program. You likely do not need 13 – 14 digits of precision for just plotting pixels on the screen. Given enough room for the tables, I would think that approach would work just fine.

 

Though I am not using tables, I used an integer, no-divide version of the Bresenham Line Algorithm for LINE in fbForth 2.0:

Spoiler

;[*** LINE ***       ( x1 y1 x2 y2 --- )     ( alternative LINE---one or the other)
*++ This is an integer, no-divide version of the Bresenham line algorithm

* LINE does the following:
*     1) Computes dy = y2-y1 and dx =  x2-x1
*     2) Determines which direction, x or y, has slope <= 1
*         x) Flips dx and dy
*         y) Leaves dx and dy alone
*     3) sets DOTCNT = dx in R4
*     4) Computes D = 2*dy-dx
*     5) Forces plotting direction to be positive for independent variable
*     6) Sets starting y|x accumulator as acc = (y|x)
*     7) Finds accumulator increment as inc = +1|-1
*     8) Plots first dot
*     9) Each time through dot plotting loop:
*         a) Loop counter check
*         b) x|y = x|y + 1
*         c) D > 0?
*             yes)
*                 y1) acc = acc + inc
*                 y2) D = D+2*(dy-dx)
*             no) D = D+2*dy
*         d) y|x = acc
*         e) Plot dot
*         f) Decrement point counter

*        DATA DTBM_N
* LINE_N .name_field 4, 'LINE '
* LINE   DATA $+2
*        BL   @BLF2A
*        DATA _LINE->6000+BANK1

* Register usage in LINE's workspace---
*       R0:  varies
*       R1:  varies
*       R2:  y2
*       R3:  x2
*       R4:  y1, then, point (dot) count for line (DOTCNT)
*       R5:  x1, then, increment for dependent coordinate (INC) (+1|-1)
*       R6:  accumulator for dependent coordinate (ACC)
*       R7:  current independent coordinate       (COORD)
*       R8:  dx, then, 2*dx
*       R9:  dy, then, 2*dy
*      R10:  sign of dy/dx or dx/dy, then, D
*      R12:  contains flag for principal axis (1 = x axis, 0 = y axis)

_LINE  LIMI 0              ; disable interrupts because __DTBM doesn't
       LI   R0,FAC+4       ; point to R2 of LINE's workspace
       MOV  *SP+,*R0+      ; pop y2 to LINE's R2
       MOV  *SP+,*R0+      ; pop x2 to LINE's R3
       MOV  *SP+,*R0+      ; pop y1 to LINE's R4
       MOV  *SP+,*R0       ; pop x1 to LINE's R5
       LWPI FAC            ; switch to LINE's workspace
       SETO R10            ; initially, store -1 as sign of slope
       MOV  R2,R0          ; calculate dy
       S    R4,R0
       MOV  R0,R1          ; prepare for sign calculation
       ABS  R0
       MOV  R0,R9
       MOV  R3,R0          ; calculate dx
       S    R5,R0
       XOR  R0,R1          ; calculate sign of slope (dy/dx|dx/dy)
       JLT  LINE01         ; negative slope?
       NEG  R10            ; change sign to +1
LINE01 ABS  R0
       MOV  R0,R8
       MOV  R9,R1
       C    R1,R0          ; compare|dy| to |dx|
       JLT  LINE04         ; dy < dx?
       MOV  R0,R9          ; no, flip dy
       MOV  R1,R8          ;        and dx
       MOV  R4,R7          ; assume starting with y1
       MOV  R5,R6          ;   and x1 (to ACC)
       C    R4,R2          ; should we switch?
       JGT  LINE02         ; yes
       JMP  LINE03         ; no
LINE02 MOV  R2,R7          ; we're starting with y2
       MOV  R3,R6          ;   and x2 (to ACC)
LINE03 CLR  CRU            ; 0 to CRU (R12) to indicate y-axis processing
       JMP  LINE07
LINE04 MOV  R5,R7          ; assume starting with x1
       MOV  R4,R6          ;   and y1 (to ACC)
       C    R5,R3          ; should we switch?
       JGT  LINE05         ; yes
       JMP  LINE06         ; no
LINE05 MOV  R3,R7          ; we're starting with x2
       MOV  R2,R6          ;   and y2 (to ACC)
LINE06 LI   CRU,1          ; 1 to CRU (R12) to indicate x-axis processing
LINE07 MOV  R10,R5         ; get sign to INC register before we destroy it!
       SLA  R9,1           ; dy = 2*dy (we don't need dy by itself any more)
       MOV  R9,R0          ; calculate D
       S    R8,R0          ; D = 2*dy-dx
       MOV  R0,R10         ; store D in DYXSN
       MOV  R8,R4          ; load point counter
       SLA  R8,1           ; 2*dx (we don't need dx by itself any more)
       MOV  CRU,CRU        ; x or y axis?
       JNE  LINE08         ; x-axis
       MOV  R7,R0          ; y-axis, COORD to y for DOT
       MOV  R6,R1          ; ACC to x for DOT
       JMP LNLOOP          ; to first plot
LINE08 MOV  R7,R1          ; x-axis, COORD to x for DOT
       MOV  R6,R0          ; ACC to y for DOT
LNLOOP BL   @__DTBM        ; plot first dot (R0 = y, R1 = x)
       MOV  R4,R4          ; are we done?
       JEQ  LINEX          ; yup!
       DEC  R4             ; decrement counter
       INC  R7             ; increment principal coordinate
*++ Calculate D
       MOV  R9,R1          ; get 2*dy
       MOV  R10,R0         ; D > 0?
       JGT  LINE09         ; yup
       JMP  LINE10         ; nope
LINE09 A    R5,R6          ; inc/dec dependent variable
       S    R8,R1          ; 2*dy-2*dx
LINE10 A    R1,R10         ; D = D+[2*dy or 2*dy-2*dx)]
       MOV  CRU,CRU        ; x-axis or y-axis?
       JEQ  LNYAX          ; y-axis
       MOV  R7,R1          ; x-axis, get next x for DOT
       MOV  R6,R0          ; get accumulator contents to y for DOT
       JMP  LNLOOP         ; go to plot
LNYAX  MOV  R7,R0          ; y-axis, get next y for DOT
       MOV  R6,R1          ; get accumulator contents to x for DOT
       JMP  LNLOOP         ; plot the dot (R0 = y, R1 = x) & on to next point
LINEX  LWPI MAINWS         ; RESTORE MAIN WS
       B    @RTNEXT        ; back to bank 0 and the inner interpreter
;]

 

...lee

  • Like 3
Link to comment
Share on other sites

Great information, everyone!  It sounds like there are a few approaches, but the floating-point VDP usage is largely unavoidable.  Worst case, I can snapshot the bytes in that area before the operation and then restore previous values after the operation.  It just seemed kind of silly to have to resort to that if there were alternatives.  Thanks for all your help!

Link to comment
Share on other sites

Of course, there's always writing your own to use whatever memory you prefer.

The code in the TI ROM was written to be space-efficient and to not rely on having much CPU memory, so you could likely improve the speed as well. :)

 

 

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...