theincrediblepeep Posted May 15, 2021 Share Posted May 15, 2021 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? LISS1 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted May 15, 2021 Share Posted May 15, 2021 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? 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! 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 15, 2021 Share Posted May 15, 2021 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 3 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 16, 2021 Share Posted May 16, 2021 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 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 16, 2021 Share Posted May 16, 2021 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 9 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 16, 2021 Share Posted May 16, 2021 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. (?) 2 2 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted May 16, 2021 Share Posted May 16, 2021 (edited) 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 May 16, 2021 by senior_falcon 2 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 16, 2021 Share Posted May 16, 2021 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 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 16, 2021 Share Posted May 16, 2021 I will post a Forth alternative to Bresenham on the Camel99 Topic for you. Not as fast but interesting... 1 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted May 16, 2021 Share Posted May 16, 2021 3 hours ago, senior_falcon said: A clever programmer could probably use a sprite to hide it. A very clever quick and dirty fix. 1 Quote Link to comment Share on other sites More sharing options...
theincrediblepeep Posted May 16, 2021 Author Share Posted May 16, 2021 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! Quote Link to comment Share on other sites More sharing options...
Tursi Posted May 17, 2021 Share Posted May 17, 2021 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. 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.