+TheBF Posted April 9, 2020 Author Share Posted April 9, 2020 Einstein once said that insanity is doing the same thing over and over and expecting a different result. I have been working getting the various features of this editor working they way I want but I was still getting these random characters inserted into the text when I used a repeating key routine. It never happen with a non-repeating key routine. I had first translated the code here: Repeating key into Forth almost literally. I tried a great number of things that I thought might cure it but no luck. So in desperation I re-wrote it Forth Assembler, where everything happens in a separate workspace. My original Forth translation must be pretty good because it does exactly the same thing! ? Looks like I need to re-think my control key handler. (?) I will try things on real iron as well. At least I now have some key-strokes to make the problem happen on demand. \ http://www.unige.ch/medecine/nouspikel/ti99/keyboard.htm#quick%20scan \ *-------------------------------------------- \ * Keyboard scanning with auto-repeat. \ * Put even values in R0 and R1 either at assembly or at run time. \ * Put an odd value in R0 to disable auto-repeat. \ *-------------------------------------------- NEEDS MOV, FROM DSK1.ASM9900 NEEDS .S FROM DSK1.TOOLS NEEDS MARKER FROM DSK1.MARKER MARKER COLD HERE HEX CREATE WREGS1 0080 , \ R0: Time before auto-repeat kicks in 0020 , \ R1: Delay between repeats 0080 , \ R2: Current delay FF00 , \ R3: old Key buffer 0500 , \ R4: Keyboard argument 0000 , \ R5: scratch 0000 , \ R6: time counter 0000 , \ R7: scratch 0000 , 0000 , 0000 , 0000 , 0000 , 0000 , 0000 , 0000 , 0000 , HEX CREATE (RKEY) R2 R1 CMP, \ Are we repeating? NE IF, \ IF NOT R4 8374 @@ MOVB, \ Set keyboard argument R0 R2 MOV, \ use long delay ENDIF, R2 R6 MOV, \ Reload counter register BEGIN, 83C8 @@ SETO, \ Erase previous key's scan code 83C8 @@ 83CA @@ MOVB, \ Ditto for keyboard 5 83E0 LWPI, 000E @@ BL, \ Call scanning routine WREGS1 LWPI, 8375 @@ R11 MOVB, \ Get key's ascii code R11 R3 CMPB, \ Same as before? NE IF, \ No 8375 @@ R3 MOVB, \ Memorize current key (will be >FF if no key) R0 R2 MOV, \ Load initial delay R3 8 R13 () MOVB, \ Pass key to Forth's TOP of stack register RTWP, \ return to Forth ENDIF, R6 DECT, \ Yes: wait. Never zero if odd delay EQ UNTIL, \ Keep scanning (as key could change) \ Done with waiting R1 R2 MOV, \ load repeat delay R3 8 R13 () MOVB, \ Pass key to Forth's TOP of stack register RTWP, \ return to Forth \ vector to call MYSCAN with BLWP CREATE MYSCAN WREGS1 , (RKEY) , CODE RKEY? ( -- c|0) TOS PUSH, TOS CLR, MYSCAN @@ BLWP, TOS SWPB, TOS 00FF CI, EQ IF, TOS CLR, ENDIF, NEXT, ENDCODE Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 9, 2020 Author Share Posted April 9, 2020 I think my agony is over. I decided to do a complete re-write. I used an concept which I wrote for serial port sending to the real TI99 as a starting point. TIMEKEY waits for a period of time for a key. If a key is pressed it exits immediately. If not key is pressed it times out and returns zero. I got no errors when I used TIMEKEY with a single delay value. It made me wonder if it would work if I controlled the delay value with different states. I had a feeling that something was not right using the trick of setting >83C8 to >FF to force KSCAN to repeat all the time, since the Assembler version showed the same problem. So here, I only switch that on when a "new" repeating key is detected otherwise it is not enabled. In the test condition where I could make the random characters repeatably this version seems flawless. Now I can get back debugging/designing the editor functions instead of this !@#$% problem. \ New repeating key Apr 9 2020 B Fox HEX VARIABLE T 0100 T ! VARIABLE OLDKEY : KEEP ( c -- c) DUP OLDKEY ! ; : NEW? ( c -- c ? ) DUP OLDKEY @ <> ; : DELAY ( n -- ) T ! ; : TIMEDKEY ( wait-time -- 0 | c ) BEGIN 1- DUP \ decrement wait-time WHILE \ while wait-time<>0 KEY? ?DUP \ read key, dup if <> 0 IF \ if key was pressed NEW? \ test if new key IF KEEP \ it's new key remember it 100 DELAY \ set long delay time THEN NIP \ NIP wait-time EXIT \ exit & return the key ELSE \ no key was pressed 100 DELAY \ reset the delay THEN REPEAT NEW? \ timed-out, is it a new key? IF 83C8 ON \ yes, enable repeating THEN 5 DELAY \ then set the fast delay ; : BLINK ( char -- ) TMR@ 1FFF > \ wait for 9901 to 1/2 expire IF DROP CURS @ \ replace char with cursor THEN VPUT ; \ then write to screen : RKEY VPOS VC@ >R BEGIN PAUSE R@ BLINK T @ TIMEDKEY ?DUP UNTIL R> VPUT ; Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 10, 2020 Author Share Posted April 10, 2020 I have much more respect for the use of tidy little blocks in traditional Forth systems. I got my 500 line editor onto the real iron. It takes about 4 seconds to save the 468 lines of source code for the SAMS editor on Classic99. Save the same file to a floppy disk on the TI-99 and it takes about 40 seconds. Oh well. I am just a couple of little bugs away from having a functional multi-file editor that can live on real iron. I have not timed the compile time but typically it is 2X slower than on Classic99 so that should be about 2 minutes. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 15, 2020 Author Share Posted April 15, 2020 Sometimes you have know when it is time to surrender. I spent way to much time trying to get the Nouspikel repeating key algorithm to work reliably. Even re-writing it in assembler, following the code on the web, gave the same result. I finally relented and took the code from old TI-Forth. Interesting to note the Forth Assembler version of Nouspikel used 242 bytes, partly because it uses a separate workspace. The updated TI-Forth version uses 232 bytes!. Forth for the win. I was able to make it a little simpler by factoring out the blinking cursor and using some special functions I use in the kernel (1+@, increment variable and fetch value; OFF set variable to zero). I changed some of the variable names to make more sense to me and voila! It works perfectly. Note: Sometime this week I will be releasing a 3 disk set that is a functional system with the SAMS multi-file editor and also copies of TI's EDIT V3.0 for 40 column and 80 columns. DSK3 will have a number of demo programs to give examples of how to use the library files. \ TI-forth repeating key modified for CAMEL99 DECIMAL 40 CONSTANT LD 5 CONSTANT SD VARIABLE OKEY VARIABLE KC VARIABLE DLY LD DLY ! HEX : BLINK ( char --) TMR@ 1FFF > IF DROP CURS @ THEN VPUT ; HEX : RKEY ( -- char|0) VPOS VC@ >R BEGIN R@ BLINK 83C8 ON ( force repeating KSCAN) KEY? ?DUP IF ( key is pressed ) KC 1+@ IF ( waiting to repeat ) DLY @ KC @ < IF ( long enough ) SD DLY ! 1 DUP KC ! ( force exit) ELSE OKEY @ OVER = IF ( need to wait more ) DROP FALSE ELSE ( force exit ) 1 DUP KC ! THEN THEN ELSE ( new key ) TRUE ( force loop exit ) THEN ELSE ( no key pressed) LD DLY ! KC OFF FALSE THEN UNTIL DUP OKEY ! R> VPUT ; 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 15, 2020 Author Share Posted April 15, 2020 In the topic below there is a discussion of Pascal using strings in a CASE statement. This got me wondering what would it take to add this to Camel99 Forth. Not bad for a "low level" language. \ string case statement NEEDS DIM FROM DSK1.STRINGS NEEDS CASE FROM DSK1.CASE : $OF ( -- ) POSTPONE OVER POSTPONE =$ POSTPONE IF POSTPONE DROP ; IMMEDIATE : TEST ( $ -- ) CASE " APPLE" $OF CR ." Granny Smith" ENDOF " PEAR" $OF CR ." Barlett" ENDOF " GRAPE" $OF CR ." Concord" ENDOF CR ." Unknown fruit" ENDCASE ; 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 17, 2020 Author Share Posted April 17, 2020 Here is a three disk package of the current version of Camel99 Forth. It includes a rebuild on my new computer (DSK1.CAML259B) along with the original DSK1.CAMEL99 It includes the SAMS editor ED99SAMS. I have not implemented repeating keys in this version because I am still seeing an occasional random key injected into the files. That is way more problem than not repeating. To that end I have included EDIT40 and EDIT80 on disk two, the editor disk, as well. There is also a release notes document and brief instructions on how to play with the ED99 SAMS editor. Should anybody be brave enough to play with this please send me all the bugs. Happy Friday CAMEL99.259.zip 5 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 18, 2020 Author Share Posted April 18, 2020 New Undocumented feature in CAMEL99 Forth V2.59B With the addition of the WARM command we can re-boot Forth back to a previous dictionary content point. If you INCLUDE DSK1.MARKER as your first addition to the system you get the ANS Forth word MARKER https://forth-standard.org/standard/core/MARKER AND you get a Camel99 word called LOCK After including DSK1.MARKER you can INCLUDE some utilities for example: INCLUDE DSK1.TOOLS INCLUDE DSK1.DIR Then invoke the LOCK command. LOCK records the dictionary pointers for the existing dictionary. Now you can load a project, test it etc. as normal. When you want to return to the bare system but keep the tools and dir utility in memory just invoke WARM and the system reverts to what it was when you used the LOCK command. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 25, 2020 Author Share Posted April 25, 2020 Super Cart is pretty cool I have spent some time cleaning up the cross-compiler that builds Camel99 Forth. It's still not as pretty as I would like. In the beginning of the project I was simply happy to get it to build a working program. :) Just recently I learned that Classic99 has Super Cart RAM in place with the E/A cartridge. I didn't take to much to convince the Cross-compiler to make an image that starts at >6000. I did have to remember to move the Forth dictionary pointer to >A000 when the kernel starts. Since the kernel is built to load into RAM all my other assumptions seem to work and the E/A5 loader seemed happy to put the program at >6000. Does the loader work this way on real iron? After I beat it up for while I will put a zip version here. SUPERCARTFORTH.mp4 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 26, 2020 Author Share Posted April 26, 2020 Over in the TP99 topic there is an nice video demonstration of TP99, a Pascal system for TI-99. I am always interested in how Forth, the lonely step-child language, compares to other development platforms so I translated the Pascal program to Forth. \ ANS/Camel99 Forth NEEDS .R FROM DSK1.UDOTR ( Camel99 needs to load justified printing) VARIABLE i DECIMAL : COUNTER PAGE 0 i ! 2 2 AT-XY ." Counting from 1 to 2000" BEGIN i 1 OVER +! 10 10 AT-XY @ DUP 5 .R 2000 = UNTIL ; \ FB Forth/Turbo Forth version 0 VARIABLE i DECIMAL : COUNTER PAGE 0 i ! 2 2 GOTOXY ." Counting from 1 to 2000" BEGIN i 1 OVER +! 10 10 GOTOXY @ DUP 5 .R 2000 = UNTIL ; The development process is much faster in Forth. Source code compiles to memory and can run immediately. In that regard Forth is more like Turbo Pascal for DOS. But since most Forth systems are written in indirect threaded Forth the execution speed is slower. Turbo Forth demonstrates what happens when key parts of the Forth system are written in Assembler. Here is what I measured on Classic99 System Secs Comment ------------------------------------------------------------------------------- Turbo Forth 7 Number conversion, VDP I/O in assembler Camel99 Forth 21 Number conversion, VDP I/O in Forth + Assembler primitives FB Forth 42 Number conversion, VDP I/O in Forth + Assembler primitives As Vorticon mentioned over there "choose your poison". 1 Quote Link to comment Share on other sites More sharing options...
D-Type Posted April 26, 2020 Share Posted April 26, 2020 How fast was the Pascal version? Not really comparable, but CamelForth running on 1.5MHz Vectrex runs the following code to a PC terminal via a serial interface with a buffer that doesn't overflow in 16 seconds: : U.R \ \ u width -- ; Display u right-aligned in a field n characters >R <# 0 #S #> R> OVER - 0 MAX SPACES TYPE ; variable ii : counter 0 ii ! begin ii 1 over +! @ dup 5 u.r 2000 = until ; Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 26, 2020 Author Share Posted April 26, 2020 TP99 ran in 5 seconds, which is expected for native code on the 9900. I have not put it on my TTY version but I will later and report back here. It should be a lot faster because as you can see with Turbo Forth, my VDP driver is not full speed. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 26, 2020 Share Posted April 26, 2020 I am a bit surprised that fbForth is so much slower than the other Forths. There just might be more thrashing between bank switching and branching to low RAM for system functions with GOTOXY and .R than I thought. ...lee Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 27, 2020 Author Share Posted April 27, 2020 1 hour ago, Lee Stewart said: I am a bit surprised that fbForth is so much slower than the other Forths. There just might be more thrashing between bank switching and branching to low RAM for system functions with GOTOXY and .R than I thought. ...lee Ya I was surprised too. And I also had to go look inside Mark's code to see why it is so fast. All code. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 27, 2020 Author Share Posted April 27, 2020 3 hours ago, D-Type said: How fast was the Pascal version? Not really comparable, but CamelForth running on 1.5MHz Vectrex runs the following code to a PC terminal via a serial interface with a buffer that doesn't overflow in 16 seconds: : U.R \ \ u width -- ; Display u right-aligned in a field n characters >R <# 0 #S #> R> OVER - 0 MAX SPACES TYPE ; variable ii : counter 0 ii ! begin ii 1 over +! @ dup 5 u.r 2000 = until ; Damn that 6809 runs Forth well! At 9600 baud, the TI99 ran your code in 21.8 seconds. At 19.2k baud it was still 20.4 1 Quote Link to comment Share on other sites More sharing options...
D-Type Posted April 27, 2020 Share Posted April 27, 2020 My serial port is provided by an ARM-based multicart that puts a UART into my address space and it gives me 921,600 baud with a 256 byte buffer both ways, which doesn't fill up. Thus the test is quite "clean"! 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 29, 2020 Author Share Posted April 29, 2020 I gotta build me a super cart for the old TI-99. That 24K number looks much better than the 15.9K in the conventional version. I am pretty happy with how the super cart version is working now. I will get a copy out tomorrow. 2 Quote Link to comment Share on other sites More sharing options...
+DuaneAL Posted April 29, 2020 Share Posted April 29, 2020 I’m sure this is obvious to everyone else so please forgive my ignorance. An extra 8k comes from the super cart, right? How is the rest of the free memory split up? It has always been unclear to me what is going on with the memory expansion (high/low) and vdp ram. Thanks! Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 29, 2020 Author Share Posted April 29, 2020 (edited) Yes the super cart is an Editor Assembler cartridge with 8K static RAM in place at HEX 6000. This memory space normally has a ROM in place for big applications like Extended BASIC. The 32K word address buss looks like this: (from my memory) 0000 1FFF console ROMs 2000 3FFF Expansion RAM 8K low block 4000 5FFF expansion box cards DSR code 6000 7FFF Cartridge slot ROM/RAM 8300 83FF 16 BIT RAM CHIP in console 8400 ... sound chip memory map I/O, VDP I/O ports 9000 9FFF grom memory I/O ?? A000 FFFF expansion RAM 24K block Edit I forgot to mention the 16K VDP RAM which is not on the buss but is memory mapped via address ports in the HEX 8000 space. Edited April 29, 2020 by TheBF 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted April 29, 2020 Share Posted April 29, 2020 On 4/14/2020 at 11:51 PM, TheBF said: This got me wondering what would it take to add this to Camel99 Forth. Not bad for a "low level" language. \ string case statement NEEDS DIM FROM DSK1.STRINGS NEEDS CASE FROM DSK1.CASE : $OF ( -- ) POSTPONE OVER POSTPONE =$ POSTPONE IF POSTPONE DROP ; IMMEDIATE : TEST ( $ -- ) CASE " APPLE" $OF CR ." Granny Smith" ENDOF " PEAR" $OF CR ." Barlett" ENDOF " GRAPE" $OF CR ." Concord" ENDOF CR ." Unknown fruit" ENDCASE ; What is the difference between $OF and: : $OF OVER =$ IF DROP ; or : $OF [ OVER =$ IF DROP ] ; IMMEDIATE I'm trying to understand POSTPONE and IMMEDIATE and [ ] from Starting FORTH. One of the chapters I could not understand at all when I was younger. On 4/14/2020 at 11:51 PM, TheBF said: Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 29, 2020 Author Share Posted April 29, 2020 1 hour ago, FarmerPotato said: What is the difference between $OF and: : $OF OVER =$ IF DROP ; or : $OF [ OVER =$ IF DROP ] ; IMMEDIATE I'm trying to understand POSTPONE and IMMEDIATE and [ ] from Starting FORTH. One of the chapters I could not understand at all when I was younger. It can make your head spin. It does mine. Before ANS Forth and POSTPONE it took two words to handle this action. There was COMPILE and [COMPILE]. Arguably they describe the action better as English words go. So think of POSTPONE as a "compiler" of a word that will happen not now... but later. So here goes: Just for reference a normal "colon" word in a colon definition has its address or "execution token" compiled into memory inline kind of like this. : FOO ; : BAR ; : TEST FOO BAR ; \ COMPILES TO <LINK>,<4>,"TEST", <DOCOLON> <'FOO>, <'BAR>, <SEMI> Sometime we want to make words that compile things into a colon definition, ie: make them "inline" rather than adding another sub-routine call. Example: We want to compute the address of an array. We could do this: CREATE Q 1000 ALLOT : [] ( n array -- addr[n]) SWAP 2* + ; 9 Q [] \ returns address of 9th cell But since [] could be used inside inner loops maybe we want it faster so we could compile 'SWAP 2* +' inline everywhere in the code, but that's a pain so we can make the equivalent of a macro with: : [] POSTPONE SWAP POSTPONE 2* POSTPONE + ; IMMEDIATE Now when we use [] in a definition it will not compile a call to [] Now [] is an immediate word and so during compilation it will be interpreted (even though the compiler is turned on) and it will "compile" the addresses of "SWAP" "2*" and "+" into the definition for us. How cool. Your example for $OF is using the [ and ] words. Let's go step by step: When you compile $OF the first thing you hit is [ which turns off the compiler so now the interpreter is running... The interpreter will see OVER and try and take the 2nd item on the stack and put it on the top of the stack (might fail) Then it will try to compare to strings on the stack for equality, but there are no strings on the stack right now so it will fail there No need to continue. I am sure you see what happened now. *** Your mind is in the right place. You want to get rid of all those damned POSTPONE words. There are two ways to do that: 1. Not implemented in Camel99 but part of Forth 2012 ( I think) are the ]] [[ words. Everything between those two operators, in a colon definition, is "postponed" Example: : $OF ]] OVER =$ IF DROP [[ ; IMMEDIATE 2. Use a "text macro" Example : $OF S" OVER =$ IF DROP" EVALUATE ; IMMEDIATE This will read the text string with EVALUATE and if your compiling it will compile and if interpreting will interpret the text. These are handy and easy to understand usually. BTW the reason POSTPONE was created was because COMPILE is for non-immediate words and [COMPILE] does the job for immediate words. This was deemed to be *confusing by the committee and so POSTPONE figures out what it needs to do regardless of the IMMEDIATEness of the word your are POSTPONEing. Clear? My head hurts now. * Imagine the ANS committee thought something in Forth might be confusing. Quote Link to comment Share on other sites More sharing options...
+TheBF Posted April 29, 2020 Author Share Posted April 29, 2020 (edited) Addendum: You mentioned [ and ] Here is the definition of these two words in CAMEL99 Forth. : ] ( -- ) STATE ON ; IMMEDIATE : [ ( -- ) STATE OFF ; IMMEDIATE They simply turn on the compiler or turn off the compiler , via the STATE variable and they do it Immediately. ie: they don't care if the compiler is running at the moment or not. STATE=true means we are compiling Edited April 29, 2020 by TheBF Quote Link to comment Share on other sites More sharing options...
D-Type Posted April 29, 2020 Share Posted April 29, 2020 Postpone still confuses me as I learned and used Forth 83 for 10 years in the 90s. From memory, Starting Forth print editions don't mention Postpone, only Compile. (But there is an ansi'fied web & pdf version which has text modified to describe Postpone instead, I think.) The definition of Compile is much easier to understand and it does what you expect, so I started with that, as it's used by Postpone. Honestly, learning Compile or Postpone on their own isn't enough, you need to learn about immediate and compile modes etc. together else none of it makes sense. Starting Forth covers it all over a few meaty chapters, but you might need to read and think about it several times before it sinks in. (At least I had to.) Maybe try the SF chapters in the first edition pdf that's on the web and understand Compile, then deal with about Postpone later on? 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted April 29, 2020 Share Posted April 29, 2020 I appreciate all the idioms you listed! I think I got it. You want $OF to execute immediately and compile 4 words. [ ] do not help accomplish that... what I was getting at needs to EVALUATE an expression at run-time. POSTPONE really is the shortest way to accomplish that. BTW, I see this isn't going to compile either, because the IF isn't balanced. : $OF OVER =$ IF DROP ; P.S. At the moment I'm using MeCrisp FORTH on BlackIce, which implements some layers of ANS FORTH. I'm testing my 9958 board. It will be a while before I get to a 9900 FORTH again. 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted April 29, 2020 Share Posted April 29, 2020 9 minutes ago, D-Type said: Postpone still confuses me as I learned and used Forth 83 for 10 years in the 90s. From memory, Starting Forth print editions don't mention Postpone, only Compile. (But there is an ansi'fied web & pdf version which has text modified to describe Postpone instead, I think.) I grabbed STARTING FORTH on Kindle (2017 eBook). POSTPONE is in chapter 11 Defining Words. I had a paper copy in the 80s and I gave up on compiling words when the syntax didn't match TI FORTH. I use CREATE or <BUILDS >DOES now... 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 1, 2020 Author Share Posted May 1, 2020 (edited) Working on re-building the TTY version of Camel99 Forth I did some testing to see the effect of increasing the baud rate. I simply used WORDS and ELAPSE to see how long it took to show the dictionary of 379 words on Terraterm. Here are the results Baud Seconds 9600 2.60 19200 2.11 38400 2.10 Looks like there is very little point in going past 19,200 bps on this implementation of Forth. I might be able to go faster with a version of TYPE in Assembler. Might give that a try... Edit: However the current version is vectored and multi-tasking friendly so maybe not... Edited May 1, 2020 by TheBF 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.