Willsy Posted January 20, 2016 Share Posted January 20, 2016 Yes. I think auto motion would work. I was young and not very experienced. It was my first assembly project on the 4A. I whince at the code: using MPY to multiply by 32. Oh dear! I always did my assembly code with a pen then tried it out. Rinse and repeat until it worked. Even now I tend to work things out away from the computer! Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted January 21, 2016 Share Posted January 21, 2016 The demo from the disk. 6 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 21, 2016 Share Posted January 21, 2016 It looks like TI BASIC with the MiniMemory is very well suited for using the text mode. According to the memory map in MG Explorer the VDP roll out area starts at >03C0, just missing the 960 byte long screen image table for text mode which would run from >0000 to >03BF, with no bytes needed for a color table. The crunch buffer from >0320 to >036F would not cause problems because you wouldn't be using INPUT when running a program. So there shouldn't be any conflicts in VDP memory use. The assembly subroutines would be fairly straightforward. You'd need ACCEPT AT, DISPLAY AT, COLOR, CLEAR. Windowing and scrolling might be nice but are not essential. This would be a good project for someone who was getting into assembly language and wanted to try their hand at writing some assembly language extensions. (It is tougher to use text mode in XB because the Extended BASIC system area is from >0370 to >03BF which conflicts with the screen image table.) Quote Link to comment Share on other sites More sharing options...
Willsy Posted January 21, 2016 Share Posted January 21, 2016 Wow thanks for posting that! It's been 25 years since I saw that! Quote Link to comment Share on other sites More sharing options...
Tursi Posted January 22, 2016 Share Posted January 22, 2016 (It is tougher to use text mode in XB because the Extended BASIC system area is from >0370 to >03BF which conflicts with the screen image table.) XXB (Barry Traver) pulls it off okay, though, I remember playing with that one a lot. I never looked at how it does it, but the docs do note: 40-column ("text") mode in Extended BASIC has advantages but also limitations: you may have to experiment to discover what can and what cannot safely be done (e.g.; you should avoid file operations while in text mode). it also notes: Warning: text mode is an area in which the Extended BASIC programmer must walk with care. Two things to remember: (1) You must use CALL LINK("GRAPH") or its equivalent in order to return safely to graphics mode; and (2) any kind of error in text mode can throw you into never-never land! and Many CALLs accessed while in text mode create a screen "glitch;" so CALL LINK ("KEYR";RESPONSE$) is provided to avoid that problem. (One limitation that comes with working with text mode from Extended BASIC is that apparently all CALLs to user-defined subprograms will cause such glitches.) ... which probably explains most of it right there. They just let it run and avoid functions that cause issues. I know I wrote a full sector editing system in XXB back in the day which used the 40 column mode - I loved it. Attached on the off chance nobody has it, though it's off topic for this thread. XXB.DSK 2 Quote Link to comment Share on other sites More sharing options...
RXB Posted January 22, 2016 Share Posted January 22, 2016 (edited) Hmm there is a Text mode in XHI for XB using a 9938 that has 128K of VDP memory. Funnel Web took advantage of this feature that could be loaded from EA, TI BASIC or from XB. I am hopeful the Color Pallet gets fixed in MESS for the EVPC. Edited January 22, 2016 by RXB 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 23, 2016 Share Posted January 23, 2016 OK—I have TI Basic's RND in an ALC routine that can be called from TI Basic with CALL LINK("RND",X) where X is the name of the variable in which the user wants the random number returned. Harry is certainly right about the slowness of CALL. Recall from post #9 the code for GPL's RAND, which returns an 8-bit random number such that 0 <= n <= max (max is the maximum 8-bit number to be returned): * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * GPL RAND * * Uses GPL workspace. * * First, generates an unsigned, 16-bit "random" number and * * stores it at 83C0h. * * Calculation for new seed is * * ((seed * 6FE5h) & FFFFh + 7AB9h) & FFFFh * * Then, generates an unsigned, 8-bit random number (RN) such that * * 0 <= RN <= lim, where 0 <= lim <= 255 and supplied by caller. * * Stores random number byte at 8378h to be retrieved by caller. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * RAND LI R4,>6FE5 Generate random number MPY @>83C0,R4 RN = seed * 6FE5h AI R5,>7AB9 RN = (RN & FFFFh) + 7AB9h MOV R5,@>83C0 Load random number seed = RN * * At this point, 83C0h contains an unsigned, 16-bit pseudo-random number * MOVB *R13,R6 Fetch limit (0-255) from next GROM byte SRL R6,8 ...in Lbyte INC R6 ...+1 CLR R4 SWPB R5 swap bytes of RN DIV R6,R4 adjust to limit MOVB @>83EB,@>8378 LSB of remainder in R5 to 8378h * * Return to GPL interpreter... The following is the GPL for the TI Basic interpreter's RND, which returns a floating point random number such that 0 <= n < 1, i.e., a floating point fraction: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Basic RND * * Calls RAND at least 7 times, once for each radix-100, floating- * * point digit. If first radix-100 digit is 0, exponent is re- * * duced and RAND is called again. If the exponent ever gets to * * 0, the first word (16 bits) of the floating-point result is * * set to 0. * * Result is built in the floating point accumulator (FAC = >834A). * * * * Command order (dst,src) below is from Heiner Martin * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * RND ST @>834A,>3F Exponent for 100^0 ST @>8310,>4B Loop counter (points to >834B) RND01 RAND >63 call GPL RAND with lim = 99 (RAND byte to >8378) CZ @>8378 0? BR GROM@RND03 No, go on DEC @>834A decrement exponent for next try CZ @>834A 0? BS GROM@RND04 End with 0 if exp = 0 BR GROM@RND01 Try again RND02 RAND >63 call GPL RAND with lim = 99 RND03 ST *>8310,@>8378 store RAND in next radix-100 digit CEQ @>8310,>51 Last digit? (>8351 is last byte of FAC) BS GROM@RNDXIT Yes; we're outta here INC @>8310 No; increase loop counter BR GROM@RND02 Get next radix-100 digit RND04 CLR @>834B Set 0; returns floating-point 0 for RND RNDXIT CONT continue parsing Basic The following is my humble submission for the CALL LINK("RND",X) suggested in my opening paragraph: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Basic RND in ALC * * Invoked by CALL LINK("RND",X) * * Calls RAND at least 7 times, once for each radix-100, floating- * * point digit. If first radix-100 digit is 0, exponent is re- * * duced and RAND is called again. If the exponent ever gets to * * 0, the first word (16 bits) of the floating-point result is * * set to 0. * * Result is built in the floating point accumulator (FAC = >834A). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * REF NUMASG for E/A module NUMASG EQU >6040 for MM module DEF RND FAC EQU >834A RND MOV R11,R9 save return LI R0,>3F Exponent for 100^0 LI R1,FAC+1 First radix-100 digit location LI R2,7 load radix-100 digit counter RND01 BL @RAND call our version of GPL RAND (result in R7) CI R7,0 0? JNE RND02 No, go on DEC R0 decrement exponent for next try JEQ RND05 End with 0 if exp = 0 JMP RND01 Try again RND02 SWPB R0 exponent to MSB MOVB R0,@FAC move exponent to FAC JMP RND04 RND03 BL @RAND call our version of GPL RAND (result in R7) RND04 SWPB R7 get result to MSB MOVB R7,*R1+ store RAND in next radix-100 digit DEC R2 decrement counter JEQ RNDXIT If 0, we're outta here JMP RND03 else, get next radix-100 digit RND05 CLR @FAC Set 0; returns floating-point 0 for RND RNDXIT CLR R0 Setup for numeric variable LI R1,1 Indicate first (only) variable BLWP @NUMASG Put RND in variable whose name was passed B *R9 return to Basic RAND LI R6,>6FE5 Generate random number MPY @>83C0,R6 RN = seed * 6FE5h AI R7,>7AB9 RN = (RN & FFFFh) + 7AB9h MOV R7,@>83C0 Load random number seed = RN * * At this point, 83C0h contains an unsigned, 16-bit pseudo-random number * LI R8,100 divisor (result will be 0-99) CLR R6 SWPB R7 swap bytes of RN DIV R8,R6 adjust to limit (rem in R7) RT END The above is for the MiniMemory module. It can be used with the E/A module by uncommenting the first line with ‘NUMASG’ and commenting out the second such line. The accompanying comments should make this obvious. To use it with the E/A module, you also need to LOAD “BSCSUP”, the TI Basic support routines located on one of the E/A diskettes. The following TI Basic program works for MiniMemory and runs the CALL LINK 500 times for timing: 100 CALL INIT 110 CALL LOAD("DSK1.RND.OBJ") 120 FOR I=1 TO 500 130 CALL LINK("RND",B) 140 NEXT I 150 END I timed the above. Then, for comparison, I removed line 130 to get the baseline time. Then I changed 130 to 130 B=RND for the normal TI Basic way to get a random number. The results were 12.6 ms/(B=RND) and 59.1 ms/[CALL("RND",B)]. I did this on Classic99, so the 32KiB is attached. I don't know how to eliminate the 32KiB expansion in Classic99 to test without it; but, I should think it would be the same. The results were practically identical for the E/A module: 12.5 ms/(B=RND) and 61.9 ms/[CALL("RND",B)], with MiniMemory slightly faster on the CALL. The TI Basic program needs to LOAD the Basic Support Utilities (BSCSUP), but is otherwise the same as the one above: 100 CALL INIT 110 CALL LOAD("DSK1.BSCSUP","DSK1.RND.OBJ") 120 FOR I=1 TO 500 130 CALL LINK("RND",B) 140 NEXT I 150 END As I said, Harry was right about the slow nature of CALL. Because my RND routine is 100% ALC, except for the CALL LINK and its return, CALL LINK is really, really slow. Again, that is right in line with what Harry said. I would now expect even a call to get effectively a single, 16-bit, random number (only one call to RAND) to be slower than TI Basic's RND * 32767! I may still code it; but, it hardly seems worth the effort. ...lee 3 Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 23, 2016 Share Posted January 23, 2016 One thing that would help in generating random numbers is that usually you want it to be an integer between a low and a high limit. If you include the limits in the CALL LINK you could have the assembly routine do that for you and eliminate those steps in BASIC. Also you can generate up to 5 random numbers for each CALL LINK. (If you pass in 2 limits and pass back one random number) This is an option in XB256 and considerably speeds up the slow XB random number generator. Since BASIC has a faster RND it might not make so much of a difference there. 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted January 23, 2016 Share Posted January 23, 2016 I am hopeful the Color Pallet gets fixed in MESS for the EVPC. Rich, just watching your video ... [3:50] "kind of blue does not look right" - What I see from your video looks good to me. The mix of blue and green is cyan. The only thing is that the cyan color of the emulated 9938 looks more blueish than the cyan of the emulated TMS9928a; this is what you already notice when starting the ti99_4ev. This should indeed be verified. Both video chip emulations were written by different people. I'll try the tests on my real Geneve. 1 Quote Link to comment Share on other sites More sharing options...
RXB Posted January 23, 2016 Share Posted January 23, 2016 Thanks for checking this out. Quote Link to comment Share on other sites More sharing options...
+mizapf Posted January 23, 2016 Share Posted January 23, 2016 (edited) Strange. I tried my copy of XHi on the emulated Geneve and on the emulated TI-99/4A with EVPC. I get different results. I'll attach my copy to this message, so maybe you can try that one and we can rule out any differences in versions. [4:30] Red sky: See the screenshot below. [5:30] Rays: See screenshot below. xhi.dsk Edited January 23, 2016 by mizapf 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 23, 2016 Share Posted January 23, 2016 One thing that would help in generating random numbers is that usually you want it to be an integer between a low and a high limit. If you include the limits in the CALL LINK you could have the assembly routine do that for you and eliminate those steps in BASIC. Yeah, I thought of that; but, I'm not sure the multiple calls with BLWP @NUMREF would be significantly faster than managing the result in Basic. Also you can generate up to 5 random numbers for each CALL LINK. I'm not sure what you mean here. For one thing, my RND and TI Basic's RND both do the same thing in making 7 or more calls to the RAND function for each radix-100 digit (0 – 99) of the Basic floating point number that is ultimately returned. The difference is that the call for my function is within the same ALC routine whereas the TI Basic call is to GPL's RAND. There can be more than 7 calls if the first digit is 0. RAND is called until that digit is non-zero, the exponent getting decremented with each additional call. (If you pass in 2 limits and pass back one random number) This is an option in XB256 and considerably speeds up the slow XB random number generator. Since BASIC has a faster RND it might not make so much of a difference there. Probably so. ...lee Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 23, 2016 Share Posted January 23, 2016 I said: Also you can generate up to 5 random numbers for each CALL LINK Lee: I'm not sure what you mean here. For one thing, my RND and TI Basic's RND both do the same thing in making 7 or more calls to the RAND function for each radix-100 digit (0 – 99) of the Basic floating point number that is ultimately returned. The difference is that the call for my function is within the same ALC routine whereas the TI Basic call is to GPL's RAND. There can be more than 7 calls if the first digit is 0. RAND is called until that digit is non-zero, the exponent getting decremented with each additional call. Usually (not always) a programmer wants an integer random number between a lower and higher limit. Also the compiler only works with integers. After Rich modified RXB to use the faster TI BASIC random number generator, I did something similar to XB256. Often the lower limit is zero, so for speed I made that the default. (When I posted earlier I misremembered passing a lower limit.) From the manual: CALL LINK(“IRND”,limit,variable[,.........]) Returns a random number as an integer from 0 to limit-1. The results are the same as variable=INT(limit*RND) but IRND is much faster than the slow XB random number generator. Up to 8 random numbers can be created with one call to IRND. If you wanted a random number from 4 to 8 you would CALL LINK("IRND",5,R1)::R1=R1+4 To XB all numbers, even integers, are actually floating point numbers, but the IRND subroutine gets the limit, converts to integer, generates an integer random number, then converts it to floating point and sends it back to XB. It repeats this until there are no more arguments on the list. Because you can pass up to 16 arguments to/from an assembly subprogram you can get up to 8 random numbers per call. (Earlier I said 5 because I misremembered passing both lower and upper limits.) Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 23, 2016 Share Posted January 23, 2016 XXB (Barry Traver) pulls it off okay, though, I remember playing with that one a lot. I never looked at how it does it, but the docs do note: I took a look at how Barry got 40 columns in XB. He starts the screen at >0000 which means that the XB system area at >0370 is part of the screen. If you look with the debugger you'll see activity in that area (>0370 to >03EF) when an XB program runs. You can also sometimes see junk displayed at the bottom of the screen. To avoid this you would have to move the screen image table. The best bet would be to reserve a block of VDP ram the way missing link or XB256 do. Another way might be to put the screen table into disk buffers. But either way it is not as simple as it would be with TI BASIC and the minimemory. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 23, 2016 Share Posted January 23, 2016 Usually (not always) a programmer wants an integer random number between a lower and higher limit. Also the compiler only works with integers. After Rich modified RXB to use the faster TI BASIC random number generator, I did something similar to XB256. Often the lower limit is zero, so for speed I made that the default. (When I posted earlier I misremembered passing a lower limit.) From the manual: CALL LINK(“IRND”,limit,variable[,.........]) Returns a random number as an integer from 0 to limit-1. The results are the same as variable=INT(limit*RND) but IRND is much faster than the slow XB random number generator. Up to 8 random numbers can be created with one call to IRND. If you wanted a random number from 4 to 8 you would CALL LINK("IRND",5,R1)::R1=R1+4 To XB all numbers, even integers, are actually floating point numbers, but the IRND subroutine gets the limit, converts to integer, generates an integer random number, then converts it to floating point and sends it back to XB. It repeats this until there are no more arguments on the list. Because you can pass up to 16 arguments to/from an assembly subprogram you can get up to 8 random numbers per call. (Earlier I said 5 because I misremembered passing both lower and upper limits.) Cool! You surely know this, but TI Basic numbers are all floating point, as well. Could you not effectively get any desired number of random numbers by passing a 2-dimensional array to IRND? Of course, then you would need to modify IRND to handle it that way. ...lee Quote Link to comment Share on other sites More sharing options...
RXB Posted January 23, 2016 Share Posted January 23, 2016 Usually (not always) a programmer wants an integer random number between a lower and higher limit. Also the compiler only works with integers. After Rich modified RXB to use the faster TI BASIC random number generator, I did something similar to XB256. Often the lower limit is zero, so for speed I made that the default. (When I posted earlier I misremembered passing a lower limit.) From the manual: CALL LINK(“IRND”,limit,variable[,.........]) Returns a random number as an integer from 0 to limit-1. The results are the same as variable=INT(limit*RND) but IRND is much faster than the slow XB random number generator. Up to 8 random numbers can be created with one call to IRND. If you wanted a random number from 4 to 8 you would CALL LINK("IRND",5,R1)::R1=R1+4 To XB all numbers, even integers, are actually floating point numbers, but the IRND subroutine gets the limit, converts to integer, generates an integer random number, then converts it to floating point and sends it back to XB. It repeats this until there are no more arguments on the list. Because you can pass up to 16 arguments to/from an assembly subprogram you can get up to 8 random numbers per call. (Earlier I said 5 because I misremembered passing both lower and upper limits.) I showed in another thread about RND in XB and TI Basic they both use Floating Point, but XB starts out using Floating Point and ends with Floating Point. This just creates a huge speed difference when TI Basic just smokes XB RND for good reasons. XB actually used a Floating Point Random Number Seed while TI Basic RND uses 99 a non floating point number as a seed. You can see this in the GPL code of XB vs TI Basic. Quote Link to comment Share on other sites More sharing options...
RXB Posted January 23, 2016 Share Posted January 23, 2016 Strange. I tried my copy of XHi on the emulated Geneve and on the emulated TI-99/4A with EVPC. I get different results. I'll attach my copy to this message, so maybe you can try that one and we can rule out any differences in versions. [4:30] Red sky: See the screenshot below. [5:30] Rays: See screenshot below. I lost my MESS set up and have to start over. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 24, 2016 Share Posted January 24, 2016 ... TI Basic RND uses 99 a non floating point number as a seed. The seed for TI Basic is most definitely not 99. The number 99 is used as the limit for a radix-100, floating-point digit (must be 0 – 99) for each call to GPL's RAND. The new seed generated by RAND is an unsigned, 16-bit number, even though RAND returns nothing more than an 8-bit, unsigned number (0 – 255), depending on the limit it was passed. Obviously, TI Basic's RND gets back 0 – 99 for each radix-100 digit. TI Basic's RND calls RAND 7+ times, so there are at least 7 new seeds generated in succession. ...lee Quote Link to comment Share on other sites More sharing options...
RXB Posted January 24, 2016 Share Posted January 24, 2016 (edited) The seed for TI Basic is most definitely not 99. The number 99 is used as the limit for a radix-100, floating-point digit (must be 0 – 99) for each call to GPL's RAND. The new seed generated by RAND is an unsigned, 16-bit number, even though RAND returns nothing more than an 8-bit, unsigned number (0 – 255), depending on the limit it was passed. Obviously, TI Basic's RND gets back 0 – 99 for each radix-100 digit. TI Basic's RND calls RAND 7+ times, so there are at least 7 new seeds generated in succession. ...lee LOL you want to argue with me about GPL Code? Basic RND: 4F00 : ST @>834A,>3F Exponent 4F03 : ST @>8310,>4B Loop counter 4F06 : RAND >63 till 100 >>>>>>>>>>>>>>>> HEX >63 = DECIMAL 99 4F08 : CZ @>8378 0? 4F0A : BR GROM@>4F16 No, go on 4F0C : DEC @>834A -1 4F0E : CZ @>834A 0? 4F10 : BS GROM@>4F23 End with 0 4F12 : BR GROM@>4F06 Go on 4F14 : RAND >63 till 100 >>>>>>>>>>>>>>>> HEX >63 = DECIMAL 99 4F16 : ST *>8310,@>8378 All digits 4F1A : CEQ @>8310,>51 Till >8351 4F1D : BS GROM@>4F25 4F1F : INC @>8310 Increase loop counter 4F21 : BR GROM@>4F14 4F23 : CLR @>834B Set 0 4F25 : CONT Edited January 24, 2016 by RXB Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 24, 2016 Share Posted January 24, 2016 (edited) Rich, if you followed the code back to the GPL interpreter you would find at >027A: GPL RAND LI 4,>6FE5 Generate random number MPY @>83C0,4 AI 5,>7AB9 MOV 5,@>83C0 Load random number seed MOVB *R13,6 Fetch limit SRL 6,8 in Lbyte INC 6 + 1 CLR 4 SWPB 5 DIV 6,4 (my notes: after DIV R5 has remainder which is < limit) MOVB @>83EB,@>8378 Random number on source JMP >02AA To GPL interpreter Edited January 24, 2016 by senior_falcon Quote Link to comment Share on other sites More sharing options...
RXB Posted January 24, 2016 Share Posted January 24, 2016 Rich, if you followed the code back to the GPL interpreter you would find at >027A: GPL RAND LI 4,>6FE5 Generate random number MPY @>83C0,4 AI 5,>7AB9 MOV 5,@>83C0 Load random number seed MOVB *R13,6 Fetch limit SRL 6,8 in Lbyte INC 6 + 1 CLR 4 SWPB 5 DIV 6,4 MOVB @>83EB,@>8378 Random number on source JMP >02AA To GPL interpreter I just posted the GPL code not the Assembly. 99 or >63 is the Random number seed. So are you saying that RAND >63 or 99 decimal is not the seed? Are you saying there is no seed number? Quote Link to comment Share on other sites More sharing options...
senior_falcon Posted January 24, 2016 Share Posted January 24, 2016 I just posted the GPL code not the Assembly. 99 or >63 is the Random number seed. So are you saying that RAND >63 or 99 decimal is not the seed? Are you saying there is no seed number? Of course there is a random number seed. RAND >63 generates a random number integer between 0 and 99. If you read my post, the random number seed is at >83C0 according to Heiner Martin. But if you're like me you don't believe everything you read, so you put it to the test. Get into Classic 99 and press 1 for TI BASIC. Type in this program: 10 X=RND 20 CALL KEY(0,K,S) 30 IF S<1 THEN 20 40 GOTO 10 Get into the debugger and look at the CPU ram starting at >8300. Run the program. Every time you press a key the random number seed at >8C00 changes. Change line 10 to RANDOMIZE and then run the program. Every time you press a key the LSB of the random number seed changes. Quote Link to comment Share on other sites More sharing options...
Willsy Posted January 24, 2016 Share Posted January 24, 2016 I just posted the GPL code not the Assembly. 99 or >63 is the Random number seed. So are you saying that RAND >63 or 99 decimal is not the seed? Are you saying there is no seed number? That's not the seed. That's the limit. Learn the difference between a limit and a seed. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 31, 2016 Share Posted January 31, 2016 OK—I have written an IRND function that will work with both MiniMemory and Editor/Assembler as is and will return up to 100 16-bit, integral, random numbers with one call. It requires just two parameters—a variable with the number of random numbers to be returned and an array of limits for each number to be returned. The random numbers are returned in the same array in which the limits were passed. It is limited to positive, 16-bit integers. You can pass a limit of 0 if you want a random number as large as possible (32767 or 7FFFh). The limits are destroyed by the function because the random numbers are stored in the same positions in the array. IRND is called like this: CALL LINK("IRND",N,A()) N is the number of random numbers desired and A() is a one-dimensional array of limits for each random number desired. The array must be dimensioned at least as large as the first parameter, which cannot be higher that 100 for this particular function. This limit can be raised by changing the ARRAY BSS 800 instruction in the ALC below to reserve 8 bytes for each number in the array. I will modify this routine to allow an array of random numbers as large as memory will allow, but that will not require the above large block of memory. I expect it to be a slower routine because of the need for multiple calls for transferring 8 bytes at a time from and to VRAM as opposed to the transfers of the entire array from and to VRAM with only two transfer calls; but, it will take up much less memory. For those interested, here is the ALC for the function: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Basic IRND in ALC * * Invoked by CALL LINK("IRND",N,X()) * * * * INPUT Workspace: * * N = number of random numbers desired * * X() = array of limits for each desired random number * * R0-R4 = workspace * * R5 = reserved for radix-100 (centimal) base * * R6 = workspace * * R7 = current random number limit etc. * * R8 = CPU RAM array pointer * * R9 = working copy of N * * R10 = pointer to referenced parameters in VRAM * * * * OUTPUT Workspace: * * X() = array of range-limited random numbers * * * * The input array, X(), of limits for N random numbers is processed * * through this routine's pseudo-random number generator, IRND. All * * numbers passed from TI Basic are assumed to be positive, 16-bit * * integers in radix-100 (centimal) floating-point format. They are * * converted to 16-bit integers by CPFI below, which forces them * * positive. Any passed number exceeding 32767 is set to 32767. Each * * random number generated by IRND is converted back to floating * * point by CPIF below and stashed in X(), replacing the respective * * limits, before returning to TI Basic. * * * * IRND uses the equation from TI Forth, the last step of which is * * to do a 5-bit circular right shift to GPL RAND's routine before * * storing at 83C0h (SEED). Because GPL's RAND only ever returns one * * byte, it swaps bytes before adjusting to the limit passed to it. * * The TI Forth equation, which is the new seed is * * * * SEED = (6FE5h * SEED + 7AB9h) src 5 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEF IRND VDPWA EQU >8C02 VDP Write Address VDPRD EQU >8800 VDP Read Data VDPWD EQU >8C00 VDP Write Data FAC EQU >834A Floating Point Accumulator R11SAV EQU >8352 Return address storage VRAMAD EQU >8354 save pointer to VRAM * SGNBIT EQU >8000 CBD50 BYTE 50 EVEN COUNT DATA 0 will be updated when N retrieved ARRAY BSS 800 reserve space for 100 random numbers IRND MOV R11,@R11SAV save return MOV @>8310,R10 get parameter list pointer AI R10,20 point to 1st parameter's pointer LI R5,100 radix-100 (centimal) base for CPFI and CPIF fxns * ** Get pointer to N in VRAM * MOV R10,R0 VRAM address of pointer to N LI R1,VRAMAD use VRAMAD temporarily LI R2,2 transfer 2 bytes LI R3,VMBR set up to read from VRAM BL @VDP do it * ** Now get N * MOV @VRAMAD,R0 VRAM address of N LI R1,FAC put in FAC LI R2,8 transfer 8 bytes BL @VDP do it * ** Convert N to an integer * BL @CPFI Convert it MOV @FAC,R9 copy integer to working register MOV R9,@COUNT copy for later * ** Get pointer to array in VRAM * AI R10,8 compute VRAM array address MOV R10,R0 VRAM address of pointer to array LI R1,VRAMAD use VRAMAD temporarily LI R2,2 transfer 2 bytes LI R3,VMBR set up to read from VRAM BL @VDP do it * ** Now get N limit values from passed array address * INCT @VRAMAD increment pointer past array dim MOV @VRAMAD,R0 VRAM address of array LI R1,ARRAY CPU buffer for array MOV R9,R2 R9 still has count of FP numbers to transfer SLA R2,3 X 8 bytes/FP number LI R3,VMBR set up to read array from VRAM BL @VDP to ARRAY * ** Process array * LI R8,ARRAY load array pointer ARLOOP LI R7,FAC copy to FAC MOV *R8+,*R7+ from ARRAY MOV *R8+,*R7+ . MOV *R8+,*R7+ . MOV *R8,*R7 . BL @CPFI convert to integer MOV @FAC,R7 limit integer to R7 for RAND BL @RAND get a new random number to SEED and R1 MOV R1,@FAC prep for conversion to floating point BL @CPIF do it AI R8,-6 adjust R8 to overstore limit LI R7,FAC copy from FAC MOV *R7+,*R8+ to ARRAY MOV *R7+,*R8+ . MOV *R7+,*R8+ . MOV *R7,*R8+ . R8 now has address of next element DEC R9 JNE ARLOOP * ** Copy array values back to VRAM * MOV @VRAMAD,R0 VRAM address of array for Basic LI R1,ARRAY CPU buffer address of results MOV @COUNT,R2 count of FP numbers to transfer SLA R2,3 X 8 bytes/FP number LI R3,VMBW set up to write array from ARRAY BL @VDP to VRAM * ** Return to Basic * MOV @R11SAV,R11 restore Basic return address RT return to Basic * *== Generate a pseudo-random number =================================== * RAND LI R0,>6FE5 Generate random number MPY @>83C0,R0 RN = seed * 6FE5h AI R1,>7AB9 RN = (RN & FFFFh) + 7AB9h SRC R1,5 RN = ((RN & FFFFh) + 7AB9h) src 5 MOV R1,@>83C0 Load random number seed = RN ABS R1 We only want to process positive numbers CLR R0 DIV R7,R0 adjust to limit (rem in R1) RT * *== VDP utilities (entry point) ======================================= * * R3 has address of VDP routine to execute * R0..R2 have required parameters (see routine called) * VDP MOV R11,R4 save return STST R7 store status ANDI R7,>000F only want interrupt mask LIMI 0 disable interrupts B *R3 branch to VDP routine * ** Return to caller * VDPRET LIMI 0 assume interrupts were disabled CI R7,0 were they? JEQ VDPRT1 yes, we're done LIMI 2 no, enable interrupts VDPRT1 B *R4 * ** VDP multiple byte write * VMBW BL @WVDPWA Write out address VWTMOR MOVB *R1+,@VDPWD Write a byte DEC R2 Decrement byte count JNE VWTMOR More to write? JMP VDPRET Return to calling program * ** VDP multiple byte read * VMBR BL @WVDPRA Write out address VRDMOR MOVB @VDPRD,*R1+ Read a byte DEC R2 Decrement byte count JNE VRDMOR More to read? JMP VDPRET Return to calling program * ** Set up to write to VDP * WVDPWA ORI R0,>4000 * ** WRITE VDP ADDRESS (reading VRAM if WVDPWA not executed) * WVDPRA SWPB R0 LSB first MOVB R0,@VDPWA Write low byte of address SWPB R0 Now MSB MOVB R0,@VDPWA Write high byte of address RT Return to calling routine *------------------------------------------------------------------------- * Code derived from the Geneve MDOS L10 Floating Point Library's CFI * * NAME: CPFI: Convert Positive Floating point number to Integer * * Result: 0 <= Integer <= 32767 * * INPUT Workspace: * R0 = Integer result * R1 = radix-100 digit processing * R2 = FAC pointer * R3 = FP fraction processing * R4 = FP exponent for comparison * R5 = radix-100 (centimal) base (set up by caller) * R6 = current workspace index * FAC = Floating-point number * * OUTPUT Workspace: * FAC = Integer *------------------------------------------------------------------------- * * Called by BL @CPFI * CPFI LI R2,FAC get pointer to number ABS *R2 force FP number positive JEQ CFI11 if 0, all done CLR R0 start with zero result CLR R3 clear fraction CLR R4 clear out unused part of register MOVB *R2+,R4 get exponent STWP R6 use R6 for indexing into workspace CI R4,>3F00 is number less than one JLT CFI11 yes number < .01 - result = 0 JEQ CFI03 number > .01 and < 1 - result = 1 CI R4,>4100 is number less than 100,000? JLT CFI02 it is between 1 and 100 JEQ CFI01 it is between 100 and 10,000 CI R4,>4200 is number too big to convert? JH CFI08 yes, it is MOVB *R2+,@1(R6) get MS-centimal-digit to LSB of R0 MPY R5,R0 radix to binary MOV R1,R0 get result for next centimal digit CFI01 MOVB *R2+,@7(R6) get next integral centimal digit to LSB of R3 A R3,R0 add to previous result MPY R5,R0 radix to binary MOV R0,R0 test for overflow JNE CFI08 yes--cap to 32767 MOV R1,R0 get result for last digit JLT CFI08 overflow--cap to 32767 CFI02 MOVB *R2+,@7(R6) get least integral centimal digit to LSB of R3 A R3,R0 add to result CFI03 CB *R2,@CBD50 is rounding necessary? JLT CFI06 no--check for overflow * * INC R0 round up CFI06 CI R0,SGNBIT did unsigned result exceed 32767? JL CFI11 no--we're good CFI08 LI R0,>7FFF now just finish up with 32767 * * CFI11 MOV R0,@FAC return number in FAC RT *------------------------------------------------------------------------- * Code derived from the Geneve MDOS L10 Floating Point Library's CIF * * NAME: CPIF: Convert Positive Integer to Floating point number * * INPUT Workspace: * R0 = Dividend|quotient in radix-100-digit-processing * R1 = Remainder in radix-100-digit processing * R3 = Exponent processing * R4 = FAC pointer * R5 = radix-100 (centimal) base (set up by caller) * R6 = FAC pointer for clearing FAC * FAC = Positive integer * * OUTPUT Workspace: * FAC = Floating-point number *------------------------------------------------------------------------- * * Called by BL @CPIF * CPIF LI R4,FAC get address of FAC (integer in, FP out) MOV *R4,R0 get the integer before we clobber it JEQ CIF03 if zero, then done LI R6,FAC for clearing (see below) * CLR *R6+ and clear out FAC CLR *R6+ . CLR *R6+ . CLR *R6 . * ABS R0 force integer positive LI R3,>40 starting exponent C R0,R5 1 radix-100 digit? JL CIF02 yup CI R0,10000 nope--2 radix-100 digits? JL CIF01 yup INC R3 3 radix-100 digits--inc exponent MOV R0,R1 extract radix-100 digit CLR R0 . DIV R5,R0 . SWPB R1 . MOVB R1,@3(R4) stash digit in FAC+3 CIF01 INC R3 inc exponent MOV R0,R1 extract radix-100 digit CLR R0 . DIV R5,R0 . SWPB R1 . MOVB R1,@2(R4) stash digit in FAC+2 CIF02 SWPB R0 R0 has leftmost radix-100 digit MOVB R0,@1(R4) stash digit in FAC+1 SWPB R3 exponent to MSB MOVB R3,*R4 stash exponent in FAC CIF03 RT END Here is a ZIP file with the ALC source and the object file in FIAD format and in a 90KiB disk image: IRND.zip Here is a sample TI Basic program that calls IRND to get 100 random numbers. A() is populated with 10 groups of limits from 10 to 100, i.e., A(0) – A(9) are each 10, A(10) – A(19) are each 20, ... . The program gets the random numbers and prints them out: 100 CALL INIT 110 CALL LOAD("DSK1.IRND.OBJ") 120 DIM A(100) 130 N = 100 140 FOR I = 0 TO N-1 STEP 10 150 FOR J = I TO I+9 160 A(J) = (I/10+1)*10 170 NEXT J 180 NEXT I 190 RANDOMIZE 200 CALL LINK("IRND",N,A()) 210 FOR I = 0 TO N-1 220 PRINT A(I); 230 NEXT I 240 PRINT 250 END For what it's worth, the CALL LINK("IRND",N,A()) in the above program takes 2 seconds compared to 4.9 seconds for the equivalent A(J) = INT(RND*(I/10+1)*10) substituted in statement 160 (E/A cartridge in Classic99), not a huge savings; but, it is faster. ...lee 4 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted January 31, 2016 Share Posted January 31, 2016 Here is the same function as last post, but this one allows an unlimited number of random numbers to be generated. Of course, memory will limit what can be returned. As long as you can store the array in TI Basic, you can fill it with random numbers. The memory footprint of the routine that follows is 432 bytes, whereas the one from the last post was 1268 bytes, most of which was storage for up to 100 floating point numbers: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Basic IRND in ALC--unlimited version * * * * Invoked by CALL LINK("IRND",N,X()) * * * * INPUT Workspace: * * N = number of random numbers desired * * X() = array of limits for each desired random number * * R0-R4 = workspace * * R5 = reserved for radix-100 (centimal) base * * R6 = workspace * * R7 = current random number limit etc. * * R8 = VRAM array pointer * * R9 = working copy of N * * R10 = pointer to referenced parameters in VRAM * * * * OUTPUT Workspace: * * X() = array of range-limited random numbers * * * * The input array, X(), of limits for N random numbers is processed * * through this routine's pseudo-random number generator, IRND, one * * number at a time. The reason this version is termed "unlimited" * * is that it transfers one FP number from and to VRAM for each call * * to RAND. The other version transfers the entire array all at once * * before and after any calls to RAND. It is, thus, limited to the * * size of the "ARRAY BSS 800" instruction in that limited version. * * This means, of course, that this unlimited version is much more * * compact and, as it turns out, is just as fast. * * * * All numbers passed from TI Basic are assumed to be positive, 16- * * bit integers in radix-100 (centimal) floating-point format. They * * are converted to 16-bit integers by CPFI below, which forces them * * positive. Any passed number exceeding 32767 is set to 32767. Each * * random number generated by IRND is converted back to floating * * point by CPIF below and stashed in X(), replacing the respective * * limits, before returning to TI Basic. * * * * IRND uses the equation from TI Forth, the last step of which is * * to do a 5-bit circular right shift to GPL RAND's routine before * * storing at 83C0h (SEED). Because GPL's RAND only ever returns one * * byte, it swaps bytes before adjusting to the limit passed to it. * * The TI Forth equation, which is the new seed is * * * * SEED = (6FE5h * SEED + 7AB9h) src 5 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEF IRND VDPWA EQU >8C02 VDP Write Address VDPRD EQU >8800 VDP Read Data VDPWD EQU >8C00 VDP Write Data FAC EQU >834A Floating Point Accumulator R11SAV EQU >8352 Return address storage VRAMAD EQU >8354 save pointer to VRAM * SGNBIT EQU >8000 CBD50 BYTE 50 EVEN IRND MOV R11,@R11SAV save return MOV @>8310,R10 get parameter list pointer AI R10,20 point to 1st parameter's pointer LI R5,100 radix-100 (centimal) base for CPFI and CPIF fxns * ** Get pointer to N in VRAM * MOV R10,R0 VRAM address of pointer to N LI R1,VRAMAD use VRAMAD temporarily LI R2,2 transfer 2 bytes LI R3,VMBR set up to read from VRAM BL @VDP do it * ** Now get N * MOV @VRAMAD,R0 VRAM address of N LI R1,FAC put in FAC LI R2,8 transfer 8 bytes BL @VDP do it * ** Convert N to an integer * BL @CPFI Convert it MOV @FAC,R9 copy integer to working register * ** Get pointer to array in VRAM * AI R10,8 compute VRAM array address MOV R10,R0 VRAM address of pointer to array LI R1,VRAMAD use VRAMAD temporarily LI R2,2 transfer 2 bytes LI R3,VMBR set up to read from VRAM BL @VDP do it * ** Process array * INCT @VRAMAD increment VRAM pointer to 1st array element MOV @VRAMAD,R8 load pointer to working register ARLOOP MOV R8,R0 VRAM address of next limit value LI R1,FAC copy to FAC LI R2,8 FP numbers are 8 bytes LI R3,VMBR set up to read FP number from VRAM BL @VDP to FAC BL @CPFI convert to integer MOV @FAC,R7 limit integer to R7 for RAND BL @RAND get a new random number to SEED and R1 MOV R1,@FAC prep for conversion to floating point BL @CPIF do it MOV R8,R0 reload VRAM address of current array element LI R1,FAC copy from FAC LI R2,8 FP numbers are 8 bytes LI R3,VMBW set up to write FP number to VRAM BL @VDP from FAC AI R8,8 increment VRAM pointer to next array element DEC R9 decrement count JNE ARLOOP * ** Return to Basic * MOV @R11SAV,R11 restore Basic return address RT return to Basic * *== Generate a pseudo-random number =================================== * RAND LI R0,>6FE5 Generate random number MPY @>83C0,R0 RN = seed * 6FE5h AI R1,>7AB9 RN = (RN & FFFFh) + 7AB9h SRC R1,5 RN = ((RN & FFFFh) + 7AB9h) src 5 MOV R1,@>83C0 Load random number seed = RN ABS R1 We only want to process positive numbers CLR R0 DIV R7,R0 adjust to limit (rem in R1) RT * *== VDP utilities (entry point) ======================================= * * R3 has address of VDP routine to execute * R0..R2 have required parameters (see routine called) * VDP MOV R11,R4 save return STST R7 store status ANDI R7,>000F only want interrupt mask LIMI 0 disable interrupts B *R3 branch to VDP routine * ** Return to caller * VDPRET LIMI 0 assume interrupts were disabled CI R7,0 were they? JEQ VDPRT1 yes, we're done LIMI 2 no, enable interrupts VDPRT1 B *R4 * ** VDP multiple byte write * VMBW BL @WVDPWA Write out address VWTMOR MOVB *R1+,@VDPWD Write a byte DEC R2 Decrement byte count JNE VWTMOR More to write? JMP VDPRET Return to calling program * ** VDP multiple byte read * VMBR BL @WVDPRA Write out address VRDMOR MOVB @VDPRD,*R1+ Read a byte DEC R2 Decrement byte count JNE VRDMOR More to read? JMP VDPRET Return to calling program * ** Set up to write to VDP * WVDPWA ORI R0,>4000 * ** WRITE VDP ADDRESS (reading VRAM if WVDPWA not executed) * WVDPRA SWPB R0 LSB first MOVB R0,@VDPWA Write low byte of address SWPB R0 Now MSB MOVB R0,@VDPWA Write high byte of address RT Return to calling routine *------------------------------------------------------------------------- * Code derived from the Geneve MDOS L10 Floating Point Library's CFI * * NAME: CPFI: Convert Positive Floating point number to Integer * * Result: 0 <= Integer <= 32767 * * INPUT Workspace: * R0 = Integer result * R1 = radix-100 digit processing * R2 = FAC pointer * R3 = FP fraction processing * R4 = FP exponent for comparison * R5 = radix-100 (centimal) base (set up by caller) * R6 = current workspace index * FAC = Floating-point number * * OUTPUT Workspace: * FAC = Integer *------------------------------------------------------------------------- * * Called by BL @CPFI * CPFI LI R2,FAC get pointer to number ABS *R2 force FP number positive JEQ CFI11 if 0, all done CLR R0 start with zero result CLR R3 clear fraction CLR R4 clear out unused part of register MOVB *R2+,R4 get exponent STWP R6 use R6 for indexing into workspace CI R4,>3F00 is number less than one JLT CFI11 yes number < .01 - result = 0 JEQ CFI03 number > .01 and < 1 - result = 1 CI R4,>4100 is number less than 100,000? JLT CFI02 it is between 1 and 100 JEQ CFI01 it is between 100 and 10,000 CI R4,>4200 is number too big to convert? JH CFI08 yes, it is MOVB *R2+,@1(R6) get MS-centimal-digit to LSB of R0 MPY R5,R0 radix to binary MOV R1,R0 get result for next centimal digit CFI01 MOVB *R2+,@7(R6) get next integral centimal digit to LSB of R3 A R3,R0 add to previous result MPY R5,R0 radix to binary MOV R0,R0 test for overflow JNE CFI08 yes--cap to 32767 MOV R1,R0 get result for last digit JLT CFI08 overflow--cap to 32767 CFI02 MOVB *R2+,@7(R6) get least integral centimal digit to LSB of R3 A R3,R0 add to result CFI03 CB *R2,@CBD50 is rounding necessary? JLT CFI06 no--check for overflow * * INC R0 round up CFI06 CI R0,SGNBIT did unsigned result exceed 32767? JL CFI11 no--we're good CFI08 LI R0,>7FFF now just finish up with 32767 * * CFI11 MOV R0,@FAC return number in FAC RT *------------------------------------------------------------------------- * Code derived from the Geneve MDOS L10 Floating Point Library's CIF * * NAME: CPIF: Convert Positive Integer to Floating point number * * INPUT Workspace: * R0 = Dividend|quotient in radix-100-digit-processing * R1 = Remainder in radix-100-digit processing * R3 = Exponent processing * R4 = FAC pointer * R5 = radix-100 (centimal) base (set up by caller) * R6 = FAC pointer for clearing FAC * FAC = Positive integer * * OUTPUT Workspace: * FAC = Floating-point number *------------------------------------------------------------------------- * * Called by BL @CPIF * CPIF LI R4,FAC get address of FAC (integer in, FP out) MOV *R4,R0 get the integer before we clobber it JEQ CIF03 if zero, then done LI R6,FAC for clearing (see below) * CLR *R6+ and clear out FAC CLR *R6+ . CLR *R6+ . CLR *R6 . * ABS R0 force integer positive LI R3,>40 starting exponent C R0,R5 1 radix-100 digit? JL CIF02 yup CI R0,10000 nope--2 radix-100 digits? JL CIF01 yup INC R3 3 radix-100 digits--inc exponent MOV R0,R1 extract radix-100 digit CLR R0 . DIV R5,R0 . SWPB R1 . MOVB R1,@3(R4) stash digit in FAC+3 CIF01 INC R3 inc exponent MOV R0,R1 extract radix-100 digit CLR R0 . DIV R5,R0 . SWPB R1 . MOVB R1,@2(R4) stash digit in FAC+2 CIF02 SWPB R0 R0 has leftmost radix-100 digit MOVB R0,@1(R4) stash digit in FAC+1 SWPB R3 exponent to MSB MOVB R3,*R4 stash exponent in FAC CIF03 RT END This routine is not only much smaller, it also takes the same amount of time. There are no BLWP instructions, but I still thought it would take longer. Both this routine and the last one are called with IRND; but, the TMS9900 object code files are different. This one is IRNDU.obj (IRNDUO on the DSK image) and the one from the last post is IRND.obj (IRNDO on the DSK image). Both are present in the attached ZIP file: IRNDU.zip The only thing different from the TI Basic program in my last post is that statement 110 must load IRNDU.obj. The only change I may make in the future is to allow for randomizing within the routine. I would pass a flag to indicate Do not randomize Randomize at the beginning Randomize before every number Randomize after a specified number of random numbers I probably should check the size of the passed array with N, the count of random numbers requested—right now, that's on the user. Otherwise, I'm done with this exercise. I accomplished my goal of coding an ALC function to be called from TI Basic to pass an array without using the helper functions NUMREF, NUMASG, etc. ...lee 1 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.