Jump to content
IGNORED

Tips for mixing assembly with XB


retrodroid

Recommended Posts

I've started to develop a prototype for a platform game that I've always wanted to develop on the TI since back in the day in the early 80's when I first cut my programming teeth on TI Extended Basic.

 

For "reasons" I want to avoid the use of automated sprite motion for this game and move each of up to 8 sprites at a time pixel-by-pixel during each game loop. So far I've got most of the art/character definitions done and have a few simple character movement tests developed, using compiled XB256.

 

At first I was thrilled when my simple 2-sprite movement code resulted in something approaching 500fps when running compiled.  However, things got real fast once I added more logic to find and track the surrounding chars necessary to provide the desired movement behaviour for the characters (am I standing on a floor, or mid-air, is there a wall next to me or not, etc.).  This was really just a couple of gchar calls.  Once I had this code in place and added a couple more sprites it became very clear that even compiled XB wasn't going to provide the performance I need to implement the game this way. I also tried to optimize my sprite placement and gchar calls with XB256 equivs  but that actually slowed things down even more due to the additional string and char processing it required.

 

In recognition of this reality, I'm now wanting to implement the main game loop in assembly language and call out to it from the compiled XB program. I have limited experience with assembly, having coded a few demos back in the day after I acquired a Mini Memory cartridge.  I was able to achieve some neat effects, such as an Atari-style rainbow band at the top of the screen, or replicating the Parsec ship explosion but only using one sprite, which was rapidly moved to different locations.  :)

 

Anyway, I was wondering if anyone could provide advice on the way to proceed with this approach?  I assume the TI Editor/Assembler should be used to develop the main game loop function?  Any tips or tricks in terms of what my development cycle will look like with the hybrid approach?  Any existing games with source code available that could act as references to how it is done, etc.?

 

 

Link to comment
Share on other sites

2 hours ago, retrodroid said:

 Any existing games with source code available that could act as references to how it is done, etc.?

There may be easier or better ways today, but I used SYSTEX in the past.   Barry Travers had a program in his Genial TRAVler series titled XXB that I think did much the same.  Both are readily available on WHTECH and possibly within this forum.

Link to comment
Share on other sites

As far as approaching XB from EA:

 

Read the manual section on calling from XB environment. 

 

Start with some subroutines to demonstrate something. 

Don't assemble with C compressed. Cant use REF. The XB has some utility routines at absolute addresses instead. So make your code one big object file in place of REFs within your own stuff. 

The character table--like basic--XB also has a bias of >60. So to define char 96, go to where char 192 is defined; use 192 as the pattern number in a sprite. Turn off auto sprite motion if you're not going to use it, then your AL can use patterns 144-159 like BASIC allowed. 159 is the upper uppermost limit because 159+96=255.

 



 

Test Small things (like sprite stuff) then proceed...


 

You can use AORG >2500 or plain old RORG. I used AORG so I would know where to PEEK values. 
 

Learning to fetch arguments from XB is another chore. 

  • Like 2
Link to comment
Share on other sites

Yes, the utilities STRASG, STRREF, NUMASG and NUMREF are handy to know about. The latter two together with CIF and CFI.

 

But the whole idea of running a realtime game loop in Extended BASIC is flawed from start. Not just because Extended BASIC isn't any racing device, but also because it's unpredictable. Now and then execution stops to do a garbage collection. Compiling the whole thing will speed up things, but not change the fundamental principle.

A combination of Extended BASIC and assembly is typically beneficiary if you let the assembly do things that are impossible in BASIC (like memory image file handling) or things that take too long time (sorting or stuff like that), but then let BASIC handle things like user data input and output. BASIC is fast enough to allow you to enter data and prints on the screen faster than you can read it anyway.

 

But a cyclic loop where you need real-time performance - there's not really and room for BASIC in that equation.

  • Like 1
Link to comment
Share on other sites

22 hours ago, retrodroid said:

For "reasons" I want to avoid the use of automated sprite motion for this game and move each of up to 8 sprites at a time pixel-by-pixel during each game loop. 

