Subject: CALL LINK argument type list?

From: "Matthew" <[email-masked]>
Date: Sat, 20 Feb 2010 19:42:22 -0000

When using CALL LINK from XB to an assembly routing, the E/A manual says (pages 277 and 278):

* The value stack address in VDP RAM is stored at >8310
* The number of arguments passed is stored at >8312
* The argument types as a list of bytes are stored from >200A through >2019 (16 bytes for a max of 16 parameters)

I found the value stack address a >8310, however all the console XML routines use >836E (which also contains the value stack address)...  Anyone know why there are two locations and if one is not reliable?

I found the number of arguments in >8312 just fine.

I did *not* find the list of argument types at >200A.  During any CALL LINK the data from >2000 to about >2100 never changes.  Before I go digging through the ROM code for CALL LINK, does anyone know where the argument type list is actually stored during a CALL LINK call?

Thanks,
Matthew

---

From: ti99_forever <[email-masked]>
Date: Sat, 20 Feb 2010 13:15:18 -0800 (PST)

There is a difference for the console and XB... keep looking in the EA manual!

--- On Sat, 2/20/10, Matthew <[email-masked]> wrote:

> From: Matthew <[email-masked]>
> Subject: [TI994A] CALL LINK argument type list?
> To: [email-masked]
> Date: Saturday, February 20, 2010, 2:42 PM
> When using CALL LINK from XB to an
> assembly routing, the E/A manual says (pages 277 and 278):
> 
> * The argument types as a list of bytes are stored from
> >200A through >2019 (16 bytes for a max of 16
> parameters)
> 
> I found the value stack address a >8310, however all the
> console XML routines use >836E (which also contains the
> value stack address)...  Anyone know why there are two
> locations and if one is not reliable?
> 
> I did *not* find the list of argument types at
> >200A.  During any CALL LINK the data from >2000
> to about >2100 never changes.  Before I go digging
> through the ROM code for CALL LINK, does anyone know where
> the argument type list is actually stored during a CALL LINK
> call?
> 
> Thanks,
> Matthew
> 
> 
> 
> 
> ------------------------------------
> 
> Yahoo! Groups Links
> 
> 
>     [email-masked]
> 
> 
>

---

From: mark wills <[email-masked]>
Date: Sat, 20 Feb 2010 22:10:50 -0800 (PST)

Sorry Matthew, I dont know, bu if you find out, please let me (us) know! Maybe add an entry to the wiki or the faq, or just a post here!

I would like to know how to change a variable in assembler, also:

10 a=1
20 print a
30 call link("change")
40 print a
run
1
99

etc...

----- Original Message ----
> Sent: Sat, 20 February, 2010 19:42:22

* The value stack address in VDP RAM is stored at 
> >8310
* The 
> argument types as a list of bytes are stored from >200A through >2019 (16 
> bytes for a max of 16 parameters)

I found the value stack address a 
> >8310, however all the console XML routines use >836E (which also contains 
> the value stack address)...  Anyone know why there are two locations and if 
> one is not reliable?

I found the number of arguments in >8312 just 
> fine.

I did *not* find the list of argument types at >200A.  
> During any CALL LINK the data from >2000 to about >2100 never 
> changes.  Before I go digging through the ROM code for CALL LINK, does 
> anyone know where the argument type list is actually stored during a CALL LINK 
> call?

Thanks,
Matthew

Yahoo! 
> Groups Links

> >http://groups.yahoo.com/group/TI994A/join
    (Yahoo! ID 
> required)

    > href="mailto:[email-masked]">[email-masked]

> href="mailto:[email-masked]">[email-masked]

> >http://docs.yahoo.com/info/terms/

---

From: Insane Multitasker <[email-masked]>
Date: Sun, 21 Feb 2010 00:30:05 -0600

Matthew,
Are you trying to pass parameters of your own but not in a well-defined order?  You might already
know what I'm about to blather but I wasn't sure what you were having trouble doing ;) So
indulge me a few moments.

Generally, STRASG, STRREF, NUMASG, etc. argument types can be defined statically by your
assembly program.  For NUMASG you will need to convert integers to float, using the 
CIF XMLLNK. 

Example: 

