Jump to content
IGNORED

Extra large programs spanning multiple files


Sinphaltimus

Recommended Posts

I just thinking and I don't know if my assumptions are incorrect or what so I thought I'd post a topic.

My assumptions:
Using Extended Basic
You can load other programs from DSKx from within a program.
You can clear ram from within a program.

If you have a program that is more than 32K in size, using creative programming you can span it across several files.

Here's my thought.

Can you make an adventure game with level 1 as it's own file, level 2 as it's own file and so on and so forth. Granting you as many levels as you can fit files on a DSK.

During game play, you can clear enough ram to load the next level. So if say levels are 10k, and your program takes up the rest of your free ram (minus what ever the system needs to operate).
You could clear that 10 k of ram for the next level.

If that's correct, how does one go about doing that?
If incorrect, where does it fail. I'm thinking that once a program is loaded in to memory, you can't clear it without the use of assembly. XB alone isn't enough.
It's not possible because all programs need to reside in memory at once ot that's just the way it works.


Let's say the player reaches a certain point in the game and you will never need the previous code (line 10 - 600) to continue the game. Is there a way to rewrite the code lines with a file load command?

Link to comment
Share on other sites

You can indeed RUN "whatever.whatever" to load and run another XB program from within an XB program. The gotcha, is that variables are all reset/cleared.

 

So you have to stash your state either in a file, or in lower expansion ram, and reload state in the subsequently loaded programs...

 

If you haven't looked at this already, look up 'merge' file format. I would imagine through this process, you will have common code in each 'level' file.

and that can make it easier.

 

The obvious counter approach is to have your level data in data files, and load them, but that does require your program engine is able to hold the logic for all levels... or you could apply both techniques as needed.

 

---

 

You can stash a number in lower expansion ram with a CALL LOAD(8200,A) where 8200 is the address you will stash to, and A is the variable... then retrieve it in another program with CALL PEEK(8200,A)

 

I believe these need to be integer values between 0 and 255 only. Writing to a data file, is far more versatile, and can naturally lead to your save-game format.

 

-M@

  • Like 1
Link to comment
Share on other sites

There is no normal way within XB to load part of an XB program without destroying the current program. The only way I know to load another XB program is the RUN statement, which clears RAM of all variables and the previous program before loading and running the new program.

 

You could use file I/O to change the values of current variables and character patterns to manage the next level.

 

You could also simply chain programs with the RUN statement, realizing that each program must essentially start over. You could preserve information between programs with PEEK and LOAD statements to manage information in low RAM, where XB normally loads Assembly Language programs. Low RAM is not cleared between programs AFAIK.

 

...lee

  • Like 1
Link to comment
Share on other sites

If you haven't looked at this already, look up 'merge' file format. I would imagine through this process, you will have common code in each 'level' file.

and that can make it easier.

 

-M@

 

The problem with MERGE in this context is that you cannot, to my knowledge, use MERGE as a statement. You would need to instruct the user to type the command—probably not what you want to do.

 

...lee

  • Like 1
Link to comment
Share on other sites

You could preserve information between programs with PEEK and LOAD statements to manage information in low RAM, where XB normally loads Assembly Language programs. Low RAM is not cleared between programs AFAIK.

 

...lee

Hey Lee, What's the safe rage in lower memory for BASIC variable storage? - james

 

 

Sent from my iPhone using Tapatalk Pro

  • Like 1
Link to comment
Share on other sites

Hey Lee, What's the safe range in lower memory for BASIC variable storage? - james

 

 

Sent from my iPhone using Tapatalk Pro

 

If you do not need INIT for Assembly Language programs, you should be able to use all of lower RAM. After CALL INIT, it looks like >2600 – >3FFF is available. After CALL INIT, it is probably safest to stay close to the upper part of low RAM.

 

...lee

  • Like 1
Link to comment
Share on other sites

The problem with using XB to retrieve bytes from low RAM via PEEK is that, though you are reading individual bytes, you are using up 8 bytes of variable storage for each of those bytes. XB uses floating point to store all numbers, including integers, and FP is 8 bytes per number.

 

...lee

Link to comment
Share on other sites

To run another Exbasic program, you can use self-modifying code, as done here, taken from an Apesoft catalog program. DEV$ contains the device ("DSK1"), PRNAME$ contains the file name:

 

 

100 INPUT "DEVICE NAME: ":DEV$
110 INPUT "PROGRAM NAME:":PRNAME$
1000 CALL INIT :: CALL PEEK(-31952,A,B) :: CALL PEEK(A*256+B-65534,A,B)
1010 C=A*256+B-65534 :: PATH$=DEV$ & "." & PRNAME$ :: CALL LOAD(C,LEN(PATH$))
1020 FOR I=1 TO LEN(PATH$) :: CALL LOAD(C+I,ASC(SEG$(PATH$,I,1))) :: NEXT I :: CALL LOAD(C+I,0)
1030 PRINT "DSKX.XXXXXXXXXX"

 