If you are doing it that way, ensure that if any "enemy sprites" are on the screen, the Player execution speed stays the same if the enemies disappear/reappear.

I use "timers" and "timer maximums" , in my compiled extended basic, for instance;

 

1 player and 8 enemies on the screen, 
T1=0 :: T1M = 16 (timer and timer maximum)

for the player movement delay, I use T1 and this counts up to 16 before it allows the player to move, then it goes back to nill , to be counted up again on another move. That's all fine until one of the enemies has died and is no longer being calculated/moved.
So we would have to alter T1M accordingly.  For each dead enemy, add value of 1 to T1M.  In the end when all are dead T1M would be at 24 which would be just about ideal for smooth execution without slowdown/speedup.  'Course, auto-motion gets around all this in the movement itself but it's a pain in the testicles to keep track of it and that can end up more code/slower code in the end.

 


 

Edited by Retrospect
  • Like 2
Link to comment
Share on other sites

2 hours ago, Retrospect said:

If you are doing it that way, ensure that if any "enemy sprites" are on the screen, the Player execution speed stays the same if the enemies disappear/reappear.

I use "timers" and "timer maximums" , in my compiled extended basic, for instance;

 

1 player and 8 enemies on the screen, 
T1=0 :: T1M = 16 (timer and timer maximum)

for the player movement delay, I use T1 and this counts up to 16 before it allows the player to move, then it goes back to nill , to be counted up again on another move. That's all fine until one of the enemies has died and is no longer being calculated/moved.
So we would have to alter T1M accordingly.  For each dead enemy, add value of 1 to T1M.  In the end when all are dead T1M would be at 24 which would be just about ideal for smooth execution without slowdown/speedup.  'Course, auto-motion gets around all this in the movement itself but it's a pain in the testicles to keep track of it and that can end up more code/slower code in the end.

 


 

