Jump to content
IGNORED

Question about calling basic from assembly


Recommended Posts

OK, probably an obtuse question here, but let me set it up this way.  I understand calling assembly language from Basic.

 

But, I kind of have in mind I'd like to do the opposite, I'd like to, from assembly launch into basic.

 

This is to implement a callback, essentially.  In other words, if I have a pmg library that can animate a sprite, I also want to callback on collision detection.  Via a VBI routine...take wherever basic may have been and force it back to either a specific line number, or even back to the start of the code.

 

I write these questions because I assume an Atari guru has pretty much tried everything before...so what about it?  The problem with googling the answer, is every google on calling basic from assembly returns a thousand results on calling assembly from basic, which was a common thing, with many tutorials.

Link to comment
Share on other sites

I don't think this is possible as BASIC is tokenised and not compiled down to assembler.

 

The only thing you may be able to do is return to a different part of the BASIC program

as the return address from the USR call is on the stack, how you find the

entry points into the BASIC program may be pretty hard/if not impossible to determine.

 

May be possible with BASIC XE when using the FAST keyword, the documentation says

it pre-compiles the lines of code into addresses, so if you could locate that table and access it,

again probably a big headache to work out what address relates to what line.

 

Link to comment
Share on other sites

3 hours ago, Meadow Glen said:

This is to implement a callback, essentially.  In other words, if I have a pmg library that can animate a sprite, I also want to callback on collision detection.  Via a VBI routine...take wherever basic may have been and force it back to either a specific line number, or even back to the start of the code.

From within an interrupt, you cannot do that in a reliable way. There is of course a Zpage location that points to the current line, and which you could modify in principle, but since there is no interrupt protection within the interpreter, you cannot exclude that the interpreter is in ts in the middle of using the pointer (or parts of the pointer) while the interrupt is running. Thus, the pointer value is not reliable within the interrupt, nor can you modify it reliably. There is neither a fixed location in the Basic ROM where you could start execution as there are multiple versions of the ROM in the field.

 

What you can do is, however, set a variable to a value. Not fully reliable in the sense that a variable could be modified midway while BASIC is reading a value.

Link to comment
Share on other sites

I don't think it'd work.

In a VBI, you've interrupted the Basic flow at any given time - maybe even while it has half updated a current pointer.

 

You could have a flag and periodically check it, then take action.

Possibly you could use TRAP then somehow force an error condition.  If the program did a lot of IO then a custom device handler could insert an error on demand.

But really, a periodical check is fine.  It's understandable that Basic is too slow to do lots of PM collision detection.

Really the best method IMO is for the assembly part to process the collision stuff then combine the results into a flag and let the Basic program check it and deal with it at the end of the main loop.

Link to comment
Share on other sites

In my opinion, it is not possible to do this on interrupts. 

 

calling BASIC from machine language asking for number of stars and retrieving the result:

 

 

 

LDY #<SCRIPT

LDX #>SCRIPT

JSR xBIOS_RUN_SCRIPT

...

 

SCRIPT .BY '10 GR.0:? "How many stars": INPUT A: POKE 1536, A'

 

 

 

 

Link to comment
Share on other sites

GOTO var as thorfdbg suggests is probably the safest, reasonably low cost way of implementing a deferred callback into BASIC. Race conditions shouldn't be a problem if only one byte of the variable is changed. However, it may get in the way of compiling your BASIC program as the compiler may not preserve the variable table structure of the interpreter.

 

There is an interrupt flag that BASIC already regularly checks, which is the Break interrupt. However, you can't TRAP this on Atari BASIC. Turbo-Basic XL can with *B.

 

Link to comment
Share on other sites

there is a two-byte cell in memory (bytes 566 and 567) that stores the location of a small subroutine the computer jumps to and runs whenever the [BREAK] key is pressed.

 do a PEEK at memory locations 566 and 567.

If you have Microsoft BASIC or OSS BASIC XL/XE you can  DPEEK(566) and get the answer. Otherwise you will need to PRINT PEEK(566) + 256 * PEEK(567).

An Atari 800 you should get a vector handler location of 59220. 800XL or 130XE you should get a location of 49298. Although the routines are in different places they are exactly the same.

It is in machine language,

Here is the source code:

LDA #0

STA $11

STA $02FF

STA $02F0

STA $4D

PLA

RTI

Just exactly what does the subroutine do?

It loads a zero into the Accumulator, It stores that value into four memory locations. The first location (BRKKEY, memory location $11) is a flag to indicate if the [BREAK] key has been pressed. The second (SSFLAG, location $02FF) is a flag to start scrolling on the screen. The third (CRSINH, location $02F0) is a flag to enable the cursor.

