-
Posts
4,470 -
Joined
-
Last visited
Content Type
Profiles
Forums
Blogs
Gallery
Events
Store
Posts posted by TheBF
-
-
1 hour ago, Vorticon said:
How can I detect and identify a keypress in assembly without resorting to DSRLNK?
KSCAN in console ROM and works ok.
I do something like this in Camel99 (but with RPN syntax so this is un tested.
OLDR11 DATA 0 KSCAN LWPI >83E0 can't change WS with BLWP as R13-R15 are in use MOV R11,@OLDR11 save GPL R11 BL @>000E call keyboard scanning routine MOV @OLDR11,R11 restore GPL R11 LWPI WREGS MOVB @>837C,R1 Check flag for key pressed SLA R1,3 Flag value is >20 JNC NOKEY No key was pressed MOVB @>8375,R1 Get key code RT NOKEY R1 CLR, RT
- 1
-
Good catch! BTW you are not alone in changing things without testing.
The shame of it is Forth makes testing so simple most of the time.
Is it worth asking why you changed KEY from a colon definition to ALC?
- 1
-
From Hacker news:
Besides his contribution to language design, he authored one of the best puns ever. His last name is properly pronounced something like "Virt" but in the US everyone calls him by "Worth".
That led him to quip, "In Europe I'm called by name, but in the US I'm called by value."
😆
- 8
-
R.I.P. Niklaus Wirth.
- 6
-
20 minutes ago, jrhodes said:
I love rhubarb, especially on pancakes!
🥞
Rhubarb pancake syrup:
8 cups chopped rhubarb
3 cups water
2 cups sugarStart by adding the rhubarb and water to a pot and simmer. Use a fork to mash the rhubarb as it softens.
Strain it with a sieve and return the rhubarb water back to the pot.
Add the sugar, heating until it dissolves.
Let the syrup cool completely before pouring it into jars or bottles for storing.I am now thinking about Rhubarb Maple Syrup. Pricey but could be tasty as well.
- 2
-
7 hours ago, apersson850 said:
Mixing Forth and assembly is easy, but then you have to hang by your feet from the ceiling to read the programs right.
That's why they call me Batman. 🤣
- 4
-
1 hour ago, retrodroid said:
MOV R0, R1 ; Copy original value SRA R0, 3 ; Div by 8 SLA R0, 3 ; Mpy by 8 C R0, R1 JEQ NOREM ; R0 is divisible evenly by 8, with no remainder
vs
LI R2, 8 DIV R2, R0 ; Div by 8 JNO NOREM ; No remainder
...but it seems It would be waaay more efficient to use the second version instead.
The 9900 takes no prisoners. It can be very hard to extract faster times from the old girl by using more instructions in my experience.
Sometimes you win, but you have to test to be certain.
- 2
-
In the VDP packed string arrays in the previous post, I changed ADD$ to give it protection from writing past your allocated TABLE size.
Much better.
: ADD$ ( addr len vdp[] size -- ) 2DUP + >R \ Rpush end of array SEEKFREE ( -- addr len Vaddr) 2DUP + R> > ABORT" Can't ADD$" DUP>R VPLACE R> VALLOT ;
- 1
-
Happy New Year Everybody
I was looking at some old code I built for HsForth based on the "Let's Build a Compiler" by Jack Crenshaw
Let's Build a Compiler! (penguin.cz)
It builds a tiny Pascal compiler and one day I may get enough energy to port it to TI-99.
I wondered about putting the keyword table and the symbol table in VDP RAM. You can cram a lot of text into memory
using counted strings as a poor-mans linked list.
Somebody might want something like this for another purpose and it should port over to the other Forth systems with a few word replacements.
If you hit a wall just ask.
VC! -> VSBW VC@ -> VSBR VWRITE -> VMBW POSTPONE -> COMPILE
I have a little VDP manager library that I include to begin
\ VARIABLE VP ( moved to kernel in V2.55 ) HEX 1000 VP ! \ "VDP pointer" start of free VDP RAM : VHERE ( -- addr) VP @ ; \ FETCH the value in VDP pointer : VALLOT ( n -- ) VP +! ; \ add n to the value in VDP pointer : VC, ( n -- ) VHERE VC! 1 VALLOT ; : V, ( n -- ) VHERE V! 2 VALLOT ; : VCOUNT ( vdp$adr -- vdpadr len ) DUP 1+ SWAP VC@ ; : VCREATE ( <text> -- ) VHERE CONSTANT ; \ address when <text> invoked \ : VPLACE ( $addr len Vaddr -- ) \ like PLACE for VDP RAM. In KERNEL 2.6 \ 2DUP VC! 1+ SWAP VWRITE ;
Spoiler has the implementation:
Edit: I added protection to ADD$ so it doesn't go past the allocated size of the array.
Spoiler\ compact string tables in VDP RAM Jan 2024 Brian Fox \ NEEDS DUMP FROM DSK1.LOWTOOLS NEEDS VCOUNT FROM DSK1.VDPMEM \ "place" string caddr/u in VDP memory as byte-counted string : VS, ( caddr u -- ) VHERE OVER 1+ VALLOT VPLACE ; \ compile a string into VDP memory : ," [CHAR] " PARSE VS, ; : NEXT$ ( $addr -- $addr') VCOUNT + ; : NTH$ ( $list n -- $addr) 0 ?DO NEXT$ LOOP ; \ GOTO the nth string \ syntactic sugar. Get length of a string : VLEN ( $addr -- ) POSTPONE VC@ ; IMMEDIATE \ compile null string (0) to start list : VDP{ ( -- VDPaddr) VHERE 0 VC, ; \ compile 0 to end array : }VDP ( Vaddr -- Vaddr size ) 0 VC, \ end with a null string VHERE OVER - ; \ compute the size in bytes \ tables are recorded as a 2CONSTANT : 2CONSTANT CREATE , , DOES> 2@ ; DECIMAL \ Neil Baud's COMPARE modified to compare RAM string to VDP string \ 0 means adr1 = adr2 \ -1 means adr1 < adr2 \ 1 means adr1 > adr2 : VCOMPARE ( addr u1 Vaddr u2 -- -1|0|1 ) ROT 2DUP - >R ( a1 a2 n2 n1) ( R: n2-n1) MIN ( a1 a2 n3) BOUNDS ( loop index I becomes the VDP address) DO ( a1) COUNT I VC@ - ( a1 diff) DUP IF NIP 0< 1 OR ( -1|1) UNLOOP R> DROP EXIT THEN ( a1 diff) DROP ( a1) LOOP DROP ( ) R> DUP IF 0> 1 OR THEN \ 2's complement arithmetic ; \ LOOKUP Returns index into the table or zero : LOOKUP ( addr len table size -- ndx ) DROP NEXT$ -ROT PAD PLACE 1 SWAP BEGIN DUP VLEN WHILE ( string<>0) DUP VCOUNT PAD COUNT 2SWAP VCOMPARE WHILE ( Vcompare<>0) NEXT$ SWAP 1+ SWAP REPEAT THEN ( -- ndx Vaddr ) VLEN 0> \ if string length=0 we hit the end ( ndx ?) AND \ and ndx with flag ; \ create a table of strings that you can add to easily : TABLE: ( n -- ) CREATE VHERE \ VDP address of the table SWAP DUP , VALLOT \ record size, allocate VDP space , 0 VC, \ compile null string in the table DOES> 2@ ( -- Vaddr size) ; : SEEKFREE ( vdp[] size-- Vaddr) BOUNDS ( -- last 1st ) NEXT$ \ skip the first null BEGIN 2DUP > WHILE ( last > 1st) DUP VLEN WHILE NEXT$ REPEAT THEN NIP ; : ADD$ ( addr len vdp[] size -- ) 2DUP + >R \ Rpush end of array SEEKFREE ( -- addr len Vaddr) 2DUP + R> > ABORT" Can't ADD$" DUP>R VPLACE R> VALLOT ; : NEW ( Vaddr size -- ) 0 VFILL ; \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
And here is what it looks like when you use it.
\ >> TEST CODE << \ reset the VDP memory pointer to your chosen first address HEX 1000 VP ! \ create a finite size list of string constants VDP{ ," IF" ," ELSE" ," ENDIF" ," WHILE" ," ENDWHILE" ," DO" ," ENDDO" ," LOOP" ," ENDLOOP" ," REPEAT" ," UNTIL" ," FOR" ," TO" ," ENDFOR" ," BREAK" ," READ" ," WRITE" ," VAR" ," END" ," PROCEDURE" ," PROGRAM" }VDP 2CONSTANT KEYWORDS S" REPEAT" KEYWORDS LOOKUP . S" absent" KEYWORDS LOOKUP . 1024 TABLE: SYMBOLS SYMBOLS NEW S" symbol1" SYMBOLS ADD$ S" symbol2" SYMBOLS ADD$ S" symbol3" SYMBOLS ADD$ S" symbol4" SYMBOLS ADD$ S" symbol5" SYMBOLS ADD$ S" symbol6" SYMBOLS ADD$ S" symbol7" SYMBOLS ADD$ S" symbol8" SYMBOLS ADD$ S" symbol9" SYMBOLS ADD$ S" symbol10" SYMBOLS ADD$ S" symbol11" SYMBOLS ADD$ S" symbol12" SYMBOLS ADD$ S" symbol13" SYMBOLS ADD$ S" symbol14" SYMBOLS ADD$ \ test code to view the tables : VTYPE ( Vaddr len --) BOUNDS ?DO I VC@ EMIT LOOP ; : VPRINT ( V$ -- ) VCOUNT CR VTYPE ; : .TABLE ( table size -- ) BOUNDS NEXT$ BEGIN 2DUP > WHILE DUP VLEN WHILE DUP VPRINT NEXT$ REPEAT THEN 2DROP ;
- 2
-
* Equates were very confusing. * VRAM vs CPU RAM (I had no idea they were separate). * The workspace pointer. * BLWP * Memory mapped devices, an the memory map in general. Why were things were they are? * The notion of the `-R` flag to the assembler (I always wrote code using "R0", "R5", etc., and did not understand why assembly failed without the `-R` flag).
This little list is like the outline of a course called:
"Introduction to Computing on the TI-99"
Chapter 1: Essential Knowledge
Maybe you could give a short paragraph on what the key learning was for you, on each item, over the next few weeks to help Roberto.
(not meaning to make work for you, but it's a really good list IMHO)
-
19 minutes ago, HOME AUTOMATION said:
Executing a RESET VECTOR, while the WS, is set to the GPLWS, will save your current WS, STATUS, AND PC, there, before taking the branch.
Perhaps this matters to DSRs/hardware.
That makes sense. I was trying to save as many bytes as possible and found these two instructions gave me a reliable reset but my needs are not very sophisticated.
-
16 minutes ago, dhe said:
ABORT LIMI 2 ENABLE INTERRUPTS
LWPI GPLWS LOAD GPL WORKSPACE REGISTERS
BLWP @>0000 BRANCH THROUGH THE VECTOR >0000This seems overly complicated. I would think just blwp @>0000 would always work ?
Ya that seems odd. LWPI sets the workspace but then BLWP is going to change it to whatever is in the vector at >0000.
I get out of Forth reliably with:
CODE BYE ( -- ) 83C4 @@ CLR, \ clear interrupt vector 0000 @@ BLWP, \ ROM reset vector is at 0000 ENDCODE
Just twist your head a bit to see it in conventional notation.It's important to clear the interrupt vector because it could be hooked to code that is still in memory when you exit and it would try to keep running every 16mS.
-
19 minutes ago, dhe said:
One thing that has always given me pause in Molesworth is:
STATUS EQU >837C GPL STATUS BYTE
then before returning they do:
CLR @STATUS
So the status byte, is a byte.
CLR operates on a word.
Is it dangerous to clear a word worth of memory, when you are aiming for a byte, or does the byte after the status byte not matter?
It would be dangerous if >837D had something important in it. In the Editor/Assembler manual. >837D is described as the character at current screen position for the GPL interpreter.
So it is safe until you use >837D for some purpose in your code.
- 1
-
14 minutes ago, retrodroid said:
Modern assembly coding for the TI (or any retro platform I imagine) is sooo much nicer than it was back then with the ability to code in a modern IDE, on a modern computer, and test against multiple different emulators, etc.
I have that book as well, purchased in the 1980s at some time.
Modern tools are much better for sure, but those of using Forth Assemblers back in the 1980s (or in 2024 ) could write and test Assembly language code interactively like it was BASIC.
Now of course if you code a big error the machine crashed but the reboot process was pretty quick and you were back into the editor toute suite.
Typically the code routines were short then you concatenated them together with Forth to do more complicated things but it was pretty sweet compared to the edit/assemble/load/bomb/ process with E/A tools.
-
On 12/31/2023 at 11:35 AM, PeteE said:
+254 -256 bytes is +127 -128 words
LOL. And so it is.
Typing with my head turned off.
- 1
-
I would like to celebrate your achievement. Classic99 has given me no end of fun.
Thanks and all the best in 2024.
- 3
-
You might have a typo there (+254 -256)
9900 native jump instructions are limited to so +127 .. -128.
Or is there even more magic inside GCC?
-
That's look great.
-
I found another place where Forth is discussed on Discord.
Someone mentioned tail call optimization so I showed how I did it with a word I called GOTO ( *IP IP MOV,)
Another poster asked "Couldn't you use BRANCH?'"
After a second I realized I just had to convert the absolute address that GOTO uses, into an offset that Camel Forth BRANCH uses.
And when I tried it it made the optimization ~5% faster because BRANCH in Camel99 lives in scratch-pad RAM.
\ tail call optimizing semicolon for Camel99 Forth Nov 27 2022 Brian Fox DECIMAL : CELL- 2- ; : PREVXT ( -- XT) HERE CELL- @ ; \ fetch the XT of previous compiled word \ -; does not end with EXIT because it is branching directly to another \ list of tokens. That other list will end in EXIT or NEXT. : -; ( -- ) \ programmer controlled PREVXT >BODY \ get previous XT, compute PFA -2 ALLOT \ erase the previous XT POSTPONE BRANCH HERE - , \ compile BRANCH to the PFA POSTPONE [ \ turn off compiler REVEAL ?CSP ; IMMEDIATE : COLON? ( xt -- ?) @ [ ' DOCOL @ ] LITERAL = ; VARIABLE TAILCALL \ control tail call optimizizing with this variable \ TAILCALL ON turns optimizer on : ; ( -- ) TAILCALL @ IF PREVXT COLON? IF POSTPONE -; ELSE POSTPONE ; THEN ELSE POSTPONE ; THEN ; IMMEDIATE
- 2
-
4 hours ago, dhe said:
I printed the manpage you create for the release.
I use it as a guide to what is fair game! 😃
Thank you for keeping me on track.
I have been away from the code for a while and since I am not a real VI user, that is the only document that contains what I tried to get working.
- 1
-
My mistake. I was adding commands faster than I realized.
I have corrected d$ and will get to the paste function so it behaves as expected.
I have created so many functions that I don't always remember how to use them correctly.
-
Just now, Appeelicious said:
I think assembly will have my attention this year, but I'll keep forth in mind 😛
Assembly language is an excellent first step before trying Forth.
Forth is closer to a macro assembler than a "language"... that is until you extend it.
- 1
-
There is no handler for d$ so that one doesn't surprise me.
I need to look up what it means.
(I will never duplicate the entire command set. Not enough space in a stock console)
-
- 4
- 1
Stevie Development Thread
in TI-99/4A Development
Posted
I gotta see if it GROKs Forth.