senior_falcon Posted February 26, 2021 Author Share Posted February 26, 2021 (edited) On 2/22/2021 at 9:55 AM, senior_falcon said: I have made some progress in adding assembly support to compiled code. So far a compiled program can CALL LINK to an assembly support routine and return to the compiled code. The two test A/L subs are simple; PRINTA fills the screen with "A" and PRINTB fills the middle of the screen with "B" As yet no variables can be passed in either direction with NUMREF, NUMASG, STRREF, STRASG. I have hopes these can be modified so this possible. More progress: I can now NUMREF and NUMASG between a compiled program and assembly support routines. The assembly test program fetches a numeric variable from the compiled program with NUMREF, squares it, and and sends it back to the compiled program with NUMASG. Next up is STRREF which should be easy, then STRASG which will probably take more thought. (Edit) As expected, STRREF was straightforward. Now for STRASG. Edited February 27, 2021 by senior_falcon 7 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted February 27, 2021 Author Share Posted February 27, 2021 (edited) Now NUMREF, NUMASG, STRREF, and STRASG are able to pass values and strings back and forth between a compiled program and assembly language support routines. I was a little surprised when STRASG worked the first time! STRASG only requires 7 lines of code. This is a work in progress and there will be some nuances to work out. Of course, the gold standard is this: will it work with THE MISSING LINK? That has yet to be attempted. (Edit) CSN and CNS still need to be worked out. Edited February 27, 2021 by senior_falcon 5 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 3, 2021 Author Share Posted March 3, 2021 (edited) I am super excited. I just ran a compiled version of T40DEMO which (almost) worked fine. It bypassed certain parts of the demo.I suspect that is because when I pressed "enter" it bypassed some of the steps before I got my finger off the key. (EDIT- I take it back. It did not bypass anything.) The beauty of this approach is that it should be able to work with any assembly subs you want to use Edited March 3, 2021 by senior_falcon 6 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 5, 2021 Author Share Posted March 5, 2021 I have worked out a few minor issues that arise when running T40XB with the compiler. Now the T40DEMO program works perfectly... Except that it is too fast now. When there are two CALL LINK("INPUT"...) statements in a row, it is hard to get off the enter key fast enough to avoid entering a null value for the second one. I will modify INPUT so that it will not start until no key is pressed. I will also add a DELAY to make it easier to port from XB to compiled XB. Using FOR/NEXT loops gives drastically different delays. 8 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 5, 2021 Author Share Posted March 5, 2021 (edited) Here is a little teaser for you. The two animated GIFs below show the LINES program from TMLDEMO. One of them is running in Extended BASIC and the other is compiled. Can you figure out which is which? (Remember that you won't get a 20x increase in speed by compiling TML. It already spends much of its time doing the graphics routines which are already in assembly. But any code in XB is MUCH faster.) Edited March 5, 2021 by senior_falcon 11 Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted March 5, 2021 Share Posted March 5, 2021 2 hours ago, senior_falcon said: 1st=TML 2nd=compiled 1 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 5, 2021 Author Share Posted March 5, 2021 Yep. The code to draw the line is exactly the same, but the XB code to determine where to draw the line and the color is compiled, so the end result looks like it is about 3x faster. 2 2 Quote Link to comment Share on other sites More sharing options...
Tursi Posted March 6, 2021 Share Posted March 6, 2021 6 hours ago, senior_falcon said: Here is a little teaser for you. The two animated GIFs below show the LINES program from TMLDEMO. One of them is running in Extended BASIC and the other is compiled. Can you figure out which is which? (Remember that you won't get a 20x increase in speed by compiling TML. It already spends much of its time doing the graphics routines which are already in assembly. But any code in XB is MUCH faster.) Might be time to compile TMNT 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 6, 2021 Share Posted March 6, 2021 44 minutes ago, Tursi said: Might be time to compile TMNT How much bigger is compiled BASIC than byte coded BASIC? Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 6, 2021 Author Share Posted March 6, 2021 3 hours ago, TheBF said: How much bigger is compiled BASIC than byte coded BASIC? The compiled code is usually around 2/3 the size of the source XB program. In addition to that there is about 6K or more of runtime routines, depending on how complex your program is. So a 10 byte program will be around 6K long. A 9K program will be about 12K long and an 18K program will be about 18K long when compiled. This will vary depending on your programming style and how it happens to compile. If the compiled program turns out to be too big, there is the option of putting the runtime routines in low memory. But this only applies to straight XB. If you are using assembly support subroutines like The Missing Link, then this is not possible. 1 Quote Link to comment Share on other sites More sharing options...
Airshack Posted March 6, 2021 Share Posted March 6, 2021 10 hours ago, senior_falcon said: So a 10 byte program will be around 6K long. A 9K program will be about 12K long and an 18K program will be about 18K long when compiled. @senior_falcon Don't forget to mention that a program in excess of 24K will compile down to 24K, so it'll run on the system's upper-expansion memory even though it's larger than 24K, which is especially handy. 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 6, 2021 Share Posted March 6, 2021 10 hours ago, senior_falcon said: The compiled code is usually around 2/3 the size of the source XB program. In addition to that there is about 6K or more of runtime routines, depending on how complex your program is. So a 10 byte program will be around 6K long. A 9K program will be about 12K long and an 18K program will be about 18K long when compiled. This will vary depending on your programming style and how it happens to compile. If the compiled program turns out to be too big, there is the option of putting the runtime routines in low memory. But this only applies to straight XB. If you are using assembly support subroutines like The Missing Link, then this is not possible. Wow that's is amazing. Is the extra 1/3 in the BASIC program mostly the labels and comments that come along for the ride or is the byte code implementation not very efficient? I have noticed this in my Forth compilers. The logic for building interpreters in the old days was to sacrifice speed for reduced code size. But the 9900 has so many higher level functions that you don't get this advantage until you make some significantly complex functions in your program and then re-use them a great deal. At the low level functions the 9900 is almost (not quite) 1:1 with the Forth VM. 1 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 12, 2021 Author Share Posted March 12, 2021 (edited) Making slow but steady progress. Here is a compiled version of the TML tutorial program POTATOHEAD. I hope to be able to make some adjustments to The Missing Link for a little more speed on the assembly side. The main thing now is to modify the loader so you can save in XB and EA5 format. Disc access is possible in the assembly support routines. I can use the disk catalog in T40XB within a compiled program. Edited March 12, 2021 by senior_falcon 9 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 13, 2021 Share Posted March 13, 2021 I was just reading the manual for the BASIC compiler for the first time and I saw this: "The compiler generates "threaded code" which needs its own interpreter (the runtime routines)... This of course got my attention. I kind of have a "Threaded code R Us" mentality. Is there any place where I could learn more about this? Is it a register based VM? Is it a byte coded VM? And many more... Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 14, 2021 Author Share Posted March 14, 2021 (edited) Below is a simple XB program. 100 CALL CLEAR 110 A$="Hello World!" 120 FOR I=1 TO LEN(A$) 130 CALL HCHAR(10,I,ASC(SEG$(A$,I,1))) 140 NEXT I 150 GOTO 150 Compiling this program produces the code below DEF RUNEA,RUN,RUNV,CON RUNEA B @RUNEA5 FRSTLN L100 DATA CLEAR L110 DATA LET,SV1,SC1 L120 DATA LEN,SV1,NT1 FOR1 DATA FOR,NV1,NC1,NT1,ONE,0,0 L130 DATA SEGS,SV1,NV1,NC1,ST1 DATA ASC,ST1,NT1 DATA HCHAR,NC2,NV1,NT1 L140 DATA NEXT,FOR1+2 L150 DATA GOTO,L150 LASTLN DATA STOP OPTBAS DATA 0 NC0 ZERO DATA 0 ONE DATA 1 PI DATA 3 RND DATA 0 NC1 DATA 1 NC2 DATA 10 NV0 NV1 DATA 0 I NT1 DATA 0 SC0 SC1 DATA SC1+2 BYTE 12,72,101,108,108,111,32,87,111,114 BYTE 108,100,33 EVEN SV0 SV1 DATA 0 A$ ST1 DATA 0 SA0 NA0 FRSTDT LASTDT EVEN ENDCC COPY "DSK1.RUNTIME1.TXT" COPY "DSK1.RUNTIME2.TXT" COPY "DSK1.RUNTIME3.TXT" END The heart of the runtime routines is the code below. When the program starts up, R13 points to FRSTLN. At L100 the address of CLEAR is read and put into R12, then B *R12 goes to CLEAR. Since CLEAR uses no input, the screen is cleared, then B @RTN is performed. Now it goes to LET which knows to look for two addresses. In this case it gets SC1 (Hello World!) and plugs that into SV1 (A$) And so on... You can see there are two parts of a compiled program. The compiled code is nothing but labels. There are no assembly instructions. Then the runtime routines have to be able to use those labels to mimic what XB does. RTN LIMI 2 the main loop, all subs come back to here LIMI 0 MOV *R13+,R12 B *R12 r12 has code. i.e. GOTO, SPRITE, etc. Edited March 14, 2021 by senior_falcon 3 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 14, 2021 Share Posted March 14, 2021 13 hours ago, senior_falcon said: Below is a simple XB program. 100 CALL CLEAR 110 A$="Hello World!" 120 FOR I=1 TO LEN(A$) 130 CALL HCHAR(10,I,ASC(SEG$(A$,I,1))) 140 NEXT I 150 GOTO 150 Compiling this program produces the code below DEF RUNEA,RUN,RUNV,CON RUNEA B @RUNEA5 FRSTLN L100 DATA CLEAR L110 DATA LET,SV1,SC1 L120 DATA LEN,SV1,NT1 FOR1 DATA FOR,NV1,NC1,NT1,ONE,0,0 L130 DATA SEGS,SV1,NV1,NC1,ST1 DATA ASC,ST1,NT1 DATA HCHAR,NC2,NV1,NT1 L140 DATA NEXT,FOR1+2 L150 DATA GOTO,L150 LASTLN DATA STOP OPTBAS DATA 0 NC0 ZERO DATA 0 ONE DATA 1 PI DATA 3 RND DATA 0 NC1 DATA 1 NC2 DATA 10 NV0 NV1 DATA 0 I NT1 DATA 0 SC0 SC1 DATA SC1+2 BYTE 12,72,101,108,108,111,32,87,111,114 BYTE 108,100,33 EVEN SV0 SV1 DATA 0 A$ ST1 DATA 0 SA0 NA0 FRSTDT LASTDT EVEN ENDCC COPY "DSK1.RUNTIME1.TXT" COPY "DSK1.RUNTIME2.TXT" COPY "DSK1.RUNTIME3.TXT" END The heart of the runtime routines is the code below. When the program starts up, R13 points to FRSTLN. At L100 the address of CLEAR is read and put into R12, then B *R12 goes to CLEAR. Since CLEAR uses no input, the screen is cleared, then B @RTN is performed. Now it goes to LET which knows to look for two addresses. In this case it gets SC1 (Hello World!) and plugs that into SV1 (A$) And so on... You can see there are two parts of a compiled program. The compiled code is nothing but labels. There are no assembly instructions. Then the runtime routines have to be able to use those labels to mimic what XB does. RTN LIMI 2 the main loop, all subs come back to here LIMI 0 MOV *R13+,R12 B *R12 r12 has code. i.e. GOTO, SPRITE, etc. Well that looks pretty familiar! The RTN routine is the inner interpreter of direct threaded Forth traditionally called NEXT. Here's mine in RPN Assembler. Registers are renamed. IP is R9 W (working register) is R8 l: _next *IP+ W MOV, *W B, And so if I get this it is a token threaded system where each BASIC keyword is assigned a integer value with address threading (labels) for the user's code. Clever combination. Forth systems like Open Firmware (Sparc, Power Mac) uses a token coded system. I think it uses bytes to save space for the primary keywords with multiple tables. I really appreciate the explanation. Thank you. 3 Quote Link to comment Share on other sites More sharing options...
SteveB Posted March 27, 2021 Share Posted March 27, 2021 Hi, I stumbled across an issue with Isabella 7. I develop a game using XB256 and it progresses well. Most testing is done in Classic99 with CPU Overdrive, but I compile once in a while. Suddenly last night my program went bezerk. Still working fine when interpreted, but showing strange behaviour after being compiled. The lines 180 RC=0 :: CALL JOYST(1,X,Y) :: CALL KEY(1,K,S) :: X1=X1+X/4 :: CALL POSITION(#10,Q1,W1) 190 CALL LOCATE(#11,Q1,W1-16) 200 IF W1<32 THEN X1=MAX(X1,0) ELSE IF W1>210 THEN X1=MIN(X1,0) should obviously attach sprite #11 on the left side of #10 and do so in XP. After compiling, it is about 4 chars to the left. Furthermore the joystick is only working sideways, no up or down. I assume something in the (xb256?) runtime does not work anymore. The program has 150 lines, the compiler produces a 33k Text-file and the OBJ has 51kb. Did I hit a size limit I am not aware of? The linker tells me "Runtime in high memory, 10216 bytes remaining". It is not my largest program, but the first using XB256. Any help is appreciated! Steve Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 27, 2021 Author Share Posted March 27, 2021 (edited) Here is a short program I wrote to test the joystick and sprite placement problems you report: 30 CALL CHAR(65,RPT$("F",32)) 40 CALL MAGNIFY(2) 50 CALL SPRITE(#10,65,16,100,116,#11,66,14,100,100) 110 CALL POSITION(#10,R,C) 120 CALL JOYST(1,X,Y) 130 C=C+X/4 :: R=R-Y/4 140 CALL LOCATE(#10,R,C,#11,R,C-16) 145 CALL LINK("DELAY",100) 150 GOTO 110 This uses the joystick to move the 2 sprites around. They move the same in XB256 and when compiled. This shows the sprite placement and joystick response works as expected. Try this in XB256 to see how it works, then compile and see if it works the same. I will check to see if your line 200 might behave differently. Getting IF/THEN/ELSE to work like XB was a challenge and maybe there is an error in that code. Edited March 27, 2021 by senior_falcon 2 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 27, 2021 Author Share Posted March 27, 2021 i just ran this program to test your line 200 and it too works the same in XB or when compiled 190 FOR W1=30 TO 230 STEP 100 191 FOR X=-5 TO 5 STEP 5 192 X1=X 195 PRINT "W1 X1=";W1;X1; 200 IF W1<32 THEN X1=MAX(X1,0)ELSE IF W1>210 THEN X1=MIN(X1,0) 205 PRINT "NEW X1=";X1 210 NEXT X :: NEXT W1 So everything in your post above seems to work properly for me. Quote Link to comment Share on other sites More sharing options...
+wolhess Posted March 27, 2021 Share Posted March 27, 2021 5 hours ago, SteveB said: Hi, I stumbled across an issue with Isabella 7. I develop a game using XB256 and it progresses well. Most testing is done in Classic99 with CPU Overdrive, but I compile once in a while. Suddenly last night my program went bezerk. Still working fine when interpreted, but showing strange behaviour after being compiled. The lines 180 RC=0 :: CALL JOYST(1,X,Y) :: CALL KEY(1,K,S) :: X1=X1+X/4 :: CALL POSITION(#10,Q1,W1) 190 CALL LOCATE(#11,Q1,W1-16) 200 IF W1<32 THEN X1=MAX(X1,0) ELSE IF W1>210 THEN X1=MIN(X1,0) should obviously attach sprite #11 on the left side of #10 and do so in XP. After compiling, it is about 4 chars to the left. Furthermore the joystick is only working sideways, no up or down. I assume something in the (xb256?) runtime does not work anymore. The program has 150 lines, the compiler produces a 33k Text-file and the OBJ has 51kb. Did I hit a size limit I am not aware of? The linker tells me "Runtime in high memory, 10216 bytes remaining". It is not my largest program, but the first using XB256. Any help is appreciated! Steve Hi, i had a similar problem in my Mega Menu program development. The issue in my program was the array in line 200. I changed it to assign the value of max(x1,0) to a new variable and used the new variable in the statement e.g. 195 xn=max(x1,0) 200 if w1<32 then x1=xn this solved my problem 1 Quote Link to comment Share on other sites More sharing options...
1980gamer Posted March 28, 2021 Share Posted March 28, 2021 I have had some odd behavior also with data statements. Where the values become negative. I use Magellan to create a lot of screens and it uses read/data for char and x,y pos. From time to time memory must get a little corrupted because I will get and error on the read. and it will have the x,y or char value as a negative value! I have not said anything for 2 reasons. First, I assume I am doing something somewhere that is causing the problem. VERY LIKELY! Second I just toss in a ABS on the value that is failing and it works! Though it is very strange! something like CALL HCHAR(X,Y,ABS(CHR)) On initial load of the program and run, it works fine. But as I play test and make a changes, the consecutive executions show this behavior. I do a load of strange things as I cobble together an attempt at a game. So, I am certain I am doing something! I do use arrays often. I try to keep them under (10,10) AH.. I may have just solved it. I keep them under 10,10 so I can skip something... drawing a blank! When I am less tired, I will remember. But I am sure it is initialization related. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 28, 2021 Share Posted March 28, 2021 On 3/13/2021 at 8:12 PM, senior_falcon said: RTN LIMI 2 the main loop, all subs come back to here LIMI 0 MOV *R13+,R12 B *R12 r12 has code. i.e. GOTO, SPRITE, etc. It goes without saying that the BASIC compiler has opened up a world of possibilities for BASIC programmers on the TI-99. How many years did we all toil to get some speed out of our favourite machine. It was so painful to me it forced me to learn Forth. Now that I understand that this BASIC compiler is running direct threaded code I have some thoughts that might improve performance by as much as 20%. I was surprised some years back when we compared a sieve benchmark between compiled BASIC and my indirect-threaded Forth. The Forth program ran quicker. That didn't make sense to me at the time because I believed the BASIC compiler was generating native code. I now suspect that one of the reasons was because the RTN code above has four instructions whereas mine as an indirect threaded system has three instructions. The RTN routine above is consuming a large percentage of the runtime in threaded systems. It could approach 50% of the instructions being run for simple keywords! In an equivalent Forth system every attempt is made to make this code as fast as possible. The addition of LIMI 2 and LIMI 0 at 32 cycles essentially doubles the time taken by RTN. The performance hit is not because the interrupts are running. They only run every 16mS. Putting the interrupt polling in RTN is the simplest way to let the interrupts run but it is the worst thing to do for overall performance. My experience with cooperative multi-tasking may provide an alternative. If a routine called YIELD was created: YIELD LIMI 2 LIMI 0 RTN This routine is placed in strategic places in the system code: At the beginning or end of every BASIC keyword that has internal loops. (VCHAR,HCHAR) At the beginning of a FOR/NEXT block At beginning of ALL I/O routines That should give interrupts enough time to run in the course of any code although more tuning of the placement might be required. Needless to say RTN should run in PAD RAM. I suspect it already does. Something to put on the development stack perhaps, although I am sure there is no shortage of things that have higher priority. 1 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 28, 2021 Author Share Posted March 28, 2021 (edited) 11 hours ago, 1980gamer said: I have had some odd behavior also with data statements. Where the values become negative. I use Magellan to create a lot of screens and it uses read/data for char and x,y pos. From time to time memory must get a little corrupted because I will get and error on the read. and it will have the x,y or char value as a negative value! I have not said anything for 2 reasons. First, I assume I am doing something somewhere that is causing the problem. VERY LIKELY! Second I just toss in a ABS on the value that is failing and it works! Though it is very strange! something like CALL HCHAR(X,Y,ABS(CHR)) On initial load of the program and run, it works fine. But as I play test and make a changes, the consecutive executions show this behavior. I do a load of strange things as I cobble together an attempt at a game. So, I am certain I am doing something! I do use arrays often. I try to keep them under (10,10) AH.. I may have just solved it. I keep them under 10,10 so I can skip something... drawing a blank! When I am less tired, I will remember. But I am sure it is initialization related. The only reason I can think of for odd behavior that takes a while to develop would be an error in the garbage collection for strings. But that doesn't seem likely because the program code would get corrupted before any variables. If I understand you right, you are reading a number from a data statement that is positive in the data statement, and it reads the proper number except it is now negative? I keep them under 10,10 so I can skip something... drawing a blank! By doing this you do not have to DIM the array. The drawback is that a lot of memory can be used needlessly. A 10x10 array is 800 bytes in XB (actually 968 with option base 0). Divide that by 4 for compiled code. So you can see that if you need a 5x5 array, then the few bytes spend on DIM will save quite a bit of memory in the long run. Edited March 28, 2021 by senior_falcon Quote Link to comment Share on other sites More sharing options...
1980gamer Posted March 28, 2021 Share Posted March 28, 2021 "If I understand you right, you are reading a number from a data statement that is positive in the data statement, and it reads the proper number except it is now negative?" Yes, exactly. Yes, DIM. Not that I was considering space (memory) I just might do this for less variable effort! x(y) vs. X1 and X2 ... being lazy. Or as I argue when I am called out... Working smarter not harder! LOL 10 for y=0 to 9 20 x(y)= some random number between 1 and 9 or something. 30 next y can't imagine doing 10 lines of X1=INT(RND... ) X2=INT... plus I might add a line like: 25 if y>0 and x(y)=x(y-1) then 20 so I don't get 2 consecutive variable with the same value or some other crazy thing that pops into my head! If this was for 28 sprites I would DIM it. I just never bothered using the DIM if I needed less than 10. My thinking LATE last night, was by not using DIM, I might have been messing with the compiler. Not giving it what it needs to parse properly. But I am getting this problem before I have compiled. Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted March 28, 2021 Author Share Posted March 28, 2021 (edited) 2 hours ago, 1980gamer said: But I am getting this problem before I have compiled. I'm confused. Is the XB program reading the number negative instead of positive? Or does this only happen in a compiled program? I should add that it takes longer to retrieve a number that is in an array. If you use a lot of arrays then by using simple constants and variables you would probably notice an improvement in speed. Edited March 28, 2021 by senior_falcon 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.