Jump to content
Sign in to follow this  
idflyfish

TurboForth Random Number Generator

Recommended Posts

At the moment it uses it for the speech synth driver. The idea is to be able to feed data to the speech synth while your program runs instead of your program just freezing up like in Xb...

 

Of course, when not speaking it just returns back to the isr...

Share this post


Link to post
Share on other sites

I can only speak for Classic99, of course, and not for MESS, Win994A, or even TI Forth or TurboForth. There's no way in Classic99's debugger to observe the VDP status register as >8802 -- that's a CPU memory address, and in order for the debugger to parse it as a memory-mapped device, it must actually access the VDP, something that it is forbidden to do (because it will change the state of the debug). So, it will always return zero because there is no memory behind it. You have to watch the VDPST breakout or the VDPST register value, and you will see it changing continuously to reflect the VDP Interrupt (I have just verified this).

 

Then, why does sampling 8802h produce a number (1Fh in Classic99) other than 0?

 

I don't actually have TI Forth, so I can't check that,

 

That can be rectified, if you're interested.

 

Interestingly.. when I attempt to run that loop in TurboForth, interrupts no longer happen, but neither does it appear to actually read the status register. I removed SEED and left the rest, since it didn't know SEED.

 

SEED is defined as (current BASE = 1610) 83C0 ! . It expects a value on the stack to store into 83C0h.

 

The only change needed was to use hexadecimal numbers -- could you be having a similar problem?

 

Nope. I did include HEX before the definition of RANDOMIZE (see earlier post). It simply does not work in TI Forth in the emulators I've tried (Classic99, MESS, TI994W). I gather from your comments that whatever is going on here in the TI99/4A cannot be emulated or is not worth the effort. I am not sure how to discover the behavioral difference in the emulators between TurboForth and TI Forth, but I would like to figure it out. TI Forth is near and dear to my heart, so I will always be making comparisons with and porting programs between TI Forth and TurboForth, even as I embrace TurboForth.

 

...lee

Share this post


Link to post
Share on other sites
Yep. That'll do it. If you don't want to use $ for hex numbers, then execute HEX first:

 

Ugh... I guess that's a FORTH convention, but that's confusing. It means there is no way at all for someone reading a listing to know what any immediate value in the code actually is. "30" in the code could be a decimal 30, or a decimal 48, and you don't know unless you know what the user has typed before. :)

 

I would there propose to make the definition of RANDOMIZE (in TF) as follows:

 

: RANDOMIZE 8802 [email protected] DROP 0 BEGIN 1+ 8802 [email protected] 80 AND UNTIL $83C0 ! ;

 

Which should dove-tail neatly with Lee's RND routine published above.

 

It's probably okay, so long as your random number generator works fine with small seeds. While the number that I saw varied, it was never very large (always under a thousand in Classic99), that limits the number of sequences you will actually generate.

Share this post


Link to post
Share on other sites
Then, why does sampling 8802h produce a number (1Fh in Classic99) other than 0?

 

Because you are not sampling through the debugger! My point was just that watching the debugger memory pointed to by >8802 will never change.

 

SEED is defined as (current BASE = 1610) 83C0 ! . It expects a value on the stack to store into 83C0h.

 

Good to know, doesn't really affect the testing though. :)

 

Nope. I did include HEX before the definition of RANDOMIZE (see earlier post). It simply does not work in TI Forth in the emulators I've tried (Classic99, MESS, TI994W). I gather from your comments that whatever is going on here in the TI99/4A cannot be emulated or is not worth the effort. I am not sure how to discover the behavioral difference in the emulators between TurboForth and TI Forth, but I would like to figure it out. TI Forth is near and dear to my heart, so I will always be making comparisons with and porting programs between TI Forth and TurboForth, even as I embrace

 