I think I may have made it less painful with my new command in RXB called CALL COLLIDE

          COLLIDE        subprogram                            PAGE  C7
          -------------------------------------------------------------
 
          Format         CALL COLLIDE(#sprite-number,#sprite-number,
                         tolerance,dot-row,dot-column[,...])
 
                         CALL COLLIDE(#sprite-number,dot-row,
                         dot-column,tolerance,dot-row,
                         dot-column[,...])
 
          Description
 
          See EXTENDED BASIC MANUAL PAGE 64 has COINC. The problem is
          XB COINC never tells you the location of a sprite and this 
          absolutely limits the types of way sprites could be used. 
          If sprites CONCide where did this happen? If a sprite hits 
          a location how close did it get?
          COLLIDE tells you exactly where they did collide and the
          location of how close to the hit box you wanted be informed.
          Tolerance could be up to 256 bytes which could always be a 
          collide result or 0 for exactly on pixel of top left corner
          of the sprite. I recommend a setting of 6 for best results.
 
          Programs
 
          Clear screen                  | >100 CALL CLEAR ! SPRITES 
          Set up 3 sprites to be on     | >110 CALL SPRITE(#1,65,2,9,99
          screen                        |  ,20,22,#2,66,2,64,99,X,30,25
                                        |  ,#3,67,2,9,99,-20,-35)    
          COLLIDE scans 3 sprites for   | >120 CALL COLLIDE(#1,#2,8,R1,
          sprite hits on #1,#2,#3       |  C1,#1,#3,8,R2,C2,#2,#3,8,R3,
          sprite                        |  C3)
          Check for non zero?           | >130 IF R1+C1+R2+C2+R3+C3 
          If zero loop forever          |  THEN 140 ELSE 120
          Show hits or non hits         | >140 PRINT "#1";R1;C1;"#2";R2
                                        |  ;C2;"#3";R3;C3
          Zero out variables            | >150 R1,C1,R2,C2,R3,C3=0 
          Loop forever                  | >160 GOTO 120
                                        
          Clear screen                  | >100 CALL CLEAR ! ROW:COLUMN 
          Set up 3 sprites to be on     | >110 CALL SPRITE(#1,65,2,9,99,
          screen                        |  20,22,#2,66,2,64,99,30,25,#3,
                                        |  67,2,9,99,-20,-20)
          COLLIDE for DOT ROW DOT COLUMN| >120 COLLIDE(#1,99,99,8,R1,C1,
          at row 99 and column 99       |  #2,99,99,8,R2,C2,#3,99,99,8,
          for sprites #1,#2,#3 hit?     |  R3,C3)      
          Check for non zero?           | >130 IF R1+C1+R2+C2+R3+C3
          If zero loop forever          |  THEN 140 ELSE 120
          Zero out variables            | >150 R1,C1,R2,C2,R3,C3=0 
          Loop forever                  | >160 GOTO 120

It does all this checking from Assembly but of course as it runs from XB programs it is only 50% Assembly and 50% GPL.

CALL COINC finds a coincidence but not where they collided.

This new command not only finds the COINCIDENCE but exactly where they COLLIDE, thus where you can put that place, they hit each other.

I should do some demos of this being used in games.

Link to comment
Share on other sites

2 hours ago, SteveB said:

Which Assember tool would you recommend for a beginner? 

 

ASM994a, xdt99, xa99 or EA in Classic99?

 

I have used EA, asm994a, and xa99 (in that order). I like asm994a, but it has its quirks and is no longer maintained by its developer. For those reasons, I moved on to xa99—and I am glad I did. The developer, Ralph Benzinger ( @ralphb ) is ever-present with help, fixes, and improvements. There are a handful of others of us here on AtariAge who are using xa99 and can offer assistance along your journey through Assembler.

 

...lee

  • Like 2
Link to comment
Share on other sites

Thanks guys for the sage advice, really appreciated.

 

I should have mentioned that I'm currently developing using classic99 and TICodeEd, and using Magellan to design the screen layouts and character maps. 

Since the scope is increasing to include AL development I will need a new/different dev environment for that. Another twist is that I'm actually running on an Apple Silicon mac, so I'm running classic99_64.exe and TICodeEd.exe via Wine.

 

Ideally, I'd like to be able to use a desktop Mac or Windows editor to code the AL then automagically access the file with the assembler to assemble it, etc.

 

I've found the excellent 

...thread and plan to work my way through it as well.

 

 

 

  • Like 1
Link to comment
Share on other sites

7 hours ago, retrodroid said:

Thanks guys for the sage advice, really appreciated.

 

I should have mentioned that I'm currently developing using classic99 and TICodeEd, and using Magellan to design the screen layouts and character maps. 

Since the scope is increasing to include AL development I will need a new/different dev environment for that. Another twist is that I'm actually running on an Apple Silicon mac, so I'm running classic99_64.exe and TICodeEd.exe via Wine.

 

Ideally, I'd like to be able to use a desktop Mac or Windows editor to code the AL then automagically access the file with the assembler to assemble it, etc.

 

I've found the excellent 

...thread and plan to work my way through it as well.

 

 

 

Seems to me that asm994a assembler is your best bet (it runs fine under Wine). Use your favorite text editor for the AL source code then run it through the assembler. If all your source code is in a FIAD in Classic 99, then your assembled code is immediately available for testing.

I developed Kroll & Prumni under Linux Mint with the same tools you are using, only adding MS VS Code for the editor and asm994a for the assembler. 

  • Like 4
Link to comment
Share on other sites

12 hours ago, Vorticon said:

Seems to me that asm994a assembler is your best bet (it runs fine under Wine). Use your favorite text editor for the AL source code then run it through the assembler. If all your source code is in a FIAD in Classic 99, then your assembled code is immediately available for testing.

I developed Kroll & Prumni under Linux Mint with the same tools you are using, only adding MS VS Code for the editor and asm994a for the assembler. 

Perfect, thanks!

 

I have Asm994a(x64) running under wine64 now. Fortunately, the author had the prescience to publish a 64bit version way back in 2013.  :)

 

Starting to wonder if using XB at all makes sense for my project, might attempt a pure AL version and see how that goes. By the time I code the game loop in AL, setting up the screen map and char definitions seems like it would be pretty basic, probably the easiest part, actually. 

 

But first, I will run a few more speed tests in XB256 using arrays to store the screen map chars in order to avoid the gchar calls.

 

 

Edited by retrodroid
  • Like 2
Link to comment
Share on other sites

5 minutes ago, retrodroid said:

Starting to wonder if using XB at all makes sense for my project, might attempt a pure AL version and see how that goes. By the time I code the game loop in AL, setting up the screen map and char definitions seems like it would be pretty basic, probably the easiest part, actually.

Yes, it would be great to see more games programmed in assembly. But unless you really want a UI when assembling your code, xdt99/xas99 is a much better choice than asm994a, which has many bugs that will never be resolved. For instance, it can only handle a limited number of labels.

  • Like 3
Link to comment
Share on other sites

I also think that once you have written your game loop in assembly, having to hook it up with XB will be more difficult than writing the remaining screens in assembly. That's really the easiest, but for me the most boring, part of a game, which is why I always keep it to a minimum. 

Integrating with XB also means you will be limited in how you use the VDP memory. Maybe you want separate character and sprite pattern tables? Maybe you want to use double buffering of the name table for flicker free updates? Maybe you want to use the memory reserved for the sprite motion table for something else? Maybe you want to use one of the hybrid modes? You can't do any of that if you also want to use XB.

  • Like 1
Link to comment
Share on other sites

2 hours ago, Asmusr said:

I also think that once you have written your game loop in assembly, having to hook it up with XB will be more difficult than writing the remaining screens in assembly. That's really the easiest, but for me the most boring, part of a game, which is why I always keep it to a minimum. 

Integrating with XB also means you will be limited in how you use the VDP memory. Maybe you want separate character and sprite pattern tables? Maybe you want to use double buffering of the name table for flicker free updates? Maybe you want to use the memory reserved for the sprite motion table for something else? Maybe you want to use one of the hybrid modes? You can't do any of that if you also want to use XB.

Hmm the reason for using XB or Basic is in the name BASIC = Beginners All purpose Symbolic Instruction Code

Basic and XB are great for outline of an idea of a game, not the best code for making that game but any BEGINNERS language is not

designed to be great end product.

 

Thus, XB was never designed for what some people use it for.

 

Link to comment
Share on other sites

6 hours ago, Asmusr said:

I also think that once you have written your game loop in assembly, having to hook it up with XB will be more difficult than writing the remaining screens in assembly. That's really the easiest, but for me the most boring, part of a game, which is why I always keep it to a minimum. 

Integrating with XB also means you will be limited in how you use the VDP memory. Maybe you want separate character and sprite pattern tables? Maybe you want to use double buffering of the name table for flicker free updates? Maybe you want to use the memory reserved for the sprite motion table for something else? Maybe you want to use one of the hybrid modes? You can't do any of that if you also want to use XB.

Yes, all of that actually appeals to me as does being "closer to the metal", but it's pretty uncharted territory for me, but hey, I'm doing this for "fun" anyway, not like I have a deadline or anything.  :) 

 