MOV @value,@>834A   *move integer into 834a
BLWP @XMLLNK
DATA CIF   *convert INT to Float (routine # for xmllnk, similar to how dsrlnk works)
CLR R0  
LI  R1,4    call link variable #
CLR @>837C (might be required)
BLWP @NUMASG

Grabbing a string from XB for use in your assembly code:
STRING BSS >31   (len+string space)
CLR R0
LI R1,>3000   length MSByte
MOVB R1,@STRING
LI  R1,1    first variable
LI  R2,STRING  point to string len byte
BLWP @STRREF

to push it back out...
CLR R0
LI  R1,2  send to second variable
LI  R2,STRING
BLWP @STRASG

I think R0 is used for arrays but do not quite remember.  The status byte
may or may not be important to clear; something in my mind says it
should preceed the NUMASG call.  And as far as errors go, I don't recall how
to check for mismatches, etc.  

I don't recall ever using the addresses mentioned below in any of my parameter passing
subroutines.  That doesn't mean I did it right, though ;)

Tim

> From: [email-masked]
> Date: Sat, 20 Feb 2010 19:42:22 +0000
 		 	   		  
_________________________________________________________________
Hotmail: Trusted email with Microsoft’s powerful SPAM protection.
http://clk.atdmt.com/GBL/go/201469226/direct/01/

---

From: ti99_forever <[email-masked]>
Date: Sat, 20 Feb 2010 22:46:59 -0800 (PST)

Besides passing it back as a parameter, there is the ASSGNVAL routine that is basically undocumented, you'd need to look at the BASIC Groms probably.

--- On Sun, 2/21/10, mark wills <[email-masked]> wrote:

> From: mark wills <[email-masked]>
> Subject: Re: [TI994A] CALL LINK argument type list?
> Date: Sunday, February 21, 2010, 1:10 AM
> Sorry Matthew, I dont know, bu if you
> find out, please let me (us) know! Maybe add an entry to the
> wiki or the faq, or just a post here!
> 
> > When using CALL LINK from XB to an assembly routing,
> the E/A manual says (pages 
> > 277 and 278):
> 
> > argument types as a list of bytes are stored from
> >200A through >2019 (16 
> > >8310, however all the console XML routines use
> >836E (which also contains 
> > During any CALL LINK the data from >2000 to about
> >2100 never

---

From: "Matthew" <[email-masked]>
Date: Sun, 21 Feb 2010 20:30:33 -0000

Thanks everyone for the feedback.  I did find the information I was looking for thanks to ti99_forever telling me it is in the E/A manual and to keep looking.  Way in the back in the appendices (on page 418) and away from the main material in section 17, there is one page on the differences between the E/A utilities and the XB utilities:

CALL INIT, CALL LOAD, CALL LINK, CALL PEEK, and ERROR messages.

The "details" about the XB CALL LINK are pretty brief though:

"CALL LINK--The Editor/Assembler Loader uses its own workspace to store information from the parameter list. Only the addresses >8310 through >8312 are reserved for parameter passing purposes. TI Extended BASIC uses addresses >8300 through >8315 for this information. Your assembly language program must not modify this area if parameters are to be accessed in the program."

So, XB CALL LINK uses >8300 through >8315 for the argument type list, and the E/A CALL LINK uses >200A through >2019.  My only problem was that >2019 - >200A = >F (sixteen parameter types), but the XB range is >8315 - >8300 = >15 (21 bytes), so where exactly are the 16 argument type bytes in that range of 21 bytes?

So, using intuition and Tursi's Classic99 debugger I found that XB passes the argument type list starting at >8300, which makes sense because section 17 talks about >8312 holding the number of arguments (which it does), and >8310 holding the value stack address (which it does, but it always points to the bottom of the stack when using XB, which means the value never changes.)

For anyone interested (Mark?), what follows is what I learned about parameter passing between XB and assembly.

I needed to pass a parameter from my assembly routing back to XB.  I have never done this because I typically write everything in assembly and I don't like having to keep track of all the places XB uses memory (which is all over the whole system.)  My routine is called like this:

CALL LINK("MYFUNC",S)

The variable S is an XB numeric variable and is passed as a variable that will receive a value from the assembly program.  The LINK() call can actually pass up to 16 parameters, and they can be any kind of XB variable.  Because of the variable nature of the number of parameters and their data types (numeric, string, etc.), on the assembly side you need to know what the types of each parameter are, and how many were passed.

It is the list of "data types" passed that I was looking for.  All the examples I saw in the E/A manual and everywhere else assume you know the types of the parameters passed and their order, but I don't like to assume and I wanted to issue an error if the wrong data type was passed (rather than have my code crash.)

When XB does a CALL LINK() it does a few things:

1. Writes the number of arguments passed to >8312

2. Writes the "types" of each argument as a byte array starting at >8300

3. Writes a string expression of the linked name to the value stack

4. Writes (pushes) an argument "entry" for each argument on to the VS (value stack) which is located in VDP RAM.  The address of the VS is maintained at CPU address >836E and is updated (incremented by 8) for each argument.  In my testing the initial value at >836E was >0958 and the first parameter (the name of the linked function) was first on the stack at >0960, so the VS address is adjusted *prior to* a value being pushed on the stack, and the stack grows *down* towards higher addresses in VDP RAM.  Also, CPU RAM >8310 always contained >0958, so that is possibly used as a pointer to the top of the stack?

5. Branches to the assembly routine with BL (*NOT* BLWP)

Thus, in the assembly language program I define things like this:

VDPADR EQU  >8C02     * VDP set read/write address
VDPRD  EQU  >8800     * VDP read data
XBWS   EQU  >83E0     * Workspace when called from XB
ARGTYP EQU  >8300     * Argument types passed by CALL LINK
ARGC   EQU  >8312     * Number of arguments passed by CALL LINK
VSTOP  EQU  >8310     * Top of the value stack in VDP RAM
VSBTM  EQU  >836E     * Bottom of value stack in VDP RAM
STATUS EQU  >837C     * Return status for CALL LINK

ZERO   BYTE >00       * Zero value byte
ONE    BYTE >01       * One value byte
TWO    BYTE >02       * Two value byte
ERRBA  BYTE >1C       * Error Bad Argument
       EVEN

The first thing you would need to check is the number of parameters passed.  You could check for an exact number, or that at least the number of parameters you needed were passed, it is up to you.  In my case, I check that 1 argument is passed and that it is numeric.

CB   @ARGC,@ONE        * Make sure 1 argument was passed
JNE  SPDERR       
CB   @ARGTYP,@TWO      * Check the argument is a numeric variable
JEQ  SPD0

SPDERR
MOVB @ERRBA,@STATUS    * Return Bad Argument (for XB this is >1C)
B    *R11

SPD0
continue...

The byte indicators at >8300 for the data types passed are:

0 - numeric expression
1 - string expression
2 - numeric variable
3 - string variable
4 - numeric array
5 - string array

The entries in the VS will vary depending on the argument type, which is why you need to have this list, since you can't determine the VS type from the actual data on the VS.  The E/A manual describes the format of each type, and Thierry has details on his Tech Pages (look on the BASIC Interpreter page.)  Basically it goes like this:

Each entry is 8-bytes:

Numeric expression, type 0:
Byte 0 - 7 contains a radix-100 numeric value

String expression, type 1:
Byte 0 and 1 contain >1C00
Byte 2 contain >65 (tag for a string in TI BASIC)
Byte 3 not used
Byte 4 and 5 contain a pointer to the string data in VDP RAM
Byte 6 and 7 contain the length of the string and byte 6 is always zero because strings can only be up to 255 characters long

Numeric expression type 2:
Byte 0 and 1 contain a pointer to the variables symbol table entry in VDP RAM
Byte 2 contains 0
Byte 3 not used
Byte 4 and 5 contain a pointer to the 8-byte value of the variable.  When the PEB is attached with memory expansion, this pointer is an address in CPU RAM, otherwise it is a pointer to VDP RAM
Byte 6 and 7 not used

String variable type 3:
Byte 0 and 1 contain a pointer to the variables symbol table entry in VDP RAM
Byte 2 contains >65
Byte 3 not used
Byte 4 and 5 contain a pointer to the string data in VDP RAM.  I do not know if the PEB is attached if strings are still stored in VDP or CPU RAM like the numeric variables...  anyone?
Byte 6 and 7 contain the length of the string and byte 6 is always zero because strings can only be up to 255 characters long

Anyway, you get the idea.  See the E/A manual on page 280 for the format of the numeric and string arrays.  I only needed the numeric variable format, so I was done at that point.

Now, the cool thing about the variable types (as opposed to the expressions (types 0 and 1)) is that you are changing the actual bytes of the variable's value, so the value you write is seen upon return to XB.  In C this is the same as passing by reference, i.e. a pointer.  You just have to make sure that you write a value in the format that XB uses for the variable type, and in the case of numeric variables, that is an 8-byte radix-100 numeric number.  I was always scared of this format because I never looked into it (fear of the unknown.)  Actually it is not to bad (quite easy actually, compared to things like IEEE floating point formats), and I only needed to return a 0 or 1.  The E/A page 279 explains the format, and Thierry has more info on his site too.

I didn't care about the symbol table entry for the variable since the VS entry gives me a pointer to the actual data for the variable.  So, to get the address of the variable's value I need to:

1. Get the address for the top of the VS, which is stored at >836E.  Since I made sure only 1 argument was passed, and that the argument was numeric, the top of the VS points to the numeric variable entry I need.

2. Read 8 bytes from the VS address in VDP RAM.

3. Look at bytes 4 and 5 to get the address in CPU RAM of the variable's value.

4. Write either 0 or 1 to the variable's value.

5. Return

SPD0
MOV  @VSTACK,R0        * Get the address of the value stack
AI   R0,4              * Adjust to the 4th byte
MOVB @XBWS+1,@VDPADR   * Send low byte of VDP RAM write address
MOVB @XBWS,@VDPADR     * Send high byte of VDP RAM write address
MOVB @VDPRD,@XBWS      * Read high byte from VDP RAM
MOVB @VDPRD,@XBWS+1    * Read low byte from VDP RAM

R0 now holds the CPU address of the numeric variable's actual data value, which is a radix-100 number.  The values 0 and 1 in radix-100 format look like this:

0 in radix-100: >00 >00 >xx >xx >xx >xx >xx >xx
1 in radix-100: >40 >01 >00 >00 >00 >00 >00 >00

The >xx is "don't care".  But since the value 1 needs the trailing >00 values, the whole number will be filled out with >00.

LI   R2,8          * Write 8 bytes to the radix 100 value
CB   @ZERO,@ACTIVE * My check to return 0 or 1
JEQ  SPD1
LI   R1,>4001      * Radix 100 for the value 1
MOVB R1,*R0+       * Write the >40
SWPB R1
MOVB R1,*R0+       * Write the >01
DECT R2            * Reduce the number of >00 values to write

SPD1
MOVB @ZERO,*R0+    * Write the remaining >00 values
DEC  R2
JNE  SPD1

MOVB @ZERO,@STATUS * Return everything OK
B    *R11

That's pretty much it.  The bytes >40 and >01 are written with MOVB instead of just MOV R1,*R0 because I don't know the the variable's 8-byte value is guaranteed to be on an even address boundary.  It probably is, but I'm not going to take the chance, and I want to reuse this code.

I'm sure people will ask why I didn't just use the NUMREF and NUMASG utilities.  Well, I'm a performance freak and I don't like branching off to other utilities if I don't have to.  Those utilities are general purpose, very heavy, and require a BLWP and all that.  And all I needed was to write a 0 or 1, so it seemed overkill.  Besides, I still needed to consult the argument type list and number of arguments manually, since to use the utilities you have to know your data types and locations in the argument list.

Since I only needed to report a 0 or 1, which my routine was already maintaining in CPU RAM, it would have been real nice to just do a CALL PEEK(addr,S).  The problem is, from XB you have no way to know what the address is.  And if I wrote a function to provide the address, then why not just return the value (which is what I did.)  I could have stuck the value in a well known address, but since XB stomps all over the CPU and VDP RAM, there was no place safe to do that, besides what if I needed more than 1 value in the future?  Also, having hard-coded addresses in an XB program is clunky and a bad idea.

Either way, there you have it.  And think, this was only 1/4th of the adventure I had in the last few days!  I'm probably going to write up the whole process, so look for a future post (it has to do with sound.)

Matthew

--- In [email-masked], mark wills <markrobertwills@...> wrote:
> > From: Matthew <matthew@...>

---

From: ti99_forever <[email-masked]>
Date: Sun, 21 Feb 2010 12:48:38 -0800 (PST)

Damn fine detail, Matthew... this is a keeper.
I'd done this same thing many years ago, but did not document it well (or at all).
You are really programming close to the metal when you don't use the standard "glue-on" routines like NUMREF, STRREF, STRASG, NUMASG... Usually though, you can use these routines and they return an error for wrong data type, etc.
But determining the data type allows more flexibility... and TI Basic doesn't have those utilities built-in, requiring linking with BSCSUP.

Sorry I couldn't be more detailed, but I knew it was in there...

--- On Sun, 2/21/10, Matthew <[email-masked]> wrote:

> Subject: [TI994A] Re: CALL LINK argument type list?
> Date: Sunday, February 21, 2010, 3:30 PM
> Thanks everyone for the
> feedback.  I did find the information I was looking for
> thanks to ti99_forever telling me it is in the E/A manual
> and to keep looking.  Way in the back in the appendices
> (on page 418) and away from the main material in section 17,
> there is one page on the differences between the E/A
> utilities and the XB utilities:
> 
> "CALL LINK--The Editor/Assembler Loader uses its own
> workspace to store information from the parameter list. Only
> the addresses >8310 through >8312 are reserved for
> parameter passing purposes. TI Extended BASIC uses addresses
> >8300 through >8315 for this information. Your
> assembly language program must not modify this area if
> parameters are to be accessed in the program."
> 
> So, XB CALL LINK uses >8300 through >8315 for the
> argument type list, and the E/A CALL LINK uses >200A
> through >2019.  My only problem was that >2019 -
> >200A = >F (sixteen parameter types), but the XB range
> is >8315 - >8300 = >15 (21 bytes), so where exactly
> are the 16 argument type bytes in that range of 21 bytes?
> 
> So, using intuition and Tursi's Classic99 debugger I found
> that XB passes the argument type list starting at >8300,
> which makes sense because section 17 talks about >8312
> holding the number of arguments (which it does), and
> >8310 holding the value stack address (which it does, but
> it always points to the bottom of the stack when using XB,
> which means the value never changes.)
> 
> For anyone interested (Mark?), what follows is what I
> learned about parameter passing between XB and assembly.
> 
> I needed to pass a parameter from my assembly routing back
> to XB.  I have never done this because I typically
> write everything in assembly and I don't like having to keep
> track of all the places XB uses memory (which is all over
> the whole system.)  My routine is called like this:
> 
> CALL LINK("MYFUNC",S)
> 
> The variable S is an XB numeric variable and is passed as a
> variable that will receive a value from the assembly
> program.  The LINK() call can actually pass up to 16
> parameters, and they can be any kind of XB variable. 
> Because of the variable nature of the number of parameters
> and their data types (numeric, string, etc.), on the
> assembly side you need to know what the types of each
> parameter are, and how many were passed.
> 
> It is the list of "data types" passed that I was looking
> for.  All the examples I saw in the E/A manual and
> everywhere else assume you know the types of the parameters
> passed and their order, but I don't like to assume and I
> wanted to issue an error if the wrong data type was passed
> (rather than have my code crash.)
> 
> 4. Writes (pushes) an argument "entry" for each argument on
> to the VS (value stack) which is located in VDP RAM. 
> The address of the VS is maintained at CPU address >836E
> and is updated (incremented by 8) for each argument. 
> In my testing the initial value at >836E was >0958 and
> the first parameter (the name of the linked function) was
> first on the stack at >0960, so the VS address is
> adjusted *prior to* a value being pushed on the stack, and
> the stack grows *down* towards higher addresses in VDP
> RAM.  Also, CPU RAM >8310 always contained >0958,
> so that is possibly used as a pointer to the top of the
> stack?
> 
> ARGC   EQU  >8312 
>    * Number of arguments passed by CALL LINK
> VSTOP  EQU  >8310     *
> The first thing you would need to check is the number of
> parameters passed.  You could check for an exact
> number, or that at least the number of parameters you needed
> were passed, it is up to you.  In my case, I check that
> 1 argument is passed and that it is numeric.
> 
> CB   @ARGC,@ONE        *
> The entries in the VS will vary depending on the argument
> type, which is why you need to have this list, since you
> can't determine the VS type from the actual data on the
> VS.  The E/A manual describes the format of each type,
> and Thierry has details on his Tech Pages (look on the BASIC
> Interpreter page.)  Basically it goes like this:
> 
> Each entry is 8-bytes:
> 
> Byte 6 and 7 contain the length of the string and byte 6 is
> always zero because strings can only be up to 255 characters
> long
> 
> Byte 4 and 5 contain a pointer to the 8-byte value of the
> variable.  When the PEB is attached with memory
> expansion, this pointer is an address in CPU RAM, otherwise
> it is a pointer to VDP RAM
> Byte 6 and 7 not used
> 
> String variable type 3:
> Byte 4 and 5 contain a pointer to the string data in VDP
> RAM.  I do not know if the PEB is attached if strings
> are still stored in VDP or CPU RAM like the numeric
> variables...  anyone?
> Byte 6 and 7 contain the length of the string and byte 6 is
> always zero because strings can only be up to 255 characters
> long
> 
> Anyway, you get the idea.  See the E/A manual on page
> 280 for the format of the numeric and string arrays.  I
> only needed the numeric variable format, so I was done at
> that point.
> 
> Now, the cool thing about the variable types (as opposed to
> the expressions (types 0 and 1)) is that you are changing
> the actual bytes of the variable's value, so the value you
> write is seen upon return to XB.  In C this is the same
> as passing by reference, i.e. a pointer.  You just have
> to make sure that you write a value in the format that XB
> uses for the variable type, and in the case of numeric
> variables, that is an 8-byte radix-100 numeric number. 
> I was always scared of this format because I never looked
> into it (fear of the unknown.)  Actually it is not to
> bad (quite easy actually, compared to things like IEEE
> floating point formats), and I only needed to return a 0 or
> 1.  The E/A page 279 explains the format, and Thierry
> has more info on his site too.
> 
> I didn't care about the symbol table entry for the variable
> since the VS entry gives me a pointer to the actual data for
> the variable.  So, to get the address of the variable's
> value I need to:
> 
> 1. Get the address for the top of the VS, which is stored
> at >836E.  Since I made sure only 1 argument was
> passed, and that the argument was numeric, the top of the VS
> points to the numeric variable entry I need.
> 
> R0 now holds the CPU address of the numeric variable's
> actual data value, which is a radix-100 number.  The
> values 0 and 1 in radix-100 format look like this:
> 
> 0 in radix-100: >00 >00 >xx >xx >xx >xx
> >xx >xx
> 1 in radix-100: >40 >01 >00 >00 >00 >00
> >00 >00
> 
> The >xx is "don't care".  But since the value 1
> needs the trailing >00 values, the whole number will be
> filled out with >00.
> 
> LI   R2,8         
> MOVB R1,*R0+       * Write the
> >40
> MOVB R1,*R0+       * Write the
> >01
> That's pretty much it.  The bytes >40 and >01
> are written with MOVB instead of just MOV R1,*R0 because I
> don't know the the variable's 8-byte value is guaranteed to
> be on an even address boundary.  It probably is, but
> I'm not going to take the chance, and I want to reuse this
> code.
> 
> I'm sure people will ask why I didn't just use the NUMREF
> and NUMASG utilities.  Well, I'm a performance freak
> and I don't like branching off to other utilities if I don't
> have to.  Those utilities are general purpose, very
> heavy, and require a BLWP and all that.  And all I
> needed was to write a 0 or 1, so it seemed overkill. 
> Besides, I still needed to consult the argument type list
> and number of arguments manually, since to use the utilities
> you have to know your data types and locations in the
> argument list.
> 
> Since I only needed to report a 0 or 1, which my routine
> was already maintaining in CPU RAM, it would have been real
> nice to just do a CALL PEEK(addr,S).  The problem is,
> from XB you have no way to know what the address is. 
> And if I wrote a function to provide the address, then why
> not just return the value (which is what I did.)  I
> could have stuck the value in a well known address, but
> since XB stomps all over the CPU and VDP RAM, there was no
> place safe to do that, besides what if I needed more than 1
> value in the future?  Also, having hard-coded addresses
> in an XB program is clunky and a bad idea.
> 
> Either way, there you have it.  And think, this was
> only 1/4th of the adventure I had in the last few
> days!  I'm probably going to write up the whole
> process, so look for a future post (it has to do with
> sound.)
> 
> Matthew
> 
> 
> > Sorry Matthew, I dont know, bu if you find out, please
> let me (us) know! Maybe add an entry to the wiki or the faq,
> or just a post here!
> > 
> > > When using CALL LINK from XB to an assembly
> routing, the E/A manual says (pages 
> > > 277 and 278):
> > 
> > * The number of arguments passed is stored at
> >8312
> > * The 
> >200A.

---

From: Owen Brand <[email-masked]>
Date: Sun, 21 Feb 2010 15:52:21 -0500

Wow....  That is some excellent documentation and will be CRUCIAL to  
my upcoming efforts.  This message has been saved to my desktop.  Look  
forward to a full write up my friend.  :)

Owen Brand
Opry99er.com

On Feb 21, 2010, at 3:30 PM, "Matthew" <[email-masked]> wrote:

> Thanks everyone for the feedback. I did find the information I was  
> looking for thanks to ti99_forever telling me it is in the E/A  
> manual and to keep looking. Way in the back in the appendices (on  
> page 418) and away from the main material in section 17, there is  
> one page on the differences between the E/A utilities and the XB  
> utilities:
>
> "CALL LINK--The Editor/Assembler Loader uses its own workspace to  
> store information from the parameter list. Only the addresses >8310  
> through >8312 are reserved for parameter passing purposes. TI  
> Extended BASIC uses addresses >8300 through >8315 for this  
> information. Your assembly language program must not modify this  
> area if parameters are to be accessed in the program."
>
> So, XB CALL LINK uses >8300 through >8315 for the argument type  
> list, and the E/A CALL LINK uses >200A through >2019. My only  
> problem was that >2019 - >200A = >F (sixteen parameter types), but  
> the XB range is >8315 - >8300 = >15 (21 bytes), so where exactly are  
> the 16 argument type bytes in that range of 21 bytes?
>
> So, using intuition and Tursi's Classic99 debugger I found that XB  
> passes the argument type list starting at >8300, which makes sense  
> because section 17 talks about >8312 holding the number of arguments  
> (which it does), and >8310 holding the value stack address (which it  
> does, but it always points to the bottom of the stack when using XB,  
> For anyone interested (Mark?), what follows is what I learned about  
> parameter passing between XB and assembly.
>
> I needed to pass a parameter from my assembly routing back to XB. I  
> have never done this because I typically write everything in  
> assembly and I don't like having to keep track of all the places XB  
> uses memory (which is all over the whole system.) My routine is  
> called like this:
>
> CALL LINK("MYFUNC",S)
>
> The variable S is an XB numeric variable and is passed as a variable  
> that will receive a value from the assembly program. The LINK() call  
> can actually pass up to 16 parameters, and they can be any kind of  
> XB variable. Because of the variable nature of the number of  
> parameters and their data types (numeric, string, etc.), on the  
> assembly side you need to know what the types of each parameter are,  
> and how many were passed.
>
> It is the list of "data types" passed that I was looking for. All  
> the examples I saw in the E/A manual and everywhere else assume you  
> know the types of the parameters passed and their order, but I don't  
> like to assume and I wanted to issue an error if the wrong data type  
> was passed (rather than have my code crash.)
>
> 2. Writes the "types" of each argument as a byte array starting at  
> >8300
>
> 4. Writes (pushes) an argument "entry" for each argument on to the  
> VS (value stack) which is located in VDP RAM. The address of the VS  
> is maintained at CPU address >836E and is updated (incremented by 8)  
> for each argument. In my testing the initial value at >836E was  
> >0958 and the first parameter (the name of the linked function) was  
> first on the stack at >0960, so the VS address is adjusted *prior  
> to* a value being pushed on the stack, and the stack grows *down*  
> towards higher addresses in VDP RAM. Also, CPU RAM >8310 always  
> contained >0958, so that is possibly used as a pointer to the top of  
> the stack?
>
> The first thing you would need to check is the number of parameters  
> passed. You could check for an exact number, or that at least the  
> number of parameters you needed were passed, it is up to you. In my  
> case, I check that 1 argument is passed and that it is numeric.
>
> The entries in the VS will vary depending on the argument type,  
> which is why you need to have this list, since you can't determine  
> the VS type from the actual data on the VS. The E/A manual describes  
> the format of each type, and Thierry has details on his Tech Pages  
> (look on the BASIC Interpreter page.) Basically it goes like this:
>
> Each entry is 8-bytes:
>
> Byte 6 and 7 contain the length of the string and byte 6 is always  
> zero because strings can only be up to 255 characters long
>
> Byte 4 and 5 contain a pointer to the 8-byte value of the variable.  
> When the PEB is attached with memory expansion, this pointer is an  
> address in CPU RAM, otherwise it is a pointer to VDP RAM
> Byte 6 and 7 not used
>
> String variable type 3:
> Byte 4 and 5 contain a pointer to the string data in VDP RAM. I do  
> not know if the PEB is attached if strings are still stored in VDP  
> or CPU RAM like the numeric variables... anyone?
> Byte 6 and 7 contain the length of the string and byte 6 is always  
> zero because strings can only be up to 255 characters long
>
> Anyway, you get the idea. See the E/A manual on page 280 for the  
> format of the numeric and string arrays. I only needed the numeric  
> variable format, so I was done at that point.
>
> Now, the cool thing about the variable types (as opposed to the  
> expressions (types 0 and 1)) is that you are changing the actual  
> bytes of the variable's value, so the value you write is seen upon  
> return to XB. In C this is the same as passing by reference, i.e. a  
> pointer. You just have to make sure that you write a value in the  
> format that XB uses for the variable type, and in the case of  
> numeric variables, that is an 8-byte radix-100 numeric number. I was  
> always scared of this format because I never looked into it (fear of  
> the unknown.) Actually it is not to bad (quite easy actually,  
> compared to things like IEEE floating point formats), and I only  
> needed to return a 0 or 1. The E/A page 279 explains the format, and  
> Thierry has more info on his site too.
>
> I didn't care about the symbol table entry for the variable since  
> the VS entry gives me a pointer to the actual data for the variable.  
> So, to get the address of the variable's value I need to:
>
> 1. Get the address for the top of the VS, which is stored at >836E.  
> Since I made sure only 1 argument was passed, and that the argument  
> was numeric, the top of the VS points to the numeric variable entry  
> I need.
>
> R0 now holds the CPU address of the numeric variable's actual data  
> value, which is a radix-100 number. The values 0 and 1 in radix-100  
> format look like this:
>
> The >xx is "don't care". But since the value 1 needs the trailing  
> >00 values, the whole number will be filled out with >00.
>
> That's pretty much it. The bytes >40 and >01 are written with MOVB  
> instead of just MOV R1,*R0 because I don't know the the variable's 8- 
> byte value is guaranteed to be on an even address boundary. It  
> probably is, but I'm not going to take the chance, and I want to  
> reuse this code.
>
> I'm sure people will ask why I didn't just use the NUMREF and NUMASG  
> utilities.  Well, I'm a performance freak and I don't like branching  
> off to other utilities if I don't have to. Those utilities are  
> general purpose, very heavy, and require a BLWP and all that. And  
> all I needed was to write a 0 or 1, so it seemed overkill. Besides,  
> I still needed to consult the argument type list and number of  
> arguments manually, since to use the utilities you have to know your  
> data types and locations in the argument list.
>
> Since I only needed to report a 0 or 1, which my routine was already  
> maintaining in CPU RAM, it would have been real nice to just do a  
> CALL PEEK(addr,S). The problem is, from XB you have no way to know  
> what the address is. And if I wrote a function to provide the  
> address, then why not just return the value (which is what I did.) I  
> could have stuck the value in a well known address, but since XB  
> stomps all over the CPU and VDP RAM, there was no place safe to do  
> that, besides what if I needed more than 1 value in the future?  
> Also, having hard-coded addresses in an XB program is clunky and a  
> bad idea.
>
> Either way, there you have it. And think, this was only 1/4th of the  
> adventure I had in the last few days! I'm probably going to write up  
> the whole process, so look for a future post (it has to do with  
> sound.)
>
> Matthew
>
> > Sorry Matthew, I dont know, bu if you find out, please let me (us)  
> know! Maybe add an entry to the wiki or the faq, or just a post here!
> >
> > > When using CALL LINK from XB to an assembly routing, the E/A  
> manual says (pages
> > > 277 and 278):
> >
> > > argument types as a list of bytes are stored from >200A through  
> >2019 (16

---

From: mark wills <[email-masked]>
Date: Sun, 21 Feb 2010 20:27:42 -0800 (PST)

VERY nice, that's going in my "saved" folder!

Thanks

Mark

----- Original Message ----
> Sent: Sun, 21 February, 2010 21:30:33
> Thanks everyone for the feedback.  I did find the information I was looking for 
> thanks to ti99_forever telling me it is in the E/A manual and to keep looking.  
> Way in the back in the appendices (on page 418) and away from the main material 
> in section 17, there is one page on the differences between the E/A utilities 
> and the XB utilities:
> 
> "CALL LINK--The Editor/Assembler Loader uses its own workspace to store 
> information from the parameter list. Only the addresses >8310 through >8312 are 
> reserved for parameter passing purposes. TI Extended BASIC uses addresses >8300 
> through >8315 for this information. Your assembly language program must not 
> modify this area if parameters are to be accessed in the program."
> 
> So, XB CALL LINK uses >8300 through >8315 for the argument type list, and the 
> E/A CALL LINK uses >200A through >2019.  My only problem was that >2019 - >200A 
> = >F (sixteen parameter types), but the XB range is >8315 - >8300 = >15 (21 
> bytes), so where exactly are the 16 argument type bytes in that range of 21 
> bytes?
> 
> So, using intuition and Tursi's Classic99 debugger I found that XB passes the 
> argument type list starting at >8300, which makes sense because section 17 talks 
> about >8312 holding the number of arguments (which it does), and >8310 holding 
> the value stack address (which it does, but it always points to the bottom of 
> the stack when using XB, which means the value never changes.)
> 
> I needed to pass a parameter from my assembly routing back to XB.  I have never 
> done this because I typically write everything in assembly and I don't like 
> having to keep track of all the places XB uses memory (which is all over the 
> whole system.)  My routine is called like this:
> 
> CALL LINK("MYFUNC",S)
> 
> The variable S is an XB numeric variable and is passed as a variable that will 
> receive a value from the assembly program.  The LINK() call can actually pass up 
> to 16 parameters, and they can be any kind of XB variable.  Because of the 
> variable nature of the number of parameters and their data types (numeric, 
> string, etc.), on the assembly side you need to know what the types of each 
> It is the list of "data types" passed that I was looking for.  All the examples 
> I saw in the E/A manual and everywhere else assume you know the types of the 
> parameters passed and their order, but I don't like to assume and I wanted to 
> issue an error if the wrong data type was passed (rather than have my code 
> crash.)
> 
> 4. Writes (pushes) an argument "entry" for each argument on to the VS (value 
> stack) which is located in VDP RAM.  The address of the VS is maintained at CPU 
> address >836E and is updated (incremented by 8) for each argument.  In my 
> testing the initial value at >836E was >0958 and the first parameter (the name 
> of the linked function) was first on the stack at >0960, so the VS address is 
> adjusted *prior to* a value being pushed on the stack, and the stack grows 
> *down* towards higher addresses in VDP RAM.  Also, CPU RAM >8310 always 
> contained >0958, so that is possibly used as a pointer to the top of the stack?
> 
> The first thing you would need to check is the number of parameters passed.  You 
> could check for an exact number, or that at least the number of parameters you 
> needed were passed, it is up to you.  In my case, I check that 1 argument is 
> passed and that it is numeric.
> 
> The entries in the VS will vary depending on the argument type, which is why you 
> need to have this list, since you can't determine the VS type from the actual 
> data on the VS.  The E/A manual describes the format of each type, and Thierry 
> has details on his Tech Pages (look on the BASIC Interpreter page.)  Basically 
> it goes like this:
> 
> Each entry is 8-bytes:
> 
> Byte 6 and 7 contain the length of the string and byte 6 is always zero because 
> strings can only be up to 255 characters long
> 
> Byte 4 and 5 contain a pointer to the 8-byte value of the variable.  When the 
> PEB is attached with memory expansion, this pointer is an address in CPU RAM, 
> otherwise it is a pointer to VDP RAM
> Byte 6 and 7 not used
> 
> String variable type 3:
> Byte 4 and 5 contain a pointer to the string data in VDP RAM.  I do not know if 
> the PEB is attached if strings are still stored in VDP or CPU RAM like the 
> numeric variables...  anyone?
> Byte 6 and 7 contain the length of the string and byte 6 is always zero because 
> strings can only be up to 255 characters long
> 
> Anyway, you get the idea.  See the E/A manual on page 280 for the format of the 
> numeric and string arrays.  I only needed the numeric variable format, so I was 
> done at that point.
> 
> Now, the cool thing about the variable types (as opposed to the expressions 
> (types 0 and 1)) is that you are changing the actual bytes of the variable's 
> value, so the value you write is seen upon return to XB.  In C this is the same 
> as passing by reference, i.e. a pointer.  You just have to make sure that you 
> write a value in the format that XB uses for the variable type, and in the case 
> of numeric variables, that is an 8-byte radix-100 numeric number.  I was always 
> scared of this format because I never looked into it (fear of the unknown.)  
> Actually it is not to bad (quite easy actually, compared to things like IEEE 
> floating point formats), and I only needed to return a 0 or 1.  The E/A page 279 
> explains the format, and Thierry has more info on his site too.
> 
> I didn't care about the symbol table entry for the variable since the VS entry 
> gives me a pointer to the actual data for the variable.  So, to get the address 
> of the variable's value I need to:
> 
> 1. Get the address for the top of the VS, which is stored at >836E.  Since I 
> made sure only 1 argument was passed, and that the argument was numeric, the top 
> of the VS points to the numeric variable entry I need.
> 
> R0 now holds the CPU address of the numeric variable's actual data value, which 
> is a radix-100 number.  The values 0 and 1 in radix-100 format look like this:
> 
> The >xx is "don't care".  But since the value 1 needs the trailing >00 values, 
> the whole number will be filled out with >00.
> 
> That's pretty much it.  The bytes >40 and >01 are written with MOVB instead of 
> just MOV R1,*R0 because I don't know the the variable's 8-byte value is 
> guaranteed to be on an even address boundary.  It probably is, but I'm not going 
> to take the chance, and I want to reuse this code.
> 
> I'm sure people will ask why I didn't just use the NUMREF and NUMASG utilities.  
> Well, I'm a performance freak and I don't like branching off to other utilities 
> if I don't have to.  Those utilities are general purpose, very heavy, and 
> require a BLWP and all that.  And all I needed was to write a 0 or 1, so it 
> seemed overkill.  Besides, I still needed to consult the argument type list and 
> number of arguments manually, since to use the utilities you have to know your 
> Since I only needed to report a 0 or 1, which my routine was already maintaining 
> in CPU RAM, it would have been real nice to just do a CALL PEEK(addr,S).  The 
> problem is, from XB you have no way to know what the address is.  And if I wrote 
> a function to provide the address, then why not just return the value (which is 
> what I did.)  I could have stuck the value in a well known address, but since XB 
> stomps all over the CPU and VDP RAM, there was no place safe to do that, besides 
> what if I needed more than 1 value in the future?  Also, having hard-coded 
> addresses in an XB program is clunky and a bad idea.
> 
> Either way, there you have it.  And think, this was only 1/4th of the adventure 
> I had in the last few days!  I'm probably going to write up the whole process, 
> so look for a future post (it has to do with sound.)
> 
> Matthew
> 
> 
> --- In [email-masked], mark wills wrote:
> >
> > Sorry Matthew, I dont know, bu if you find out, please let me (us) know! Maybe 
> add an entry to the wiki or the faq, or just a post here!
> > 
> > > From: Matthew 
> > > When using CALL LINK from XB to an assembly routing, the E/A manual says 
> (pages 
> > > 277 and 278):
> >