Do a LIST after the program terminates; finally you can replace PRINT with RUN (PRINT is just for test purposes). Note that the RUN line must be the last program line.

  • Like 2
Link to comment
Share on other sites

The one thing you do NOT lose when you RUN a second XB program - all character definitions remain defined. I've used this in the past to define all characters in one program then RUN a second for the actual game.

 

You can also use that to transfer data between programs without LOAD/PEEK (which require memory expansion) -- CALL CHARPAT returns the definition string. If you can store your interesting data in a couple of character patterns, you can retrieve it that way in the next program. ;)

  • Like 4
Link to comment
Share on other sites

The problem with using XB to retrieve bytes from low RAM via PEEK is that, though you are reading individual bytes, you are using up 8 bytes of variable storage for each of those bytes. XB uses floating point to store all numbers, including integers, and FP is 8 bytes per number.

 

...lee

Hmm RXB does not have this issue.

 

RXB has CALL MOVES that allows any size of memory of any type (i.e. RAM/VDP/GROM/GRAM) to be moved or copied.

 

Ez way is to put FP numbers into a string and save values also using CALL HEX(FP number,Hex String)

 

28079 in FP normally takes 8 bytes to store including 2 bytes for pointer so actually takes 10 bytes per FP number,

but RXB CALL HEX would convert that to a hex string of >6DAF which would only take 5 bytes for same storage plus 2 for pointer thus 7 bytes vs 10 bytes.

 

RXB Example:

N=28079 :: CALL HEX(N,N$) :: CALL MOVES("$R",4,N$,8192) ! This would put >6DAF at lower 8K address >2000 thus you have saved that number.

Link to comment
Share on other sites

Actually the entire point of this post is mute using RXB as you can use the SAMS with RXB for 960K or storage for variables or programs.

 

Example is this video of RXB using 72K of Assembly from a single XB program and using CALL USER running all XB programs and assembly from SAMS alone.

 

Once loaded you do not need disk at all as it does a PHONY DISK drive in lower 8K to save the programs.

 

 