Well, I can take a look at some point. What I am trying to get at is not that it's something that can not be emulated, but that something is wrong with the testing methodology, because every piece of the test that you describe is provably working in emulation. Not only that, but you claim that three people working independently and creating their own emulations have all missed it. (Even weirder in the MESS case as it means that the behaviour was even missed across multiple systems). It's not impossible, but it lowers the likelihood. If it is some strange, previously unknown interaction of the hardware, then it probably needs to be in there!

 

So, it might be worth investigating, if you want to post your test bed and instructions on how to run this specific test case.

Share this post


Link to post
Share on other sites

Matthew...

 

Thanks for all your information. I should note that it was TI programmers who wrote the code to poll 8802h in TI Forth's RANDOMIZE routine listed far above but shown again here:

HEX
: RANDOMIZE 8802 [email protected] DROP 0 BEGIN 1+ 8802 [email protected] 80 AND UNTIL SEED ;

 

I would have thought they, more than anyone, would know what they were doing in this regard. And, on the real iron, it works rather well. As I mentioned earlier, it does not work at all on the three emulators I tested it on (Classic99, MESS, TI994W) because 8802h never changes.

 

...lee

 

Just for the record (and to save people paging back in the thread!) I have re-posted Lee's code above. Note Lee was using HEX so all literals would be recognised as hex numbers, so his code is correct as written.

 

That said, Lee, I could not get your code to fail, using Classic99 and TF V1.1, as you can see below.

 

Suggest you re-run your experiment. Very puzzling. Perhaps it's the voltages? Of course, TF was only tested on 240V AC systems. Correct operation cannot be guaranteed on 110V systems ;) :P

 

post-24932-0-77596700-1322132717_thumb.png

Share this post


Link to post
Share on other sites

The same program also works on MESS:

post-24932-0-81294700-1322133383_thumb.png

 

