packages feed

clash-shockwaves 1.0.1 → 1.1.1

raw patch · 18 files changed

+976/−252 lines, 18 filesnew-uploaderPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Clash.Shockwaves: styles :: Waveform a => [WaveStyle]
- Clash.Shockwaves.BitList: binPack :: BitPack a => a -> BitList
- Clash.Shockwaves.BitList: binUnpack :: BitPack a => BitList -> a
- Clash.Shockwaves.Internal.BitList: binPack :: BitPack a => a -> BitList
- Clash.Shockwaves.Internal.BitList: binUnpack :: BitPack a => BitList -> a
- Clash.Shockwaves.Internal.Translator: hasLutT :: Translator -> Bool
- Clash.Shockwaves.Internal.Translator: mergeDuplicateSubsignals :: [(SubSignal, Structure)] -> [(SubSignal, Structure)]
- Clash.Shockwaves.Internal.Util: bitsize :: BitPack a => Proxy a -> Int
- Clash.Shockwaves.Internal.Util: safeVal :: NFData a => a -> Either (Maybe Value) a
- Clash.Shockwaves.Internal.Util: safeValOr :: NFData a => a -> a -> a
- Clash.Shockwaves.Internal.Util: typeNameP :: forall {k} (a :: k). Typeable a => Proxy a -> TypeName
- Clash.Shockwaves.Internal.Waveform: WfLUT :: a -> WaveformForLUT a
- Clash.Shockwaves.Internal.Waveform: WfNum :: a -> WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a
- Clash.Shockwaves.Internal.Waveform: errMsg :: Maybe Value -> Value
- Clash.Shockwaves.Internal.Waveform: hasLut :: Waveform a => Bool
- Clash.Shockwaves.Internal.Waveform: instance (Clash.Shockwaves.Internal.Waveform.Waveform a, Clash.Shockwaves.Internal.Waveform.WaveformLUT a, Clash.Class.BitPack.Internal.BitPack a, GHC.Internal.Data.Typeable.Internal.Typeable a) => Clash.Shockwaves.Internal.Waveform.Waveform (Clash.Shockwaves.Internal.Waveform.WaveformForLUT a)
- Clash.Shockwaves.Internal.Waveform: instance Clash.Class.BitPack.Internal.BitPack a => Clash.Class.BitPack.Internal.BitPack (Clash.Shockwaves.Internal.Waveform.WaveformForLUT a)
- Clash.Shockwaves.Internal.Waveform: instance GHC.Internal.Generics.Generic (Clash.Shockwaves.Internal.Waveform.WaveformForLUT a)
- Clash.Shockwaves.Internal.Waveform: newtype WaveformForLUT a
- Clash.Shockwaves.Internal.Waveform: rFromVal :: Value -> Render
- Clash.Shockwaves.Internal.Waveform: styHead :: [WaveStyle] -> WaveStyle
- Clash.Shockwaves.Internal.Waveform: styles :: Waveform a => [WaveStyle]
- Clash.Shockwaves.Internal.Waveform: styles' :: Waveform a => [WaveStyle]
- Clash.Shockwaves.Internal.Waveform: tFromVal :: Value -> Translation
- Clash.Shockwaves.Internal.Waveform: wrapStyle :: WaveStyle -> Translator -> Translator
- Clash.Shockwaves.LUT: WfLUT :: a -> WaveformForLUT a
- Clash.Shockwaves.LUT: newtype WaveformForLUT a
- Clash.Shockwaves.LUT: rFromVal :: Value -> Render
- Clash.Shockwaves.LUT: safeVal :: NFData a => a -> Either (Maybe Value) a
- Clash.Shockwaves.LUT: safeValOr :: NFData a => a -> a -> a
- Clash.Shockwaves.LUT: tFromVal :: Value -> Translation
- Clash.Shockwaves.Waveform: WfNum :: a -> WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a
- Clash.Shockwaves.Waveform: hasLut :: Waveform a => Bool
- Clash.Shockwaves.Waveform: hasLutT :: Translator -> Bool
- Clash.Shockwaves.Waveform: styles :: Waveform a => [WaveStyle]
- Clash.Shockwaves.Waveform: width :: Waveform a => Int
+ Clash.Shockwaves: constructorStyles :: Waveform a => [WaveStyle]
+ Clash.Shockwaves.BitList: hasUndefined :: BitList -> Bool
+ Clash.Shockwaves.BitList: length :: BitList -> Int
+ Clash.Shockwaves.BitList: pack :: BitPack a => a -> BitList
+ Clash.Shockwaves.BitList: unpack :: BitPack a => BitList -> a
+ Clash.Shockwaves.Internal.BitList: hasUndefined :: BitList -> Bool
+ Clash.Shockwaves.Internal.BitList: instance GHC.Internal.Bits.Bits Clash.Shockwaves.Internal.BitList.BitList
+ Clash.Shockwaves.Internal.BitList: length :: BitList -> Int
+ Clash.Shockwaves.Internal.BitList: mask :: Int -> Natural
+ Clash.Shockwaves.Internal.BitList: pack :: BitPack a => a -> BitList
+ Clash.Shockwaves.Internal.BitList: unpack :: BitPack a => BitList -> a
+ Clash.Shockwaves.Internal.Translator: getStaticLuts :: Translator -> [(String, LUT)]
+ Clash.Shockwaves.Internal.Translator: hasGeneratedLutT :: Translator -> Bool
+ Clash.Shockwaves.Internal.Types: BPAnd :: [BitPart] -> BitPart
+ Clash.Shockwaves.Internal.Types: BPHasUndefined :: BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPIf :: BitPart -> BitPart -> BitPart -> BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPInvert :: BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPNHot :: Slice -> BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPOneHot :: Slice -> BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPOr :: [BitPart] -> BitPart
+ Clash.Shockwaves.Internal.Types: BPReverse :: BitPart -> BitPart
+ Clash.Shockwaves.Internal.Types: BPXor :: [BitPart] -> BitPart
+ Clash.Shockwaves.Internal.Types: instance GHC.Internal.Base.Semigroup Clash.Shockwaves.Internal.Types.Structure
+ Clash.Shockwaves.Internal.Types: mergeDuplicateSubsignals :: [(SubSignal, Structure)] -> [(SubSignal, Structure)]
+ Clash.Shockwaves.Internal.Util: bitSize :: BitPack a => Int
+ Clash.Shockwaves.Internal.Util: defaultTypeName :: forall {k} (a :: k). Typeable a => TypeName
+ Clash.Shockwaves.Internal.Util: erroringZipWith :: String -> (a -> b -> c) -> [a] -> [b] -> [c]
+ Clash.Shockwaves.Internal.Util: pprintT :: Translator -> String
+ Clash.Shockwaves.Internal.Util: safeNF :: NFData a => a -> Maybe a
+ Clash.Shockwaves.Internal.Util: safeNFErr :: NFData a => a -> Either (Maybe Value) a
+ Clash.Shockwaves.Internal.Util: safeNFOr :: NFData a => a -> a -> a
+ Clash.Shockwaves.Internal.Util: unsafeHead :: [a] -> a
+ Clash.Shockwaves.Internal.Waveform: WaveformForLut :: a -> WaveformForLut a
+ Clash.Shockwaves.Internal.Waveform: WaveformForNumber :: a -> WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a
+ Clash.Shockwaves.Internal.Waveform: constructorStyles :: Waveform a => [WaveStyle]
+ Clash.Shockwaves.Internal.Waveform: constructorStyles' :: Waveform a => [WaveStyle]
+ Clash.Shockwaves.Internal.Waveform: defaultRender :: Value -> Render
+ Clash.Shockwaves.Internal.Waveform: defaultTranslator :: (BitPack a, WaveformG (Rep a ())) => Translator
+ Clash.Shockwaves.Internal.Waveform: hasGeneratedLut :: Waveform a => Bool
+ Clash.Shockwaves.Internal.Waveform: inheritSingleFieldStyle :: Translator -> Translator
+ Clash.Shockwaves.Internal.Waveform: instance (Clash.Shockwaves.Internal.Waveform.Waveform a, Clash.Shockwaves.Internal.Waveform.WaveformLUT a, Clash.Class.BitPack.Internal.BitPack a, GHC.Internal.Data.Typeable.Internal.Typeable a) => Clash.Shockwaves.Internal.Waveform.Waveform (Clash.Shockwaves.Internal.Waveform.WaveformForLut a)
+ Clash.Shockwaves.Internal.Waveform: instance Clash.Class.BitPack.Internal.BitPack a => Clash.Class.BitPack.Internal.BitPack (Clash.Shockwaves.Internal.Waveform.WaveformForLut a)
+ Clash.Shockwaves.Internal.Waveform: instance GHC.Internal.Generics.Generic (Clash.Shockwaves.Internal.Waveform.WaveformForLut a)
+ Clash.Shockwaves.Internal.Waveform: newtype WaveformForLut a
+ Clash.Shockwaves.Internal.Waveform: noConstructorSubsignals :: Bool -> Translator -> Translator
+ Clash.Shockwaves.Internal.Waveform: renameConstructors :: [String] -> Translator -> Translator
+ Clash.Shockwaves.Internal.Waveform: renameFields :: [[String]] -> Translator -> Translator
+ Clash.Shockwaves.Internal.Waveform: staticL :: WaveformLUT a => Maybe [(a, Translation)]
+ Clash.Shockwaves.Internal.Waveform: staticLut :: BitPack a => [(a, Translation)] -> LUT
+ Clash.Shockwaves.Internal.Waveform: staticLutL :: WaveformLUT a => Maybe LUT
+ Clash.Shockwaves.Internal.Waveform: tGeneratedLut :: (Waveform a, WaveformLUT a) => Translator
+ Clash.Shockwaves.Internal.Waveform: tStaticLut :: (Waveform a, WaveformLUT a) => LUT -> Translator
+ Clash.Shockwaves.Internal.Waveform: translateStaticL :: (Waveform a, WaveformLUT a) => a -> Translation
+ Clash.Shockwaves.Internal.Waveform: withConstructorStyles :: [WaveStyle] -> Translator -> Translator
+ Clash.Shockwaves.LUT: WaveformForLut :: a -> WaveformForLut a
+ Clash.Shockwaves.LUT: defaultRender :: Value -> Render
+ Clash.Shockwaves.LUT: newtype WaveformForLut a
+ Clash.Shockwaves.LUT: safeNF :: NFData a => a -> Maybe a
+ Clash.Shockwaves.LUT: safeNFOr :: NFData a => a -> a -> a
+ Clash.Shockwaves.LUT: staticL :: WaveformLUT a => Maybe [(a, Translation)]
+ Clash.Shockwaves.LUT: tGeneratedLut :: (Waveform a, WaveformLUT a) => Translator
+ Clash.Shockwaves.LUT: tStaticLut :: (Waveform a, WaveformLUT a) => LUT -> Translator
+ Clash.Shockwaves.Waveform: BPAnd :: [BitPart] -> BitPart
+ Clash.Shockwaves.Waveform: BPHasUndefined :: BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPIf :: BitPart -> BitPart -> BitPart -> BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPInvert :: BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPNHot :: Slice -> BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPOneHot :: Slice -> BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPOr :: [BitPart] -> BitPart
+ Clash.Shockwaves.Waveform: BPReverse :: BitPart -> BitPart
+ Clash.Shockwaves.Waveform: BPXor :: [BitPart] -> BitPart
+ Clash.Shockwaves.Waveform: WaveformForNumber :: a -> WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a
+ Clash.Shockwaves.Waveform: bitSize :: BitPack a => Int
+ Clash.Shockwaves.Waveform: constructorStyles :: Waveform a => [WaveStyle]
+ Clash.Shockwaves.Waveform: defaultTranslator :: (BitPack a, WaveformG (Rep a ())) => Translator
+ Clash.Shockwaves.Waveform: defaultTypeName :: forall {k} (a :: k). Typeable a => TypeName
+ Clash.Shockwaves.Waveform: fromTranslation :: Translation -> Structure
+ Clash.Shockwaves.Waveform: hasGeneratedLut :: Waveform a => Bool
+ Clash.Shockwaves.Waveform: hasGeneratedLutT :: Translator -> Bool
+ Clash.Shockwaves.Waveform: inheritSingleFieldStyle :: Translator -> Translator
+ Clash.Shockwaves.Waveform: noConstructorSubsignals :: Bool -> Translator -> Translator
+ Clash.Shockwaves.Waveform: pprintT :: Translator -> String
+ Clash.Shockwaves.Waveform: renameFields :: [[String]] -> Translator -> Translator
+ Clash.Shockwaves.Waveform: withConstructorStyles :: [WaveStyle] -> Translator -> Translator
- Clash.Shockwaves.Internal.Types: TChangeBits :: Translator -> BitPart -> TranslatorVariant
+ Clash.Shockwaves.Internal.Types: TChangeBits :: BitPart -> Translator -> TranslatorVariant
- Clash.Shockwaves.Internal.Types: TLut :: LUTName -> TypeRef -> TranslatorVariant
+ Clash.Shockwaves.Internal.Types: TLut :: LUTName -> Maybe LUT -> TypeRef -> TranslatorVariant
- Clash.Shockwaves.Internal.Waveform: constrTranslatorsG :: WaveformG a => [WaveStyle] -> [Translator]
+ Clash.Shockwaves.Internal.Waveform: constrTranslatorsG :: WaveformG a => [Translator]
- Clash.Shockwaves.Internal.Waveform: tLut :: (Waveform a, WaveformLUT a) => Proxy a -> Translator
+ Clash.Shockwaves.Internal.Waveform: tLut :: (Waveform a, WaveformLUT a) => Maybe LUT -> Translator
- Clash.Shockwaves.Internal.Waveform: tRef :: Waveform a => Proxy a -> Translator
+ Clash.Shockwaves.Internal.Waveform: tRef :: Waveform a => Translator
- Clash.Shockwaves.Internal.Waveform: translatorG :: WaveformG a => Int -> [WaveStyle] -> Translator
+ Clash.Shockwaves.Internal.Waveform: translatorG :: WaveformG a => Int -> Translator
- Clash.Shockwaves.LUT: tLut :: (Waveform a, WaveformLUT a) => Proxy a -> Translator
+ Clash.Shockwaves.LUT: tLut :: (Waveform a, WaveformLUT a) => Maybe LUT -> Translator
- Clash.Shockwaves.Waveform: TChangeBits :: Translator -> BitPart -> TranslatorVariant
+ Clash.Shockwaves.Waveform: TChangeBits :: BitPart -> Translator -> TranslatorVariant
- Clash.Shockwaves.Waveform: TLut :: LUTName -> TypeRef -> TranslatorVariant
+ Clash.Shockwaves.Waveform: TLut :: LUTName -> Maybe LUT -> TypeRef -> TranslatorVariant
- Clash.Shockwaves.Waveform: tRef :: Waveform a => Proxy a -> Translator
+ Clash.Shockwaves.Waveform: tRef :: Waveform a => Translator