Fourth is a flag (ATRACT, location $4D) to reset or start the attract mode.

Finally the routine returns control to your BASIC program.

the last two instructions in the vector interrupt handler will, if called, simply return control back to the main calling program, in effect disabling the [BREAK] key! To do this, insert a POKE 566, PEEK(5 66) +12 instruction at the beginning of your BASIC program and you'll disable the [BREAK] key

This way easier than POKEing two memory locations after every print statement.

-=-=-=-=-=

If you want the graphics screen to go into attract mode every time someone presses the [BREAK] key you can add one line to the assembler program shown earlier, store this new version of the break interrupt handler below in a safe part of memory, say Page 6, and then POKE this new handler location into the 16 bit interrupt vector, at locations 566 and 567.

The listing which follows is a BASIC subroutine that you can use in your own programs to alter the break interrupt handler. To use it make sure that the first line of your main program does a GOSUB 31000.

Whenever the [BREAK] key is pressed while your program is running, the screen will go into attract mode and the program will continue running. To alter this program so that the [BREAK] key is ignored but the screen does not go into the attract mode, simply change the number POKEd into 567 from 0 to 4.

31000 REM break key handler

31020 POKE 1536,169:POKE 1537,128

31030 POKE 1538,133:POKE 1539,77

31040 POKE 1540,104:POKE 1541,64

31050 POKE 567,INT(l536/256)

31060 POKE 566,1536-PEEK(567)*256

31070 RETURN

some more magazine mayhem...

[BREAK] KEY TRAP

Sometimes you prefer your program to detect the [BREAK] key when it is pressed, instead of simply disabling [BREAK] entirely. The following short program is an example of how to do it.

10 FOR A=0 TO 6: READ B:POKE 256+A,B:NEXT A
20 POKE 566,0:POKE 567,1
30 DATA 169,1,141,7,1,104,64
40 POKE 263,0
50 IF PEEK(263)=0 THEN 50
60 ? "BREAK WAS PRESSED": GOTO 40

Edited by _The Doctor__
Link to comment
Share on other sites

Hmmm....

 

Phaeron just gave me an idea that might work though it's a bit kludgematic.

Use the old trick where you set E: to force accept input - POKE 842,13 ?

 

When you want program attention, the assembler sets the BREAK flag (store 0 in 17)

Have your text window set to cater for the "STOPPED AT LINE ... / READY" message and have a printed "GOTO nnn" printed which then gets executed.

That should work.   You can have a fullscreen mode with the memory still allocated for the text window and with some trickery it all works.   Graphics modes reserve the text window area even if not used.   Just a few things need to be set so you have the right config.

 

But the problem I foresee - you interrupt your game loop at some point then probably want to re-enter once the collision processing is done.

There's potential for a breakdown of processing - especially since Basic checks for Break at the end of each statement, not just between lines.  You could just put one statement per line (which will mean slow running) then  you could just determine where the STOP occurred then add 10 and GOTO there once finished (ensuring your game loop has increments of line numbers to suit)

Edited by Rybags
Link to comment
Share on other sites

10 hours ago, Rybags said:

Phaeron just gave me an idea that might work though it's a bit kludgematic.

Use the old trick where you set E: to force accept input - POKE 842,13 ?

 

When you want program attention, the assembler sets the BREAK flag (store 0 in 17)

Have your text window set to cater for the "STOPPED AT LINE ... / READY" message and have a printed "GOTO nnn" printed which then gets executed.

Potentially, though there are a couple of "problems" left. What you could do instead of writing something on the screen is to change the editor vector entry in HATABS and let BASIC fetch some command there. You can make BASIC fetch a command by triggering the BREAK key, as suggested.

 

There are a couple of problems with this approach: Problem #1 is that you cannot change the E: HATABS entry atomically as CIO may just use it. One can potentially avoid this problem by checking the return PC on the interrupt stack, and simply avoiding the patch if the return PC is witin the Os. Unfortunately, while this prevents the problem it also prevents the mechanism that should be implemented in first place. One could delay the patch creation to the next VBI then.

 

Second problem: Interruption through a (simulated) break key cannot be necessarily continued with CONT, as the Basic interpreter only stores the line number, but not the offset within the line. Thus, it would also a particular coding style of the source.

 

Link to comment
Share on other sites

My thought on the whole matter is it's probably unnecessary, would be annoying to debug or modify.  Best to use traditional methods.

You can have smooth gameplay by basing much of the game on regular interrupts.

For information passing the logical method is to use flags then just have the gameplay pause while necessary Basic processing takes place.