(RXB game IN THE DARK does a very similar action using over 300K

 

Link to comment
Share on other sites

I believe that with some clever assembly support it would indeed be possible to chain together any number of XB programs while completely retaining all the variables and strings from one program to the next. If X is 17 and A$ is "Hello World" in the first program they would stay the same when the second program runs. You have to play a trick on XB so it doesn't find out that a new program has been loaded.


Here's the first program:

1 CALL PEEK(flaglocation,X)::IF X=1 THEN 2::CALL LINK("MOVPRG",-20480)::RUN

..the complete 1st program here with many lines of code, then

2000 PRG$="DSK1.XBPROG2"::GOTO 30000

30000 CALL LINK("LOADXB",PRG$)::GOTO 1


Line 1 looks to see if this program has been relocated. If the value at flaglocation is 1 then it has been relocated and it is OK to go on. Otherwise MOVPRG should move the program so that the line number table starts at >B000 (-20480). This address should be as close to >A000 as possible while still leaving room for all the numberic variables and arrays. Using SIZE and some simple arithmetic should give the right value for this


The line number table goes from high to low, so starting at >B000 it would be:

30000 and a pointer to the contents of line 30000

then all the other line numbers and pointers in descending order.


MOVPRG would put the contents of line 30000 safely into low memory and update the pointer to it. Also, it would move the line number table so it starts at >B000, plus setting the flag at flaglocation. All this would be done automatically by "MOVPRG".


Now line 1 comes to RUN and the program runs again but this time X=1 and the program can proceed.


Now the program executes. When it is time to load the next XB program line 2000 sends the program to line 30000. Remember that the contents of line 30000 are in low memory where they cannot be overwritten. But XB runs fine out of that location.


Line 30000 uses another assembly sub, LOADXB, that loads an IV254 XB program but instead of using RUN we use our own loader so we have control over what happens next. Once the program is loaded LOADXB copies the line number table of the newly loaded program so it is immediately after the entry for line 30000, and of course all the line number table pointers in scratch pad ram are updated. (Probably a few other things would need to happen as well) Then the program goes back to line 1, but this time it is line 1 in the newly loaded program.


One big caveat is that the first program to run would have to have ALL the numeric and string variables used by the various programs. The initial prescan allocates space for them all. If the second program has FOR Z=1 TO 10 and the first program didn't have a Z then XB at best would throw an error and more likely would just crash.


I should add that the XB programs should be IV254; otherwise they will trash the contents of VDP ram when they are loaded.


It's an interesting exercise, but is probably more trouble than it is worth.


(edit) Turns out that MOVPRG is way more complex than necessary. All you have to do is make sure the first program is the longest. That can be done by padding it with long REM statements if necessary. Then the program does not need to be relocated and there is only one prescan needed. Then you just need to use MOVPRG to relocate line 30000 to low memory. Line 1 becomes simply: 1 CALL LINK("MOVPRG")

Edited by senior_falcon
  • Like 3
Link to comment
Share on other sites

 

The fact that one can use RXB does not render the entire point of this post moot because the question was not about RXB—it was about Extended Basic. Let us try to keep this thread on the tracks.

 

...lee

RXB is 100% compatible with XB, this is like using a product you know will not work vs one that you know can do the job.....what is the point of that?

 

I understand you want ONLY ORIGINAL XB so you can ONLY TACKLE THE PROBLEM USING ASSEMBLY and that pretty much why you ignore my solution product answer.

 

This is why the answer turned to only Assembly and hopefully shuts me down I guess. I can not think of any other reason.

 

RXB runs on Hardware, all the Emulators and has a proven record of success.

 

I did not see the post as saying ONLY XB 110 ONLY.

Link to comment
Share on other sites

 

I believe that with some clever assembly support it would indeed be possible to chain together any number of XB programs while completely retaining all the variables and strings from one program to the next. If X is 17 and A$ is "Hello World" in the first program they would stay the same when the second program runs. You have to play a trick on XB so it doesn't find out that a new program has been loaded.
Here's the first program:
1 CALL PEEK(flaglocation,X)::IF X=1 THEN 2::CALL LINK("MOVPRG",-20480)::RUN
..the complete 1st program here with many lines of code, then
2000 PRG$="DSK1.XBPROG2"::GOTO 30000
30000 CALL LINK("LOADXB",PRG$)::GOTO 1
Line 1 looks to see if this program has been relocated. If the value at flaglocation is 1 then it has been relocated and it is OK to go on. Otherwise MOVPRG should move the program so that the line number table starts at >B000 (-20480). This address should be as close to >A000 as possible while still leaving room for all the numberic variables and arrays. Using SIZE and some simple arithmetic should give the right value for this
The line number table goes from high to low, so starting at >B000 it would be:
30000 and a pointer to the contents of line 30000
then all the other line numbers and pointers in descending order.
MOVPRG would put the contents of line 30000 safely into low memory and update the pointer to it. Also, it would move the line number table so it starts at >B000, plus setting the flag at flaglocation. All this would be done automatically by "MOVPRG".
Now line 1 comes to RUN and the program runs again but this time X=1 and the program can proceed.
Now the program executes. When it is time to load the next XB program line 2000 sends the program to line 30000. Remember that the contents of line 30000 are in low memory where they cannot be overwritten. But XB runs fine out of that location.
Line 30000 uses another assembly sub, LOADXB, that loads an IV254 XB program but instead of using RUN we use our own loader so we have control over what happens next. Once the program is loaded LOADXB copies the line number table of the newly loaded program so it is immediately after the entry for line 30000, and of course all the line number table pointers in scratch pad ram are updated. (Probably a few other things would need to happen as well) Then the program goes back to line 1, but this time it is line 1 in the newly loaded program.
One big caveat is that the first program to run would have to have ALL the numeric and string variables used by the various programs. The initial prescan allocates space for them all. If the second program has FOR Z=1 TO 10 and the first program didn't have a Z then XB at best would throw an error and more likely would just crash.
I should add that the XB programs should be IV254; otherwise they will trash the contents of VDP ram when they are loaded.
It's an interesting exercise, but is probably more trouble than it is worth.

 

Pretty ingenious solution and similar to my idea for multiple 24K for XB using the SAMS.

Link to comment
Share on other sites

RXB is 100% compatible with XB, this is like using a product you know will not work vs one that you know can do the job.....what is the point of that?

 

I understand you want ONLY ORIGINAL XB so you can ONLY TACKLE THE PROBLEM USING ASSEMBLY and that pretty much why you ignore my solution product answer.

 

This is why the answer turned to only Assembly and hopefully shuts me down I guess. I can not think of any other reason.

 

RXB runs on Hardware, all the Emulators and has a proven record of success.

 

I did not see the post as saying ONLY XB 110 ONLY.

 

But.... *SAMS required?

Link to comment
Share on other sites

I have been doing some testing on how to chain XB programs together. Here are some results:
TEST1
1 !
10 !SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
20 !SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
25 CALL LINK("MOVEXB")
30 DIM X(24)
40 FOR I=1 TO 24 :: X(I)=SQR(I):: NEXT I
50 A$="DSK2.TEST2" :: GOTO 30000
30000 CALL LINK("LDI254",A$):: GOTO 1
This program fills the X() array with square roots but does not print anything on the screen.
TEST2
1 !****************************************************
10 FOR I=1 TO 24 :: PRINT X(I):: NEXT I
20 END
30000 !
This prints out the values contained in the X() array. Notice that there is no DIM in this program. If you RUN TEST2 by itself, elements 1 to 10 in the X(n) array are set to 0 and it prints out zeros until it comes to X(11) where the program stops with BAD SUBSCRIPT IN 10.
Both of these programs have been saved in IV254 format. The long rems are to make the program long enough to save as IV254.
When TEST1 runs MOVEXB in line 25 copies the contents of the last line to low memory and changes the the line number table to point to the relocated line of code. Lines 30, 40 and 50 are self explanatory. Line 30000 loads the IV254 file TEST2 into the same memory locations used by OLD TEST2. It resets the pointer for the last line to point to the relocated code from TEST1 which was CALL LINK("LDI254",A$)::GOTO 1. That way if you want to continue chaining programs you could have 50 A$="DSK2.TEST3"::GOTO 30000 and so on.
GOTO 1 in line 30000 goes to line 1 in the newly loaded program. None of the variables or strings are reset with this and if all goes well TEST2 will print out the 24 square roots stored in X()
Let's see how it works:

gallery_34177_1071_35658.gif

 

All the variables were saved and passed along to the new program without having to resort to PEEKs and POKEs. Pretty cool, eh?
If you want TEST2 to run as a new program and not a continuation of TEST1 then change line 30000 to be RUN instead of GOTO 1. An advantage here is that the file name can be A$. XB does not like RUN A$.

 

RXB is 100% compatible with XB, this is like using a product you know will not work vs one that you know can do the job.....what is the point of that?

 

I understand you want ONLY ORIGINAL XB so you can ONLY TACKLE THE PROBLEM USING ASSEMBLY and that pretty much why you ignore my solution product answer.

 

This is why the answer turned to only Assembly and hopefully shuts me down I guess. I can not think of any other reason.

 

 

Although you quoted Lee in the above post I was the only one to mention an assembly language solution, so I assume this was directed at me. One possible reason might be that this method is way better. It works automatically and instantly. If you want to store more than just a few values it is a whole lot better than messing around with PEEK and POKE. With assembly you are not restricted to using what someone else thought was the right way - you can custom make a subroutine to do exactly what you want. As a well known TI-er once said: "Look you can use a wine bottle as a hammer, does not mean something is wrong with Wine bottles because you can hammer nails with it."

  • Like 3
Link to comment
Share on other sites

 

 

Although you quoted Lee in the above post I was the only one to mention an assembly language solution, so I assume this was directed at me. One possible reason might be that this method is way better. It works automatically and instantly. If you want to store more than just a few values it is a whole lot better than messing around with PEEK and POKE. With assembly you are not restricted to using what someone else thought was the right way - you can custom make a subroutine to do exactly what you want. As a well known TI-er once said: "Look you can use a wine bottle as a hammer, does not mean something is wrong with Wine bottles because you can hammer nails with it."

 

What I am saying is if a tool exists for a problem why are you using a Wine bottle as a hammer when you can use the hammer?

 

It sounds like you are suggesting ignoring the hammer available and just looking for things you can use like the wine bottle to get the job done, I guess to avoid using the correct tool on purpose.

 

I assume to prove it can be done multiple ways, but still it makes little sense to go so complicated of a route when a easy to use tool is there and ignored on purpose?

 

I created RXB for this reason and everyone seems to go to great extremes to avoid using it....or am I wrong about this?

Edited by RXB
Link to comment
Share on other sites

Also it is awesome Senior_Falcon comes up with so many ways to attack a problem in XB, but again why I am discouraged with the lack of using my XB designed around things like this.

 

I left the TI community for a number of years for that same reason.

Edited by RXB
Link to comment
Share on other sites

What I am saying is if a tool exists for a problem why are you using a Wine bottle as a hammer when you can use the hammer?

 

It sounds like you are suggesting ignoring the hammer available and just looking for things you can use like the wine bottle to get the job done, I guess to avoid using the correct tool on purpose.

 

I don't see why you compare assembly subroutines to driving nails with a wine bottle. To me it is more like driving nails with a pneumatic nail gun.

 

Maybe I am misunderstanding RXB. Can you easily pass a floating point number from one XB program to another with RXB? I don't think you can, but perhaps I am mistaken.

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