3 hours ago, RXB said:

Hmm the reason for using XB or Basic is in the name BASIC = Beginners All purpose Symbolic Instruction Code

Basic and XB are great for outline of an idea of a game, not the best code for making that game but any BEGINNERS language is not

designed to be great end product.

 

Thus, XB was never designed for what some people use it for.

 

True, but there's enjoyment and challenge to be had out of seeing far you can take it as well.  Most of us were frustrated would-be game developers back in the day trying to make XB do things it was never going to pull off due to the poor performance.  So there's a PTSD type memory there where we'd like to, FINALLY, overcome those remembered limitations and create something amazing, or even just "fun".  For me personally, I'm not really interested in mucking around with the actual H/W, or complex peripherals, etc., I just want to create this game and see what I can do within the limitations of the TMS9900 and the rather "slapdash" architecture of the TI99/4A itself.  

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

11 hours ago, RXB said:

What does that mean? Is that a joke? A crack at my post? 

Of course it's regarding xB and assy. 

Basically, if I'm writing in assy, where I have my invested for learning it, and then go to basic for something. Why wouldn't I just do it all in assy? 

Edited by GDMike
  • Like 1
Link to comment
Share on other sites

On 12/16/2022 at 1:19 PM, Asmusr said:

Yes, it would be great to see more games programmed in assembly. But unless you really want a UI when assembling your code, xdt99/xas99 is a much better choice than asm994a, which has many bugs that will never be resolved. For instance, it can only handle a limited number of labels.

