Jump to content
IGNORED

Tips for mixing assembly with XB


retrodroid

Recommended Posts

In my assy programs I find that 

the utility words always rely on user setting up REQUIRED registers prior to being called. 

I've made it a habit of setting a couple 2 or 3 to be used for passing values to subroutines as well. This way I know that they are corrupted on return and I handle them with care. But they are always the same registers that I set, clear / set again before sending to another sub.

I also use flags that do the same if the value needed is going to be global.

 

R0, location,(address,  screen location, buffer location)

 

R1, value word or byte

R2, number of bytes passed if needed.

R4, temp flag

R5, temp value

POS, same as R0 but global for screen location 

R3, usually it's an address location

This is my settings.. but that's me.

Because you could reserve labels to do the same.

 

Edited by GDMike
Link to comment
Share on other sites

2 hours ago, Vorticon said:

Got it. I have always thought these registers got altered by the XB assembly utility routines. Is this not the case?

As mentioned before I saw your question, no. You call them with BLWP, so they have their own workspace. The only thing you do is load address, data and a data counter in some of your own registers (as specified in the subroutine description), then BLWP @WMBW, for example. That routine will peek into your registers, via its own R13, but that's it.

I think what @GDMike wrote was to say that he does the same. Use a few registers to pass arguments to subroutines. Which is a good idea, as long as you use BLWP, of course. If you use BL, then you are in the same workspace right after the call, so you have to consider every register you use.

The subroutine called by BLWP will return via its R14, which points right after your BLWP instruction. It's only if it's expecting data inline after the call instruction (like DSRLNK usually does) it will fetch that by a MOV *R14+,xxx and thus advance the return address to be after your data.

Edited by apersson850
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

2 hours ago, Vorticon said:

Got it. I have always thought these registers got altered by the XB assembly utility routines. Is this not the case?

 

Are they not all accessed by BLWPBLWP does not touch them because of the context switch.

 

...lee

 

PS: Sorry for the redundancy.

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

34 minutes ago, Lee Stewart said:

 BLWP does not touch them because of the context switch.

To fully cover the subject:

When you call something with BLWP, the called routine gets data about the caller in the new workspace it uses.

  • R13: The caller's workpace.
  • R14: The caller's return address.
  • R15: The caller's status register.

Thus the caller can read your workspace via R13. MOV *R13,R5 will copy the caller's R0 to the called routine's R5. MOV @10(R13),R4 will move the caller's R5 to the called routine's R4.

But this works both ways, so it's possible for the called routine to return a result to the caller's register. MOV R5,@2(R13) will return the value in R5 to the caller's R1.

 

Since you can modify your return address too, it's possible to have a call like

BLWP @DSRLNK

DATA 8

In the called DSRLNK routine, there will be one instruction like MOV *R14+,R2, which copies the data after the call and at the same time advance the return address, so that you return to the instruction after the data statement.

 

Finally, the fact that you have the caller's status register content in R15 means that you can return a condition too. This code sequence will first clear, then set the equal bit on return, so the caller can use JEQ or JNE to test the outcome of the subroutine. Normally you would of course have some code in between clearing and setting, and setting should be conditional.

ANDI R15,>DFFF ;Clear equal bit

ORI R15,>2000 ;Set equal bit

This does nothing to the status register in the subroutine, but to what the status register will contain when execution is returned to the caller.

 

  • Like 4
Link to comment
Share on other sites

On 12/28/2022 at 11:14 PM, Lee Stewart said:

 

Usually you only need to bother clearing the GPL status byte just before you call a GPLLNK routine, but @apersson850’s point about clearing it before returning to XB is well taken.

 

...lee

I have yet another question on a clean return to XB ... when I mess around with different graphic modes... is there a routine to restore the standard XB resolution, characters etc? There must be a routine somewhere in the console for the initial setup of the screen, but I could not find anything in the E/A manual.

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, SteveB said:

I have yet another question on a clean return to XB ... when I mess around with different graphic modes... is there a routine to restore the standard XB resolution, characters etc? There must be a routine somewhere in the console for the initial setup of the screen, but I could not find anything in the E/A manual.

 

Sorry no, there is a routine to restore the characters set back to default (CALL CHARSET) but only restores 32 to 95.

In order to restore to XB default Graphics mode you have to restart XB. (RXB has CALL XB that does this)

Normal XB has these set up in GROM 3, GROM4 and GROM 5 and calls them before doing DSK1.LOAD

 

RXB does have CALL MOVES where you can load a string variable into the VDP Registers and change graphics modes.

RXB also has CALL POKER that allows you to load values into the F18 Graphics registers and change the graphics modes and locations.

RXB comes with a demo in the package called POKER:

100 ! POKER IS A RXB COMMANDFOR PUTTING VALUES INTO THE VDP REGISTERS 0 TO 7
110 CALL POKER(7,244,1,240)! SET RXB TO TEXT MODE
120 FOR D=0 TO 1E2 :: NEXT D
130 CALL POKER(1,232)!       SET RXB TO MULTI COLOR MODE
140 FOR D=0 TO 1E2 :: NEXT D
150 CALL POKER(0,2,1,2)!    SET RXB TO BIT MAP MODE
160 FOR D=0 TO 1E2 :: NEXT D
170 CALL POKER(0,224,0,32)! RXB NORMAL MODE

I forgot to tell you to move the VDP Stack location or it will crash some XB programs, CALL VDPSTACK(address)

  allows you to move the VDP stack to a safer location. THE MISSING LINK does same thing. 

Link to comment
Share on other sites

3 hours ago, SteveB said:

