-
Posts
4,470 -
Joined
-
Last visited
Content Type
Profiles
Forums
Blogs
Gallery
Events
Store
Posts posted by TheBF
-
-
Typically the ASM code you need is not very big so 10 bytes may or may not be important. Speed/size. It's the classic trade-off.
BTW on 6809 is might be smaller because of 8 bit op-codes in some cases. However the ASM[ will be pretty much the same for any ITC Forth. (I think)
-
Give me a day. I should be able to make a script to combine a pile of source code files into one big file.
- 1
-
CAMEL99 Forth /TTY
For anyone interested here is a re-built version of CAMEL99 Forth /TTY. This is the first time I have put this out to the public. I am not 100% certain it is a perfect mirror of what is on my floppy disk here but it should start ok. If you get into trouble type COLD to reboot the system if it is still responding.
It runs over RS232/1 on a regular TI-994a with RS232 card and floppy drives. I would be interested to hear what happens with some of the alternative disk systems out there. It "should" work with whatever DSR is installed for the device. (he said quietly, his lip trembling slightly...)
Disk utilities are CAT, DIR and MORE (to see a text file)
Editors are only working for VDP and console keyboard at this time. More work for me.
Disclaimer: Not all of the demo programs on DSK3. work as expected because they were made for VDP terminal. Caveat Emptor
- 4
-
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...
-
1 hour ago, D-Type said:
What is the state of the art for '99 Forth cross compilers regarding macro inlining of small code words?
I was thinking about how to improve the speed of my 6809 Vectrex/Camel Forth and came to a similar conclusion as this thread i.e. instead of rewriting the compiler as STC (not enough time, never going to happen) I could make it make it STC-ish by inclining code and reducing the call overhead.
(I remembered the inlining thread that came after this one and searched for it, but first came across this thread - will reread the inlining thread next. Simple inlining was actually what I was thinking about using initially, but of course the mind wanders...)
In-lining Assembly language in indirect threaded code is pretty space wasteful. I wrote a way to do it and here is how it goes.
You need to create the indirect links to move from threaded code to native machine code. That adds 4 bytes to enter the code.
After the machine runs the instruction pointer has moved forward but the Forth interpreter doesn't know about it so you have to move Forth IP register forward to which I did by compiling more machine code. That added 4 more bytes. Then you compile a way to run the Forth inner interpreter which in my case is another 2 bytes.
So all together you add 10 bytes just to enter and exit machine code from within ITC Forth code.
Not great.
\ put inline ASM in colon definitions : ASM[ HERE CELL+ , \ compile a pointer to the next cell HERE CELL+ , \ which is the CFA of the inline code [ ; IMMEDIATE \ switch to interpreter mode : ]ASM 0209 , HERE 2 CELLS + , \ macro: LI R9,HERE+4 \ moves Forth IP reg.) NEXT, ] ; IMMEDIATE \ switch ON compiler
Better to just write some code words because at least they are re-useable elsewhere.
However for 1 use the size of the dictionary entry is probably bigger than using ASM[ ]ASM so … maybe it's useful.
Now in a sub-routine threaded system it is beautiful. In fact on some processors like the 9900 the Forth instruction and machine code are the same size as the CALL <ADDRESS> combination.
So for STC systems it's best to inline most of the Forth intrinsic instructions. ( + - @ ! etc.)
- 1
-
2 hours ago, Tursi said:
Hmm.. makes it seem unlikely. Is it possible that the instruction before the decrement is responsible? It's unlikely, but sometimes I don't trust the internal PC in debug statements, the cause can be an instruction or two earlier.
I just noticed I was focused on A074, cause that's where the arrow is, but the debug says A072. Definitely look at the previous instruction. The PC needs to be incremented before the hardware access occurs.
I was thinking the it must be something like that.
(I am your favourite pain in the _ss I think.)
It was happening in my key scan loop which was calling the 9901 timer to determine when to flash the cursor or flash the space character. {called BL in Forth (blank)}
: KEY ( -- char) BEGIN \ start the loop PAUSE \ Essential for Multi-tasking with Console \ *BAD* TMR@ 1FFF < \ compare harware timer to 1FFF \ *good* 8378 @ 0F AND 7 < \ compare interrupt counter to 7 IF CURS @ \ true? fetch the cursor char ELSE BL \ false? get the screen char THEN VPUT \ then put on screen KEY? \ check the keyboard ?DUP \ DUP IF <> 0 UNTIL \ loop until a key pressed BL VPUT ; \ put the space char on screen
Here is VPUT which does the talking to the 9918. The BL to WMODE sets LIMI 0 on entry.
variable: VPG \ holds address of VDP page ( >400 increments only) CODE: VPUT ( char -- ) \ put a char at cursor position TOS PUSH, R1 STWP, \ workspace is USER area base address 32 (R1) R3 MOV, \ vrow->r3 2E (R1) R3 MPY, \ vrow*c/l->tos 34 (R1) TOS ADD, \ add vcol VPG @@ TOS ADD, \ add video page address l: _VC! ( char Vaddr -- ) \ VSBW in Forth style pronounced "Vee-Cee-store" TOS R0 MOV, WMODE @@ BL, *SP SWPB, *SP+ VDPWD @@ MOV, \ write char & POP 2 LIMI, TOS POP, \ refill TOS NEXT, END-CODE
Here is that code to read the 9901 timer, which you have seen before. ?
CODE: TMR@ ( -- n) \ read the TMS9901 timer 0 LIMI, TOS PUSH, R12 2 LI, \ cru = 1 (honest, 2=1) -1 SBO, \ SET bit 0 TO 1, Enter timer mode TOS 0E STCR, \ READ TIMER (14 bits) -1 SBZ, \ RESET bit 1, exit timer mode 2 LIMI, NEXT, END-CODE
First I remove the call to TMR@ above and voila! Problem solved.
So then I remove the LIMI 2 instruction at the end of this and it flashed the warning once, but only once for the 2 ..3 minutes that I tried to make it happen.
Not sure why calling the timer did it.
-
R6 is the base address of the data stack and starts at >FF7C.
There will be occasions where I put a VDP address on the data stack and then run a VDP read or write routine but all of these are now running with interrupts off.
It seems quite hard to nail down.
It might be related to my disk DSR routine... I will check if it is doing VDP on it's own.
(EDIT: Not DSR. BLWP to the DSR routine starts with LIMI 0 and ends the LIMI 2 )
-
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
-
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.
-
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.
- 1
-
-
So that was a pretty easy fix.
I LIMI 0 at the start of the VDP address setting sub-routine and LIMI 2 after the last instruction that touches the VDP in the routine.
Timings using the screen time-out counter seem about the same.
Most of the time the VDP warnings are gone but occasionally I get this"
Warning: PC >A072 reading VDP with LIMI 2
And here is the debugger code that runs at >A072
A072 0646 dect R6 (14) > A074 C584 mov R4,*R6 A076 C108 mov R8,R4 A078 045A b *R10
This is the runtime code for a Forth variable. (which is just a pointer to memory like a label on a DATA statement)
Push R4 ( top of stack cache register) onto the data stack
Move the address of the interpreter pointer (R8) into R4
Why would that show the VDP warning?
Edit: And now the debug screen is repeating this over and over.
-
Nice lecture.
Ok I will fix my end.
You just explained a bug I encountered with automotion running when I tried to clear the screen in the console.
Lots of stuff I am clueless about.
Now I know.
Thanks
-
On 4/27/2020 at 12:24 PM, Tursi said:
Version 399.025
<SNIP>
- add debug warning when VDP accessed with interrupts active
- <snip>Version 399.024
- Fix reading imagedisk files by sector - file type was not being ignored
http://harmlesslion.com/software/classic99
Hi Tursi, Thanks again for all your efforts with this program. It's a beaut. I am running 399.025 now.
I have written Camel99 Forth to keep interrupts running as much as possible so that I can use ISR counters measuring elapsed time for code evaluations.
So I have interrupts masked while setting the VDP addresses and during KSCAN calls, but I do VDP read/writing with LIMI 2.
I don't seem to have any bad effects from this on real iron but I don't push things anywhere near a speed limit.
I can't find a reference in the manual. Is there a flag to disable the VDP warnings?
My debug screen is full of warnings.
-
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
-
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.
-
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
-
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 primitivesAs Vorticon mentioned over there "choose your poison".
- 1
-
Has anyone ever used this chip in a Supercart?
I has an 8 byte clock and calendar built in. I used it in an industrial product in the 90s.
- 1
-
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.
- 1
-
14 hours ago, oddemann said:
Snazzle! A snake game. Think I got most bugs, but 580 is "bugging" me!
(Book: "Zappers: having fun programming and playing 23 games for TI -99/4A")
BAD VALUE IN 580
Any ideas?
Sometimes99er got the bug, and now it is correct! Have fun playing it!100 REM SNAZZLE 110 RANDOMIZE 120 DIM S(100,2),TABLE(26) 130 TABLE(5)=1 140 TABLE(4)=2 150 TABLE(24)=3 160 TABLE(19)=4 170 FOR LEVEL=1 TO 3 180 CALL CLEAR 190 PRINT " YOU ARE NOW ENTERING":::::::::: 200 PRINT "L EEEE V V EEEE L" 210 PRINT "L E V V E L" 220 PRINT "L EEE V V EEE L" 230 PRINT "L E VV E L" 240 PRINT "LLLL EEEE VV EEEE LLLL" 250 PRINT :::TAB(11);"# ";LEVEL 260 FOR T=1 TO 1000 270 NEXT T 280 CALL CLEAR 290 SCORE=0 300 FOR I=1 TO L 310 S(I,1)=0 320 S(I,2)=0 330 NEXT I 340 ON LEVEL GOSUB 1150,1160,1200 350 X =INT(RND*26)+2 360 Y =INT(RND*22)+2 370 CALL GCHAR(Y,X,T) 380 IF T<>32 THEN 350 390 D=INT(RND*4)+1 400 RC=31 410 CALL CHAR(128,"FFFFFFFFFFFFFFFF") 420 CALL COLOR(13,5,1) 430 CALL CHAR(136,"FFFFFFFFFFFFFFFF") 440 CALL CHAR(144,"00FF7E4C4C7EFF00") 450 CALL COLOR(14,7,1) 460 CALL HCHAR(1,1,128,RC) 470 CALL HCHAR(24,1,128,RC) 480 CALL VCHAR(1,1,128,24) 490 CALL VCHAR(1,RC,128,24) 500 L=4 510 GOSUB 1090 520 REM 530 FOR I=0 TO L 540 IF S(I,2)=0 THEN 560 550 CALL HCHAR(S(I,2),S(I,1),32) 560 S(I,1)=X 570 S(I,2)=Y 580 CALL GCHAR(Y,X,T) 590 IF T<>32 THEN 790 600 CALL HCHAR(Y,X,136) 610 CALL KEY(3,KEY,STATUS) 620 IF STATUS THEN 740 630 ON D GOSUB 660,680,700,720 640 NEXT I 650 GOTO 530 660 Y=Y-1 670 RETURN 680 X=X+1 690 RETURN 700 Y=Y+1 710 RETURN 720 X=X-1 730 RETURN 740 IF (KEY<65)+(KEY>90) THEN 630 750 KEY=KEY-64 760 IF TABLE(KEY)=0 THEN 630 770 D=TABLE(KEY) 780 GOTO 630 790 REM 800 IF (T=128)+(T=136)THEN 1010 810 CALL SOUND(50,1700,0) 820 CALL SOUND(50,892,0) 830 L=L+3 840 SCORE=SCORE+1 850 IF SCORE=10 THEN 920 860 SCORE$=STR$(SCORE) 870 FOR J=1 TO LEN(SCORE$) 880 CALL HCHAR(1,J+10,ASC(SEG$(SCORE$,J,1))) 890 NEXT J 900 GOSUB 1090 910 GOTO 600 920 FOR I=1 TO 16 930 CALL SCREEN(I) 940 CALL SOUND(50,I*110,0) 950 NEXT I 960 NEXT LEVEL 970 CALL CLEAR 980 PRINT "CONGRATULATIONS!" 990 PRINT " YOU HAVE WON":::::: 1000 END 1010 FOR I=4 TO 1 STEP -.25 1020 CALL SOUND(50,I*110,0) 1030 CALL SCREEN(15) 1040 CALL SCREEN(2) 1050 NEXT I 1060 FOR T=1 TO 1000 1070 NEXT T 1080 END 1090 RX=INT(RND*(RC-2))+2 1100 RY =INT(RND*22)+2 1110 CALL GCHAR(RY,RX,T) 1120 IF T<>32 THEN 1090 1130 CALL HCHAR(RY,RX,144) 1140 REM 1150 RETURN 1160 CALL HCHAR(4,4,128,22) 1170 CALL HCHAR(12,12,128,6) 1180 CALL HCHAR(20,4,128,22) 1190 RETURN ^ 1200 FOR I=5 TO 25 STEP 5 1210 CALL VCHAR(7,I,128,17) 1220 NEXT I 1230 CALL HCHAR(4,12,128,26) 1240 RETURN
One more, 1190 RETURN ^
- 1
-
4 hours ago, Kchula-Rrit said:
While investigating my runaway light show problem, I think I found a bug in TI's VMBW routine! Here's a disassembly of the VMBW routine:
If R2 is zero (writing zero bytes to VDP) it will decrement before the check, sending 65536 bytes to the VDP, causing the "lights show," and trashing any PABs and other stuff. VMBR has the same "problem."
Maybe not necessarily a bug; TI probably did not expect someone to send "nothing" to the VDP.
K-R.
Thanks for mentioning this.
After reviewing my own version of this I was able to take some bytes out it by using your observation.
My original version used a jump around the routine if the the count was zero.
It's pretty much free to protect from 0 count arguments by using the the carry flag to exit the loop when the count transitions from 0 to -1.
Here it is in Forth Assembler:
CODE: VWRITE ( RAM-addr VDP-addr cnt -- ) R0 POP, \ vaddr to R0 R1 POP, \ cpu addr to R1 WMODE @@ BL, R3 VDPWD LI, \ vdp addr. in a reg. makes this 12.9% faster BEGIN, TOS DEC, \ decr count in R4 OC WHILE, \ while carry=true *R1+ *R3 MOVB, \ write byte to vdp write port REPEAT, TOS POP, \ refill top of stack cache register NEXT, \ return to Forth END-CODE
And it assembles to this:
* VWRITE (VMBW) A7D8 C036 mov *R6+,R0 A7DA C076 mov *R6+,R1 A7DC 06A0 bl @>a754 \ set write address A7E0 0203 li R3,>8c00 A7E4 0604 dec R4 A7E6 1702 jnc >a7ec A7E8 D4F1 movb *R1+,*R3 A7EA 10FC jmp >a7e4 A7EC C136 mov *R6+,R4 A7EE 045A b *R10 \ return to Forth
I set R3 to the VDP write port address because I have found it is almost 13% faster on large memory block moves.
-
47 minutes ago, Kchula-Rrit said:
While investigating my runaway light show problem, I think I found a bug in TI's VMBW routine! Here's a disassembly of the VMBW routine:
VMBW_START 2200 BL @VDP_SET_WRITE_ADDR >06A0,>223A '..":' 2200 VMBW_LOOP 2204 * Get data from caller's buffer, * pointed-to by R1 MS byte, * and send to VDP. MOVB *R1+,@VDPWD >D831,>8C00 '.1..' 2204 * Done? DEC R2 >0602 '..' 2208 * If not, send another byte. JNE BW >16FC '..' 220A * Return to caller. RTWP >0380 '..' 220C
If R2 is zero (writing zero bytes to VDP) it will decrement before the check, sending 65536 bytes to the VDP, causing the "lights show," and trashing any PABs and other stuff. VMBR has the same "problem."
Maybe not necessarily a bug; TI probably did not expect someone to send "nothing" to the VDP.
K-R.
I ended up putting a protection jump around mine, but your idea is better. I will re-organize the loop.
Thanks
- 1
-
45 minutes ago, Lee Stewart said:
This is how TI Forth does screen/block I/O. This method uses DSR Level 1 Read/Write Sector subprogram >010 via what is termed a transfer block at FAC (>834A in 16-bit scratchpad memory) instead of a PAB in VRAM as required by DSR Level 3 file I/O. Only one sector at a time is transferred to a program-designated 256-byte buffer in VRAM. TI Forth moves 4 contiguous sectors (1 at a time) into a 1 KiB VRAM buffer before copying said buffer to a CPU RAM block buffer for Forth’s use. This kind of sector access is obviously dangerous as it totally disregards the file system and can easily trash a disk that contains files such as does the TI Forth system disk. That is the main reason I developed fbForth (from TI Forth), which uses DSR Level 3 file-record I/O (eight 128-byte records/block) via VRAM PABs to manage Forth blocks located in separate blocks files.
...lee
Has anyone every written an alternate DOS that uses raw sectors?
As I write this I remember that USCD Pascal seems to have a different disk system but I am thinking more along the lines of putting an MS DOS format on TI disks for example.
Machine Forth OMG
in TI-99/4A Development
Posted
It's a neat little hack. I think you just need the macro to use your IP register instead of R9 to make it work. ??