6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 4:56 pm

All times are UTC




Post new topic Reply to topic  [ 73 posts ]  Go to page Previous  1, 2, 3, 4, 5
Author Message
PostPosted: Tue Jul 07, 2020 12:35 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
scotws wrote:
If you are all-out for the smallest code possible, and you are going to be writing different games, which means you're going to keep running into the size problem, you might want to consider creating a Token Thread Code (TTC) Forth instead of using Tali. See http://www.bradrodriguez.com/papers/moving1.htm for the AFAIK best introduction to the differences. It will be slower - possibly a lot slower - but you could strip the Forth down to the bare essentials and use single-byte tokens for fantastic size games.

If I was writing a graphics intensive Forth application, I'd try a really lean Indirect Thread Code (ITC) Forth ( or maybe even a Token Thread Code Forth if memory was really tight ) and write the graphics routines as code words.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 08, 2020 9:09 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
BigEd wrote:
I'd quite like to understand what's going on with this game which makes it so large: it is certain that the game can't be more compact? (Having said which, how much memory are we talking about?)

Just from a quick look at the examples presented, it looks like this Forth code might be a direct translation of C into Forth. That is something Jeff Fox advised against.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 09, 2020 3:25 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Quote:
If I was writing a graphics intensive Forth application, I'd try a really lean Indirect Thread Code (ITC) Forth ( or maybe even a Token Thread Code Forth if memory was really tight ) and write the graphics routines as code words.
That's a good idea to save space, but I was going for as much performance as possible. With SamCoVT's help, I was able to eliminate a lot of functionality I didn't need and get everything to fit while still staying with STC.

Quote:
Just from a quick look at the examples presented, it looks like this Forth code might be a direct translation of C into Forth. That is something Jeff Fox advised against.
It depends on what you mean by "direct." Most of the highest level words like ColorTile have the same purpose as the corresponding C functions, but the subwords and internal functionality are implemented from scratch. I knew the purpose of the functions, so there was no need to translate the C to Forth line by line.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 10, 2020 10:25 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Druzyek wrote:
It depends on what you mean by "direct." Most of the highest level words like ColorTile have the same purpose as the corresponding C functions, but the subwords and internal functionality are implemented from scratch. I knew the purpose of the functions, so there was no need to translate the C to Forth line by line.

It looks like you might be thinking in 'C' or at least not as much in Forth. For example, this piece of code from the word ColorTile:
Code:
         dup c@                        \ get first byte of length,color pair
         swap 1+ swap                  \ increment tile pointer

can be replaced with this:
Code:
         count                         \ get first byte of length,color pair
                                       \ and increment tile pointer

and SamCoVT's suggestion:
Code:
: TileHW ( addr -- addr+2 w h)
   dup c@ swap 1+  \ Get width
   dup c@ swap 1+  \ Get height
   -rot ;          \ Arrange the results.

could be rewritten:
Code:
: TileHW ( addr -- addr+2 w h)
   count           \ Get width
   swap count      \ Get height
   rot swap ;      \ Arrange the results.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 12:30 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
SamCoVT wrote:
Druzyek wrote:
The next request would be a way to recognize errors immediately. As it is now, all the text gets pasted in instantly from a text file and any errors scroll immediately off the screen. Would it be possible to implement a separate output for error messages like stdout and stderr in C? It seems like modifying or replacing ABORT might do it. Another way might be to add a flag in zero page that causes an error message to go into an infinite loop when on but that can be switched off later after the file has been pasted in so the prompt still works interactively even when you cause errors. What do you think?


The great part about Forth is that you can actually go in and change the things that you think should work differently. I'll be interested to see what you come up with for a solution to this problem, as I also end up pasting very large inputs at times, and it would be nice to have it stop at the first error instead of having to scroll back and find it. I often want to throw away all the rest of the input, as a word that didn't compile will mess up most of the code that follows, and I would need to modify ACCEPT to do that. A flag in zero page, like you suggested might work well for my situation, and I could look for a control code (perhaps CTRL-Q) to allow regular input again. You will find (although I commented it out) where CTRL-P and CTRL-N were handled in ACCEPT for the input history. Do be careful as some CTRL combinations are handled by the terminal and not passed to the application (at least on Linux, anyway), such as CTRL-L (clears the screen).