Honestly, at least for the average AL programmer, asm994a works just fine and I have yet to have any issues with it even when working on massive programs like Ultimate Planet with numerous labels and to date over 2000 lines of AL code. Can't beat its ease of use either.  Curious to get more specifics on the bugs you mention as I have yet to encounter one.

Link to comment
Share on other sites

6 minutes ago, Vorticon said:

Honestly, at least for the average AL programmer, asm994a works just fine and I have yet to have any issues with it even when working on massive programs like Ultimate Planet with numerous labels and to date over 2000 lines of AL code. Can't beat its ease of use either.  Curious to get more specifics on the bugs you mention as I have yet to encounter one.

The thing about the labels is the only bug I specifically remember. I think @Lee Stewart moved away from asm994a for the same reason, but maybe he remembers other issues? But another reason for using xdt99 is that it allows you to build your entire project from the command line using a bat/script file. I recognize that the leaning curve is less steep when you have a graphical user interface, but in the long run it's really worthwhile learning the command line interface of xas99. It can be as simple as xas99.py -R my-project.a99, and I combine that with other commands in a bat file to build the entire cartridge bin file or disk image. It's so much faster to run a single bat file than having to repeat the same steps in a graphical user interface over and over.

  • Like 2
Link to comment
Share on other sites

1 hour ago, Vorticon said:

Honestly, at least for the average AL programmer, asm994a works just fine and I have yet to have any issues with it even when working on massive programs like Ultimate Planet with numerous labels and to date over 2000 lines of AL code. Can't beat its ease of use either.  Curious to get more specifics on the bugs you mention as I have yet to encounter one.

 

1 hour ago, Asmusr said:

The thing about the labels is the only bug I specifically remember. I think @Lee Stewart moved away from asm994a for the same reason, but maybe he remembers other issues?

 

I ran into the limitation on the number of labels during fbForth 2.0 development about seven years ago. I was up to 2872 labels when the error occurred. The error did not say there were too many labels, but that there were duplicate labels I know I did not have. Sometimes no error was reported, but things were obviously not working properly, making debugging a daunting task! It forced me to write the floating point library as a separate module. Since then, I found a way to cut out enough labels that would not have required the rewrite. Of course, the beginning ALC programmer is not likely to approach the 20,000+ lines (includes comments) of the fbForth cartridge.

 

I also had to work around a couple of other problems:

  • The DORG directive is not properly handled.
  • The undocumented preprocessor conditionals cause insidious errors without clues as to their cause. I finally realized I could not use labels such as IF, THEN, ELSE, etc., without running afoul of the preprocessor. I needed those labels for clarity, so I just prepended them with ‘_’ to solve that problem.

If you insist on using asm994a, be sure you are running version 3.010, which fixes what I seem to recall was a conditional branching error. That error was serious enough that Cory Burr was convinced to fix it long after he said he was done with supporting asm994a.

 

...lee

Edited by Lee Stewart
more information
  • Like 1
Link to comment
Share on other sites

Yes I was aware of the branching bug but as you said that got fixed a long time ago. None of the issues you mention are likely to be encountered by the vast majority of AL programmers. 

As Rasmus mentioned, there is certainly value in the batch assembly process with xas-99, but again that's an advanced usage. 

On a personal level, I prefer to use the simplest and easiest tool available that does what I need it to do. Time in my more mature age has become increasingly valuable 😁

  • Like 1
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...