Meadow Glen Posted February 14, 2022 Share Posted February 14, 2022 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. Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted February 14, 2022 Share Posted February 14, 2022 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. Quote Link to comment Share on other sites More sharing options...
ilmenit Posted February 14, 2022 Share Posted February 14, 2022 Take a look at this intro: https://www.pouet.net/prod.php?which=78757 It does what you need and is very short to disassemble. I saw also description how to do such calls in one scanned magazine from the 80s. Will try to find it. Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted February 14, 2022 Share Posted February 14, 2022 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. Quote Link to comment Share on other sites More sharing options...
Mark2008 Posted February 15, 2022 Share Posted February 15, 2022 (edited) deleted Edited February 15, 2022 by Mark2008 Quote Link to comment Share on other sites More sharing options...
Rybags Posted February 15, 2022 Share Posted February 15, 2022 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. Quote Link to comment Share on other sites More sharing options...
xxl Posted February 15, 2022 Share Posted February 15, 2022 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' Quote Link to comment Share on other sites More sharing options...
phaeron Posted February 15, 2022 Share Posted February 15, 2022 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. Quote Link to comment Share on other sites More sharing options...
_The Doctor__ Posted February 15, 2022 Share Posted February 15, 2022 (edited) 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 February 15, 2022 by _The Doctor__ Quote Link to comment Share on other sites More sharing options...
Rybags Posted February 15, 2022 Share Posted February 15, 2022 (edited) 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 February 15, 2022 by Rybags Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted February 15, 2022 Share Posted February 15, 2022 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. Quote Link to comment Share on other sites More sharing options...
Rybags Posted February 15, 2022 Share Posted February 15, 2022 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. Quote Link to comment Share on other sites More sharing options...
danwinslow Posted February 16, 2022 Share Posted February 16, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted February 16, 2022 Share Posted February 16, 2022 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. Quote Link to comment Share on other sites More sharing options...
danwinslow Posted February 16, 2022 Share Posted February 16, 2022 Sure, but if you're thinking about doing something like calling back into basic from assembler, that's probably a sign that you should just be using assembler. I wasn't knocking basic at all. 1 Quote Link to comment Share on other sites More sharing options...
Meadow Glen Posted February 16, 2022 Author Share Posted February 16, 2022 (edited) 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 February 16, 2022 by Meadow Glen Quote Link to comment Share on other sites More sharing options...
Meadow Glen Posted February 16, 2022 Author Share Posted February 16, 2022 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. Quote Link to comment Share on other sites More sharing options...
Meadow Glen Posted February 16, 2022 Author Share Posted February 16, 2022 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. Quote Link to comment Share on other sites More sharing options...
Rybags Posted February 16, 2022 Share Posted February 16, 2022 Flags in memory would be easier than variables. If you want to use variables for communication then a string is probably best. ADR() is already there for you. And if you work on byte sized chunks, half baked values doesn't become a problem. Quote Link to comment Share on other sites More sharing options...
thorfdbg Posted February 17, 2022 Share Posted February 17, 2022 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. 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.