I have yet another question on a clean return to XB ... when I mess around with different graphic modes... is there a routine to restore the standard XB resolution, characters etc? There must be a routine somewhere in the console for the initial setup of the screen, but I could not find anything in the E/A manual.

Should be easy to restore manually. XB's, VDP register values, are, >00,>E0,>00,>20,>00,>06,>00,>07.(from Classic99's debugger)

  • Like 1
Link to comment
Share on other sites

4 hours ago, SteveB said:

I have yet another question on a clean return to XB ... when I mess around with different graphic modes... is there a routine to restore the standard XB resolution, characters etc? There must be a routine somewhere in the console for the initial setup of the screen, but I could not find anything in the E/A manual.

 

Yes, you can do this using

BLWP @GPLLNK

DATA >6917

 

This is a GPL routine used by XB that will:

Clear the screen

Initialize the random number generator

load the character sets

set the background to cyan

set the character colors

initialize the sprites

sets all the VDP registers except for R0

 

Also, I think you have to move the byte for VR1 (which is >E0) to @>83D4

 

Here's the problem. The XB support utilities loaded with CALL INIT do not include GPLLNK or DSRLNK. I have always used Millers Graphics GPL and DSRLNK for this.

If you use XB 2.9 G.E.M. then you can CALL INITG and those will be loaded in addition to the usual support utilities.

GPLLNK    EQU >24F4

DSRLNK   EQU >253A

 

Another advantage of XB 2.9 G.E.M. is that CALL LOAD will load the assembly program 20 times faster. As your assembly programs grow in length, you will start to appreciate this more and more.

 

 

  • Like 3
Link to comment
Share on other sites

16 hours ago, RXB said:

If you want a great listing of what Assembly can do with BL and BLWP take a look at the XB ROMS and how much is there for only 12K of Assembly.

I think SPEED subroutine is the one that is most impressive and complicated.

It's too complicated for a beginner to understand the concept, though.

Link to comment
Share on other sites

6 hours ago, apersson850 said:

It's too complicated for a beginner to understand the concept, though.

Yea even the best look at the XB ROMs and see how complicated it can get quickly.

But there are quite a few tricks they use in there you never see anywhere else.

Link to comment
Share on other sites

Any examples? 

But of course there should have been some people who were good at the TMS 9900 involved in the development. Unfortunately it frequently takes far too much study to realize what they do to be able to use that just to set an example for your own work, if you are actually trying to do something else, not really work on that program (Extended BASIC in this case).

  • Like 1
Link to comment
Share on other sites

1 hour ago, apersson850 said:

Any examples? 

But of course there should have been some people who were good at the TMS 9900 involved in the development. Unfortunately it frequently takes far too much study to realize what they do to be able to use that just to set an example for your own work, if you are actually trying to do something else, not really work on that program (Extended BASIC in this case).

