ForthHub/discussion

Conditionals design and implementation

iru- opened this issue · 8 comments

iru- commented

There are at least two differing semantics for IF and the words that build on it:

  1. classical: IF consumes the top of the stack and branches on false (usually 0)
    : test ( n -- ) if ." true" else ." false" then ;

  2. machineforth: IF branches on a flag external to the stack (usually the processor flags), preserving the stack contents
    : test ( n -- ) 0 <> drop if ." true" else ." false" then drop ;

What are your opinion/experience on the pros and cons of the two approaches?

Using both approaches in a system on a J1 forth processor.

There's a classical 'if', branching on zero stack top and popping off the value, and custom 'c-if' I've added for my needs, branching on the carry flag not set, without popping the stack.
Helps greatly when processing strings of bytes, packed into 16-bit words. The J1 has no byte addressing, and storing bytes as words in not acceptable in tight embedded environment. So this need had to be addressed.

iru- commented

@vstrakh sorry, I didn't fully understand. How does c-if help in your case? Why is it better for you than the classifcal one?

J1 is running within FPGA, using very limited resources. It has tiny stacks, originally 15 cells for data, and 17 cells for return stack. Avoiding extra constants/masks, as well as extra instructions - is crucial.

With J1 you have a memory organized as 16-bit words. To print some strings you must read the bytes, and send it to UART/whatever. The 'type' word would accept the word address and the length of string in bytes.

: type ( w-addr n -- )
    >r 2* begin
        waddr @ c-if bswap then emit 1+
    next
    drop
;

'waddr' takes the offset in bytes, shifts it right to produce the required word address, and affects carry flag, which then is used to swap the halves of the word when accessing odd bytes. The original byte offset is staying at the stack top, the fetch consumes the produced word address, but doesn't affect the carry flag.

Making the same with classical if would require more stack manipulations, more instructions to the CPU that is not extremely fast.

cwpjr commented
cwpjr commented
cwpjr commented
iru- commented

@cwpjr could you elaborate on the (dis)advantages you encountered in each approach for the domain of application?

If I specialize/customize a or my forth this way, it is usually for a demonstrable advantage in a specific domain.

On Tue, May 28, 2019 at 4:49 AM iru- @.***> wrote: There are at least two differing semantics for IF and the words that build on it: 1. Classical: IF consumes the top of the stack and branches on false (usually 0). E.g. : test ( n -- ) if ." true" else ." false" then ; 2. machineforth: IF branches on a flag external to the stack (usually the processor flags), preserving the stack contents. E.g. : test ( n -- ) 0 <> drop if ." true" else ." false" then ; What are your opinion/experience on the pros and cons of the two approaches? — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <#82?email_source=notifications&email_token=ABILVRLSNQIRUI3PEUUNA6DPXT5ZBA5CNFSM4HQBUZ62YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4GWF2CXQ>, or mute the thread https://github.com/notifications/unsubscribe-auth/ABILVROGAJFDCWNTJV2PB7DPXT5ZBANCNFSM4HQBUZ6Q .

Ouch - I can see the reason for this inside tight loops with bit manupulation, but please don't call it "if", its a low-level machine word, please give it a new name.