Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,498
  • Joined

  • Last visited

Everything posted by TheBF

  1. I re-purposed a benchmark I found online years ago and made two versions. One uses a RAM variable (just an address in Forth) and the other uses a VDP variable. The difference showed VDP was 23% slower reading and writing an integer (2 bytes) than in expansion RAM. This was measured on real hardware, but I am using RS232 and terminal emulator for the Forth console. 23% will give you a nice performance boost on RXB.
  2. This is cool idea. I did some cheap and dirty experiments putting integers and strings in VDP RAM instead in normal RAM and running some simple benchmarks. I was surprised that the speed difference was only about 12% if I remember right. When you think about it, If you write code to set the VDP address and then read or write sequential data on the VDP chip it is just a normal memory read or write from the CPU. The VDP chip is handling the memory incrementing AND on TI-99 it is a full speed read/write operation because the VDP chip in on the motherboard. Read/writes to expansion RAM are throttled down to 8 bit chunks so not ideal. Of course read/writes to random locations in VDP RAM will be slower. Come to think of that I didn't do that test. I will give it try. So SAMS is a great alternative to VDP. It will be a hell of a neat BASIC system, but don't be shocked if it you don't see 2x performance.
  3. I know this is a really old thread but I found this file in "test" folder while trying to reorganize my stuff. I followed the link in my file. I don't think I published this but I created the file in March 2020. I made a test program to try and measure this question with the 9901 timer but I probably was not very confident in my system or my ability back then. So here is a result measured on my real TI-99 using the 9901 timer. There is compensation for the Forth interpreter substracted from the result. (~106 uS because the 9901 code is executed twice to measure the loop) I run the loop 100 times to reduce jitter. There are still some random fluctuations in the loop even though interrupts are off. (hardware?) On Classic 99 I see both instructions showing (14) clocks so T = 28 * 0.333 = 9.324uS My test is showing 8.3 to 8.95 uS so pretty close. So there's another answer @Willsy and only 9 years late! COM1_19200bps - TI-99 VT100 VT 2024-03-08 16-16-27.mp4
  4. Very nice. Have you spoken to a professional about that OCD? <wink wink> ( don't be writing your own scripts now)
  5. Oh I see now that I actually read the rest of your code. You use the quotient as the 1st digit. OK. Very specific number conversion. I will leave it with you as an exercise to to make an integer version. I am happy that I am able to help in some small way.
  6. And then remember that an HEX integer can hold up to 4 digits, a HEX byte can be up to 2 digits. So if you read the file as integers you need a 4 digit buffer, if as bytes a 2 byte buffer You put the results of the characters into the buffer backwards. ie: right to left So you need to read a byte, process 2 chars into the buffer. The leftmost chars could be a zero. That is why I recommended the other procedure to "make a number" which will be a little buffer of characters that you can print to the screen.
  7. Ok one bug down. Only the results of the mod operation , passed through the digit convertor goes into the buffer. This name dec2hex is a bit misleading since a binary number you are processing is neither BASE 10 nor BASE 16. This process of converting it to text, is what will determine if it decimal or hexadecimal or binary or whatever. This is should work and it's smaller! function todigit(n : integer) : char; begin if n > 9 then n := n + 7 todigit := chr(n + 48); end; (*todigit *)
  8. My update wasn't that bad but there seems to be a bug in the file windows where they "stop responding". Not like the file system is important or anything...
  9. I'm biased by you know what, but you might try factoring this into some smaller pieces. Here are the pieces used in a Forth system to chop an integer into a set of ascii digits. TODIGIT converts a binary digit to ascii but handles the gap between 0 .. 9 and A .. F. Then you need a way to divide and modulo-divide an integer by the radix, in this case 16. The quotient is retained, the modulus is passed to TODIGIT and the ascii character is placed in a buffer starting from right to left. Lather rinse and repeat until there is nothing left in the quotient. In very bad pseudo code: (I don't think like this any more) function TODIGIT ( X : integer) var out : char IF X > 9 THEN X=X+7 { handles ABCDEF } out := x + 48 { ascii 0 } return out end; procedure MAKE_NUMBER ( input: integer ) var hp, quotient , modulus , length : integer var hbuff() 6 bytes { should be global and big enough to hold a 16 bit number } hp := 6 { called a hold pointer in Forth } length:=0 repeat quotient := input / 16 { if you made 16 a global variable you code convert to different bases } modulus := input mod 16 hbuff(hp):=todigit(modulus) { put the ascii digit in the buffer } hp:=hp-1 { move the pointer to the next digit location inc(length) until quotient=0 return hbuff() , length { length needs to global to make this easy to do in Pascal ? ) end; Maybe that will give some helpful hints. ???
  10. When I reviewed the thread on this program I found the results of this program compiled with the BASIC compiler. "Maybe versus Weiand's Forth: Compiled-Basic: 1m40s Weiand-Forth: 3m" But the Weiand Forth version was written by Lucien who admitted that he was new to Forth and the algorithm is completely different. Now, with a line by line translation, we can see that indirect-threaded Forth and compiled BASIC are running about the same speed. If we compiled my BASIC version with simpler printing it would probably take the extra 20 seconds off or maybe more. @Lee Stewart wrote a version using Forth idiomatically at it runs on my system in 1:02 with the default scroll code. If increase the scroll buffer to the entire screen it runs in 55 seconds, but that's wasteful. LOL. I am moving over to the old Seven's problem post. I wonder if my JIT can swallow the new version... ?
  11. I just followed the early thread and the program I posted was written by @unhuman I will add that to the post. Thanks for making me do my homework professor.
  12. Outsider curiosity question. Do you need any special incantations to declare a leaf sub-routine? Perhaps the compiler simply looks for any calls within the sub-routine and modifies the entry and exit code?
  13. You got those eagle eyes. So this is similar to the case of C@ in our Forth systems where we would use: SRA R6,8 rather than SWPB R6 The GCC team was fighting with this for a while too.
  14. That's a strange bug for sure. Something I notice is that you are shuffling the data across a few registers. You could be reading more directly to the final destination. Not sure it fix the bug but it will reduce the time spent in getbyte. STCR *Rx,8 INC Rx or maybe (have not tried this but I think it's valid) STCR *R10+,8 That way the data goes into the buffer directly with auto incrementing.
  15. Still working on cleaning up my repository and I came across the old sevens problem. I always wanted a version that was a literal translation of the BASIC so I did one. It's fun to look at. I did not use any tricks unless you call one DUP a trick. Here is the TI BASIC version that runs in 27 minutes. I am afraid I have lost the accreditation for it so speak up if it's yours. (Lucien?) Edit: Original program was written by @unhuman. I modified lines 340 to 360 to speed up printing. The original used HCHAR. And here is a Forth literal translation that runs in edit: 1 minute 10 seconds on my indirect threaded system. ( Re-timed using a stop-watch because the there was too much VDP I/O playing with the ISR timer) I have included the BASIC code as comments. It would be faster if I replace the VARIABLEs with VALUEs but this is vanilla Forth. Most systems have character array creator CARRAY or it can be made easily enough.
  16. When I first got the system running it compiled very slowly. I did a little test typing 1 to 9 with a space between each digit and hitting enter. This was a worst case search and it was something like 3 or 4 seconds. I wrote (FIND) in Assembler and the same test takes just under 1 second. Brad made Camel Forth for small size so somethings suffer. Interesting stuff on the hashing. PolyForth used to limit the dictionary to the length, three characters and a hash value for the rest. I can't remember the details but that was for compact size. F83 created 4 search threads and put each word in a different thread by hashing the 1st character. This speeds up the average search time by 4. Forth Inc. uses 8 search threads. I have considered doing a 4 way hashed dictionary. I did make a hash table of the entire dictionary to compare search times using only Forth code and it was 3 times faster than what I have now. Hashing is amazing when you find the right one.
  17. Part of the innards of a Forth system is some way to "parse" through source, extracting one space delimited word at a time. Traditionally this was done with BL WORD. Looks simple but if you peek behind on the curtain on any Forth system there is fair bit of code behind WORD. Here is a modern way to code PARSE-NAME that I found on the Forth Standard site. PARSE-NAME is what they use these days instead of BL WORD. This code is note-worthy to me because of the word XT-SKIP which is like SKIP but instead of testing for a character match, XT-SKIP runs a piece of code so it can compare any range of characters. In this case any character less than a space is white space and anything not white space is a valid character but we could put any code in there. This appears to be a lot less code than I used in CAMEL99 Forth but on the other hand I have WORD PARSE and PARSE-WORD and I make PARSE-NAME with: : PARSE-NAME BL PARSE-WORD ; Anyway I thought some folks might want to see how modern languages are influencing Forth thought leaders and how Forth can replicate those "mapping" features without much trouble. (this code compiles on Camel99 FORTH) \ PARSE-NAME from https://forth-standard.org/standard/core/PARSE-NAME : white? ( c -- f ) BL 1+ U< ; \ space and below are white chars : -white? ( c -- f ) white? 0= ; \ everything above are not : xt-skip ( addr1 n1 xt -- addr2 n2 ) \ skip all characters satisfying xt ( c -- f ) >R BEGIN DUP WHILE OVER C@ R@ EXECUTE WHILE 1 /STRING REPEAT THEN R> DROP ; : PARSE-NAME ( "name" -- c-addr u ) SOURCE >IN @ /STRING ['] white? xt-skip OVER >R ['] -white? xt-skip ( -- end-word restlen) ( r: start-word ) 2DUP 1 MIN + SOURCE DROP - >IN ! DROP R> TUCK - ;
  18. I promise I didn't pay anybody but Camel99 Forth is listed among the systems at the Forth Standard site. I believe it may be because I joined a Forth group on Github and Lars Brinkhof probably stuck the link in the list. ?? Systems (forth-standard.org) The things that can happen on the interweb with these kids nowadays.
  19. Yes, I knew about the A and B address modifications so my numbers in the code reflect that. The dirty details of how bad it gets with TI-99 expansion RAM is where I stopped. However if the speedup can be 110% then using a 2X more cycles as a "rule of thumb" is reasonable I guess.
  20. That makes for nice light work for the Forth system. Very nice.
  21. You know it's a wonder I don't have a much flatter forehead. I was thinking about how to transfer binary data over RS232 now that I have this reliable com port receiver. I realized that the way I implement KEY? would be a problem because my version tests for a key and returns the ASCII value pressed OR returns a zero if no key was pressed. But binary data can contain zeros. So I started wondering how does Forth handle that? I went to the Standard and see this: 10.6.1.1755 KEY? key-question ( -- flag ) If a character is available, return true. Otherwise, return false. Oops! I implemented this incorrectly. KEY? is just the test. KEY is what reads the character. I thought I would be "efficient" and while I was checking, just read the character as well. By using KEY? and KEY together you can collect binary data no problem. If you do it my way... not so much. Time for some kernel fixing.
  22. No I counted from the book so it's the very best case which is why I doubled the number. I don't actually know how to calculate the slow down from the the TI-99 wait state generator. I took a look at the Classic99 dis-assembler and see between 0 difference from the text book for a register in the scratch-pad to what seems like double the cycles in some cases. Yes indeed my ISR does those things and hits the CTS pin when the buffer is 1/2 full. Again the code below is in RPN assembler and Forth but I think it could be worked into the Pascal environment from what you have said about working with interrupts. There are two big pieces. The "installer" that sets up the magic to trick the console ISR and the actual ISR to collect data into the queue. It's all derived work from other people but it's working well now so when the time comes it might be useful to @Vorticon to translate it.
  23. Ok. That make sense. My RS232 ISR executes in 314 cycles on a zero wait-state machine (105uS) from my counts from the 9900 manual. Looking at Classic99 I see about 50% overhead compared to the textbook cycles. ?? But let's say it's 2X slower. If so that would ~210uS. If we are sending at 19,200bps full speed we have characters hitting about every 500uS, so that could consume over 40% of the CPU.
  24. Could this work with fast serial communication? At 9600 bps you have a byte coming in every millisecond or so. 16mS interrupt time would not allow very fast communication or am I missing the important part somewhere?
×
×
  • Create New...