Files

+ CHANGELOG.md view
@@ -0,0 +1,221 @@+## v1.1.1 - *16 Jul, 2026*++### Changed:+- `defaultTranslator` now has a `BitPack` constraint instead of `Waveform`.+  [#135](https://github.com/clash-lang/clash-shockwaves/issues/135)++### Fixed:+- Fixed a bug that caused the Surfer plugin to reject metadata files including signed integer translators.+  [#142](https://github.com/clash-lang/clash-shockwaves/issues/142)++## v1.1.0 - *08 Jun, 2026*++### Consistency changes:+Shockwaves 1.1 includes a number of changes to make the library more internally consistent.+This mostly includes a number of renamed functions.++### Static LUTs:+Sometimes, you want the flexibility of a LUT,+but translating all values of a type is rather inefficient.+You can now create _static LUTs_, where you define the entire LUT yourself,+rather than building it up by translating values that pop up in simulation.++Please see the updated [HOWTO guide on using LUTs](docs/howto/LUTS.md) for more information!+[#92](https://github.com/clash-lang/clash-shockwaves/issues/92)++### Modifying the default translator:+It was already possible to set styles, but more advanced deviations from the default+required a completely custom implementation.+Shockwaves 1.1 introduces functions for obtaining the default translators for types,+as well as several function for modifying these, by adding constructor styles and+inheriting styles (both of which are used by default), but also renaming fields+and compacting the subsignal structure. See [the new HOWTO guide](docs/howto/DEFAULT.md).+[#50](https://github.com/clash-lang/clash-shockwaves/issues/50)++### More BitPart options:+With the new `BitPart` options, the `ChangeBits` translator has become a lot more+powerful. Beyond simply reordering bits, it is now possible to perform various operations+on bits. See [the updated documentation](docs/howto/ADVANCED.md) for more.+[#54](https://github.com/clash-lang/clash-shockwaves/issues/54)++### Surfer protection:+The Surfer translator extension now verifies the Shockwaves translators it's served.++Previously, incorrect custom `Waveform` instances could crash the extension,+taking Surfer down with it.+The new verification step checks for any major issues that would crash Surfer,+replacing any truly problematic translators, and also warns of (probably) incorrect+constructions such as translators that request more bits than they actually use.++For performance reasons, lookup tables are not checked, and values not matching the+reported structure might still cause crashes.+[#33](https://github.com/clash-lang/clash-shockwaves/issues/33)++### Added:+- `WaveformLUT` now has a method `staticL`.+  This method can be overwritten to define a static LUT,+  (which renders `translateL` and `structureL` obsolete).+  [#92](https://github.com/clash-lang/clash-shockwaves/issues/92)++- `defaultTranslator` returns the unstyled translator that is used when deriving `Waveform`.+  [#50](https://github.com/clash-lang/clash-shockwaves/issues/50)+- `withConstructorStyles` applies a list of styles to the constructors of a translator.+  [#124](https://github.com/clash-lang/clash-shockwaves/issues/124)+- `inheritSingleFieldStyle` applies the `Inherit 0` style to product translators with only one field.+  [#124](https://github.com/clash-lang/clash-shockwaves/issues/124)+- `noConstructorSubsignals` removes the constructor subsignals from a default translator.+  The resulting structure is like that of `Maybe` and `Bool`.+  [#50](https://github.com/clash-lang/clash-shockwaves/issues/50)+- `renameFields` can be used to rename the fields of a product type.+  [#50](https://github.com/clash-lang/clash-shockwaves/issues/50)++- `Bits` instance for `BitList`.+  [#114](https://github.com/clash-lang/clash-shockwaves/issues/114)+- `BitList.length` returns a `BitList`'s length.+  [#114](https://github.com/clash-lang/clash-shockwaves/issues/114)+- `BitList.hasUndefined` returns whether a `BitList` has any undefined bits.+  [#114](https://github.com/clash-lang/clash-shockwaves/issues/114)++- New `BitPart` options: (`BP`)`HasUndefined`, `Reverse`, `Invert`, `And`, `Or`, `Xor`, `OneHot`, `NHot` and `If`.+  [#54](https://github.com/clash-lang/clash-shockwaves/issues/54)+- Added the configuration option `override_number_format` to the Surfer extension, which lets you set the format of all numbers.+  [#115](https://github.com/clash-lang/clash-shockwaves/issues/115)++- `bitSize` returns the number of bits based on the `BitSize` class.+- `defaultTypeName` derives a unique name automatically for a type.+  The name consists of the simple type name plus a hash to prevent name collisions.+  [#111](https://github.com/clash-lang/clash-shockwaves/issues/111)+- `pprintT` prints a translator's structure, and can be used for debugging purposes when creating custom translators.+++### Changes:+- `TLut` now has a field for the optional static LUT.+  [#92](https://github.com/clash-lang/clash-shockwaves/issues/92)+- `tLut` has been renamed to `tGeneratedLut`, and `tStaticLut` has been added.+  A new `tLut` function switches between the two.+  [#92](https://github.com/clash-lang/clash-shockwaves/issues/92)+- `hasLut` has been renamed to `hasGeneratedLut`.+  [#92](https://github.com/clash-lang/clash-shockwaves/issues/92)++- Renamed `BitList.binPack` and `BitList.binUnpack` to `BitList.pack` and `BitList.unpack`.+  [#114](https://github.com/clash-lang/clash-shockwaves/issues/114)++- The functions `tRef`, `tLut` (and the new `tStaticLut` and `tGeneratedLut`) no longer take proxy arguments.+  [#111](https://github.com/clash-lang/clash-shockwaves/issues/111)++- Swapped the order of the `TChangeBits` constructor fields to be easier to use without record syntax.++- `Bit` now uses a static LUT. It is displayed as `0`/`1`/`x`, and styles can be+  controlled through style variables `bit_low` and `bit_high`.+  [#92](https://github.com/clash-lang/clash-shockwaves/issues/92)+- `BitVector` now contains subsignals for all bits.+  The toplevel value is still generated by a number translator, and as such, may be modified through config files.+  [#48](https://github.com/clash-lang/clash-shockwaves/issues/48)++- Renamed `safeVal` and `safeValOr` to `safeNF` and `safeNFOr`.+  `safeNF` now returns a `Maybe` value instead of an `Either` holding a potential error message.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)+- Renamed both `WaveformForLUT` and its constructor `WfLut` to `WaveformForLut`.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)+- Renamed `WfNum` to `WaveformForNumber`.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)+- Rename `styles` in `Waveform` to `constructorStyles`.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)+- Renamed `rFromVal` to `defaultRender`.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)++- To prevent issues, the translators specified for types must consume the same number of bits+  as are used to represent the data (as specified by `BitSize`).+  `tRef` now includes a check for this,+  which prevents types with incorrect widths both from being referenced and used directly.+  [#126](https://github.com/clash-lang/clash-shockwaves/issues/126)++++### Fixes:+- VCD files generated by Shockwaves now contain both the Clash and Shockwaves version,+  which was previously not properly implemented yet.+  [#37](https://github.com/clash-lang/clash-shockwaves/issues/37)++### Deprecated:+- `width` has been deprecated from the `Waveform` class.+  Instead, use `bitSize`.++### Removed:+- Removed `tFromVal`.+  [#112](https://github.com/clash-lang/clash-shockwaves/issues/112)++## v1.0.1 - *11 May, 2026*++Shockwaves now supports Clash 1.10!++## v1.0.0 - *07 Apr, 2026*++The first official full release!++Since the 0.0 release, a lot of things have been changed and fixed.+Furthermore, many changes were made behind the scenes to make the project more maintainable.+The system is now fully usable with no (known) bugs,+but more features and improvements are already on their way!++### Added:+- Added several options for rendering numbers.+  [#52](https://github.com/clash-lang/clash-shockwaves/issues/52)+  [#49](https://github.com/clash-lang/clash-shockwaves/issues/49)+  [#62](https://github.com/clash-lang/clash-shockwaves/issues/62)+- Added HOWTO guides on using the advanced translators (advance sum/product, bitchange)+  and precedence values, as well as notes on differences between translations in Haskell+  and Surfer.+  [#51](https://github.com/clash-lang/clash-shockwaves/issues/51)+  [#59](https://github.com/clash-lang/clash-shockwaves/issues/59)+  [#45](https://github.com/clash-lang/clash-shockwaves/issues/45)+- Linked the HOWTO guides on GitHub in the Haddock documentation.+- A permanent downloads of the Surfer extension is now available on the GitHub release page.++### Changed:+- Renamed the `shockwaves` library to `clash-shockwaves`, and `surfer_shockwaves` to `surfer-shockwaves` to match.+  [#70](https://github.com/clash-lang/clash-shockwaves/issues/70)+- Adding a config file is now part of the setup guide too.+  The provided config file has some good defaults, and immediately improve the user experience+  without the need to actually go into the configuration options.+- Made the unknown style var log message a less alarming warning.+  After all, having missing style variables is expected.+  [#73](https://github.com/clash-lang/clash-shockwaves/issues/73)+- Changed the `BitPart` `BPSlice` option to slice from a different `BitPart`'s output instead of the input,+  and added `BPIn` to refer to the input.+  Part of [#54](https://github.com/clash-lang/clash-shockwaves/issues/54)+- The clock, reset and enable signals are now visible in their non-alarming states+  (reset deasserted, enable on). The default config makes these less obtrusive.+  [#78](https://github.com/clash-lang/clash-shockwaves/issues/78)+- The source code is now formatted using Fourmolu.++### Fixed:+- When (advanced) sum translators have multiple translators that generate subsignals with the same name,+  these are now merged recursively, instead of being added separately.+  [#36](https://github.com/clash-lang/clash-shockwaves/issues/36)+- Replaced several instances of `unknown` with `undefined`.+  [#47](https://github.com/clash-lang/clash-shockwaves/issues/47)+- `CLASH_OPAQUE` annotations have been replaced with `OPAQUE`.+  [#72](https://github.com/clash-lang/clash-shockwaves/issues/72)+- Made the code compatible with the stack LTS-23.28 resolver (GHC 9.8.4).++## v0.0.1hd - *04 Mar, 2026*++### Added:+- Added proper links and instructions for adding dependencies to the setup HOWTO guide.+  [#41](https://github.com/clash-lang/clash-shockwaves/issues/41)+  ++### Changed:+- Loosened clash version constraints to allow versions 1.8.2 and 1.8.3.+  [#40](https://github.com/clash-lang/clash-shockwaves/issues/40)++### Fixed:+- After renaming `traceMap#` to `maps#`, an annotation was left; this has been fixed.+  [#39](https://github.com/clash-lang/clash-shockwaves/issues/39)+- `Maybe` accidentally used style variable `$maybe_just` instead of `maybe_just`.+  [#38](https://github.com/clash-lang/clash-shockwaves/issues/38)++## v0.0.0hsd - *04 Mar, 2026*++Initial release.
+ README.md view
@@ -0,0 +1,111 @@+# Shockwaves Haskell Library++This is the Haskell library for Shockwaves, a typed waveform solution designed for Clash.++The basic concept of the library is that for all types for which signals exist in simulation,+the `Waveform` class is implemented. This class provides all the functionality needed to provide+metadata about types when simulating. This metadata is stored separately, and can be used+by the waveform viewer to reconstruct a typed representation in the waveform viewer.++By default, `Waveform` uses `Generics` to derive a waveform viewer representation similar+to `Show`. Types with multiple constructors and constructors with fields get subsignals.++The `Waveform` class can of course be customized. This allows for more advanced control over+the way data is represented in the waveform viewer. Particularly, through `WaveformLUT`,+translations can be implemented as lookup tables, allowing for arbitrary code execution+in Haskell to create whatever data is desired.++The library includes a modified version of `Clash.Signal.Trace` that uses `Waveform` to+generate metadata.++++## Default behaviour++The default implementations of Waveform make several "clever" choices in how to display values.++For types with multiple constructors and fields, subsignals are created per constructor,+and for each constructor, subsignals are created for each of its fields.+Constructor subsignals are labeled with the name of the constructor,+and field subsignals with the field names.+If there are no field names, the subsignals are numbered instead.+The value displayed at the toplevel is the same as that of the current constructor.++If a type has only one constructor, there is no need for subsignals for the constructor.+Instead, the subsignals for the fields added to the toplevel signal directly.++If a constructor has exactly one field, it will by default copy the style of the contained value.++If a constructor is an operator and has exactly two fields, the constructor will be rendered as+and infix. The operator precedence is used to appropriately add parentheses in nested values.+If an operator constructor has a different number of fields, it is parenthesized and used as normal.++Values are always rendered according to the information actually stored in the binary representation.+This means the system will render both `(undefined,undefined)` and `undefined` as `(undefined,undefined)`:+since there is only one constructor, the value can only be that constructor, and this is known+regardless of whether the value was actually `undefined` during code execution or not.+The translation functions provided in the library, which are meant for creating LUT-based translations,+mimic this behaviour.++Shockwaves has several waveform styles, some of which are special.+If a translation has the `WSError` style, this is propagated through all signals above.+This style is used for undefined values.+`WSWarn` is displayed in the same manner, but not propagated.++++# Quick start++This sections contains instructions for some common uses of Shockwaves.+See also the [HOWTO guides](https://github.com/clash-lang/clash-shockwaves/tree/main/docs/howto/README.md).++## Trace signals++Shockwaves has the same functions as `Clash.Signal.Trace`, with only minor changes:++```hs+import qualified Clash.Shockwaves.Trace as T++mainCounter :: ... -> Signal System Bool+mainCounter = ... (T.trace "counter" counter) ...++main :: IO ()+main = do+  let cntrOut = exposeClockResetEnable mainCounter systemClockGen systemResetGen enableGen+  vcd <- T.dumpVCD (0, 100) cntrOut ["counter"]+  case vcd of+    Left msg ->+      error msg+    Right (contents,meta) -> do+      writeFile     "mainCounter.vcd"  contents+      writeFileJSON "mainCounter.json" meta++```++## Derive Waveform++The easiest way to use Shockwaves is to simply derive the `Waveform` class for all types+that appear in the output. This requires `Generic` and `Typeable` to also be derived.++```hs+data MyData = A Int | B Bool+  deriving (Generic,Typeable,Waveform,NFDataX,BitPack)+```++## Adding coloured constructors++It might be useful to mark the different constructors of a type using various colors.+To do this, one simply needs to do a custom implementation of Waveform where `constructorStyles`+is overwritten with a list of waveform styles, in the order that the constructors appear.++```hs+{-# LANGUAGE OVerloadedStrings #-}++instance Waveform MyData where+  constructorStyles = ["#0fc", WSWarn]+```++## Custom Waveform instances++It is possible to customize the `Waveform` instances.+For this, please see the [HOWTO guides](https://github.com/clash-lang/clash-shockwaves/tree/main/docs/howto/README.md).
clash-shockwaves.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                clash-shockwaves-version:             1.0.1+version:             1.1.1 license:             BSD-2-Clause license-file:        LICENSE copyright:           Copyright © 2026 QBayLogic B.V.@@ -11,7 +11,15 @@                      The library allows the user to specify what the waveforms                      for a data type should look like, and includes tools for                      storing this metadata in simulations.+bug-reports:         https://github.com/clash-lang/clash-shockwaves/issues category:            Hardware+extra-source-files:  README.md+                     CHANGELOG.md+                    +source-repository head+  type: git+  location: https://github.com/clash-lang/clash-shockwaves.git+  subdir: clash-shockwaves  flag large-tuples   description:
src/Clash/Shockwaves.hs view
@@ -19,7 +19,7 @@ -} module Clash.Shockwaves (   -- * Waveform-  Waveform (styles),+  Waveform (constructorStyles),   WaveStyle (..),    -- * Tracing
src/Clash/Shockwaves/BitList.hs view
@@ -16,15 +16,19 @@   split,   concat,   slice,+  length,    -- * Using BitList with BitVector   bvToBl,   blToBv,-  binPack,-  binUnpack,+  pack,+  unpack,    -- * Using BitList as a number   toInteger,++  -- * Rest+  hasUndefined, ) where  import Clash.Shockwaves.Internal.BitList
src/Clash/Shockwaves/Internal/BitList.hs view
@@ -10,8 +10,9 @@ -} module Clash.Shockwaves.Internal.BitList where -import Clash.Prelude hiding (concat, drop, split, take)-import Clash.Sized.Internal.BitVector+import qualified Clash.Class.BitPack as BP+import Clash.Prelude hiding (concat, drop, pack, split, take, unpack)+import Clash.Sized.Internal.BitVector hiding (unsafeMask) import Data.Aeson hiding (Value) import Data.Aeson.Types (toJSONKeyText) import Data.String (IsString (fromString))@@ -43,6 +44,10 @@     showBit 0 1 = '1'     showBit _ _ = 'x' +-- | Return the length of the 'BitList'.+length :: BitList -> Int+length (BL _ _ l) = l+ -- | Convert a 'BitVector' into a 'BitList'. bvToBl :: (KnownNat n) => BitVector n -> BitList bvToBl (BV @n m i) = BL m i (natToNum @n)@@ -55,12 +60,12 @@ blToBv _ = errorX "BitList does not match BitVector size"  -- | Pack a value into a 'BitList'.-binPack :: (BitPack a) => a -> BitList-binPack = bvToBl . pack+pack :: (BitPack a) => a -> BitList+pack = bvToBl . BP.pack  -- | Unpack a value from a 'BitList'.-binUnpack :: (BitPack a) => BitList -> a-binUnpack = unpack . blToBv+unpack :: (BitPack a) => BitList -> a+unpack = BP.unpack . blToBv  -- | Discard the /n/ most significant bits. drop :: Int -> BitList -> BitList@@ -104,6 +109,41 @@ toInteger :: BitList -> Maybe Integer toInteger (BL m i _) | m == 0 = Just $ fromIntegral i toInteger _ = Nothing++-- | Check whether any of the bits in the `BitList` are undefined.+hasUndefined :: BitList -> Bool+hasUndefined (BL m _ _) = m /= 0++instance Bits BitList where+  -- binary operations are right-aligned when not equal in length+  -- & and | short circuit on unknowns (0 & x = 0, 1 | x = 1)+  (.&.) (BL ma ia la) (BL mb ib lb) = BL ((ma .&. mb) .|. (ma .&. ib) .|. (ia .&. mb)) (ia .&. ib) (max la lb)+  (.|.) (BL ma ia la) (BL mb ib lb) = BL ((ma .|. mb) .&. (mask l - v)) v l+   where+    l = max la lb+    v = ia .|. ib+  xor (BL ma ia la) (BL mb ib lb) = BL m (((ia `xor` ib) .|. m) - m) (max la lb)+   where+    m = ma .|. mb++  complement (BL m i l) = BL m (mask l `xor` (i .|. m)) l+  shift (BL m i l) a = BL (shift m a .&. mask l) (shift i a .&. mask l) l+  rotate (BL m i l) a =+    BL+      ((shift m a' .|. shift m (a' - l)) .&. mask l)+      ((shift i a' .|. shift i (a' - l)) .&. mask l)+      l+   where+    a' = a `mod` l+  bitSize (BL _ _ l) = l+  bitSizeMaybe (BL _ _ l) = Just l+  isSigned _ = False+  testBit (BL _ i _) = testBit i+  bit n = BL 0 (bit n) (n + 1)+  popCount (BL _ i _) = popCount i++mask :: Int -> Natural+mask l = (1 `shiftL` l) - 1  instance Semigroup BitList where   (<>) = concat
src/Clash/Shockwaves/Internal/Trace/CRE.hs view
@@ -52,7 +52,7 @@ -} data CREWave dom = CREWave {clock :: ClockWave, reset :: ResetWave dom, enable :: EnableWave}   deriving (Generic, Typeable, BitPack, NFDataX)-  deriving (Waveform) via (WaveformForLUT (CREWave dom))+  deriving (Waveform) via (WaveformForLut (CREWave dom))  vConst :: Render -> Translator vConst r = Translator 0 $ TConst $ tConst r
src/Clash/Shockwaves/Internal/Translator.hs view
@@ -15,11 +15,13 @@ import Clash.Shockwaves.Internal.BitList import Clash.Shockwaves.Internal.Types import Clash.Shockwaves.Internal.Util+ import Data.Bifunctor (first) import qualified Data.List as L import Data.List.Extra (chunksOf) import qualified Data.Map as M-import Data.Maybe (fromMaybe, isJust)+import Data.Maybe (fromMaybe, isJust, isNothing, listToMaybe)+import Data.String (IsString (fromString)) import Data.Tuple.Extra (second) import Math.NumberTheory.Logarithms (intLog2) import Numeric (showHex)@@ -73,10 +75,27 @@ {- FOURMOLU_DISABLE -} -- | Change bits using 'BitPart'. changeBits :: BitPart -> BitList -> BitList-changeBits (BPConcat bps) bin = L.foldl (<>) "" $ L.map (`changeBits` bin) bps-changeBits (BPLit bl)    _bin = bl-changeBits (BPSlice s bp) bin = BL.slice s $ changeBits bp bin-changeBits BPIn           bin = bin+changeBits BPIn                bin = bin+changeBits (BPLit bl)          _   = bl+changeBits (BPSlice s bp)      bin = BL.slice s $ changeBits bp bin+changeBits (BPConcat bps)      bin = L.foldl (<>) "" $ L.map (`changeBits` bin) bps+changeBits (BPHasUndefined bp) bin = (["0","1"] L.!!) $ fromEnum $ BL.hasUndefined $ changeBits bp bin+changeBits (BPReverse bp)      bin = fromString $ L.reverse $ show $ changeBits bp bin+changeBits (BPInvert bp)       bin = complement $ changeBits bp bin+changeBits (BPAnd bps)         bin = L.foldl1 (.&.) $ L.map (`changeBits` bin) bps+changeBits (BPOr bps)          bin = L.foldl1 (.|.) $ L.map (`changeBits` bin) bps+changeBits (BPXor bps)         bin = L.foldl1 xor $ L.map (`changeBits` bin) bps+changeBits (BPOneHot (f,t) bp) bin = case BL.toInteger $ changeBits bp bin of+  Just x  -> fromString $ L.map (("01" L.!!) . fromEnum . (== fromIntegral x)) [f..t-1]+  Nothing -> fromString $ L.replicate (t-f) 'x'+changeBits (BPNHot (f,t) bp)   bin = case BL.toInteger $ changeBits bp bin of+  Just x  -> fromString $ L.map (("01" L.!!) . fromEnum . (<= fromIntegral x)) [f..t-1]+  Nothing -> fromString $ L.replicate (t-f) 'x'+changeBits (BPIf t f x c)      bin = let c' = show $ changeBits c bin+                                     in case listToMaybe c' of+                                          Just '1' -> changeBits t bin+                                          Just '0' -> changeBits f bin+                                          _        -> changeBits x bin {- FOURMOLU_ENABLE -}  {- FOURMOLU_DISABLE -}@@ -119,7 +138,7 @@     _ ->       errorX         "Ref should only appear as a nested type that is translated through split; for referenced types, modify Waveform.translate"-  TLut _ _ -> case subs of+  TLut _ _ _ -> case subs of     [("", t)] -> t     _ ->       errorX@@ -189,7 +208,7 @@   | width <= blLength   , bin <- BL.take width bin'' = case variant of       TRef _ TypeRef{translateBinRef} -> translateBinRef bin-      TLut _ TypeRef{translateBinRef} -> translateBinRef bin+      TLut _ _ TypeRef{translateBinRef} -> translateBinRef bin       TNumber{format, spacer, prefix, warn} -> Translation (if isJust render then render else Just ("undefined", WSError, 11)) []        where         bin' = show bin@@ -267,9 +286,7 @@  -- structure -{- | Return the t'Structure' implied by a t'Translator'. Useful for determining-the structure of a constant translation.--}+-- | Return the t'Structure' implied by a t'Translator'. structureT :: Translator -> Structure structureT (Translator _ t) = case t of   TRef _ TypeRef{structureRef} -> structureRef@@ -280,7 +297,7 @@   TAdvancedSum{rangeTrans, defTrans} -> structureT $ Translator 0 $ TSum (defTrans : L.map snd rangeTrans)   TProduct{subs} -> Structure $ L.map (second structureT) subs   TConst trans -> fromTranslation trans-  TLut _ TypeRef{structureRef} -> structureRef+  TLut _ _ TypeRef{structureRef} -> structureRef   TNumber{} -> Structure []   TArray{sub, len} ->     Structure@@ -297,25 +314,6 @@   TDuplicate n t' -> Structure [(n, structureT t')]   TChangeBits{sub} -> structureT sub --- | Merge duplicate subsignals in a list of subsignal structures.-mergeDuplicateSubsignals :: [(SubSignal, Structure)] -> [(SubSignal, Structure)]-mergeDuplicateSubsignals = L.reverse . L.foldr addSignal [] . L.reverse- where-  addSignal ::-    (SubSignal, Structure) -> [(SubSignal, Structure)] -> [(SubSignal, Structure)]-  addSignal sig signals = case L.mapAccumL mergeOrPass (Just sig) signals of-    (Nothing, signals') -> signals'-    (Just sig', signals') -> sig' : signals'-   where-    mergeOrPass ::-      Maybe (SubSignal, Structure) ->-      (SubSignal, Structure) ->-      (Maybe (SubSignal, Structure), (SubSignal, Structure))-    mergeOrPass (Just (name, Structure s)) (name', Structure s')-      | name == name' =-          (Nothing, (name, Structure $ mergeDuplicateSubsignals (s' <> s)))-    mergeOrPass newsig oldsig = (newsig, oldsig)- -- | Construct a t'Structure' from a t'Translation'. fromTranslation :: Translation -> Structure fromTranslation (Translation _ subs) = Structure $ L.map (second fromTranslation) subs@@ -329,7 +327,7 @@ foldTranslator m f (Translator _ variant) = case variant of   -- leaf translators   TRef _ TypeRef{translatorRef}     -> f [m translatorRef]-  TLut _ _                          -> f []+  TLut _ _ _                        -> f []   TConst _                          -> f []   TNumber{}                         -> f [] @@ -347,9 +345,9 @@ {- FOURMOLU_ENABLE -}  -- | Test if there is a LUT translator in a translator (following references).-hasLutT :: Translator -> Bool-hasLutT (Translator _ (TLut _ _)) = True-hasLutT t = foldTranslator hasLutT or t+hasGeneratedLutT :: Translator -> Bool+hasGeneratedLutT (Translator _ (TLut _ lut _)) = isNothing lut+hasGeneratedLutT t = foldTranslator hasGeneratedLutT or t  {- | Add all type references in a translator structure to a type map. To add the types in a type, run this function on a reference to said type.@@ -369,14 +367,15 @@ -} addValueT :: Translator -> BitList -> [LUTMap -> LUTMap] addValueT translator@(Translator _ variant) =-  if hasLutT translator+  if hasGeneratedLutT translator     then case variant of       -- leaf translators       TRef _ TypeRef{translatorRef} -> addValueT translatorRef-      TLut name TypeRef{translateBinRef} -> go+      TLut _ (Just _) _ -> const []+      TLut name Nothing TypeRef{translateBinRef} -> go        where         go bin =-          let translation = safeValOr (errorT "error") (translateBinRef bin)+          let translation = safeNFOr (errorT "error") (translateBinRef bin)            in [M.alter (Just . insertIfMissing bin translation . fromMaybe M.empty) name]       TConst _ -> const []       TNumber{} -> const []@@ -425,3 +424,9 @@         fSub = addValueT sub         go bin = fSub $ changeBits bits bin     else const []++-- | Get all static LUTs in a Translator, not following references.+getStaticLuts :: Translator -> [(String, LUT)]+getStaticLuts (Translator _ (TRef _ _)) = []+getStaticLuts (Translator _ (TLut name l _)) = fromMaybe [] $ (\lut -> [(name, lut)]) <$> l+getStaticLuts t = foldTranslator getStaticLuts L.concat t
src/Clash/Shockwaves/Internal/Types.hs view
@@ -164,7 +164,7 @@   | {- | A reference to a lookup table. Implement @Waveform@ through @WaveformLUT@     to stably use this functionality.     -}-    TLut LUTName TypeRef+    TLut LUTName (Maybe LUT) TypeRef   | {- | Select one translator to be used based on the first bits of the binary     representation. Translate the rest of the bits using the selected translator.     To be exact, if /k/ translators are provided, /ceil(log2(k))/ bits will be@@ -285,8 +285,8 @@     onto the subtranslator.     -}     TChangeBits-      { sub :: Translator-      , bits :: BitPart+      { bits :: BitPart+      , sub :: Translator       }   | {- | Translate the binary data as an integer. @format@ and @spacer@ determine     how exactly the value is displayed.@@ -319,6 +319,37 @@     BPSlice Slice BitPart   | -- | Pass the binary data onto multiple 'BitPart's, and concatenate their results.     BPConcat [BitPart]+  | -- | Return `1` if there are undefined bits in the binary.+    BPHasUndefined BitPart+  | -- | Return bits in reverse order.+    BPReverse BitPart+  | -- | Invert 0 and 1.+    BPInvert BitPart+  | {- | Bitwise and. If values of different lengths are provided, values are zero-padded on the left.+    Short-cirtuits (@x & 0 = 0@).+    -}+    BPAnd [BitPart]+  | {- | Bitwise or. If values of different lengths are provided, values are zero-padded on the left.+    Short-cirtuits (@x | 1 = 1@).+    -}+    BPOr [BitPart]+  | -- | Bitwise xor. If multiple values of different lengths are provided, values are zero-padded on the left.+    BPXor [BitPart]+  | {- | Turn a binary value into a one-hot signal based on the provided range.+    This essentially loops over all values in the range, creating a 1 iff the input+    BitPart's result is equal to that value.+    I.e. BPOneHot (0,3) "10" results in "001".+    -}+    BPOneHot Slice BitPart+  | {- | Turn a binary value into a n-hot signal based on the provided range.+    This essentially loops over all values in the range, creating a 1 iff the input+    BitPart's result is less than or equal to that value.+    -}+    BPNHot Slice BitPart+  | {- | Switch bitparts based on the first bit in the condition bitpart:+    `BPIf (true) (false) (undef) (cond)`+    -}+    BPIf BitPart BitPart BitPart BitPart   deriving (Show)  -- | Parts of the value of 'TAdvancedProduct'.@@ -362,8 +393,17 @@ instance ToJSON BitPart where   toJSON (BPConcat bps) = object ["C" .= bps]   toJSON (BPLit bl) = object ["L" .= show bl]-  toJSON (BPSlice s bp) = object ["S" .= [toJSON s, toJSON bp]]+  toJSON (BPSlice s a) = object ["S" .= [toJSON s, toJSON a]]   toJSON BPIn = "I"+  toJSON (BPHasUndefined a) = object ["X" .= a]+  toJSON (BPReverse a) = object ["R" .= a]+  toJSON (BPInvert a) = object ["~" .= a]+  toJSON (BPAnd as) = object ["&" .= as]+  toJSON (BPOr as) = object ["|" .= as]+  toJSON (BPXor as) = object ["^" .= as]+  toJSON (BPOneHot s i) = object ["h" .= [toJSON s, toJSON i]]+  toJSON (BPNHot s i) = object ["H" .= [toJSON s, toJSON i]]+  toJSON (BPIf t f x c) = object ["?" .= [t, f, x, c]]  instance ToJSON ValuePart where   toJSON (VPLit s) = object ["L" .= s]@@ -398,7 +438,7 @@                 ]           ]       TConst t -> object ["C" .= toJSON t]-      TLut lut TypeRef{structureRef} -> object ["L" .= [toJSON lut, toJSON structureRef]]+      TLut lut _ TypeRef{structureRef} -> object ["L" .= [toJSON lut, toJSON structureRef]]       TNumber{format, spacer, prefix, warn} ->         object           [ "N"@@ -464,3 +504,25 @@     NFHex -> "H"     NFOct -> "O"     NFBin -> "B"++-- | Merge duplicate subsignals in a list of subsignal structures.+mergeDuplicateSubsignals :: [(SubSignal, Structure)] -> [(SubSignal, Structure)]+mergeDuplicateSubsignals = L.reverse . L.foldr addSignal [] . L.reverse+ where+  addSignal ::+    (SubSignal, Structure) -> [(SubSignal, Structure)] -> [(SubSignal, Structure)]+  addSignal sig signals = case L.mapAccumL mergeOrPass (Just sig) signals of+    (Nothing, signals') -> signals'+    (Just sig', signals') -> sig' : signals'+   where+    mergeOrPass ::+      Maybe (SubSignal, Structure) ->+      (SubSignal, Structure) ->+      (Maybe (SubSignal, Structure), (SubSignal, Structure))+    mergeOrPass (Just (name, Structure s)) (name', Structure s')+      | name == name' =+          (Nothing, (name, Structure $ mergeDuplicateSubsignals (s' <> s)))+    mergeOrPass newsig oldsig = (newsig, oldsig)++instance Semigroup Structure where+  (<>) (Structure a) (Structure b) = Structure $ mergeDuplicateSubsignals $ a <> b
src/Clash/Shockwaves/Internal/Util.hs view
@@ -11,8 +11,9 @@ -} module Clash.Shockwaves.Internal.Util where -import Clash.Prelude+import Clash.Prelude hiding (sub) import Clash.Shockwaves.Internal.Types+import Clash.Shockwaves.Style (RGB (..)) import Control.DeepSeq (NFData, force) import Control.Exception (SomeException, catch, evaluate) import Control.Exception.Base (Exception (toException))@@ -22,7 +23,7 @@ import Data.List.Split (chunksOf) import Data.Map (Map) import qualified Data.Map as M-import Data.Maybe (fromMaybe, listToMaybe)+import Data.Maybe (fromMaybe, isJust, listToMaybe) import Data.Proxy import Data.Typeable import GHC.IO (unsafeDupablePerformIO)@@ -51,8 +52,8 @@ writeFileJSON = encodeFile  -- | Returns the 'BitSize' of a type as a runtime 'Int'.-bitsize :: (BitPack a) => Proxy a -> Int-bitsize (_ :: Proxy a) = fromInteger $ natVal $ Proxy @(BitSize a)+bitSize :: forall a. (BitPack a) => Int+bitSize = fromInteger $ natVal $ Proxy @(BitSize a)  -- | Wrap parentheses around a value. parenthesize :: Value -> Value@@ -70,15 +71,15 @@ joinWith _ [x] = x joinWith _ [] = "" -{- | Obtain the name of a type from a proxy value.+{- | Obtain the default name of a type. The name consists of a unique fingerprint (which is safe to use) and a human readable representation of the type (which may not be unique if multiple sources define the same types). -}-typeNameP :: (Typeable a) => Proxy a -> TypeName-typeNameP p = show (typeRepFingerprint r) <> ":" <> show r+defaultTypeName :: forall a. (Typeable a) => TypeName+defaultTypeName = show (typeRepFingerprint r) <> ":" <> show r  where-  r = typeRep p+  r = typeRep (Proxy @a)  -- | Shorthand function for obtaining the runtime 'String' of a type level Symbol. sym :: forall s. (KnownSymbol s) => String@@ -87,8 +88,8 @@ {- | Check if a value is completely defined. If not, optionally return an error message. -}-safeVal :: (NFData a) => a -> Either (Maybe Value) a-safeVal x =+safeNFErr :: (NFData a) => a -> Either (Maybe Value) a+safeNFErr x =   unsafeDupablePerformIO     $ catch       ( evaluate@@ -101,13 +102,15 @@       )       (\(XException e) -> return $ Left (Just e)) +-- | Check if a value is completely defined.+safeNF :: (NFData a) => a -> Maybe a+safeNF = either (const Nothing) Just . safeNFErr+ {- | Check if a value is completely defined. If not, return the default value provided. -}-safeValOr :: (NFData a) => a -> a -> a-safeValOr y x = case safeVal x of-  Right x' -> x'-  Left _e -> y+safeNFOr :: (NFData a) => a -> a -> a+safeNFOr y x = fromMaybe y $ safeNF x  -- | Evaluate to WHNF. If this fails, return a default value. safeWHNF :: a -> Maybe a@@ -155,3 +158,84 @@ -- | Add a translator by name to the type map. addType :: String -> Translator -> (TypeMap -> TypeMap) addType = M.insert++-- | `zipWith` variant that errors on lists of different length+erroringZipWith :: String -> (a -> b -> c) -> [a] -> [b] -> [c]+erroringZipWith _ _ [] [] = []+erroringZipWith e f (x : xs) (y : ys) = f x y : erroringZipWith e f xs ys+erroringZipWith e _ _ _ = error e++-- | 'head' but without complaints+unsafeHead :: [a] -> a+unsafeHead (x : _) = x+unsafeHead _ = error "empty list has no head"++{- | Debug function for pretty printing t'Translator's.+The output of this function may change. It is merely intended as a debug tool+when creating and modifying translators.+-}+pprintT :: Translator -> String+pprintT = pprintT' 0+ where+  pprintT' :: Int -> Translator -> String+  pprintT' indent (Translator w v) =+    space+      <> ( case v of+             TRef n _ref ->+               trans "Ref" <> " " <> n+             TLut n sLut _ref ->+               trans "Lut" <> " (" <> (if isJust sLut then "static" else "generated") <> ") " <> n+             TSum ts ->+               (trans "Sum" <> "\n")+                 <> joinWith "\n" (L.map (pprintT' indent') ts)+             TAdvancedSum{defTrans, rangeTrans} ->+               (trans "AdvancedSum" <> "\n")+                 <> (space' <> "default" <> "\n")+                 <> (pprintT' indent' defTrans <> "\n")+                 <> (space' <> "subs" <> "\n")+                 <> joinWith "\n" (L.map (pprintT' indent') (defTrans : L.map snd rangeTrans))+             TProduct{subs, start, sep, stop} ->+               (trans "Product" <> " ()" <> start <> "/" <> sep <> "/" <> stop <> ")")+                 <> L.concatMap (\(s, t) -> "\n" <> space' <> s <> "\n" <> pprintT' indent' t) subs+             TArray{sub, len, start, sep, stop} ->+               ( (trans "Array" <> " len:" <> show len)+                   <> (" (" <> start <> "/" <> sep <> "/" <> stop <> ")\n")+               )+                 <> pprintT' indent' sub+             TAdvancedProduct{sliceTrans} ->+               (trans "AdvancedProduct" <> "\n")+                 <> joinWith "\n" (L.map (pprintT' indent' . snd) sliceTrans)+             TDuplicate n t ->+               (trans "Dup" <> space' <> n <> "\n")+                 <> pprintT' indent' t+             TStyled sty t ->+               (trans "Styled" <> " " <> showStyle sty <> "\n")+                 <> pprintT' indent' t+             TChangeBits{sub} ->+               (trans "ChangeBits" <> "\n")+                 <> pprintT' indent' sub+             TNumber{format} ->+               trans "Number" <> " " <> show format+             TConst (Translation val _) ->+               trans "Const" <> " " <> case val of+                 Just (val', _, _) -> val'+                 _ -> "_"+         )+   where+    space = L.replicate indent ' '+    space' = L.replicate (indent + 2) ' '+    trans s = s <> "[" <> show w <> "]"+    indent' = indent + 4+    showStyle = \case+      WSDefault -> "Default"+      WSError -> "Error"+      WSHidden -> "Hidden"+      WSInherit n -> "Inherit " <> show n+      WSNormal -> "Normal"+      WSWarn -> "Warn"+      WSUndef -> "Undef"+      WSHighImp -> "HighImp"+      WSDontCare -> "DontCate"+      WSWeak -> "Weak"+      WSColor (RGB r g b) -> "Color (" <> show r <> "," <> show g <> "," <> show b <> ")"+      WSVar var dflt -> "$" <> var <> "/" <> showStyle dflt
src/Clash/Shockwaves/Internal/Waveform.hs view
@@ -17,7 +17,7 @@ -} module Clash.Shockwaves.Internal.Waveform where -import Clash.Prelude+import Clash.Prelude hiding (bitSize)  import Clash.Shockwaves.BitList (BitList) import qualified Clash.Shockwaves.BitList as BL@@ -28,6 +28,7 @@  import Data.Char (isAlpha) import qualified Data.List as L+import qualified Data.Map as M import Data.Maybe (fromMaybe, listToMaybe) import Data.Proxy import Data.Typeable@@ -42,6 +43,7 @@ import Clash.Num.Saturating (Saturating) import Clash.Num.Wrapping (Wrapping) import Clash.Num.Zeroing (Zeroing)+import Data.Bifunctor (first) import Data.Complex (Complex) import Data.Functor.Identity (Identity) import Data.Ord (Down)@@ -70,31 +72,11 @@ -- making values  -- | Get a 'Render' from a 'Value' using 'WSDefault' and precedence 11.-rFromVal :: Value -> Render-rFromVal v = Just (v, WSDefault, 11)---- | Get a t'Translation' from a 'Value' using 'WSDefault' and precedence 11.-tFromVal :: Value -> Translation-tFromVal v = Translation (rFromVal v) []---- | Create an error value from an optional error message.-errMsg :: Maybe Value -> Value-errMsg = maybe "undefined" (\e -> "{undefined: " <> e <> "}")---- | First 'WaveStyle' in an infinite list of values.-styHead :: [WaveStyle] -> WaveStyle-styHead (s : _) = s-styHead _ = error "style list must be long enough"+defaultRender :: Value -> Render+defaultRender v = Just (v, WSDefault, 11)  -- making translators -{- | Wrap a t'Translator' in a 'TStyled' translator using some style, unless the-provided style is 'WSDefault'.--}-wrapStyle :: WaveStyle -> Translator -> Translator-wrapStyle WSDefault t = t-wrapStyle s t = tStyled s t- {- | Wrap a t'Translator' in a 'TStyled' variant translator with the provided style. -}@@ -107,36 +89,71 @@ tDup :: SubSignal -> Translator -> Translator tDup name (Translator w t) = Translator w $ TDuplicate name (Translator w t) --- | Generate a translator reference for a type.-tRef :: (Waveform a) => Proxy a -> Translator-tRef (_ :: Proxy a) =-  Translator (width @a)-    $ TRef-      (typeName @a)-      TypeRef-        { translateBinRef = translateBin @a-        , translatorRef = translator @a-        , structureRef = structure @a-        }+{- | Generate a translator reference for a type.+Also checks whether the translator width matches the value of 'bitSize' for+the type: if not, the function errors.+-}+tRef :: forall a. (Waveform a) => Translator+tRef+  | w == bitSize @a =+      Translator (bitSize @a)+        $ TRef+          (typeName @a)+          TypeRef+            { translateBinRef = translateBin @a+            , translatorRef = translator @a+            , structureRef = structure @a+            }+  | otherwise =+      error+        $ "The Translator width and BitSize for type "+        <> show (typeName @a)+        <> " do not match."+ where+  Translator w _ = translator @a  -- | Create a constant translator that consumes 0 bits and has no subsignals. tConst :: Render -> Translator tConst r = Translator 0 $ TConst $ Translation r [] +{- | Create a LUT translator for a type, using either the static LUT or the translation+function specified in 'WaveformLUT'+-}+tLut :: forall a. (Waveform a, WaveformLUT a) => Maybe LUT -> Translator+tLut l = case l of+  Just lut -> tStaticLut @a lut+  Nothing -> tGeneratedLut @a+ -- | Create a LUT translator for a type, using the translation function of 'WaveformLUT'.-tLut :: forall a. (Waveform a, WaveformLUT a) => Proxy a -> Translator-tLut _ =-  Translator (width @a)+tGeneratedLut :: forall a. (Waveform a, WaveformLUT a) => Translator+tGeneratedLut =+  Translator (bitSize @a)     $ TLut       (typeName @a)+      Nothing       TypeRef-        { translateBinRef = translateL @a . BL.binUnpack+        { translateBinRef = translateL @a . BL.unpack         , structureRef = structureL @a         , translatorRef = translator @a         } +-- | Create a LUT translator for a type, using the static LUT in 'WaveformLUT'.+tStaticLut :: forall a. (Waveform a, WaveformLUT a) => LUT -> Translator+tStaticLut lut =+  Translator (bitSize @a)+    $ TLut+      (typeName @a)+      (Just lut)+      TypeRef+        { translateBinRef = translateStaticL @a . BL.unpack+        , structureRef = L.foldl1 (<>) $ L.map fromTranslation $ M.elems lut+        , translatorRef = translator @a+        }+ ------------------------------------------ WAVEFORM -------------------------------------- +{-# DEPRECATED width "Use bitSize instead" #-}+ {- |  'Waveform' is the main class for making types displayable in the waveform viewer.@@ -155,12 +172,15 @@   Overriding this value is only really useful for derive via strategies.   -}   typeName :: TypeName-  typeName = typeNameP (Proxy @a)+  typeName = defaultTypeName @a    -- | The translator used for the data type. Must match the structure value.   translator :: Translator   default translator :: (WaveformG (Rep a ())) => Translator-  translator = translatorG @(Rep a ()) (width @a) (styles' @a)+  translator =+    inheritSingleFieldStyle+      $ withConstructorStyles (constructorStyles @a)+      $ defaultTranslator @a    {- | List of styles used for constructors. @@ -169,18 +189,27 @@   this list can be overridden to provides styles for the constructors, in order.   To not change a style, use 'WSDefault'.   -}-  styles :: [WaveStyle]-  styles = []+  constructorStyles :: [WaveStyle]+  constructorStyles = [] -  -- | Runtime bitsize of the type.+  {- |+  Defines the width of the translator based on @bitSize@+  -}   width :: Int-  width = bitsize (Proxy @a)+  width = bitSize @a +{- | Return the default translator that is derived for a data type.+This default can be modified to obtain a slightly different translator.+-}+defaultTranslator ::+  forall a. (BitPack a, WaveformG (Rep a ())) => Translator+defaultTranslator = translatorG @(Rep a ()) (bitSize @a)+ {- | Function to translate values. This function creates a translation from the binary representation of the data using translateBin, and the translator. -} translate :: forall a. (Waveform a, BitPack a) => a -> Translation-translate = translateBin @a . BL.binPack+translate = translateBin @a . BL.pack  {- | Translate binary data. Normally, this simply translates the value according to the translator.@@ -192,15 +221,15 @@  -- | Register this type and all its subtypes. addTypes :: forall a. (Waveform a) => TypeMap -> TypeMap-addTypes = addTypesT $ tRef (Proxy @a)+addTypes = addTypesT $ tRef @a --- | Helper function that fills the 'styles' list with 'WSDefault'.-styles' :: forall a. (Waveform a) => [WaveStyle]-styles' = styles @a <> L.repeat WSDefault+-- | Helper function that fills the 'constructorStyles' list with 'WSDefault'.+constructorStyles' :: forall a. (Waveform a) => [WaveStyle]+constructorStyles' = constructorStyles @a <> L.repeat WSDefault --- | Check if the type requires LUTs for translation.-hasLut :: forall a. (Waveform a) => Bool-hasLut = hasLutT $ translator @a+-- | Check if the type requires values to be added to LUTs.+hasGeneratedLut :: forall a. (Waveform a) => Bool+hasGeneratedLut = hasGeneratedLutT $ translator @a  -- | Return the structure of a type. structure :: forall a. (Waveform a) => Structure@@ -208,8 +237,125 @@  -- | Add all (sub) values that use 'TLut' to their respective LUTs. addValue :: forall a. (Waveform a) => a -> [LUTMap -> LUTMap]-addValue = addValueT (translator @a) . BL.binPack+addValue = addValueT (translator @a) . BL.pack +-- translator modification++{- | Remove constructor subsignals from a (generated) translator.+This results in all constructor field subsignals becoming direct subsignals of the toplevel signal.+Set rename to `True` to add the constructor's name as a prefix to the signal name.++Essentially, this function searches through 'TStyled' and 'TSum' for any 'TDuplicate' translators to remove.+If renaming subsignals, it then searches through 'TStyled' to rename subsignals in 'TProduct'.+-}+noConstructorSubsignals :: Bool -> Translator -> Translator+noConstructorSubsignals rename (Translator w (TStyled s t)) = Translator w $ TStyled s $ noConstructorSubsignals rename t+noConstructorSubsignals rename (Translator w (TSum subs)) = Translator w $ TSum $ noConstructorSubsignals rename <$> subs+noConstructorSubsignals rename (Translator _ (TDuplicate n t)) = if rename then prefixFields t else t+ where+  prefixFields (Translator w (TStyled s t')) = Translator w $ TStyled s $ prefixFields t'+  prefixFields (Translator w p@TProduct{subs}) = Translator w p{subs = (\(s, t') -> (n <> "." <> s, t')) <$> subs}+  prefixFields t' = t'+noConstructorSubsignals _ t = t++{- | Rename constructor fields. This is particularly useful for non-record types.+The input is a list of a list of field names, per constructor.+Errors if the number of constructors/fields does not match the structure of the 'Translator'.+For translators other than 'TProduct', use an empty list of fieldnames.+-}+renameFields :: [[String]] -> Translator -> Translator+renameFields names (Translator w (TStyled s t)) = Translator w $ TStyled s $ renameFields names t+renameFields names (Translator w (TDuplicate n t)) = Translator w $ TDuplicate n $ renameFields names t+renameFields names (Translator w (TSum subs)) =+  Translator w+    $ TSum+    $ erroringZipWith+      ("Incorrect number of constructors:" <> show names)+      (\n t -> renameFields [n] t)+      names+      subs+renameFields names (Translator w p@TProduct{subs}) =+  Translator+    w+    p+      { subs =+          erroringZipWith+            ("Incorrect number of fields" <> show fieldNames)+            (\n (_, t) -> (n, t))+            fieldNames+            subs+      }+ where+  fieldNames = case names of+    [x] -> x+    _ -> error ("Incorrect number of constructors: " <> show names)+renameFields [[]] t = t+renameFields names t =+  error+    ( "renameFields encountered unexpected Translator for names "+        <> show names+        <> ": "+        <> show t+    )++{- | Rename the constructors subsignals of a data type.+Errors if the number of constructor subsignal names provided is incorrect,+or when called on a translator that does not have a sum translator.+-}+renameConstructors :: [String] -> Translator -> Translator+renameConstructors names (Translator w (TStyled s t)) = Translator w $ TStyled s $ renameConstructors names t+renameConstructors names (Translator w (TDuplicate n t)) = Translator w $ TDuplicate n $ renameConstructors names t+renameConstructors names (Translator w (TSum subs)) =+  Translator w+    $ TSum+    $ erroringZipWith+      ("Incorrect number of constructors:" <> show names)+      renameConstructor+      names+      subs+ where+  renameConstructor :: String -> Translator -> Translator+  renameConstructor name (Translator w' (TStyled s t)) = Translator w' $ TStyled s $ renameConstructor name t+  renameConstructor name (Translator w' (TDuplicate _n t)) = Translator w' $ TDuplicate name t+  renameConstructor _ t = t+renameConstructors _ _ = error "renameFields called on translator without explicit constructors"++{- | Wrap constructors with a single field in the @WSInherit 0@ style.+Ignores any structures that are wrapped in a TStyled translator.+-}+inheritSingleFieldStyle :: Translator -> Translator+inheritSingleFieldStyle t@(Translator _ (TStyled _ _)) = t+inheritSingleFieldStyle (Translator w (TDuplicate n t)) = Translator w $ TDuplicate n $ inheritSingleFieldStyle t+inheritSingleFieldStyle (Translator w (TSum ts)) = Translator w $ TSum $ L.map inheritSingleFieldStyle ts+inheritSingleFieldStyle t@(Translator _ TProduct{subs}) = if L.length subs == 1 then tStyled (WSInherit 0) t else t+inheritSingleFieldStyle t = t -- TODO: continue on AS,AP,P,Ar,CB++{- | Apply constructor styles. This wraps 'TProduct' translators and modifies the style of 'TConst' translators.+Does nothing if the list of styles is empty.+Otherwise, errors if the number of styles does not match the number of constructors.+-}+withConstructorStyles :: [WaveStyle] -> Translator -> Translator+withConstructorStyles [] t = t+withConstructorStyles sty (Translator w (TDuplicate n t)) = Translator w $ TDuplicate n $ withConstructorStyles sty t+withConstructorStyles sty (Translator w (TSum ts)) =+  Translator w+    $ TSum+    $ erroringZipWith+      "withConstructorStyles called with incorrect number of styles"+      (\s t -> withConstructorStyles [s] t)+      sty+      ts+withConstructorStyles [WSDefault] t = t+withConstructorStyles [s] (Translator w (TStyled _ t)) = Translator w $ TStyled s t+withConstructorStyles [s] (Translator w (TConst (Translation r ss))) = Translator w $ TConst $ Translation r' ss+ where+  r' = (\(v, _, p) -> (v, s, p)) <$> r+withConstructorStyles [s] t = tStyled s t+withConstructorStyles _ t =+  error+    $ "withConstructorStyles called with incorrect number of styles for translator "+    <> show t+ ------------------------------------------- GENERIC -------------------------------------  {- | A class for obtaining the required behaviour of 'Waveform' through "GHC.Generics".@@ -220,13 +366,13 @@    Defined only for full types and constructors   -}-  translatorG :: Int -> [WaveStyle] -> Translator+  translatorG :: Int -> Translator    {- | Return a list of translators for constructors as subsignals.    Defined for constructors, @:+:@ and types with multiple constructors.   -}-  constrTranslatorsG :: [WaveStyle] -> [Translator]+  constrTranslatorsG :: [Translator]    {- | Return a list of translators for fields. @@ -260,8 +406,8 @@  -- void type (assuming it has a custom bitpack implementation) instance WaveformG (D1 m1 V1 k) where-  translatorG _ _ = tConst Nothing-  constrTranslatorsG _ = undefined+  translatorG _ = tConst Nothing+  constrTranslatorsG = undefined   fieldTranslatorsG = undefined    widthG = undefined@@ -284,7 +430,7 @@  -- multiple constructors type instance (WaveformG ((a :+: b) k)) => WaveformG (D1 m1 (a :+: b) k) where-  translatorG w sty = Translator w . TSum $ constrTranslatorsG @((a :+: b) k) sty+  translatorG w = Translator w . TSum $ constrTranslatorsG @((a :+: b) k)   constrTranslatorsG = constrTranslatorsG @((a :+: b) k)   fieldTranslatorsG = undefined @@ -296,10 +442,10 @@ -- multiple constructors instance (WaveformG (a k), WaveformG (b k)) => WaveformG ((a :+: b) k) where   translatorG = undefined-  constrTranslatorsG sty = a <> b+  constrTranslatorsG = a <> b    where-    a = constrTranslatorsG @(a k) sty-    b = constrTranslatorsG @(b k) (L.drop (L.length a) sty)+    a = constrTranslatorsG @(a k)+    b = constrTranslatorsG @(b k)   fieldTranslatorsG = undefined    widthG = undefined@@ -315,15 +461,8 @@   (WaveformG (fields k), KnownSymbol name) =>   WaveformG (C1 (MetaCons name fix True) fields k)   where-  translatorG _ sty = t'+  translatorG _ = t    where-    t' = case styHead sty of-      WSDefault ->-        if L.length subs == 1-          then-            tStyled (WSInherit 0) t-          else t-      s -> tStyled s t     subs = fieldTranslatorsG @(C1 (MetaCons name fix True) fields k)     t =       Translator (widthG @(fields k))@@ -337,9 +476,9 @@           , subs = subs           } -  constrTranslatorsG sty =+  constrTranslatorsG =     [ tDup (sym @name)-        $ translatorG @(C1 (MetaCons name fix True) fields k) undefined sty+        $ translatorG @(C1 (MetaCons name fix True) fields k) undefined     ]   fieldTranslatorsG = fieldTranslatorsG @(fields k) @@ -353,15 +492,8 @@   (WaveformG (fields k), KnownSymbol name, PrecF fix) =>   WaveformG (C1 (MetaCons name fix False) fields k)   where-  translatorG _ sty = t'+  translatorG _ = t    where-    t' = case styHead sty of-      WSDefault ->-        if L.length subs == 1-          then-            tStyled (WSInherit 0) t-          else t-      s -> tStyled s t     subs = fieldTranslatorsG @(C1 (MetaCons name fix False) fields k)     t =       if isOperator@@ -395,9 +527,9 @@     sname = safeName (sym @name)     isOperator = not (isAlpha $ fromMaybe '_' $ listToMaybe $ sym @name) && (L.length subs == 2) -  constrTranslatorsG sty =+  constrTranslatorsG =     [ tDup (sym @name)-        $ translatorG @(C1 (MetaCons name fix False) fields k) undefined sty+        $ translatorG @(C1 (MetaCons name fix False) fields k) undefined     ]   fieldTranslatorsG = enumLabel $ fieldTranslatorsG @(fields k) @@ -443,9 +575,9 @@   where   translatorG = undefined   constrTranslatorsG = undefined-  fieldTranslatorsG = [(sym @name, tRef (Proxy @t))]+  fieldTranslatorsG = [(sym @name, tRef @t)] -  widthG = width @t+  widthG = bitSize @t    translateWithG _ _ = undefined   translateFieldsG x = [(sym @name, translate $ unK1 $ unM1 x)]@@ -454,9 +586,9 @@ instance (Waveform t) => WaveformG (S1 (MetaSel Nothing p q r) (Rec0 t) k) where   translatorG = undefined   constrTranslatorsG = undefined-  fieldTranslatorsG = [("", tRef (Proxy @t))]+  fieldTranslatorsG = [("", tRef @t)] -  widthG = width @t+  widthG = bitSize @t    translateWithG _ _ = undefined   translateFieldsG x = [("", translate $ unK1 $ unM1 x)]@@ -465,7 +597,7 @@  {- | Class for easily defining custom translations for a type by using LUTs.-To use this class, a type must derive 'Waveform' via 'WaveformForLUT'.+To use this class, a type must derive 'Waveform' via 'WaveformForLut'.  Bye default, the implementation uses 'GHC.Generics.Generic' for defining subsignals and operator precedence, and 'Show' for displaying the value.@@ -474,7 +606,7 @@   -- | Provides the hierarchy of subsignals.   structureL :: Structure   default structureL :: (WaveformG (Rep a ())) => Structure-  structureL = structureT $ translatorG @(Rep a ()) 0 (L.repeat WSDefault)+  structureL = structureT $ translatorG @(Rep a ()) 0    {- | Translate a value. The translations must adhere to the structure defined in 'structureL'.   This function must be robust to @undefined@ values!@@ -484,9 +616,32 @@     (Generic a, Show a, WaveformG (Rep a ()), PrecG (Rep a ())) => a -> Translation   translateL = translateWith renderShow splitL +  {- | A static lookup table.+  To use a static lookup table rather than one created from the values found during simulation,+  set this to a list of values and their translations. Set 'translateL' and 'structureL' to 'undefined'.+  -}+  staticL :: Maybe [(a, Translation)]+  staticL = Nothing++-- | Return the static LUT of a type with 'WaveformLUT'+staticLutL :: forall a. (WaveformLUT a) => Maybe LUT+staticLutL = staticLut <$> staticL @a++-- | Turn a list of (value,translation) pairs into a LUT+staticLut :: (BitPack a) => [(a, Translation)] -> LUT+staticLut = M.fromList . L.map (first BL.pack)++-- | Translate a value from a type with a static LUT+translateStaticL :: forall a. (Waveform a, WaveformLUT a) => a -> Translation+translateStaticL x = case staticLutL @a of+  Just lut -> case M.lookup (BL.pack x) lut of+    Just t -> t+    Nothing -> errorT "{value missing from LUT}"+  Nothing -> error "cannot translate type; it has no static LUT" -- TODO rewrite using maybe function instead of case+ -- | Make sure a t'Translation' is fully defined. If not, return a t'Translation' with @"undefined"@. safeTranslation :: Translation -> Translation-safeTranslation = safeValOr (errorT "undefined")+safeTranslation = safeNFOr (errorT "undefined")  {- | Given a function that renders a value, and a function that (given this 'Render') prodices the subsignals, create a translation.@@ -496,9 +651,9 @@   (a -> Render) -> (Render -> a -> [(SubSignal, Translation)]) -> a -> Translation translateWith d s x = Translation ren subs  where-  ren = safeValOr (errorR "undefined") $ d x+  ren = safeNFOr (errorR "undefined") $ d x   subs =-    safeValOr []+    safeNFOr []       $ s ren x  -- | Display a value with 'Show', the default wave style, and operator precedence determined using 'Generic'.@@ -556,21 +711,21 @@  @ type T = ... deriving (...)-deriving via WaveformForLUT T instance Waveform T+deriving via WaveformForLut T instance Waveform T  isntance WaveformLUT T where   ... @ -}-newtype WaveformForLUT a = WfLUT a deriving (Generic, BitPack, Typeable)+newtype WaveformForLut a = WaveformForLut a deriving (Generic, BitPack, Typeable)  instance   (Waveform a, WaveformLUT a, BitPack a, Typeable a) =>-  Waveform (WaveformForLUT a)+  Waveform (WaveformForLut a)   where-  typeName = typeNameP (Proxy @a)+  typeName = defaultTypeName @a -  translator = tLut (Proxy @a)+  translator = tLut @a (staticLutL @a)  ----------------------------------------------- PREC ---------------------------------- @@ -664,8 +819,8 @@   (WaveformConst a, BitPack a, Typeable a) =>   Waveform (WaveformForConst a)   where-  typeName = typeNameP (Proxy @a)-  translator = Translator (bitsize $ Proxy @a) $ TConst $ constTrans @a+  typeName = defaultTypeName @a+  translator = Translator (bitSize @a) $ TConst $ constTrans @a  -- NUMBERS @@ -678,7 +833,7 @@ @ -} newtype WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a-  = WfNum a+  = WaveformForNumber a   deriving (Generic, BitPack, Typeable)  -- | Pair of a 'Nat' and 'Symbol', used for type-level spacer values.@@ -694,9 +849,9 @@   ) =>   Waveform (WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a)   where-  typeName = typeNameP (Proxy @a)+  typeName = defaultTypeName @a   translator =-    Translator (width @(WaveformForNumber f s a))+    Translator (bitSize @(WaveformForNumber f s a))       $ TNumber         { format = formatVal (Proxy @f)         , spacer = spacerVal (Proxy @s)@@ -753,60 +908,52 @@ --------------------------------------- IMPLEMENTATIONS ----------------------------------  instance WaveformConst () where-  constRen = rFromVal "()"+  constRen = defaultRender "()" deriving via WaveformForConst () instance Waveform ()  -- | Configure styles through style variables @bool_false@ and @bool_true@. instance Waveform Bool where   translator =-    Translator 1-      $ TSum-        [ tConst $ Just ("False", "$bool_false", 11)-        , tConst $ Just ("True", "$bool_true", 11)-        ]+    noConstructorSubsignals False+      $ withConstructorStyles ["$bool_false", "$bool_true"]+      $ defaultTranslator @Bool  -- | Configure styles through style variables @maybe_nothing@ and @maybe_just@. instance (Waveform a) => Waveform (Maybe a) where   translator =-    Translator (width @(Maybe a))-      $ TSum-        [ Translator 0 $ TConst $ Translation (Just ("Nothing", "$maybe_nothing", 11)) []-        , tStyled (WSVar "maybe_just" (WSInherit 0))-            $ Translator (width @a)-            $ TProduct-              { start = "Just "-              , sep = ""-              , stop = ""-              , labels = []-              , preci = 10-              , preco = 10-              , subs = [("Just.0", tRef (Proxy @a))]-              }-        ]+    noConstructorSubsignals True+      $ withConstructorStyles ["$maybe_nothing", WSVar "maybe_just" $ WSInherit 0]+      $ defaultTranslator @(Maybe a)  -- | Configure styles through style variables @either_left@ and @either_right@. instance (Waveform a, Waveform b) => Waveform (Either a b) where-  styles = ["$either_left", "$either_right"]+  constructorStyles = ["$either_left", "$either_right"]  instance (BitPack Char) => WaveformLUT Char where   structureL = Structure []   translateL = translateAtomShow-deriving via WaveformForLUT Char instance (BitPack Char) => Waveform Char+deriving via WaveformForLut Char instance (BitPack Char) => Waveform Char  instance WaveformLUT Bit where-  structureL = Structure []-  translateL = translateAtomShow-deriving via WaveformForLUT Bit instance Waveform Bit+  staticL =+    Just+      [ (high, Translation (Just ("1", "$bit_high", 11)) [])+      , (low, Translation (Just ("0", "$bit_low", 11)) [])+      , (undefined, Translation (Just ("x", WSWarn, 11)) [])+      ]+  structureL = undefined -- Structure []+  translateL = undefined -- translateAtomShow+deriving via WaveformForLut Bit instance Waveform Bit  instance WaveformLUT Double where   structureL = Structure []   translateL = translateAtomSigShow-deriving via WaveformForLUT Double instance Waveform Double+deriving via WaveformForLut Double instance Waveform Double  instance WaveformLUT Float where   structureL = Structure []   translateL = translateAtomSigShow-deriving via WaveformForLUT Float instance Waveform Float+deriving via WaveformForLut Float instance Waveform Float  deriving via WaveformForNumber NFSig DecSpacer Int instance Waveform Int deriving via WaveformForNumber NFSig DecSpacer Int8 instance Waveform Int8@@ -843,24 +990,24 @@  -- number wrappers instance (Waveform a) => Waveform (Zeroing a) where-  translator = tDup "zeroing" $ tRef (Proxy @a)+  translator = tDup "zeroing" $ tRef @a  instance (Waveform a) => Waveform (Wrapping a) where-  translator = tDup "wrapping" $ tRef (Proxy @a)+  translator = tDup "wrapping" $ tRef @a  instance (Waveform a) => Waveform (Saturating a) where-  translator = tDup "saturating" $ tRef (Proxy @a)+  translator = tDup "saturating" $ tRef @a  instance (Waveform a) => Waveform (Overflowing a) where-  translator = tDup "overflowing" $ tRef (Proxy @a)+  translator = tDup "overflowing" $ tRef @a  instance (Waveform a) => Waveform (Erroring a) where-  translator = tDup "erroring" $ tRef (Proxy @a)+  translator = tDup "erroring" $ tRef @a  -- vectors instance (KnownNat n, Waveform a) => Waveform (Vec n a) where   translator =-    Translator (width @(Vec n a))+    Translator (bitSize @(Vec n a))       $ if natVal (Proxy @n) /= 0         then           TArray@@ -870,16 +1017,35 @@             , preci = 5             , preco = 5             , len = fromIntegral $ natVal (Proxy @n)-            , sub = tRef (Proxy @a)+            , sub = tRef @a             }         else-          TConst $ tFromVal "Nil"+          TConst $ Translation (defaultRender "Nil") [] -deriving via-  WaveformForNumber NFBin BinSpacer (BitVector n)-  instance-    (KnownNat n) => Waveform (BitVector n)+-- deriving via+--   WaveformForNumber NFBin BinSpacer (BitVector n)+--   instance+--     (KnownNat n) => Waveform (BitVector n) +instance (KnownNat n) => Waveform (BitVector n) where+  translator =+    Translator n+      $ TChangeBits (BPConcat [BPHasUndefined BPIn, BPIn])+      $ Translator (n + 1)+      $ TSum [t, tStyled WSWarn t]+   where+    t =+      Translator n+        $ TAdvancedProduct+          { sliceTrans = bits <> [((0, n), num)]+          , hierarchy = L.map (\i -> (show (n - 1 - i), i)) [0 .. n - 1]+          , valueParts = [VPRef n 0]+          , preco = 11+          }+    bits = L.map (\i -> ((i, i + 1), tRef @Bit)) [0 .. n - 1]+    num = Translator n $ TNumber NFBin (Just (8, "_")) "0b" True+    n = bitSize @(BitVector n)+ -- fixed point instance   (BitPack (Fixed r i f), KnownNat i, KnownNat f, Show (Fixed r i f), Typeable r) =>@@ -888,14 +1054,14 @@   structureL = Structure []   translateL = translateAtomSigShow deriving via-  WaveformForLUT (Fixed r i f)+  WaveformForLut (Fixed r i f)   instance     (BitPack (Fixed r i f), KnownNat i, KnownNat f, Show (Fixed r i f), Typeable r) =>     Waveform (Fixed r i f)  -- snat instance (KnownNat n, BitPack (SNat n)) => WaveformConst (SNat n) where-  constRen = rFromVal $ show $ natVal $ Proxy @n+  constRen = defaultRender $ show $ natVal $ Proxy @n deriving via   WaveformForConst (SNat n)   instance@@ -919,14 +1085,14 @@   translatorRTree :: Translator  instance (Waveform a) => WaveformRTree True 0 a where-  translatorRTree = tRef (Proxy @a)+  translatorRTree = tRef @a  instance   (Waveform (RTree d1 a), Waveform a, d ~ d1 + 1, KnownNat d, KnownNat d1) =>   WaveformRTree False d a   where   translatorRTree =-    Translator (bitsize $ Proxy @(RTree d a))+    Translator (bitSize @(RTree d a))       $ TProduct         { start = "<"         , sep = ","@@ -937,14 +1103,14 @@         , subs = [("left", tsub), ("right", tsub)]         }    where-    tsub = tRef (Proxy @(RTree d1 a))+    tsub = tRef @(RTree d1 a)  {- | A translator for displaying values with zero or more fields like tuples. This function will error if called for a type that has more than one constructor! -} tupleTranslator :: forall t. (BitPack t, WaveformG (Rep t ())) => Translator tupleTranslator =-  Translator (bitsize (Proxy @t))+  Translator (bitSize @t)     $ TProduct       { start = "("       , sep = ","
src/Clash/Shockwaves/LUT.hs view
@@ -9,7 +9,7 @@ -} module Clash.Shockwaves.LUT (   -- * WaveformLUT-  WaveformLUT (structureL, translateL),+  WaveformLUT (structureL, translateL, staticL),   translateWith,   renderWith,   renderShow,@@ -20,15 +20,16 @@   noSplit,   splitL,   precL,-  WaveformForLUT (..),+  WaveformForLut (..),   tLut,+  tGeneratedLut,+  tStaticLut,    -- * Utility-  tFromVal,-  rFromVal,+  defaultRender,   safeWHNF,-  safeVal,-  safeValOr,+  safeNF,+  safeNFOr,   safeTranslation,   errorT,   errorR,
src/Clash/Shockwaves/Style.hs view
@@ -41,13 +41,13 @@ data Col = Red | Green | Blue | Yellow | Cyan | Magenta deriving ...  instance Waveform Col where-  styles = [ WSColor (RGB 255 0 0) -- RGB value-           , wsColor C.lime        -- Colour value-           , "blue"                -- color name-           , "#ffff00"             -- hexadecimal color-           , "$cyan"               -- style variable "cyan"; defaults to WSDefault-           , WSVar "magenta"       -- style variable "magenta", defaults to #ff00ff-                   "#f0f"+  constructorStyles = [ WSColor (RGB 255 0 0) -- RGB value+                      , wsColor C.lime        -- Colour value+                      , "blue"                -- color name+                      , "#ffff00"             -- hexadecimal color+                      , "$cyan"               -- style variable "cyan"; defaults to WSDefault+                      , WSVar "magenta"       -- style variable "magenta", defaults to #ff00ff+                      ] @  and in a translation:
src/Clash/Shockwaves/Trace.hs view
@@ -130,6 +130,7 @@ import           Data.List             (foldl') #endif import           Data.List             (foldl1', unzip5, transpose, uncons)+import qualified Data.Map              as M import qualified Data.Map.Strict       as Map import           Data.Maybe            (fromMaybe, catMaybes) import qualified Data.Text             as Text@@ -149,10 +150,11 @@  -- Shockwaves import           Clash.Shockwaves.Internal.Types hiding (Value)+import           Clash.Shockwaves.Internal.Translator (getStaticLuts) import           Clash.Shockwaves.Internal.Waveform hiding (width)  #ifdef CABAL-import qualified Data.Version+import           Data.Version          (showVersion) import qualified Paths_clash_shockwaves #endif @@ -244,7 +246,7 @@           ( encode (typeRep @a)           , period           , width-          , if hasLut @a then map ((\f -> maybe id (const $ foldl1 (.) f) $ uncons f) . addValue) $ sample signal else repeat id+          , if hasGeneratedLut @a then map ((\f -> maybe id (const $ foldl1 (.) f) $ uncons f) . addValue) $ sample signal else repeat id           , mkTrace signal)           traceMap }     in@@ -479,16 +481,18 @@   slice :: [a] -> [a]   slice values = drop offset $ take cycles values -  lutMap = foldl (flip ($)) Map.empty $ concat addValuess'+  staticLuts = Map.fromList $ concatMap getStaticLuts (M.elems typeMap) -- map over the types, collect all LUTs in a map+  lutMap = foldl (flip ($)) staticLuts $ concat $ addValuess'    headerDate       = ["$date", Text.pack $ iso8601Format now, "$end"]  #ifdef CABAL-  clashVer         = "Shockwaves" <> Data.Version.showVersion Paths_clash_shockwaves.version -- actually Shockwaves version; TODO+  clashVer         = "Clash " <> VERSION_clash_prelude <>+                     " / Shockwaves " <> showVersion Paths_clash_shockwaves.version #else-  clashVer         = "development"+  clashVer         = "development version" #endif-  headerVersion    = ["$version", "Generated by Clash", Text.pack clashVer , "$end"]+  headerVersion    = ["$version", "Generated by:", Text.pack clashVer , "$end"]   headerComment    = ["$comment", "No comment", "$end"]   headerTimescale  = ["$timescale", (show timescale) ++ "ps", "$end"]   headerWires      = [ Text.unwords $ headerWire w l n
src/Clash/Shockwaves/Waveform.hs view
@@ -11,12 +11,12 @@ -} module Clash.Shockwaves.Waveform (   -- * The Waveform class-  Waveform (translator, styles, width),+  Waveform (translator, constructorStyles),   translate,   translateBin,-  hasLut,+  hasGeneratedLut,   translateBinT,-  hasLutT,+  hasGeneratedLutT,    -- * Translations   Translation (..),@@ -34,6 +34,7 @@   Structure (..),   structure,   structureT,+  fromTranslation,    -- ** Translator-specific types   NumberFormat (..),@@ -47,6 +48,13 @@   BitPart (..),    -- ** Creating Translators+  bitSize,+  pprintT,+  defaultTranslator,+  withConstructorStyles,+  inheritSingleFieldStyle,+  noConstructorSubsignals,+  renameFields,   tRef,   tDup,   tStyled,@@ -56,9 +64,13 @@   WaveformConst (..),   WaveformForConst,   WaveformForNumber (..),++  -- ** Creating special Waveform instances+  defaultTypeName, ) where  import Clash.Shockwaves.Internal.Translator import Clash.Shockwaves.Internal.Types+import Clash.Shockwaves.Internal.Util  import Clash.Shockwaves.Internal.Waveform
tests/Tests/Types.hs view
@@ -4,7 +4,7 @@  module Tests.Types where -import Clash.Prelude+import Clash.Prelude hiding (bitSize) import Clash.Shockwaves.LUT import Clash.Shockwaves.Waveform import Data.Typeable@@ -30,14 +30,17 @@  infixl 5 ://: data Op a b = a ://: b-  deriving (ShowX, BitPack, NFDataX, Generic, Typeable, Waveform)+  deriving (ShowX, BitPack, NFDataX, Generic, Typeable)+instance (Waveform a, Waveform b) => Waveform (Op a b) where+  translator = renameFields [["lhs", "rhs"]] $ defaultTranslator @(Op a b)+ data St = St {a :: Bool, b :: Int}   deriving (ShowX, BitPack, NFDataX, Generic, Typeable, Waveform)  data C = Red | Green | Blue   deriving (ShowX, BitPack, NFDataX, Generic, Typeable) instance Waveform C where-  styles = [WSVar "red" "#f00", WSVar "green" "lime", WSVar "blue" "#0000ff"]+  constructorStyles = [WSVar "red" "#f00", WSVar "green" "lime", WSVar "blue" "#0000ff"]  infixr 6 :**: data Mix z@@ -52,7 +55,7 @@   = La Bool Bool   | Lb Bool Bool   deriving (ShowX, BitPack, NFDataX, Generic, Typeable)-  deriving (Waveform) via (WaveformForLUT L)+  deriving (Waveform) via (WaveformForLut L)  instance WaveformLUT L where   translateL = translateWith (renderWith labelL styleL precL) splitL@@ -68,10 +71,10 @@  instance (KnownNat a) => Waveform (Pointer a) where   translator =-    Translator (width @(Unsigned a))+    Translator (bitSize @(Unsigned a))       $ TAdvancedSum-        { index = (0, width @(Unsigned a))-        , defTrans = Translator (width @(Unsigned a)) $ TNumber NFHex (Just (2, "_")) "0X" False+        { index = (0, bitSize @(Unsigned a))+        , defTrans = Translator (bitSize @(Unsigned a)) $ TNumber NFHex (Just (2, "_")) "0X" False         , rangeTrans = [((0, 1), tConst $ Just ("NULL", WSWarn, 11))]         } @@ -79,14 +82,14 @@  instance (Waveform a) => Waveform (NumRep a) where   translator =-    Translator (width @a)+    Translator (bitSize @a)       $ TAdvancedProduct         { sliceTrans =             L.map-              ((0, width @a),)-              ( tRef (Proxy @a)+              ((0, bitSize @a),)+              ( tRef @a                   : L.map-                    (Translator (width @a))+                    (Translator (bitSize @a))                     [ TNumber NFBin (Just (4, "_")) "0b" False                     , TNumber NFOct (Just (4, "_")) "0o" False                     , TNumber NFHex (Just (2, "_")) "0X" False@@ -94,7 +97,7 @@                     , TNumber NFSig (Just (3, "_")) "" False                     ]               )-              <> [((width @a - 1, width @a), tRef $ Proxy @Bool)]+              <> [((bitSize @a - 1, bitSize @a), tRef @Bool)]         , hierarchy =             [("bin", 1), ("oct", 2), ("hex", 3), ("unsigned", 4), ("signed", 5), ("odd", 6)]         , valueParts = [VPLit "{", VPRef 0 (-1), VPLit ", odd=", VPRef 6 (-1), VPLit "}"]@@ -128,7 +131,7 @@               , preci = 10               , preco = 10               , labels = []-              , subs = [("sub", tRef (Proxy @(Maybe Bool)))]+              , subs = [("sub", tRef @(Maybe Bool))]               }         , tDup "B" $ tConst $ Just ("SSB", WSDefault, 11)         , Translator 2@@ -139,7 +142,7 @@               , preci = 10               , preco = 10               , labels = []-              , subs = [("sub", tRef (Proxy @(Either Bool Bool)))]+              , subs = [("sub", tRef @(Either Bool Bool))]               }         , tDup "D" $ tConst $ Just ("SSD", WSDefault, 11)         ]
tests/tests.hs view
@@ -208,6 +208,8 @@                                 ["True :> False :> Nil","undefined :> undefined :> Nil", VECSPINE     ,"undefined :> undefined :> Nil"]   , testGroup "Vec 0" $ renders [ Nil @Bool, undef]                                 ["Nil"     ,"Nil" ]+  , testGroup "Bit" $ renders [low, undef]+                              ["0",   "x" ]   , testGroup "Maybe L" $ renders [ Just (La False False)  ,  Just undef     , undef     ]                                   ["Just (False <A> False)", "Just undefined","undefined"]   , testGroup "Signed 32" $ renders [ 0 ,  12345 ,   -123456789 :: Signed 32]@@ -234,7 +236,7 @@     Nothing -> ("", WSNormal)  pat :: (Show t) => (t -> Int) -> t -> Assertion-pat f v = case safeVal (f v) of+pat f v = case safeNFErr (f v) of   Right _ -> return ()   Left e -> assertFailure $ show v <> ": " <> fromMaybe "error" e @@ -269,8 +271,8 @@     [ (M True 3                     , \( T _ ["0":@T _ [],"1":@T _ []]                                          )->0)     , (undef                        , \( T _ ["0":@T _ [],"1":@T _ []]                                          )->0) ]   , testGroup "Op" $ pats-    [ (True ://: (False ://: False) , \( T _ ["0":@T _ _,"1":@T _ ["0":@T _ _, "1":@T _ _]]                     )->0)-    , (undef                        , \( T _ ["0":@T _ _,"1":@T _ ["0":@T _ _, "1":@T _ _]]                     )->0) ]+    [ (True ://: (False ://: False) , \( T _ ["lhs":@T _ _,"rhs":@T _ ["lhs":@T _ _, "rhs":@T _ _]]             )->0)+    , (undef                        , \( T _ ["lhs":@T _ _,"rhs":@T _ ["lhs":@T _ _, "rhs":@T _ _]]             )->0) ]   , testGroup "St" $ pats     [ (St{b=3,a=False}              , \( T _ ["a":@T _ [],"b":@T _ []]                                          )->0)     , (undef                        , \( T _ ["a":@T _ [],"b":@T _ []]                                          )->0) ]
tests/vcd.hs view
@@ -40,6 +40,7 @@   , test "Maybe" $ values [Nothing, Just True, undef]   , test "Vec2"  $ values [True :> False :> Nil, undef :> undef :> Nil, undef]   , test "Vec0"  $ values [Nil @Bool, undef]+  , test "Bit"   $ values [high, undefined]   , test "Signed32" $ values [0::Signed 32,12345,1234567,-123456,-1234567]   , test "Pointer16" $ values $ Pointer @16 <$> [0,1,2,3,undef]   , test "NumRepU3" $ values $ NumRep <$> [0,1,3,4,7,undef :: Unsigned 3]