After all it's a Basic game in it's roots and you don't expect 100% smoothness.

Link to comment
Share on other sites

15 hours ago, danwinslow said:

The thing to do here is to pitch basic and write the whole thing in assembler :) . It's actually not that much harder, it's just more tedious.

Can't say I agree with that, I've used many programming languages over the course of my career, BASIC

has always been there, it's great to prototype ideas, it's always quicker to develop and if speed

is not an issue then it's as good as any other language,

 

Married with USR calls it can be as good as any pure machine code program.

 

Don't get me wrong, I've written many utilities in pure assembler, usually the main reason is memory

availability/flexibility, losing at least 8K of memory to BASIC is way too much for some applications and

being able to choose what memory areas you use is obviously where assembler wins.

Link to comment
Share on other sites

Well, I do write my games in assembler- I've got various games that are 30 to 90% complete and seemingly never finish anything, but I do have a clone of space war - a rather simple game, done.  Plays.  Well nobody actually wins, just runs forever.

 

 the reason for desiring this is about an article idea.

 

So, basically, it goes back to, the TI-99, and the release of the Extended Basic cartridge.

 

A lot of us were excited by the prospect of Extended Basic, on that platform it enabled sprites, which you could define and set in motion.  With machine language routines handling the animation of sprites, it would've enabled games in basic, that otherwise were impossible.  The issue was, by the time you got to checking for collision detection the sprites would have flowed through each other.  It just didn't work for much.

 

What was always missing was the callback.  Machine language detection of sprite collision, forcing a goto on collision, logic.  Of course it wasn't implemented on the TI - probably would've been impossible.

 

I appreciate all your help.  Lot's of things i need to look at now.  It may not be possible, but early authors hinted it was....based on google searching I found "The Atari Wedge: Adding Commands To Atari BASIC"


The author added some commands to basic- a hack, of course, and then ended with this "In future issues, we'll go into how you can tell BASIC what to do from machine language. We'll even try to pursue that elusive aim – actually adding commands to a running program."

 

Probably didn't ever actually do that, at least I couldn't find it.  

 

It seems it'd be quite the hack to do this, and yet altering the goto, maybe something I will need to experiment with.

 

Edited by Meadow Glen
Link to comment
Share on other sites

Imagine you have this completely ludicrous construct

 

10 PRINT "HELLO"

20 GOTO 30

30 PRINT "AGAIN"

40 GOTO 50

50 REM DO SOMETHING ELSE

 

In this way, you could sprinkly meaningless hooks, in various areas of the gameloop, that could be ruthless manipulated later from a VBI - achieving the effect of controlling the basic flow...maybe, I don't know...my mind glazes over when dealing with some of these OS tables, but.....anyway, maybe something to toy with on the weekend.

Link to comment
Share on other sites

Hmm, maybe this is simpler than I know.

 

 

10 PRINT "HELLO"

20 GOTO HOOK1

30 PRINT "AGAIN"

40 GOTO HOOK2

50 REM DO SOMETHING ELSE

 

if HOOK1 = 30 then it goes to 30

if HOOK2 = 50 then it goes to 50

 

Then, it's already been established you can manipulate variables from the machine code.

 

I don't know....I guess try it, see if it works, lol....hate to imagine outloud like this, but you all already know a lot more, so.....always helpful to chat about it.

 

Link to comment
Share on other sites

16 hours ago, Meadow Glen said:

I appreciate all your help.  Lot's of things i need to look at now.  It may not be possible, but early authors hinted it was....based on google searching I found "The Atari Wedge: Adding Commands To Atari BASIC"


The author added some commands to basic- a hack, of course, and then ended with this "In future issues, we'll go into how you can tell BASIC what to do from machine language. We'll even try to pursue that elusive aim – actually adding commands to a running program."

The way how the "Wedge" worked was exactly by the technique I mentioned above: It added a custom hook into the editor handler E: via HATABS, interpreted "commands" there and forwarded what remains to its client, BASIC. Thus, BASIC is actually not extended at all, it is just a command interpreter that sits between the Os and Basic that does the job.

 

In particular, you could not use those "commands" within BASIC programs, but only in direct mode (simply because it was not the BASIC interpreter that was modified but only the editor). Actually, unlike Microsoft Basic, Atari BASIC has no hook to add in new commands. The tokenizer and the token interpreter are hard-wired, without any possibility to add something from the outside.

 

The only way how you can add custom commands to BASIC is via "USR()" and calling into machine language. Of course, they don't "read" as custom commands in the source, but that is just syntactic sugar around the principle of calling into a custom program from your source.

 

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