ABORT (which you will find really just falls into QUIT) might be one place to make changes. It is called (jumped to, really, as it resets the stack anyway) after the error message has been printed. If you want the location where the error message is actually printed, you will need to look at "error:" in taliforth.asm. I believe this routine is used for all of the errors that would end up calling ABORT. You'll also want to look in "xt_number:" (just before the "_all_converted:" label) in native_words.asm if you want the name of an unknown word.

If Forth can't find a word, it tries to turn it into a number, so the spot where it realizes that the text at the input is not a number (and therefore an unknown word) is actually in the NUMBER routine.

You have the luxury of writing your own emulator, so you could make a "stderr" that goes somewhere else without actually needing to add hardware. You could just make an extra address that you write to for output, and then write some forth words to use it.

Keep us posted on whatever you end up with for a solution.

It seems ABORT is doing what it's supposed to do. TaliForth2 stops doing whatever it was doing, reports the error and goes into the QUIT loop to wait for user input. Since the 'user input' is actually text that is pasted into the emulator, it responds as though the error is ignored by the user who just keeps typing. Is it possible for the 65C02 system emulator to emulate mass storage for TaliForth2 ? Maybe a specific directory could be used as the mass storage the emulator could read. If the file were INCLUDEed instead of pasted into TaliForth2 , interpretation/compilation should stop at the first error.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 12:42 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
dwight wrote:
Symetric math is often better for polar math. Floored math is better for single lines or XY rectangular vectors. Symetric math makes zero an unique point. Floored math makes zero an offset. This can be vary important when doing multiple precision math on things like XY tables. Using math that rounds towards zero can really mess things up because it makes zero a unique point. You can't smoothly cross zero. As soon as you try to include offsets, thing go bad quickly.
It is easier to understand which is which by doing /mod instead of just mod. Both still need to follow the rule Dividend=Divisor*Quotient+Remainder. I've learned that I prefer floored math for most calculations but most processors round toward zero.
As an example. If one makes a table of sine and cosine with symetric math and incrementally calculates the next point around a circle, it won't close. If you use floored math, the circle will be a little off center but will close. This happens even for floating point but most don't notice the tiny error until many revolutions have been completed.
Dwight

Floored math is also better for Turtle graphics where you want to keep the heading within 0 and 359 degrees inclusive.
Code:
   <some heading value> 360 MOD HEADING !


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 1:01 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Druzyek wrote:

Creating a headerless version is going to be more work than I thought, so I won't be going down the rabbit hole after all. Instead, I should be able to fit the remaining code into additional banks by copying the entire 12k Tali Forth 2 installation into each of those banks.

What about a version of TaliForth2 with separated headers? The headers could reside in a separate set of banks. Each header would need an additional field to point to the word's executable code. The header banks could be switched in just long enough for the interpreter/compiler to get the address of the word to interpret or compile.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 3:18 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Quote:
It looks like you might be thinking in 'C' or at least not as much in Forth. For example, this piece of code from the word ColorTile:
If you mean defining a word called count that does "dup c@ swap 1+ swap" then you are no better off if your goal is performance. Either Tali Forth 2 will inline the word, which is essentially what I am doing by hand, or it will keep count and you lose performance jumping into it and out of it. The only improvement, if I understand you right, is making the source slightly more readable but possibly at the cost of speed.

Quote:
What about a version of TaliForth2 with separated headers? The headers could reside in a separate set of banks. Each header would need an additional field to point to the word's executable code. The header banks could be switched in just long enough for the interpreter/compiler to get the address of the word to interpret or compile.
Good idea. It would still use the same amount of memory, but grouping the code together without the headers would let me squeeze more into each bank so I would have to switch banks less often when the program is running.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 3:20 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
JimBoyd wrote:
It seems ABORT is doing what it's supposed to do. TaliForth2 stops doing whatever it was doing, reports the error and goes into the QUIT loop to wait for user input.