And also on Win994A (though it doesn't return very satisfactory results):

post-24932-0-19964800-1322133431_thumb.png

 

The program did not work with TI994W - it just hung.

 

Mark.

Share this post


Link to post
Share on other sites

That said, Lee, I could not get your code to fail, using Classic99 and TF V1.1, as you can see below.

 

Suggest you re-run your experiment. Very puzzling. Perhaps it's the voltages? Of course, TF was only tested on 240V AC systems. Correct operation cannot be guaranteed on 110V systems ;) :P

 

Mark...

 

Trust me. It does not work---but, I was talking about TI Forth---not, TurboForth. As soon as I discovered it would not work in TI Forth on the emulators, I wanted to track down the problem(s) because I really like the emulators---but, I want to be able to rely on their operation vis-à-vis the real iron. Plus---it certainly is (will be) educational for me.

 

Regarding interrupts in TI Forth, I believe TI Forth has its own ISR that executes at the end of every Forth word. I see that I will need to try to figure out exactly what's going on in that regard inside TI Forth so I can attempt to talk intelligently about what is not working in the emulators. I do not mean to confuse the issue concerning TurboForth; but, I do use both and I constantly compare them.

 

...lee

Share this post


Link to post
Share on other sites

So I tracked down TI Forth and gave it a try in Classic99... sure enough, it does hang.

 

First thing I checked was, "does it really read from >8802?". The answer is "yes, it does".

 

My second question was, "does it only read >8802 from one place?". The answer is "almost, interrupts are enabled".

 

"does it get differing values?". The answer is that it does not seem to.

 

The apparent problem in TI Forth /seems/ to be that it leaves interrupts enabled around this code. This means that as soon as the interrupt bit is set (assuming all other parts are enabled). This would mean that the race between code or the ISR getting the interrupt is within one instruction, the odds of it hitting are almost zero, and so the program hangs.

 

So why doesn't this happen on real hardware? A good question. It seems to be running a pretty tight loop, in scratchpad even. :) The only time interrupts are off is when the ISR is running. So the interrupt bit would have to be set during the MOV instruction that reads status, unless interrupts are disabled somewhere else.

 

There are only three places they can be:

 

LIMI 0 -- does not seem to be the case, the mask is locked at 2 in Classic99 during execution.

 

VDP Register 1 -- does not seem to be the case either, it seems locked at >F0, which enables interrupts

 

CRU interrupt mask - this one is harder to check in Classic99, and the most interesting since it's the least used method and may be least reliable in emulation. But Classic99 does check the CRU mask bit, and I did a quick test to try and see if CRU was ever written - it's not except by the ISR. Further to that, Classic99 thinks the CRU interrupt mask is set, so should work. TI didn't tend to document this approach, it would be strange to see they used it.

 

All that leaves is interrupt timing, and this is where Matthew's comments come into strongest play. The setting of the VDP status register is completely asynchronous on the real TI, while in emulation it will usually be balanced with other parts in some way. If this balance is set so, some code may not behave the same way.

 

To prove nothing else was at fault, I disabled VDP interrupts from the debugger (that's the only setting you can make in the Classic99 debugger today), by changing VDP Register 1 to >D0. It was necessary to do this for every test, but that allowed the code above to finally see the status register and to return. I also reviewed the 9900 data manual to make sure I wasn't missing something about when interrupts are tested for, but sure enough they are tested for after every CPU instruction.

 

How would we fix this? I would never have considered this code to be correct, honestly, since it relies on a tight race. If it somehow took a multiple of VDP scanlines to execute, it would never be able to fire, but luckily it doesn't, so in theory, yes, it should eventually hit. However, in emulation the ratio of scanlines to CPU instructions is probably incorrect, and this causes the issue -- particularly for frame-based emulation, which I believe all three major emulators are today. So, this is probably the cause. There's no good solution, except not to rely on races. And, for me at least, it's another reason for me to get my VDP update done already, I think the scanline-based VDP has a better shot at running this. ;)

Share this post


Link to post
Share on other sites

So I tracked down TI Forth and gave it a try in Classic99... sure enough, it does hang.

.

.

.

How would we fix this? I would never have considered this code to be correct, honestly, since it relies on a tight race. If it somehow took a multiple of VDP scanlines to execute, it would never be able to fire, but luckily it doesn't, so in theory, yes, it should eventually hit. However, in emulation the ratio of scanlines to CPU instructions is probably incorrect, and this causes the issue -- particularly for frame-based emulation, which I believe all three major emulators are today. So, this is probably the cause. There's no good solution, except not to rely on races. And, for me at least, it's another reason for me to get my VDP update done already, I think the scanline-based VDP has a better shot at running this. ;)

 

Tursi...

 

Thanks so much for your persistence and work on this. I believe I understand a lot more, now. This should help me as I try to dig into the TI Forth source code now and again. Thanks again...

 

...lee

Share this post


Link to post
Share on other sites

Hi,

 

Here is a little routine to generate random numbers, doesn't use any MUL or DIV. That's the one I use in MLC.

 

* a table with 17 number

rnddat    data    1966,23,3,31415,2718,7,666,17881,48
   data    57,28030,991,8,7412,69,884,11357

* the two pointers in the table (10=5th number and 34=17th number as they are WORDS)

index    data    10,34

random    li    r0,index
   mov    *r0+,r1		 * first pointer
   mov    *r0,r2		   * second one
   mov    @rnddat-2(r1),r4   * take first number
   a    @rnddat-2(r2),r4	   * add second
   mov    r4,@rnddat-2(r2)  * stores result to modify table
   srl    r4,4                          * from 0 to >fff
   mov    r4,@RETURN   	 * into "return value", that's the RND generated
   li    r4,34						   * end of list
   dect    r0						  * back on fist index
   dect    r1						 * previous value for next RND
   jne    rd1
   mov    r4,r1					 * if 0, back to the end of list
rd1    mov    r1,*r0+		    * stores pointer
   dect    r2						 * same for second pointer
   jne    rd2
   mov    r4,r2
rd2    mov    r2,*r0
   b    *r11

 

The idea is to replace one value in the table with the sum of two values. And doing this circularly. Only 12 lower bits are kept when returning the RND number, you can reduce this by changing the SRL R4,4 to SRL R4,8 for example to get only one byte.

 

Starting with the same table produces the same random list.

 

Guillaume.

Share this post


Link to post
Share on other sites

Mark (Willsy)...

 

If I want to do things with the CRU in TurboForth Assembler, do I need to use different workspace registers since TurboForth is using R12 as the stack pointer. The reason I ask in this thread is that I am trying to get a better random number seed than the 8-bit VDP timer by implenting the assembly code from Tursi's post in another thread (http://www.atariage....ost__p__2021341) using the TMS9901 as a 14-bit countdown timer.

 

...lee

Share this post


Link to post
Share on other sites

If I want to do things with the CRU in TurboForth Assembler, do I need to use different workspace registers since TurboForth is using R12 as the stack pointer.

You don't have to but its a good idea to. There's some notes in the assembler doc on this subject.

 

R12 is the pointer to NEXT (the routine which executes each of the words in a definition) - all you have to do is save it somewhere and restore it afterwards. Of course, the stack is a convenient place:

 

ASM: SEED
 SP INCT
 R12 *SP MOV,
 ...
 ...
 *SP R12 MOV,
  DECT SP
;ASM

 

Or if you can't be bothered with the stack:

 

ASM: SEED
 ...
 ...
 R12 $8328 LI,
;ASM

 

Here, we just restore R12 to its rightful value; >8328 is the address of the NEXT routine in pad-ram. You can confirm this by using Classic99's debugger, with a breakpoint set to the address of the first instruction in your code and simply observe the value of R12 before you mess with it! How do you know the address of your assembly word? Tick is your friend. ' (tick) returns the CFA (code-field address) of the word, which is actually a pointer to the address immediately after itself. So, a simple way to get the address of your assembly routines for debugging purposes is:

 

 ' <AssemblyWordName> 2+ $.

which will return the address of the first executable instruction in your routine. The debugger in Classic99 is enabled by pressing SCROLL LOCK. Then you can display it with either the Edit menu or by pressing HOME.

 

Remember R3 (PC), R4 (SP) & R5 (RSP) are sacred. If you need to use those registers it's best to change workspace. See the assembler doc (attached) chapters 3 & 9.

 

Assembler.pdf

 

Mark

Share this post


Link to post
Share on other sites

... R12 is the pointer to NEXT (the routine which executes each of the words in a definition) ....

 

Mark

 

Oops! :woozy: I knew it was in use but was too lazy to look it up in favor of my obviously not-so-good memory.

 

Thanks for your very informative (as usual) response. :)

 

...lee

Share this post


Link to post
Share on other sites

Remember R3 (PC), R4 (SP) & R5 (RSP) are sacred.

Mark

 

Mark...

 

Any particular reason you used different registers for TurboForth pointers from what they are in TI Forth? :?

 

...lee

Share this post


Link to post
Share on other sites

Yep! I simply didn't know what registers were in use in TI Forth! TurboForth was a total "from-scratch" "blank-sheet" effort. It wasn't based in any way on TI Forth or on any pre-existing code. I just started from nothing. Not that there's anything with wrong with TI Forth. Indeed, it probably would have saved me some time if I had studied it first!

 

I do things back-ass backwards, as usual :)

Share this post


Link to post
Share on other sites

Yep! I simply didn't know what registers were in use in TI Forth! TurboForth was a total "from-scratch" "blank-sheet" effort. It wasn't based in any way on TI Forth or on any pre-existing code. I just started from nothing. Not that there's anything with wrong with TI Forth. Indeed, it probably would have saved me some time if I had studied it first!

 

I do things back-ass backwards, as usual :)

 

That's amazing, actually! :-o

 

...Of course, it now makes any TF-TIF porting of CODEd words rather dif...er...interesting and instructive. :twisted: :P

 

...lee

Share this post


Link to post
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.

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...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...