retroclash-lib-0.1.0: src/RetroClash/SevenSegment.hs
{-# LANGUAGE PartialTypeSignatures, RecordWildCards, ApplicativeDo #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
module RetroClash.SevenSegment
( SevenSegment(..)
, encodeHexSS
, showSS
, showSSs
, muxRR
, driveSS
, sevenSegmentPort
-- , bytesSS
) where
import Clash.Prelude
import qualified Data.List as L
import RetroClash.Utils
import RetroClash.Clock
data SevenSegment n anodes segments dp = SevenSegment
{ anodes :: "AN" ::: Vec n (Active anodes)
, segments :: "SEG" ::: Vec 7 (Active segments)
, dp :: "DP" ::: Active dp
}
deriving (Generic)
muxRR
:: (KnownNat n, HiddenClockResetEnable dom)
=> Signal dom Bool
-> Signal dom (Vec n a)
-> (Signal dom (Vec n Bool), Signal dom a)
muxRR tick xs = (selector, current)
where
(selector, i) = roundRobin tick
current = (!!) <$> xs <*> i
driveSS
:: (KnownNat n, HiddenClockResetEnable dom, _)
=> (a -> (Vec 7 Bool, Bool))
-> Signal dom (Vec n (Maybe a))
-> Signal dom (SevenSegment n anodes segments dp)
driveSS draw digits = do
anodes <- map toActive <$> anodes
segments <- map toActive <$> segments
dp <- toActive <$> dp
pure SevenSegment{..}
where
(anodes, digit) = muxRR (risePeriod (SNat @(Milliseconds 1))) digits
(segments, dp) = unbundle $ maybe (repeat False, False) draw <$> digit
sevenSegmentPort :: PortName
sevenSegmentPort = PortProduct "SS" $ PortName <$> ["AN", "SEG", "DP"]
bytesSS
:: forall n div dom clk sync. (KnownNat n, KnownNat div, HiddenClockResetEnable dom)
=> Unsigned div
-> Signal dom (Vec n (Maybe (Unsigned 8)))
-> (Signal dom (Vec (n * 2) Bool), Signal dom (Vec 7 Bool))
bytesSS div bytes = (shownDigit, segments)
where
digit = regEn (0 :: Index (n * 2)) timer $ nextIdx <$> digit
where
counter = countFromTo 0 div (pure True)
timer = counter .==. pure 0
shownDigit = oneHot <$> digit
segments = maybe (pure False) encodeHexSS <$> nibble
nibble = (!!) <$> nibbles <*> digit
nibbles = concatMap (traverse splitByte) <$> bytes
splitByte :: Unsigned 8 -> Vec 2 (Unsigned 4)
splitByte byte = hi :> lo :> Nil
where
(hi, lo) = bitCoerce byte
encodeHexSS :: Unsigned 4 -> Vec 7 Bool
encodeHexSS n = case n of
-- a b c d e f g
0x0 -> True :> True :> True :> True :> True :> True :> False :> Nil
0x1 -> False :> True :> True :> False :> False :> False :> False :> Nil
0x2 -> True :> True :> False :> True :> True :> False :> True :> Nil
0x3 -> True :> True :> True :> True :> False :> False :> True :> Nil
0x4 -> False :> True :> True :> False :> False :> True :> True :> Nil
0x5 -> True :> False :> True :> True :> False :> True :> True :> Nil
0x6 -> True :> False :> True :> True :> True :> True :> True :> Nil
0x7 -> True :> True :> True :> False :> False :> False :> False :> Nil
0x8 -> True :> True :> True :> True :> True :> True :> True :> Nil
0x9 -> True :> True :> True :> True :> False :> True :> True :> Nil
0xa -> True :> True :> True :> False :> True :> True :> True :> Nil
0xb -> False :> False :> True :> True :> True :> True :> True :> Nil
0xc -> True :> False :> False :> True :> True :> True :> False :> Nil
0xd -> False :> True :> True :> True :> True :> False :> True :> Nil
0xe -> True :> False :> False :> True :> True :> True :> True :> Nil
0xf -> True :> False :> False :> False :> True :> True :> True :> Nil
showSS :: Vec 7 Bool -> String
showSS (a :> b :> c :> d :> e :> f :> g :> Nil) = unlines . L.concat $
[ L.replicate 1 $ horiz a
, L.replicate 3 $ vert f b
, L.replicate 1 $ horiz g
, L.replicate 3 $ vert e c
, L.replicate 1 $ horiz d
]
where
horiz True = " ###### "
horiz False = " ...... "
vert b1 b2 = part b1 <> " " <> part b2
where
part True = "#"
part False = "."
showSSs :: [Vec 7 Bool] -> String
showSSs = unlines . L.map (L.intercalate " ") . L.transpose . L.map (lines . showSS)