I think you're thinking of ABORT" (pronounced "abort-quote"). ABORT" examines a flag on the stack, and if it's true, ABORT" will give the error message and abort. ABORT by itself (without the " at the end) does not report errors, and is not conditional.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 22, 2020 7:39 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
GARTHWILSON wrote:

I think you're thinking of ABORT" (pronounced "abort-quote"). ABORT" examines a flag on the stack, and if it's true, ABORT" will give the error message and abort. ABORT by itself (without the " at the end) does not report errors, and is not conditional.

I wasn't very clear on that. I meant that TaliForth2 reports the error, by way of ABORT" which jumps to ABORT ( if I'm looking at the right TaliForth2 source ). ABORT is doing what it's supposed to do by jumping to the QUIT loop to wait for user input.
With the source pasted in, it's like there is a mad typist at the keyboard ignoring all errors and continuing to type.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 22, 2020 7:42 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Druzyek wrote:
Quote:
It looks like you might be thinking in 'C' or at least not as much in Forth. For example, this piece of code from the word ColorTile:
If you mean defining a word called count that does "dup c@ swap 1+ swap" then you are no better off if your goal is performance. Either Tali Forth 2 will inline the word, which is essentially what I am doing by hand, or it will keep count and you lose performance jumping into it and out of it. The only improvement, if I understand you right, is making the source slightly more readable but possibly at the cost of speed.

No. I mean using the word COUNT already supplied by TaliForth2.
Code:
xt_count:
                jsr underflow_1

                lda (0,x)       ; Get number of characters (255 max)
                tay

                ; move start address up by one
                inc 0,x         ; LSB
                bne +
                inc 1,x         ; MSB

                ; save number of characters to stack
*               tya
                dex
                dex
                sta 0,x         ; LSB
                stz 1,x         ; MSB, always zero

z_count:        rts


COUNT is a required word in the Forth-79 and Forth-83 standard. It is also a core word of ANSI Standard Forth.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 27, 2020 1:36 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Quote:
No. I mean using the word COUNT already supplied by TaliForth2.
This is a neat hack. Thanks! The word is apparently meant to fetch the length byte of a counted string, but this is a clever way to repurpose it for something else.


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 07, 2020 7:54 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Druzyek wrote:
Quote:
No. I mean using the word COUNT already supplied by TaliForth2.
This is a neat hack. Thanks! The word is apparently meant to fetch the length byte of a counted string, but this is a clever way to repurpose it for something else.

Really? It seemed like a logical use. Another use is in a high level definition of TYPE
Code:
: TYPE  ( ADR CNT -- )  \ TYPE takes an address of a string
                        \ and how many characters to display.
   0 ?DO
      COUNT EMIT
   LOOP
   DROP ;

Quote:
I had some trouble with 2R> since I assumed it would be R> R> but it actually reverses the order.

No, it doesn't. 2R> and 2>R move a pair of cells while retaining the byte order and therefore the cell order.
Although 2R> is semantically equivalent to R> R> SWAP , that is because moving a pair of cells one at a time with the sequence R> R> or the sequence >R >R reverses the order.
Given the numbers 137 and 42 already on the return stack, the sequence R> R> moves the data like this:
Code:

   42
  137
 ------  ------
 return   data

R>

  137      42
 ------   ------
 return    data

R>

           137
            42
 ------   ------
 return    data


The word 2R> moves the data like this:
Code:

   42
  137
 ------  ------
 return   data

2R>

            42
           137
 ------   ------
 return    data

Quote:
6.2.0410
2R>
“two-r-from”
CORE EXT
Interpretation: Interpretation semantics for this word are undefined.
Execution: ( – – x1 x2 ) ( R: x1 x2 – – )
Transfer cell pair x1 x2 from the return stack. Semantically equivalent to R> R> SWAP.
See: 3.2.3.3 Return stack, 6.1.0580 >R 6.1.2060 R> 6.1.2070 R@ 6.2.0340 2>R, 6.2.0415
2R@, A.6.2.0410 2R>.



Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 73 posts ]  Go to page Previous  1, 2, 3, 4, 5

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: