GDMike Posted December 30, 2022 Share Posted December 30, 2022 (edited) 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 December 30, 2022 by GDMike Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 30, 2022 Share Posted December 30, 2022 41 minutes ago, Vorticon said: Got it. I have always thought these registers got altered by the XB assembly utility routines. Is this not the case? I think BLWP is "Branch and Load Workspace Pointer" and therefore switches the context, doesn't it? 1 Quote Link to comment Share on other sites More sharing options...
GDMike Posted December 30, 2022 Share Posted December 30, 2022 (edited) Moves the program counter. Yes, Edited December 30, 2022 by GDMike Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 30, 2022 Share Posted December 30, 2022 (edited) 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 December 30, 2022 by apersson850 2 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted December 30, 2022 Share Posted December 30, 2022 (edited) 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 BLWP? BLWP does not touch them because of the context switch. ...lee PS: Sorry for the redundancy. Edited December 30, 2022 by Lee Stewart comment 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 30, 2022 Share Posted December 30, 2022 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. 4 Quote Link to comment Share on other sites More sharing options...
+RXB Posted December 30, 2022 Share Posted December 30, 2022 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. XBROMS.zip Quote Link to comment Share on other sites More sharing options...
SteveB Posted December 30, 2022 Share Posted December 30, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
+RXB Posted December 31, 2022 Share Posted December 31, 2022 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. Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted December 31, 2022 Share Posted December 31, 2022 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) 1 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted December 31, 2022 Share Posted December 31, 2022 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. 3 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted December 31, 2022 Share Posted December 31, 2022 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. Quote Link to comment Share on other sites More sharing options...
+RXB Posted December 31, 2022 Share Posted December 31, 2022 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. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 1 Share Posted January 1 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). 1 Quote Link to comment Share on other sites More sharing options...
+RXB Posted January 1 Share Posted January 1 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? Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 2 Share Posted January 2 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? 1 Quote Link to comment Share on other sites More sharing options...
+RXB Posted January 2 Share Posted January 2 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 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 2 Share Posted January 2 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? 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted January 2 Share Posted January 2 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. 1 Quote Link to comment Share on other sites More sharing options...
+RXB Posted January 2 Share Posted January 2 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 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted January 3 Share Posted January 3 On 12/31/2022 at 7:22 PM, RXB said: But there are quite a few tricks they use in there you never see anywhere else. I see. I misunderstood this statement of yours, where I thought you meant that they used some clever programming style, not just a lot of code. 1 Quote Link to comment Share on other sites More sharing options...
retrodroid Posted January 4 Author Share Posted January 4 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. 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.