2785 7502              AORG >7502   
  2787                
  2788 7502 A000  CONTAD DATA >A000             Address of a continue stmt  
  2789      A026  GPLIST EQU  >A026             GPL subprogram linked list  
  2790                
  2791      00C8  UNQSTZ EQU  >C8               Unquoted string token   
  2792                

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0064
  2793 7504 8000  INUSE  DATA >8000             In-use flag   
  2794 7506 4000  FNCFLG DATA >4000             User-defined function flag  
  2795 7508 2000  SHRFLG DATA >2000             Shared-value flag   
  2796            *   
  2797            * ERROR CODES   
  2798            *   
  2799      1203  ERRSND EQU  >1203             * SUBEND NOT IN SUBPROGRAM  
  2800      0F03  ERRREC EQU  >0F03             * RECURSIVE SUBPROGRAM CALL   
  2801      0E03  ERRIAL EQU  >0E03             * INCORRECT ARGUMENT LIST   
  2802      1103  ERROLP EQU  >1103             * ONLY LEGAL IN A PROGRAM   
  2803                
  2804            ************************************************************
  2805            * CALL - STATEMENT EXECUTION  
  2806            * Finds the subprogram specified in the subprogram table,   
  2807            * evaluates and assigns any arguments to the formal   
  2808            * parameters, builds the stack block, and transfers control 
  2809            * into the subprogram.  
  2810            *  General register usage:  
  2811            *     R0 - R6 Temporaries   
  2812            *     R7      Pointer into formals in subprogram name entry 
  2813            *     R8      Character returned by PGMCHR  
  2814            *     R9      Subroutine stack  
  2815            *     R10     Temporary   
  2816            *     R11     Return link   
  2817            *     R12     Temporary   
  2818            *     R13     GROM read-data address  
  2819            *     R14     Interpreter flags   
  2820            *     R15     VDP write-address address   
  2821            ************************************************************
  2822 750A 06A0  CALL   BL   @PGMCHR           Skip UNQSTZ & get name length 
       750C 6C74  
  2823 750E D808         MOVB R8,@FAC15         Save lengthfor FBS  
       7510 8359  
  2824 7512 D108         MOVB R8,R4             For the copies to be made   
  2825 7514 0984         SRL  R4,8               below  
  2826 7516 C020         MOV  @PGMPTR,R0        Get pointer to name   
       7518 832C  
  2827 751A D060         MOVB @RAMFLG,R1        ERAM or VDP?  
       751C 8389  
  2828 751E 130D         JEQ  CALL04            VDP   
  2829            * ERAM, must copy into VDP  
  2830 7520 C140         MOV  R0,R5             Pointer to string in ERAM   
  2831 7522 0200         LI   R0,CRNBUF         Destination in VDP  
       7524 0820  
  2832 7526 C0C4         MOV  R4,R3             Length for this move  
  2833 7528 D7E0         MOVB @R0LB,*R15        Load out the VDP write address
       752A 83E1  
  2834 752C 0260         ORI  R0,WRVDP          Enable the VDP write  
       752E 4000  
  2835 7530 D7C0         MOVB R0,*R15           Second byte of VDP write  
  2836 7532 D835  CALL02 MOVB *R5+,@XVDPWD      Move a byte   
       7534 8C00  
  2837 7536 0603         DEC  R3                One less byte to move   
  2838 7538 16FC         JNE  CALL02            Loop if not done  
  2839 753A A804  CALL04 A    R4,@PGMPTR        Skip over the name  
       753C 832C  
  2840 753E 0201         LI   R1,FAC            Destination in CPU  
       7540 834A  
  2841 7542 D7E0         MOVB @R0LB,*R15        Load out VDP read address   

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0065
       7544 83E1  
  2842 7546 0240         ANDI R0,>3FFF          Kill VDP write-enable   
       7548 3FFF  
  2843 754A D7C0         MOVB R0,*R15           Both bytes  
  2844 754C 1000         NOP                    Don't go to fast for it   
  2845 754E DC60  CALL06 MOVB @XVDPRD,*R1+      Move a byte   
       7550 8800  
  2846 7552 0604         DEC  R4                One less bye to move  
  2847 7554 16FC         JNE  CALL06            Loop if not done  
  2848 7556 C120         MOV  @SUBTAB,R4        Get beginning of subpgm table 
       7558 833A  
  2849 755A 133C         JEQ  SCAL89            If table empty, search in GPL 
  2850 755C 06A0         BL   @FBS001           Search subprogram table   
       755E 15E6  
  2851 7560 75D4         DATA SCAL89            If not found, search in GPL   
  2852            * Pointer to table entry returned in both R4 and FAC  
  2853 7562 06A0         BL   @PGMCHR           Get next token  
       7564 6C74  
  2854 7566 C0C4         MOV  R4,R3             Duplicate pointer for GETV  
  2855 7568 06A0         BL   @GETV1            Get flag byte   
       756A 1880  
  2856 756C 1130         JLT  SCAL90            If attempted recursive call   
  2857 756E 0A11         SLA  R1,1              Check for BASIC/GPL program   
  2858 7570 1106         JLT  GPLSU             GPL subprogram  
  2859 7572 D2E0         MOVB @PRGFLG,R11       Imperative call to BASIC sub? 
       7574 8344  
  2860 7576 1614         JNE  SCAL01            No, OK-handle BASIC subprogram
  2861 7578 0200         LI   R0,ERROLP         Can't call a BASIC sub  
       757A 1103  
  2862 757C 102D         JMP  SCAL91              imperatively  
  2863            *   
  2864            * Handle a GPL subprogram   
  2865            *   
  2866 757E 05C9  GPLSU  INCT R9  
  2867 7580 CE60         MOV  @CONTAD,*R9+      Put address of a cont on stack
       7582 7502  
  2868 7584 C64D         MOV  R13,*R9           Save address for real BASIC   
  2869 7586 0223         AI   R3,6              Now set up new environment  
       7588 0006  
  2870 758A 06A0         BL   @GET1             Get access address of GPL subp
       758C 6C9E  
  2871 758E DB41         MOVB R1,@GRMWAX(R13)    Load out the address into GRO
       7590 0402  
  2872 7592 06C1         SWPB R1                Need to kill time here  
  2873 7594 DB41         MOVB R1,@GRMWAX(R13)    Next byte also   
       7596 0402  
  2874 7598 06A0         BL   @SAVREG           Restore registers to GPL  
       759A 1E8C  
  2875 759C 0460         B    @RESET            And enter the routine   
       759E 006A  
  2876            *   
  2877            * Execute BASIC subprogram  
  2878            *   
  2879      75A0  SCAL01 EQU  $   
  2880            *-----------------------------------------------------------
  2881            * Fix "An error happened in a CALL statement keeps its  
  2882            *      in-use flag set" bug.  5/12/81   
  2883            *  Move the following 3 lines after finishing processing  
  2884            *  the parameter list, before entering the subprogram.  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0066
  2885            *        SRL  R1,1             Restore mode to original form
  2886            *        SOCB @INUSE,R1        Set the in-use flag bit  
  2887            *        BL   @PUTV1           Put the byte back  
  2888            * Save the pointer to table entry for setting in-use flag   
  2889            * later.  
  2890            * $$$$$$$ USE VDP(0374) 2 BYTES AS TEMPRORARY HERE  
  2891 75A0 0204         LI   R4,>0374          R4: address register for PUT1 
       75A2 0374  
  2892 75A4 C043         MOV  R3,R1             R1: data register for PUT1  
  2893 75A6 06A0         BL   @PUT1             Save the pointer to table   
       75A8 6CB2  
  2894            *                              entry in VDP temporary   
  2895            *-----------------------------------------------------------
  2896 75AA C303         MOV  R3,R12            Save subtable address   
  2897 75AC 04E0         CLR  @FAC2             Indicate non-special entry  
       75AE 834C  
  2898 75B0 06A0         BL   @VPUSH            Push subprogram entry on stack
       75B2 6BAA  
  2899 75B4 C10C         MOV  R12,R4            Restore sub table address   
  2900 75B6 C1C4         MOV  R4,R7   
  2901 75B8 0227         AI   R7,6              Point to 1st argument in list 
       75BA 0006  
  2902 75BC C0C7         MOV  R7,R3             Formals' pointer  
  2903 75BE 06A0         BL   @GET1             Check to see if any   
       75C0 6C9E  
  2904 75C2 C041         MOV  R1,R1             Any args?   
  2905 75C4 133F         JEQ  SCAL32            None, jump forward  
  2906 75C6 0288         CI   R8,LPARZ*256      Must see a left parenthesis   
       75C8 B700  
  2907 75CA 1640         JNE  SCAL34            If not, error   
  2908 75CC 1013         JMP  SCAL08            Jump into argument loop   
  2909 75CE 0200  SCAL90 LI   R0,ERRREC         * RECURSIVE SUBPROGRAM CALL   
       75D0 0F03  
  2910 75D2 1002         JMP  SCAL91  
  2911 75D4 0200  SCAL89 LI   R0,>000A          GPL check for DSR subprogram  
       75D6 000A  
  2912 75D8 0460  SCAL91 B    @ERR  
       75DA 6652  
  2913 75DC 1031  SCAL93 JMP  SCAL12            Going down!   
  2914 75DE 06A0  SCAL05 BL   @POPSTK           Short stack pop routine   
       75E0 60D4  
  2915 75E2 C1E0         MOV  @ARG4,R7          To quickly restore R7   
       75E4 8360  
  2916 75E6 05C7         INCT R7                To account for SCAL80   
  2917 75E8 0288  SCAL06 CI   R8,RPARZ*256      Actual list ended?  
       75EA B600  
  2918 75EC 132D         JEQ  SCAL30            Actuals all scanned   
  2919 75EE 0288         CI   R8,COMMAZ*256     Must see a comma then   
       75F0 B300  
  2920 75F2 1626         JNE  SCAL12            Didn't, so error  
  2921            * Scan next actual. Check if it is just a name  
  2922 75F4 C820  SCAL08 MOV  @PGMPTR,@ERRCOD   Save text ptr in case of expr 
       75F6 832C  
       75F8 8322  
  2923 75FA 06A0         BL   @PGMCHR           Get next character  
       75FC 6C74  
  2924 75FE 1179         JLT  SCAL40            No, so must be an expression  
  2925 7600 C307         MOV  R7,R12            Save formals pointer  
  2926 7602 06A0         BL   @SYM              Read name & see if recognized 

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0067
       7604 6312  
  2927 7606 06A0         BL   @GETV             Check function flag   
       7608 187C  
  2928 760A 834A         DATA FAC   
  2929 760C C1CC         MOV  R12,R7            Restore formals pointer first 
  2930 760E 2460         CZC  @FNCFLG,R1        User-defined function?  
       7610 7506  
  2931 7612 166F         JNE  SCAL40            Yes, pass by value  
  2932 7614 0288         CI   R8,LPARZ*256      Complex type?   
       7616 B700  
  2933 7618 1620         JNE  SCAL15            No  
  2934 761A 06A0         BL   @PGMCHR           Check if formal entry   
       761C 6C74  
  2935 761E 0288         CI   R8,RPARZ*256      FOO() ?   
       7620 B600  
  2936 7622 1319         JEQ  SCAL14            Yes, handle it as such  
  2937 7624 0288         CI   R8,COMMAZ*256     or FOO(,...) ?  
       7626 B300  
  2938 7628 1613         JNE  SCAL35            No, an array element FOO(I... 
  2939 762A 06A0  SCAL10 BL   @PGMCHR           Formal array, scan to end   
       762C 6C74  
  2940 762E 06A0         BL   @EOSTMT           Check if end-of-statement   
       7630 6862  
  2941 7632 1306         JEQ  SCAL12            Premature end of statement  
  2942 7634 0288         CI   R8,COMMAZ*256     Another comma?  
       7636 B300  
  2943 7638 13F8         JEQ  SCAL10            Yes, continue on to end   
  2944 763A 0288         CI   R8,RPARZ*256      End yet?  
       763C B600  
  2945 763E 130B         JEQ  SCAL14            Yes, merge in below   
  2946 7640 0460  SCAL12 B    @ERRONE           * SYNTAX ERROR  
       7642 664E  
  2947 7644 0460  SCAL32 B    @SCAL62           Going down!   
       7646 77B8  
  2948 7648 0460  SCAL30 B    @SCAL60   
       764A 77B4  
  2949 764C 0460  SCAL34 B    @SCAL88   
       764E 7878  
  2950 7650 0460  SCAL35 B    @SCAL50   
       7652 7744  
  2951 7654 10C9  SCAL37 JMP  SCAL06  
  2952            *   
  2953            * Here for Scalers/Arrays by Reference  
  2954 7656 06A0  SCAL14 BL   @PGMCHR           Pass the right parenthesis  
       7658 6C74  
  2955 765A 0288  SCAL15 CI   R8,COMMAZ*256     Just a name?  
       765C B300  
  2956 765E 1303         JEQ  SCAL16            Yes   
  2957 7660 0288         CI   R8,RPARZ*256      Start an expression?  
       7662 B600  
  2958 7664 1646         JNE  SCAL40            Yes, name starts an expression
  2959 7666 06A0  SCAL16 BL   @GETV             Get mode of name  
       7668 187C  
  2960 766A 834A         DATA FAC               Ptr to s.t. entry left by SYM 
  2961 766C D081         MOVB R1,R2             Save for check below  
  2962 766E 06A0         BL   @SCAL80           And fetch next formal info  
       7670 787E  
  2963 7672 D042         MOVB R2,R1             Copy for this check   
  2964 7674 0241         ANDI R1,>C700            for the comparison  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0068
       7676 C700  
  2965 7678 C006         MOV  R6,R0             Use a temporary rgister   
  2966 767A 0240         ANDI R0,>C700            for the comparison  
       767C C700  
  2967 767E 8001         C    R1,R0             Must be exact match   
  2968 7680 16E5         JNE  SCAL34            Else can't pass by reference  
  2969 7682 E1A0         SOC  @SHRFLG,R6        Set the shared symbol flag  
       7684 7508  
  2970 7686 D046         MOVB R6,R1             Load up for PUTV  
  2971 7688 C105         MOV  R5,R4             Address to put the flag   
  2972 768A 06A0         BL   @PUTV1            Set the flag in the s.t. entry
       768C 6422  
  2973 768E 0244         ANDI R4,>3FFF          Kill VDP write-enable bit   
       7690 3FFF  
  2974            *   
  2975            * The following section finds actual's value space address  
  2976            *  and puts it in R1.   
  2977            *  FAC contains the symbol table's address.   
  2978            * If actual is NOT shared.......................  
  2979            *  Symbol table's address+6 will point to the value space   
  2980            *   except for numeric ERAM cae. In a numeric ERAM case   
  2981            *   GET1 to get pointer to the ERAM value space.  
  2982            * If actual is SHARED........................   
  2983            *  GET1 to get the pointer in symbol table's address+6  
  2984            *  In a numeric ERAM case, GETG to get the indirect point   
  2985            *   to the actual's vlaue space pointer after GET1 is call  
  2986            *   
  2987 7692 C060         MOV  @FAC,R1           Ptr to actual s.t. entry  
       7694 834A  
  2988 7696 0221         AI   R1,6              Ptr to actuals value space  
       7698 0006  
  2989 769A 0246         ANDI R6,>8700          Keep info on string or array  
       769C 8700  
  2990 769E 0242         ANDI R2,>2000          Is actual shared?   
       76A0 2000  
  2991 76A2 130C         JEQ  SCAL23            No, use it  
  2992 76A4 C0C1         MOV  R1,R3             Else look further   
  2993 76A6 06A0         BL   @GET1             Get the true pointer  
       76A8 6C9E  
  2994 76AA D186         MOVB R6,R6             Array or string?  
  2995 76AC 160F         JNE  SCAL24            Yes, both are special cases   
  2996 76AE D0A0         MOVB @RAMTOP,R2        ERAM present?   
       76B0 8384  
  2997 76B2 130C         JEQ  SCAL24            No ERAM, so skip  
  2998            * Numeric variable, shared, ERAM.   
  2999 76B4 C0C1         MOV  R1,R3             Get ptr to original from ERAM 
  3000 76B6 06A0         BL   @GETG2            Get indirect pointer  
       76B8 6CCE  
  3001 76BA 1008         JMP  SCAL24  
  3002            * Shared bit is NOT on.   
  3003 76BC D186  SCAL23 MOVB R6,R6             Check for array or string   
  3004 76BE 1606         JNE  SCAL24            Yes, take what's in there   
  3005 76C0 D0A0         MOVB @RAMTOP,R2        ERAM exists?  
       76C2 8384  
  3006 76C4 1303         JEQ  SCAL24            No  
  3007 76C6 C0C1         MOV  R1,R3             Numeric and ERAM case   
  3008 76C8 06A0         BL   @GET1             Get ERAM value space address  
       76CA 6C9E  
  3009            *                             R4 pointing to value space of 

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0069
  3010 76CC 0224  SCAL24 AI   R4,6               subprogram's symbol table  
       76CE 0006  
  3011 76D0 D186         MOVB R6,R6             Array or string case?   
  3012 76D2 160C         JNE  SCAL26            Yes, so just put ptr in VDP   
  3013            * Here check for ERAM program and if ERAM then copy the   
  3014            * address of shared value space into corresponding value  
  3015            * space in ERAM   
  3016 76D4 D1A0         MOVB @RAMTOP,R6        Get the ERAM flag   
       76D6 8384  
  3017 76D8 1309         JEQ  SCAL26            If no ERAM, simple case   
  3018 76DA C181         MOV  R1,R6             Keep shared value space addres
  3019 76DC C0C4         MOV  R4,R3             Put ptr in value space in ERAM
  3020 76DE 06A0         BL   @GET1             Get value space address in ERA
       76E0 6C9E  
  3021 76E2 C101         MOV  R1,R4             Copy address into R4 for PUTG2
  3022 76E4 C046         MOV  R6,R1             Get the value to put in ERAM  
  3023 76E6 06A0         BL   @PUTG2            Write it into ERAM  
       76E8 6CD8  
  3024 76EA 10B4         JMP  SCAL37            Loop for next argument  
  3025 76EC 06A0  SCAL26 BL   @PUT1             Set symbol indirect link  
       76EE 6CB2  
  3026 76F0 10B1         JMP  SCAL37            And loop for next arg   
  3027            *   
  3028            * Here to pass an expression by value   
  3029            *   
  3030 76F2 C820  SCAL40 MOV  @ERRCOD,@PGMPTR   Restore text pointer  
       76F4 8322  
       76F6 832C  
  3031 76F8 C807         MOV  R7,@FAC4          Save formals pointer  
       76FA 834E  
  3032 76FC 04E0         CLR  @FAC2             Don't let VPUSH mess up   
       76FE 834C  
  3033 7700 06A0  SCAL42 BL   @PGMCHR           Set up for the parse  
       7702 6C74  
  3034            * Save formals ptr & SUBTAB ptr and evaluate the expression 
  3035 7704 06A0         BL   @PSHPRS   
       7706 6B9C  
  3036 7708   B6         BYTE RPARZ             Stop on an rpar or comma  
  3037 7709   6A  DCBH6A BYTE >6A               (CBH6A copy)  
  3038 770A 06A0         BL   @POPSTK           Restore formals pointer   
       770C 60D4  
  3039 770E A820         A    @C16,@VSPTR       But keep it on stack  
       7710 6BF8  
       7712 836E  
  3040 7714 06A0         BL   @VPUSH            Save parse result   
       7716 6BAA  
  3041 7718 C1E0         MOV  @ARG4,R7          Restore formals pointer   
       771A 8360  
  3042 771C 06A0         BL   @SCAL80           And fetch next formal's info  
       771E 787E  
  3043 7720 C805         MOV  R5,@FAC           Set up for assignment   
       7722 834A  
  3044 7724 06A0         BL   @SMB              Get value space   
       7726 61DC  
  3045 7728 6820         S    @C16,@VSPTR       Get to s.t. info  
       772A 6BF8  
       772C 836E  
  3046 772E 06A0         BL   @VPUSH            Set up for ASSG   
       7730 6BAA  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0070
  3047 7732 A820         A    @C8,@VSPTR        Get back to parse result  
       7734 706C  
       7736 836E  
  3048 7738 06A0         BL   @VPOP             Get parse result back   
       773A 6C2A  
  3049 773C 06A0         BL   @ASSG             Assign the value to the formal
       773E 6334  
  3050 7740 0460         B    @SCAL05           And go back for more  
       7742 75DE  
  3051            *   
  3052            * Here for array elements   
  3053            *   
  3054 7744 0620  SCAL50 DEC  @PGMPTR           Restore text pointer to lpar  
       7746 832C  
  3055 7748 020B         LI   R11,FAC2          Optimize to save  
       774A 834C  
  3056 774C 04FB         CLR  *R11+             Don't let VPUSH mess up (FAC2)
  3057 774E CEC7         MOV  R7,*R11+          Save formals pointer    (FAC4)
  3058 7750 C6E0         MOV  @ERRCOD,*R11      For save on stack       (FAC6)
       7752 8322  
  3059 7754 06A0         BL   @VPUSH            Save the info   
       7756 6BAA  
  3060 7758 0208         LI   R8,LPARZ*256      Load up R8 with the lpar again
       775A B700  
  3061 775C C820         MOV  @FAC,@PAD0        Save ptr to s.t. entry  
       775E 834A  
       7760 8300  
  3062 7762 06A0         BL   @SMB              Check if name or expression   
       7764 61DC  
  3063 7766 0288         CI   R8,COMMAZ*256   
       7768 B300  
  3064 776A 1309         JEQ  SCAL54            Name if ended on a comma  
  3065 776C 0288         CI   R8,RPARZ*256  
       776E B600  
  3066 7770 1306         JEQ  SCAL54             or rpar  
  3067 7772 06A0         BL   @VPOP             Get saved info back   
       7774 6C2A  
  3068 7776 C820         MOV  @FAC6,@PGMPTR     Else expr, Restore test pointe
       7778 8350  
       777A 832C  
  3069 777C 10C1         JMP  SCAL42            And handle like an expression 
  3070            *   
  3071            * Passing array elements by reference   
  3072 777E 06A0  SCAL54 BL   @POPSTK           Restore symbol pointer  
       7780 60D4  
  3073 7782 C1E0         MOV  @ARG4,R7  
       7784 8360  
  3074 7786 06A0         BL   @SCAL80           Get next formal's info  
       7788 787E  
  3075 778A 06A0         BL   @GETV             Check actualOs mode   
       778C 187C  
  3076 778E 8300         DATA PAD0              Get back header information   
  3077 7790 0241         ANDI R1,>C000          Throw away all but string & fu
       7792 C000  
  3078 7794 9046         CB   R6,R1             Check mode match (string/num) 
  3079 7796 1612         JNE  JNE88             Don't, so error   
  3080            * Can set bit in R1 since MSB (R1)=MSB (R6)   
  3081 7798 F060         SOCB @SHRFLG,R1        Set the share flag  
       779A 7508  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0071
  3082 779C C105         MOV  R5,R4             Address for PUTV  
  3083 779E 06A0         BL   @PUTV1            Put it in the s.t. entry  
       77A0 6422  
  3084 77A2 0244         ANDI R4,>3FFF          Kill VDP write, enable bit  
       77A4 3FFF  
  3085 77A6 C060         MOV  @FAC,R1           Assuming string, ref link=@FAC
       77A8 834A  
  3086 77AA D186         MOVB R6,R6             Check if it is a string   
  3087 77AC 118F         JLT  SCAL24            If so, go set ref. link   
  3088 77AE C060         MOV  @FAC4,R1          Numeric, ref. link=@FAC4(v.s.)
       77B0 834E  
  3089 77B2 108C         JMP  SCAL24            Now set the link and go on  
  3090            *   
  3091            * Here when done parsing actuals  
  3092            *   
  3093 77B4 06A0  SCAL60 BL   @PGMCHR           Pass the right parenthesis  
       77B6 6C74  
  3094 77B8 06A0  SCAL62 BL   @EOSTMT           Must be at end of statement   
       77BA 6862  
  3095 77BC 165D  JNE88  JNE  SCAL88            If not, error   
  3096 77BE C0C7         MOV  R7,R3             Formals must also have ended  
  3097 77C0 05C7         INCT R7  
  3098 77C2 C807         MOV  R7,@FAC           Keep R7, POPSTK destorys R7   
       77C4 834A  
  3099 77C6 06A0         BL   @GET1             Get the last arg address  
       77C8 6C9E  
  3100 77CA C041         MOV  R1,R1             Formals end?  
  3101 77CC 1655         JNE  SCAL88            Didn't, so error  
  3102            *   
  3103            * Now set up the stack entry  
  3104            *   
  3105 77CE 06A0         BL   @VPUSH            Check if enough room for push 
       77D0 6BAA  
  3106 77D2 6820         S    @C8,@VSPTR        Get back right pointer  
       77D4 706C  
       77D6 836E  
  3107 77D8 06A0         BL   @POPSTK           Retrieve ptr to subprog s.t.  
       77DA 60D4  
  3108 77DC 020C         LI   R12,FAC           For code optimization   
       77DE 834A  
  3109 77E0 C04C         MOV  R12,R1            Store following data in FAC   
  3110 77E2 C81C         MOV  *R12,@ARG2        Save new environment pointer  
       77E4 835E  
  3111            *   
  3112            * First push entry. PGMCHR, EXTRAM, SYMTAB and RAM(SYNBOL)  
  3113            *   
  3114 77E6 0200         LI   R0,PGMPTR         Optimize  
       77E8 832C  
  3115 77EA CC70         MOV  *R0+,*R1+         Text pointer         PGMPTR   
  3116 77EC CC70         MOV  *R0+,*R1+         Line table pointer   EXTRAM   
  3117 77EE CC60         MOV  @SYMTAB,*R1+      Symbol table pointer  
       77F0 833E  
  3118 77F2 0203         LI   R3,SYMBOL         Put address of SYMBOL   
       77F4 0376  
  3119 77F6 06A0         BL   @GET1             Get RAM(SYMBOL) in REG1   
       77F8 6C9E  
  3120 77FA C801         MOV  R1,@FAC6          Move to FAC area  
       77FC 8350  
  3121 77FE 06A0         BL   @VPUSH            Save first entry  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0072
       7800 6BAA  
  3122            *   
  3123            * Push second entry. Subprogram table pointer, >6A on warnin
  3124            *  bits and @LSUBP in the second stack.   
  3125 7802 C10C         MOV  R12,R4            Going to build entry in FAC   
  3126 7804 CD20         MOV  @ARG,*R4+         Subprogram table entry pointer
       7806 835C  
  3127 7808 DD20         MOVB @DCBH6A,*R4+      >6A = Stack ID  
       780A 7709  
  3128 780C D0A0         MOVB @FLAG,R2          Warning/break bits  
       780E 8345  
  3129 7810 0242         ANDI R2,>0600          Mask off other bits   
       7812 0600  
  3130 7814 DD02         MOVB R2,*R4+           Put bits in stack entry   
  3131 7816 C820         MOV  @LSUBP,@FAC6      Last subprogram block on stack
       7818 8348  
       781A 8350  
  3132 781C 06A0         BL   @VPUSH            Push final entry  
       781E 6BAA  
  3133 7820 C820         MOV  @VSPTR,@LSUBP     Set bottom of stack for the su
       7822 836E  
       7824 8348  
  3134            *   
  3135            * Now build the new environment by modifying PGMCHR,  
  3136            * EXTRAM and pointer to sub's symbol table.   
  3137 7826 0200         LI   R0,PGMPTR         Optimization  
       7828 832C  
  3138 782A D7E0         MOVB @ARG3,*R15        2nd byte of address   
       782C 835F  
  3139 782E 0201         LI   R1,XVDPRD         Optimize to save bytes  
       7830 8800  
  3140 7832 D7E0         MOVB @ARG2,*R15        1st byte of address   
       7834 835E  
  3141 7836 0204         LI   R4,4              Need 4 bytes  
       7838 0004  
  3142 783A DC11  SCAL70 MOVB *R1,*R0+          Read EXTRAM and PGMPTR  
  3143 783C 0604         DEC  R4  
  3144 783E 16FD         JNE  SCAL70  
  3145 7840 D811         MOVB *R1,@SYMTAB       New SYMTAB  
       7842 833E  
  3146 7844 0204         LI   R4,SYMBOL   
       7846 0376  
  3147 7848 D811         MOVB *R1,@SYMTA1   
       784A 833F  
  3148 784C C060         MOV  @SYMTAB,R1  
       784E 833E  
  3149 7850 06A0         BL   @PUT1             New RAM(SYMBOL)   
       7852 6CB2  
  3150 7854 04E0         CLR  @ERRCOD           Clean up our mess   
       7856 8322  
  3151 7858 06A0         BL   @PGMCHR           Get the next token into R8  
       785A 6C74  
  3152            *-----------------------------------------------------------
  3153            * Fix "A error happened in a CALL statement keeps it  
  3154            *   "in-use flag set" bug,    5/23/81   
  3155            * Insert following lines:   
  3156 785C 0203         LI   R3,>0374          Restore the pointer to table  
       785E 0374  
  3157            *  entry from VDP temporary, R3: address reg. for GET1  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0073
  3158 7860 06A0         BL   @GET1   
       7862 6C9E  
  3159 7864 C0C1         MOV  R1,R3             Get flag byte   
  3160 7866 06A0         BL   @GETV1  
       7868 1880  
  3161 786A F060         SOCB @INUSE,R1         Set the in-use flag bit   
       786C 7504  
  3162 786E C103         MOV  R3,R4             ??????????????????????????????
  3163 7870 06A0         BL   @PUTV1            Put the byte back   
       7872 6422  
  3164            *-----------------------------------------------------------
  3165 7874 0460         B    @NUDEND           Enter the subprogram  
       7876 65F0  
  3166 7878 0200  SCAL88 LI   R0,ERRIAL         * INCORRECT ARGUMENT LIST   
       787A 0E03  
  3167 787C 1062         JMP  $+>C6             Jump to  B @ERR   
  3168            ************************************************************
  3169            * Fetch next formal and prop for adjustment   
  3170            * Register modification   
  3171            *    R5  Address of s.t. entry (formal's entry)   
  3172            *    R6  Header byte of formal's entry  
  3173            *    R7  Updated formal's pointer   
  3174            * Destroys: R1, R2, R3, R4, R11, R12  
  3175            ************************************************************
  3176 787E C30B  SCAL80 MOV  R11,R12           Save return address   
  3177 7880 C0C7         MOV  R7,R3             Fetch symbol pointer  
  3178 7882 05C7         INCT R7                Point to next formal  
  3179 7884 06A0         BL   @GET1             Fetch s.t. pointer  
       7886 6C9E  
  3180 7888 C0C1         MOV  R1,R3             Set condition & put in place  
  3181 788A 13F6         JEQ  SCAL88            If to many actuals  
  3182 788C C101         MOV  R1,R4             Save for below  
  3183 788E C141         MOV  R1,R5             Save for return   
  3184 7890 06A0         BL   @GET1             Get header bytes  
       7892 6C9E  
  3185 7894 2060         COC  @SHRFLG,R1        Shared?   
       7896 7508  
  3186 7898 1313         JEQ  SCAL82            Yes, reset flag and old value 
  3187 789A C181         MOV  R1,R6             Save for return & test string 
  3188 789C 1101         JLT  SCAL81            If it is a string, then SCAL81
  3189 789E 045C         B    *R12              Return  
  3190 78A0 0223  SCAL81 AI   R3,6              Is string, point at value ptr 
       78A2 0006  
  3191 78A4 06A0         BL   @GET1             Get the value pointer   
       78A6 6C9E  
  3192 78A8 C101         MOV  R1,R4             Null value?   
  3193 78AA 1312         JEQ  SCAL86            Yes   
  3194 78AC 04C1         CLR  R1                No, must free current string  
  3195 78AE 0224         AI   R4,-3             Point at the backpointer  
       78B0 FFFD  
  3196 78B2 06A0         BL   @PUT1             Clear the backpointer   
       78B4 6CB2  
  3197 78B6 C103         MOV  R3,R4   
  3198 78B8 04C1  SCAL84 CLR  R1                Needed for entry from below   
  3199 78BA 06A0         BL   @PUT1             Clear the forward pointer   
       78BC 6CB2  
  3200 78BE 045C         B    *R12              Just return   
  3201 78C0 0241  SCAL82 ANDI R1,>DFFF          Reset the share flag  
       78C2 DFFF  

 99/4 ASSEMBLER
SUBPROGS                                                     PAGE 0074
  3202 78C4 06A0         BL   @PUTV1            Put it there  
       78C6 6422  
  3203 78C8 0224         AI   R4,6              Point at ref pointer  
       78CA 0006  
  3204 78CC C181         MOV  R1,R6             Set for return  
  3205 78CE 11F4         JLT  SCAL84            If string clear ref pointer   
  3206 78D0 045C  SCAL86 B    *R12              Return  
  3207            ************************************************************

Ever wonder how a CALL works in XB?

Link to comment
Share on other sites

19 minutes ago, TheBF said:

Holy crap that's a lot of code to call a sub-routine.

I see R9 is a return stack pointer.  What is the base address of that stack in XB?

Well it finds any name you give a SUB up to 16 character names for a SUB like say SUB TESTANAMELIKETHIS(variable(2,1,2),X)

It finds any name like CALL HCHAR or CALL SPRITE or CALL PATTERN

It finds and sets up all ARRAY values by name.

It finds variable names and sets them up in memory.

It also looks for any CALL that is outside of XB like say CALL CAT on the TIPI or a RAMDISK name.

 

VDP Stack is normally set to >0958 

The Subroutine stack is pointed to by >8388

 

  • Thanks 1
Link to comment
Share on other sites

8 hours ago, TheBF said:

Holy crap that's a lot of code to call a sub-routine.

The ability to create your own subprograms is one of the more powerful in Extended BASIC, so the amount of code is not too surprising.

Looking at it for a couple of minutes I didn't locate any particular way of programming, smart trick, clever use of instructions and/or addressing or similar. Just a lot of options to handle. Did I miss something?

  • Like 1
Link to comment
Share on other sites

6 hours ago, apersson850 said:

The ability to create your own subprograms is one of the more powerful in Extended BASIC, so the amount of code is not too surprising.

Looking at it for a couple of minutes I didn't locate any particular way of programming, smart trick, clever use of instructions and/or addressing or similar. Just a lot of options to handle. Did I miss something?

I think that your grasp of it is far better than mine so I don't think so.

Sub programs were my one of my favourite features of XB but I had never considered what it took to implement them in Assembler.

 

  • Like 1
Link to comment
Share on other sites

9 hours ago, apersson850 said:

The ability to create your own subprograms is one of the more powerful in Extended BASIC, so the amount of code is not too surprising.

Looking at it for a couple of minutes I didn't locate any particular way of programming, smart trick, clever use of instructions and/or addressing or similar. Just a lot of options to handle. Did I miss something?

This code was written in 1980 long before most of the tricks we use today.

Actually, some of the code is from 1979.

I did not get my first TI99/4A till DEC 1983

Link to comment
Share on other sites

On 12/25/2022 at 7:08 AM, SteveB said:

Returning to the original subject: I haven't found an easy and well documented example of passing parameters from XB to AL and back, for example CALL ADD(x,5,result) .. I learned there are 6 types of parameters and there is some kind of stack. 

 

Can someone provide an example or an explanation? 

 

Thank you

Steve

Not sure if this might be redundant at this point, but I recently came across this topic in the https://ia600503.us.archive.org/7/items/tibook_introduction-to-assembly-language-for-the-ti-home-computer/introduction-to-assembly-language-for-the-ti-home-computer.pdf book - "CHAPTER ELEVEN, MIXING ASSEMBLY WITH BASIC" covers using assembly routines from both TI Basic and XB, including passing parameters into the routine.

 

1882868819_ScreenShot2023-01-04at11_34_30AM.thumb.png.8e460c91be9542c76466363650e1f59a.png

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