discussion icon indicating copy to clipboard operation
discussion copied to clipboard

How do you do struct packing in FORTH?

Open RickCarlino opened this issue 8 years ago • 21 comments

FORTH 200X introduced structs. I can't find any documentation on online or in documentation for the best way to perform struct packing, though.

Is it possible in FORTH (GForth, specifically)? I'm trying build an MQTT message packet which requires setting flags that are smaller than one byte.

RickCarlino avatar Dec 30 '15 04:12 RickCarlino

Flags are bits in a cell in Forth. A Nybble is 4 bits. Depends on where your flags reside in the quibble!

On Tue, Dec 29, 2015 at 10:31 PM, Rick Carlino [email protected] wrote:

FORTH 200X introduced structs https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Forth200x-Structures.html. I can't find any documentation on online or in documentation for the best way to perform struct packing, though.

Is it possible in FORTH (GForth, specifically)? I'm trying build an MQTT message packet which requires setting flags that are smaller than one byte.

— Reply to this email directly or view it on GitHub https://github.com/ForthHub/discussion/issues/20.

cwpjr avatar Dec 30 '15 05:12 cwpjr

I remember doing bit fields in the polyForth DataBase Support System (see https://dl.dropboxusercontent.com/u/49100658/pFDatabase-5.zip), but it's been a while, and I'm not sure what happened to that support. I'll keep looking.

DRuffer avatar Dec 30 '15 05:12 DRuffer

My ARM Forth includes:

SETBITS [SETBITS](addr val --) Logical OR the value-bits with the contents of addr using read, modify, write method. ( Create and initialize variable TEST_SETBITS ) VARIABLE TEST_SETBITS 110b TEST_SETBITS ! ( Use SETBITS to modify TEST_SETBITS ) TEST_SETBITS 10001b SETBITS ( View results ) TEST_SETBITS @ .B ( 10111 ) See CLRBITS and ANDBITS

On Tue, Dec 29, 2015 at 11:23 PM, Dennis Ruffer [email protected] wrote:

I remember doing bit fields in the polyForth DataBase Support System (see https://dl.dropboxusercontent.com/u/49100658/pFDatabase-5.zip), but it's been a while, and I'm not sure what happened to that support. I'll keep looking.

— Reply to this email directly or view it on GitHub https://github.com/ForthHub/discussion/issues/20#issuecomment-167939303.

cwpjr avatar Dec 30 '15 05:12 cwpjr

Also:

[CLRBITS](addr value) Logical AND then NOT the value-bits with the contents of addr using read, modify, write method. ( Create and initialize variable TEST_CLRBITS ) VARIABLE TEST_CLRBITS 110b TEST_CLRBITS ! ( Use ANDBITS to modify TEST_CLRBITS ) TEST_CLRBITS 10b CLRBITS ( View results ) TEST_CLRBITS @ .B ( 100 ) See ANDBITS and SETBITS CMOVE

On Tue, Dec 29, 2015 at 11:23 PM, Dennis Ruffer [email protected] wrote:

I remember doing bit fields in the polyForth DataBase Support System (see https://dl.dropboxusercontent.com/u/49100658/pFDatabase-5.zip), but it's been a while, and I'm not sure what happened to that support. I'll keep looking.

— Reply to this email directly or view it on GitHub https://github.com/ForthHub/discussion/issues/20#issuecomment-167939303.

cwpjr avatar Dec 30 '15 05:12 cwpjr

Forth83 has !BITS and @BITS for storing and fetching bit fields.

larsbrinkhoff avatar Dec 30 '15 07:12 larsbrinkhoff

I suppose one could come up with a design to support something like this:

begin-structure foo
  begin-bitfield
    1 +bits a
    1 +bits b
    2 +bits c
    4 +bits d
  end-bitfield
end-structure

larsbrinkhoff avatar Dec 30 '15 08:12 larsbrinkhoff

I have added something like this to mecrisp-stellaris:

http://hub.darcs.net/pointfree/mecrisp-stellaris/browse/mk20dx256/bitstruct-example.txt

http://hub.darcs.net/pointfree/mecrisp-stellaris/browse/mk20dx256/bitstruct.txt

It was based on this Mitch Bradley's, Structured Data with Bit Fields but extended to support fields that contain subfields (I called them superfields).

lowfatcomputing avatar Dec 30 '15 12:12 lowfatcomputing

I like superbits. I feel they should have the superpower to solve any programming problem!

larsbrinkhoff avatar Dec 30 '15 13:12 larsbrinkhoff

Am Mittwoch, 30. Dezember 2015, 00:06:17 schrieb Lars Brinkhoff:

I suppose one could come up with a design to support something like this:

begin-structure foo
  begin-bitfield
    1 +bits a
    1 +bits b
    2 +bits c
    4 +bits d
  end-bitfield
end-structure

Since we have no nested structs, a bitfield should just be an entity of its own. But having such bit fields is indeed a good idea.

Union is also just some individual structures, and the size of the union is simply the maximum of those sizes (no syntactical support).

Bernd Paysan "If you want it done right, you have to do it yourself" net2o ID: kQusJzA;7_?t=uy@X}1GWr!+0qqp_Cn176t4(dQ_ http://bernd-paysan.de/

forthy42 avatar Dec 31 '15 17:12 forthy42

: struct 0 ;
: end-struct constant ;
: field create over , + does> @ + ;
: superfield create , does> @ + ;
: union 0 ;
: end-union dup constant + ;
: unionfield create max does> @ + ;

( sample usage )
struct
 4 field part1
 9 superfield part2_3_4
  4 field part2
  4 field part3
  1 field part4
 4 superfield part5_6
  2 field part5
  2 field part6
 union
   4 unionfield part7
   1 unionfield part8 
 end-union myunion-size
 union
   2 unionfield part9
 end-union myunion2-size
end-struct mystruct-size

 : buffer: create allot ;
 mystruct-size buffer: mybuf

 $AAAAAAAA mybuf part1 !
 $BBBBBBBB mybuf part2 !
 $CCCCCCCC mybuf part3 !
 $DD       mybuf part4 !
 $EEEE     mybuf part5 !
 $FFFF     mybuf part6 !

           mybuf part5 @ hex. cr  ( prints EEEE )
           mybuf part6 @ hex. cr  ( prints FFFF )

 $DEADBEEF mybuf part5_6 !
           mybuf part5_6 @ hex. cr ( prints DEADBEEF )

EDIT: Fixed to include implementations of actual unions supporing differently sized members as @forthy42 described them.

lowfatcomputing avatar Jan 10 '16 16:01 lowfatcomputing

I know this is an old post but I will add something in case it is of use to someone. Lowfatcomputing's struct/union example is so cool. Thanks

This is not bit structures but arrays of bits, but it might provide some ideas for managing bit fields. It seems to work on 16,32 and 64 bit platforms. It is factored for understanding. It's not real fast from using /MOD at runtime, but it's not too bad with native code compilers.

https://github.com/bfox9900/CAMEL99-V2/blob/master/LIB.ITC/BOOLEAN.FTH Edit: Fixed this link

bfox9900 avatar Aug 01 '18 12:08 bfox9900

The obvious omission to BOOLEAN.FTH is:

: BTOGGLE ( bit# addr[] -- ) BITFLD \ -- bit# addr SWAP BITMASK >R \ save mask DUP @ \ -- addr bits R> XOR SWAP ! ; \ toggle bit, store back in addr

The file has been updated on GITHub

bfox9900 avatar Aug 16 '18 13:08 bfox9900

: BTOGGLE ( bit# addr[] -- ) ...

Below is is the factoring that I use for bit toggling , it takes a mask as an argument rather than a particular bit number, so that if needed I can toggle multiple bits simultaneously in a cell.

0 shadow  Bitwise Miscellanea  4|4
1
2 set    Set <mask> bits in cell at <a>.
3
4 reset  Reset <mask> bits in cell at <a>.
5
6 toggle Xor <mask> bits in cell at <a>.

0 source  Bitwise Miscellanea  4|4
1
2 : set    ( mask a -- ) tuck @ or   \! ;inline
3 : reset  ( mask a -- ) tuck @ cand \! ;inline
4 : toggle ( mask a -- ) tuck @ xor  \! ;inline

(\! is a primitive instruction equivalent to swap !)

When I want to use a particular bit number, as is the case with your btoggle above, rather than a mask, I write <bit#> bit <addr> toggle, where bit is defined as follows:

: bit ( # -- bit ) 2** ;inline

I also have mask defined as:

 : mask ( bit -- mask ) 1- ;inline

So I can write <#bits> bit mask <addr> toggle to toggle the low <#bits>.

rdrop-exit avatar Aug 25 '18 18:08 rdrop-exit

Nice and a different way to factor it with the BIT word. Looks very efficient.

2** is 2 to the exponent ** ? How is that implemented? It would seem to be similar to RSHIFT, no?

bfox9900 avatar Aug 27 '18 14:08 bfox9900

Thanks.

2** is 2 to the exponent ** ?

That's right, it raises 2 to a power.

How is that implemented? It would seem to be similar to RSHIFT, no?

It's a primitive on my Forth, but in high-level Forth it would be equivalent to: : 2** ( u -- 1<<u ) 1 swap lshift ;

rdrop-exit avatar Aug 28 '18 00:08 rdrop-exit

Lacking better names and not finding
  any names or conventions others might have used, many years ago I
  defined primitives C_OR_BITS and C_ANDBITS,
  both with stack effect ( addr mask -- ), for setting or
  clearing bits in a byte at an address.  The mask for ANDing was a
  normal AND mask, so for example if you wanted to clear only one
  bit, there would be seven '1' bits and one '0' bit.  I put the
  extra _ in C_OR_BITS name for better vertical alignment
  and visual factoring in situations like the following (which are
  from an actual hardware setup word:
    
       VIA2ACR  11000011  C_ANDBITS    \ Reset shift register.
       VIA2ACR  00001100  C_OR_BITS    \ Set T2 & SR modes.
  
     VIA2PCR  00001110  C_OR_BITS    \ Set CA2 as high
    output for handshake.
  
  (obviously with BASE in binary at this point).
  
  O.T.:  Mark, is your \! word (in your post, quoted
  below) in common usage (even if it's not adopted into any
  standard), with that name?  I ask because I use the same primitive
  in my 65816 kernel, but called SWAP! .  It's headerless
  and is not in any applications so far, so I could easily change
  the name to whatever is in common usage.
  
  Garth
  
  
  On 08/25/2018 11:07 AM, Mark W. Humphries wrote:


  
  
    : BTOGGLE ( bit# addr[] -- ) ...
  
  Below is is the version of bit toggling I use, it takes a mask
    as an argument rather than a particular bit number, so that if
    needed I can toggle multiple bits simultaneously in a cell.
  0 shadow  Bitwise Miscellanea  4|4

1 2 set Set bits in cell at . 3 4 reset Reset bits in cell at . 5 6 toggle Xor bits in cell at .

0 source Bitwise Miscellanea 4|4 1 2 : set ( mask a -- ) tuck @ or ! ;inline 3 : reset ( mask a -- ) tuck @ cand ! ;inline 4 : toggle ( mask a -- ) tuck @ xor ! ;inline

  (\! is a primitive instruction equivalent to swap
      !)
  When I want to use a particular bit number rather than a mask
    as is the case with your btoggle above, I write <bit#>
      bit mask <addr> toggle, where bit
    and mask are defined as follows:
  : bit ( # -- bit ) 2** ;inline

: mask ( bit -- mask ) 1- ;inline

GarthWilson avatar Aug 30 '18 18:08 GarthWilson

I have SETBITS, ANDBITS and CLRBITS that take ones in the 32 but word stack as the operative for the words.

On Thu, Aug 30, 2018 at 1:42 PM Garth Wilson [email protected] wrote:

Lacking better names and not finding any names or conventions others might have used, many years ago I defined primitives C_OR_BITS and C_ANDBITS, both with stack effect ( addr mask -- ), for setting or clearing bits in a byte at an address. The mask for ANDing was a normal AND mask, so for example if you wanted to clear only one bit, there would be seven '1' bits and one '0' bit. I put the extra _ in C_OR_BITS name for better vertical alignment and visual factoring in situations like the following (which are from an actual hardware setup word:

VIA2ACR 11000011 C_ANDBITS \ Reset shift register. VIA2ACR 00001100 C_OR_BITS \ Set T2 & SR modes.

VIA2PCR 00001110 C_OR_BITS \ Set CA2 as high output for handshake.

(obviously with BASE in binary at this point).

O.T.: Mark, is your ! word (in your post, quoted below) in common usage (even if it's not adopted into any standard), with that name? I ask because I use the same primitive in my 65816 kernel, but called SWAP! . It's headerless and is not in any applications so far, so I could easily change the name to whatever is in common usage.

Garth

On 08/25/2018 11:07 AM, Mark W. Humphries wrote:

: BTOGGLE ( bit# addr[] -- ) ...

Below is is the version of bit toggling I use, it takes a mask as an argument rather than a particular bit number, so that if needed I can toggle multiple bits simultaneously in a cell. 0 shadow Bitwise Miscellanea 4|4 1 2 set Set bits in cell at . 3 4 reset Reset bits in cell at . 5 6 toggle Xor bits in cell at .

0 source Bitwise Miscellanea 4|4 1 2 : set ( mask a -- ) tuck @ or ! ;inline 3 : reset ( mask a -- ) tuck @ cand ! ;inline 4 : toggle ( mask a -- ) tuck @ xor ! ;inline

(! is a primitive instruction equivalent to swap !) When I want to use a particular bit number rather than a mask as is the case with your btoggle above, I write <bit#> bit mask toggle, where bit and mask are defined as follows: : bit ( # -- bit ) 2** ;inline : mask ( bit -- mask ) 1- ;inline

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ForthHub/discussion/issues/20#issuecomment-417425600, or mute the thread https://github.com/notifications/unsubscribe-auth/AFC6xaE-iZU9e5umbRC7VBNeyg_l690Fks5uWDIpgaJpZM4G8pFB .

cwpjr avatar Aug 31 '18 00:08 cwpjr

yep

On Mon, Aug 27, 2018 at 9:39 AM theBF [email protected] wrote:

Nice and a different way to factor it with the BIT word. Looks very efficient.

2** is 2 to the exponent ** ? How is that implemented? It would seem to be similar to RSHIFT, no?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ForthHub/discussion/issues/20#issuecomment-416249319, or mute the thread https://github.com/notifications/unsubscribe-auth/AFC6xfQDbpPFTgAhaWQH8Y2jlb4PELOCks5uVAS3gaJpZM4G8pFB .

cwpjr avatar Aug 31 '18 00:08 cwpjr

O.T.: Mark, is your ! word (in your post, quoted below) in common usage (even if it's not adopted into any standard), with that name? I ask because I use the same primitive in my 65816 kernel, but called SWAP! . It's headerless and is not in any applications so far, so I could easily change the name to whatever is in common usage. Garth

I generally use \<name> to indicate an alternative 'reversed' version of the primitive <name> where the normal argument order is either reversed or permuted in some way. It's not common usage as far as I know. It could be that I copied it from some other Forth long ago, but I can't recall.

Some other examples of this convention would be reverse subtraction \- ( x1 x2 -- x2-x1 ), and two different 2-to-1 mux primitives mux ( x1 x2 mask -- x ) and \mux ( mask x1 x2 -- x ).

rdrop-exit avatar Aug 31 '18 01:08 rdrop-exit

Darn.  The formatting is sure getting messed up in the replies, and even in my own post!  To see if it was just in the emails, I checked also on the github page, and that was messed up too.

GarthWilson avatar Aug 31 '18 03:08 GarthWilson

@rdrop-exit, I like that \<name> convention. I use the -<name> convention for negating or removing a "name", but \ works in another dimension.

larsbrinkhoff avatar Aug 31 '18 05:08 larsbrinkhoff