clash-lang / clash-prelude

CLaSH prelude library containing datatypes and functions for circuit design
http://www.clash-lang.org/
Other
31 stars 27 forks source link

Custom bit-representations #168

Closed christiaanb closed 6 years ago

christiaanb commented 6 years ago

Annotation for custom bit representations of data types

Using ANN pragma's you can tell the Clash compiler to use a custom bit-representation for a data type.

For example:

data Color = R | G | B
{-# ANN module (DataReprAnn
                  $(liftQ [t|Color|])
                  2
                  [ ConstrRepr 'R 0b11 0b00 []
                  , ConstrRepr 'G 0b11 0b01 []
                  , ConstrRepr 'B 0b11 0b10 []
                  ]) #-}

This specifies that R should be encoded as 0b00, G as 0b01, and B as 0b10. The first binary value in every ConstRepr in this example is a mask, indicating which bits in the data type are relevant. In this case all of the bits are.

Or if we want to annotate Maybe Color:

{-# ANN module ( DataReprAnn
                   $(liftQ [t|Maybe Color|])
                   2
                   [ ConstRepr 'Nothing 0b11 0b11 []
                   , ConstRepr 'Just 0b00 0b00 [0b11]
                   ] ) #-}

By default, Maybe Color is a data type which consumes 3 bits. A single bit to indicate the constructor (either Just or Nothing), and two bits to encode the first field of Just. Notice that we saved a single bit, by exploiting the fact that Color only uses three values (0, 1, 2), but takes two bits to encode it. We can therefore use the last - unused - value (3), to encode one of the constructors of Maybe. We indicate which bits encode the underlying Color by passing [0b11] to ConstRepr. This indicates that the first field is encoded in the first and second bit of the whole datatype (0b11).

Additionally contains:

expipiplus1 commented 6 years ago

Nice!

What kind of behavior does this have when these "instances" overlap? I wonder how hard it would be to have this information encoded in an instance declaration, as the instance machinery in Haskell has some nice properties for dealing with this kind of problem.

martijnbastiaan commented 6 years ago

What kind of behavior does this have when these "instances" overlap?

It throws an error: https://github.com/clash-lang/clash-compiler/blob/960c59414edabcf210c6d125034cc7787c07d0af/clash-ghc/src-ghc/Clash/GHC/LoadInterfaceFiles.hs#L232

I wonder how hard it would be to have this information encoded in an instance declaration,

I'd love to hear your thoughts on this. I did play around with it, but couldn't come up with a nice design.

as the instance machinery in Haskell has some nice properties for dealing with this kind of problem.

What properties are you looking for?

christiaanb commented 6 years ago

Ah, I guess @expipiplus1 means the overlapping instances machinery, where you can classify things like: overlappable, and overlaps. Perhaps initially we could just try to mimic that behavior, and then later on see if there is perhaps a way to use actual type classes and instances.

expipiplus1 commented 6 years ago

Exactly. Although thinking about it a little bit more it may not be so elegant, as every type already has a "default" instance defined.