Last active
August 16, 2018 09:42
-
-
Save DigitalBrains1/f428e3edf5043723f8f3f0705e637a32 to your computer and use it in GitHub Desktop.
An UART in CλaSH v0.7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveGeneric #-} | |
{-# LANGUAGE DeriveAnyClass #-} | |
{- | |
- Copyright (c) 2015, 2017 Peter Lebbing <[email protected]> | |
- All rights reserved. | |
- | |
- Redistribution and use in source and binary forms, with or without | |
- modification, are permitted provided that the following conditions are met: | |
- | |
- 1. Redistributions of source code must retain the above copyright notice, | |
- this list of conditions and the following disclaimer. | |
- | |
- 2. Redistributions in binary form must reproduce the above copyright notice, | |
- this list of conditions and the following disclaimer in the documentation | |
- and/or other materials provided with the distribution. | |
- | |
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
- POSSIBILITY OF SUCH DAMAGE. | |
-} | |
module Toolbox.ClockScale | |
( rateParams | |
, State(..) | |
, avg | |
, clkDiv | |
, oneShot | |
, staticAvg | |
, staticClkDiv | |
, staticOneShot | |
, staticAvgRate | |
, staticMaxRate | |
, staticOneShotPeriod | |
, ticksMinPeriod | |
, ticksMinPeriodTH | |
, ticksMaxRate | |
, ticksMaxRateTH | |
, nonNeg | |
) where | |
import CLaSH.Prelude | |
import Language.Haskell.TH | |
import GHC.Generics (Generic) | |
import Control.DeepSeq (NFData) | |
import Toolbox.Misc | |
{- | |
- Compute the multiplier and divisor needed for the clock scaler to scale from | |
- the clockrate "from" to ticks with a rate of "to" | |
- | |
- This is not meant to be compiled to VHDL; instead, use it to create the | |
- parameters and use those parameters directly in the design. An example of | |
- this is the convenient "staticAvgRate" function in this module that can be | |
- instantiated with Template Haskell. | |
-} | |
rateParams :: Integer -> Integer -> (Integer, Integer) | |
rateParams from to = (m, d) | |
where | |
common = lcm from to | |
m = common `div` from | |
d = common `div` to | |
data State = Stop | Run | Clear | |
deriving (Eq, Show, Generic, NFData) | |
{- | |
- Scale a clock frequency as accurately as possible | |
- | |
- Outputs True once every "tick" of the desired frequency by counting and | |
- scaling the system clock. | |
- | |
- Inputs: m - Multiplier for the system clock d - Divisor for the target clock | |
- | |
- The counter never goes to 0; it is most accurate when initialised to 1. | |
- | |
- Make sure the target clock is lower than the system clock, or you will miss | |
- ticks. Not surprising, really :). | |
- | |
- Also, the degenerate case where the divisor is 1 (or equivalently, the | |
- target clock is equal to the system clock) *will not stop* when given the | |
- command Stop or Clear. Don't use this configuration; the following would | |
- probably be more what you need: | |
- | |
- tick = (== ClockScale.Run) <$> cmd | |
- | |
- Note that it is designed to be instantiated with a static divisor and | |
- multiplier. Changing them while running will cause glitching. | |
-} | |
avg :: (KnownNat n, KnownNat (n+1)) | |
=> Unsigned (n+1) | |
-> (Unsigned n, Unsigned n, State) | |
-> (Unsigned (n+1), Bool) | |
avg s (m, d, cmd) = (s', o) | |
where | |
sinc = s + resize m | |
wrap = s >= resize d | |
s' = if cmd == Clear then | |
1 | |
else if wrap then | |
sinc - resize d | |
else if cmd == Stop then | |
s | |
else | |
sinc | |
o = wrap | |
{- Divide the clock by an integer ratio | |
- | |
- See `avg` for more documentation. | |
-} | |
clkDiv :: KnownNat n | |
=> Unsigned n | |
-> (Unsigned n, State) | |
-> (Unsigned n, Bool) | |
clkDiv s (d, cmd) = (s', o) | |
where | |
wrap = s >= d | |
s' = if cmd == Clear then | |
1 | |
else if wrap then | |
1 | |
else if cmd == Stop then | |
s | |
else | |
s + 1 | |
o = wrap | |
{- | |
- When triggered, count to d once, then stop | |
- | |
- Outputs whether d has been reached yet. Most often used to make sure an | |
- amount of work does not take less time than counting to d: trigger when | |
- you start the work, and then wait for the oneShot to output True when the | |
- work is done. If the amount of work took more than the allotted time, | |
- this makes it continue immediately; otherwise it will wait. | |
-} | |
oneShot :: KnownNat n | |
=> Unsigned n | |
-> (Unsigned n, Bool) | |
-> (Unsigned n, Bool) | |
oneShot s (d, trigger) = (s', done) | |
where | |
done = s >= d | |
s' = if trigger then | |
1 | |
else if done then | |
d | |
else | |
s + 1 | |
{- | |
- Instantiate a clock scaler with fixed parameters through Template Haskell | |
- | |
- The needed amount of bits in the state of the scaler is automatically | |
- determined from the parameters. | |
-} | |
staticAvg (m, d) = appE (appE [| staticAvg' |] (fitU m)) (fitU d) | |
staticClkDiv d = appE [| staticClkDiv' |] (fitU d) | |
{- | |
- Instantiate a oneShot with a fixed divider through Template Haskell | |
-} | |
staticOneShot d = appE [| staticOneShot' |] (fitU d) | |
{- | |
- Through Template Haskell, instantiate a clock scaler that converts clock | |
- rate `from` to ticks with a rate of `to`, with static parameters computed at | |
- compile time. | |
-} | |
staticAvgRate from to = staticAvg $ rateParams from to | |
{- | |
- Through Template Haskell, instantiate a clock divider that never exceeds the | |
- rate `to`. | |
- | |
- `staticAvgRate` can temporarily exceed the given rate (by one clock tick) to | |
- compensate for time lost. `staticMaxRate` however will never do that, but | |
- this means it will run slow if the target rate does not evenly divide the | |
- clock frequency. | |
-} | |
staticMaxRate from to = staticClkDiv $ ticksMaxRate from to | |
{- | |
- Instantiate a oneShot that waits for the specified period through | |
- Template Haskell | |
- | |
- `f` is the clock frequency, `p` the period. | |
-} | |
staticOneShotPeriod f p = staticOneShot $ ticksMinPeriod f p | |
{- | |
- Compute how many clock ticks need to pass before a certain period of time | |
- is reached | |
- | |
- `f` is the clock frequency, `p` the period. | |
-} | |
ticksMinPeriod f p = ceiling $ (fromInteger f) * p - 1 | |
-- Shorthand for Template Haskell instantiation | |
ticksMinPeriodTH f p = intLit $ ticksMinPeriod f p | |
{- | |
- Compute which clock divider approximates the given rate as closely as | |
- possible without exceeding it | |
-} | |
ticksMaxRate from to = ticksMinPeriod from (1 / to) | |
-- Shorthand for Template Haskell instantiation | |
ticksMaxRateTH from to = intLit $ ticksMaxRate from to | |
{- | |
- When computing a delay in clock ticks, this function assures that when the | |
- result of the computation is negative, no delay is done (a delay of 0). | |
- | |
- Example: $(nonNeg $(ticksMinPeriod fClk 100e-9) - 4) | |
- Computes the extra delay to have a total delay of 100 ns of which 4 clock | |
- ticks have already been spent. If 4 clock ticks are more than 100 ns, | |
- don't delay. | |
-} | |
nonNeg = intLit . max 0 | |
staticAvg' :: ( KnownNat (Max m n), KnownNat (Max m n + 1), KnownNat n | |
, KnownNat m) | |
=> Unsigned n | |
-> Unsigned m | |
-> Unsigned (Max m n + 1) | |
-> State | |
-> (Unsigned (Max m n + 1), Bool) | |
staticAvg' m d st cmd = avg st (resize m, resize d, cmd) | |
staticClkDiv' d s cmd = clkDiv s (d, cmd) | |
staticOneShot' d s trigger = oneShot s (d, trigger) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
- Copyright (c) 2012-2015, University of Twente | |
- Copyright (c) 2015,2017, Peter Lebbing <[email protected]> | |
- All rights reserved. | |
- | |
- Redistribution and use in source and binary forms, with or without | |
- modification, are permitted provided that the following conditions are met: | |
- | |
- 1. Redistributions of source code must retain the above copyright notice, | |
- this list of conditions and the following disclaimer. | |
- | |
- 2. Redistributions in binary form must reproduce the above copyright notice, | |
- this list of conditions and the following disclaimer in the documentation | |
- and/or other materials provided with the distribution. | |
- | |
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
- POSSIBILITY OF SUCH DAMAGE. | |
- | |
- This file is based on examples/Fifo.hs from the CλaSH source code. | |
-} | |
module Toolbox.FIFO | |
( Pntr | |
, fifo | |
) where | |
import CLaSH.Prelude | |
import Control.Applicative | |
import Toolbox.Misc (showCodeLoc) | |
flowError = False | |
type Pntr n = Unsigned (n + 1) | |
{- | |
- This is the same FIFO implementation as from the CλaSH examples, with an | |
- added output: the number of elements in the FIFO can be examined. This could | |
- be useful for Dataflow elements that need multiple tokens to proceed. | |
-} | |
fifo :: forall n e . (KnownNat n, KnownNat (n+1), KnownNat (2^n)) | |
=> (Pntr n, Pntr n, Vec (2^n) e) | |
-> (e, Bool, Bool) | |
-> ((Pntr n,Pntr n,Vec (2^n) e),(Bool,Bool,Pntr n, e)) | |
fifo (rpntr, wpntr, elms) (datain, wrt, rd) | |
= ((rpntr', wpntr', elms'),(full, empty, flength, dataout)) | |
where | |
wpntr' | wrt && not full = wpntr + 1 | |
| wrt && full && flowError = error "FIFOn Overflow!" | |
| otherwise = wpntr | |
rpntr' | rd && not empty = rpntr + 1 | |
| rd && empty && flowError = error "FIFOn Underflow!" | |
| otherwise = rpntr | |
mask = maxBound `shiftR` 1 | |
wind = wpntr .&. mask | |
rind = rpntr .&. mask | |
elms' | wrt = replace wind datain elms | |
| otherwise = elms | |
n = fromInteger $ natVal rpntr - 1 | |
flength = wpntr - rpntr | |
empty = flength == 0 | |
full = flength == bit n | |
dataout = elms!!rind |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{- | |
- Copyright (c) 2015, 2017 Peter Lebbing <[email protected]> | |
- All rights reserved. | |
- | |
- Redistribution and use in source and binary forms, with or without | |
- modification, are permitted provided that the following conditions are met: | |
- | |
- 1. Redistributions of source code must retain the above copyright notice, | |
- this list of conditions and the following disclaimer. | |
- | |
- 2. Redistributions in binary form must reproduce the above copyright notice, | |
- this list of conditions and the following disclaimer in the documentation | |
- and/or other materials provided with the distribution. | |
- | |
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
- POSSIBILITY OF SUCH DAMAGE. | |
-} | |
module Toolbox.Misc | |
( showCodeLoc | |
, intLit | |
, uToFit | |
, fitU | |
, vS | |
, zip4 | |
, zip5 | |
, unzip4 | |
, edgeTrigger | |
, tfold | |
, tfoldD | |
, vv | |
) where | |
import Language.Haskell.TH | |
import Control.Applicative | |
--import Data.Tuple.Select | |
import Unsafe.Coerce | |
import CLaSH.Prelude hiding (tfold) | |
import CLaSH.Signal.Bundle | |
import CLaSH.Signal.Explicit (Signal') | |
{- A Template Haskell string literal with the location of the invocation of | |
- showCodeLoc | |
-} | |
showCodeLoc = do loc <- location | |
litE $ StringL (show loc) | |
-- Shorthand for creating an integer literal | |
intLit :: Integer -> ExpQ | |
intLit = litE . integerL | |
{- Construct an Unsigned n type with n just large enough to be able to | |
- represent the number i | |
-} | |
uToFit :: Integer -> TypeQ | |
uToFit i = (appT (conT ''Unsigned) | |
( litT $ numTyLit $ toInteger $ max 1 $ floor | |
$ 1 + logBase 2 (fromInteger i))) | |
{- Convert an Integer expression to a constant of type "Unsigned n", with n | |
- being just large enough to contain the value | |
-} | |
fitU :: Integer -> ExpQ | |
fitU i = sigE (intLit i) (uToFit i) | |
{- Construct a vector from a list of signal names | |
- Example: $(vS ['s1, 's2, 's3]) is a vector of the three signals s1, s2 and | |
- s3. | |
-} | |
vS :: [Name] -> ExpQ | |
vS [] = [| pure Nil |] | |
vS (x:xs) = [| liftA2 (:>) $(varE x) $(vS xs) |] | |
zip4 as bs cs ds = (zipWith (\a (b,c,d) -> (a,b,c,d)) as) (zip3 bs cs ds) | |
zip5 as bs cs ds es | |
= (zipWith (\a (b,c,d,e) -> (a,b,c,d,e)) as) (zip4 bs cs ds es) | |
unzip4 :: Vec n (a,b,c,d) -> (Vec n a, Vec n b, Vec n c, Vec n d) | |
unzip4 xs = (as, bs, cs, ds) | |
where | |
-- as = map (sel1) xs | |
-- bs = map (sel2) xs | |
-- cs = map (sel3) xs | |
-- ds = map (sel4) xs | |
as = map (\(a, b, c, d) -> a) xs | |
bs = map (\(a, b, c, d) -> b) xs | |
cs = map (\(a, b, c, d) -> c) xs | |
ds = map (\(a, b, c, d) -> d) xs | |
-- Output True when input changes | |
edgeTrigger :: Eq a | |
=> a | |
-> a | |
-> (a, Bool) | |
edgeTrigger s i = (i, s /= i) | |
{- Fold a signal over time | |
- | |
- tfold f z (x, start) | |
- If start is True, re-initialise using (f z x) | |
-} | |
tfold :: (a -> a -> a) | |
-> a | |
-> (Signal a, Signal Bool) | |
-> Signal a | |
tfold f z = mealy (tfold' f z) z . bundle | |
tfold' f z s (x1, start) = (s', s') | |
where | |
x0 | start = z | |
| otherwise = s | |
s' = f x0 x1 | |
-- tfold with built-in one-cycle delay element | |
tfoldD :: (a -> a -> a) | |
-> a | |
-> (Signal a, Signal Bool) | |
-> Signal a | |
tfoldD f z = moore (tfoldD' f z) id z . bundle | |
tfoldD' f z s (x1, start) = f x0 x1 | |
where | |
x0 | start = z | |
| otherwise = s | |
-- TH vector of vectors | |
vv :: Lift a => [[a]] -> ExpQ | |
vv [] = [| Nil |] | |
vv (e:es) = [| $(listToVecTH e) :> $(vv es) |] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DeriveGeneric #-} | |
{-# LANGUAGE DeriveAnyClass #-} | |
{- | |
- Copyright (c) 2015, 2017 Peter Lebbing <[email protected]> | |
- All rights reserved. | |
- | |
- Redistribution and use in source and binary forms, with or without | |
- modification, are permitted provided that the following conditions are met: | |
- | |
- 1. Redistributions of source code must retain the above copyright notice, | |
- this list of conditions and the following disclaimer. | |
- | |
- 2. Redistributions in binary form must reproduce the above copyright notice, | |
- this list of conditions and the following disclaimer in the documentation | |
- and/or other materials provided with the distribution. | |
- | |
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
- POSSIBILITY OF SUCH DAMAGE. | |
-} | |
module Toolbox.Serial where | |
import CLaSH.Prelude | |
import Control.Applicative | |
import GHC.Generics (Generic) | |
import Control.DeepSeq (NFData) | |
import qualified Toolbox.ClockScale as CS | |
import qualified Toolbox.FIFO as FIFO | |
{- | |
- Serial data output routine | |
- | |
- This routine will send bytes over a serial line according to the | |
- asynchronous start/stop protocol. It only supports the dataformat 8N1 (8 | |
- databits, no parity, 1 stopbit). | |
- | |
- Inputs: (ck, ld, din): | |
- - ck: This should be the output of a ClockScaler that scales to the | |
- bitclock or baud rate of the serial line. It is True once every | |
- period of the baud rate. | |
- - ld: True if there's a new piece of data on din. Should only be | |
- asserted when output "done" is also true. | |
- - din: 8-bit word to send out | |
- | |
- Outputs: (scaler, done, txd): | |
- - scaler: a ClockScale.State that controls the ClockScaler that does | |
- the pacing for this serial output. | |
- - done: True when new data can be accepted because the previous data | |
- has been sent. | |
- - txd: The actual output line where data is sent using asynchronous | |
- start/stop. | |
-} | |
output :: (Signal Bool, Signal Bool, Signal (Unsigned 8)) | |
-> (Signal CS.State, Signal Bool, Signal Bit) | |
output = mealyB output' (repeat 0) | |
output' :: Vec 10 Bit | |
-> (Bool, Bool, Unsigned 8) | |
-> (Vec 10 Bit, (CS.State, Bool, Bit)) | |
output' shifter (ck, ld, din) = (shifter', (scaler, done, txd)) | |
where | |
shifter' = if ld then | |
1 :> (bitCoerce din :< 0) | |
else if ck then | |
0 +>> shifter | |
else | |
shifter | |
-- CλaSH issue #202 prevents the next line from working | |
-- (scaler, done) = if shifter == repeat 0 then | |
(scaler, done) = if bitCoerce shifter == (0 :: Unsigned 10) then | |
(CS.Clear, True) | |
else | |
(CS.Run , False) | |
txd = if done then | |
1 | |
else | |
last shifter | |
{- | |
- A variant of "output" that reads its data from a FIFO | |
-} | |
outputFIFO (ck, empty, din) = (ld, scaler, txd) | |
where | |
(scaler, done, txd) = output (ck, ld, din) | |
ld = (\(e, d) -> not e && d) <$> bundle (empty, done) | |
data State = WaitStart | Sample (Unsigned 2) | WaitHigh | |
deriving (Show, Generic, NFData) | |
{- Asynchronous start/stop receiver | |
- | |
- Frame format 8N1 only | |
- | |
- Inputs (cTick, dIn): | |
- - cTick: ticks from a continuously running ClockScaler that runs at 16 | |
- times the baud rate of the incoming serial line. This divides one | |
- bitperiod in 16 equal parts which are used for the sampling of the | |
- line. | |
- - dIn: the pin of the FPGA the serial data is to be read from. | |
- | |
- Outputs ((frameErr, dOut), dValid): | |
- - dValid: True if (frameErr, dOut) is valid | |
- - frameErr: True if the stopbit was not "mark" (i.e., it was "space"). | |
- This means something went wrong in reception, so the data might be | |
- corrupted as well. | |
- - dOut: The received databit | |
- | |
- Majority sampling principle: 3 samples are taken around the center of the | |
- databit, a majority counter counts the number of high samples. If this | |
- counter is 2 or 3, the most significant bit is high, otherwise, it is low. | |
- In other words, the most significant bit is the outcome of the majority | |
- vote. | |
-} | |
input :: (Signal Bool, Signal Bit) -> (Signal (Bool, Unsigned 8), Signal Bool) | |
input (cTick, dIn) = mealyB input' initInput (cTick, dInS) | |
where | |
dInS = register 1 $ register 1 dIn | |
input' s@(mode, wait, run, shift, sample) (cTick, dIn) | |
= (s', ((frameErr, dOut), dValid)) | |
where | |
s'@(mode', wait', run', shift', sample') = input'' s cTick dIn | |
frameErr = head shift' == low | |
dOut = bitCoerce $ tail shift' :: Unsigned 8 | |
dValid = run && (not run') | |
input'' :: (State, Unsigned 4, Bool, Vec 9 Bit, Unsigned 2) | |
-> Bool | |
-> Bit | |
-> (State, Unsigned 4, Bool, Vec 9 Bit, Unsigned 2) | |
input'' s False _ | |
= s | |
input'' s@(WaitStart, 0 , _ , shift, sample) _ 1 | |
= s | |
input'' (WaitStart, 0 , _ , shift, sample) _ 0 | |
= (Sample 1 , 6, False, shift, 0) | |
input'' (Sample n , 0 , run , shift, sample) _ dIn | |
= case (n, run, last shift) of | |
(3, False, _) -> if majority == high then | |
waitEdge -- Not a startbit, but a glitch | |
else | |
(Sample 1, 13, True, 1 :> repeat 0, 0) | |
(3, True , 1) -> waitEdge | |
(3, True , 0) -> (Sample 1, 13, True, shift', 0) | |
(_, _ , _) -> (Sample (n + 1), 0, run, shift, sample') | |
where | |
sample' = if dIn == 1 then | |
sample + 1 | |
else | |
sample | |
majority = msb sample' | |
shift' = majority +>> shift | |
waitEdge = if dIn == 1 then | |
(WaitStart, 0, False, shift', sample) | |
else | |
(WaitHigh , 0, False, shift', sample) | |
input'' s@(WaitHigh , 0 , run , shift, sample) _ 0 | |
= s | |
input'' s@(WaitHigh , 0 , run , shift, sample) _ 1 | |
= (WaitStart, 0, run, shift, sample) | |
input'' (mode , wait, run , shift, sample) _ _ | |
= (mode, wait - 1, run, shift, sample) | |
-- Initial state for input | |
initInput :: (State, Unsigned 4, Bool, Vec 9 Bit, Unsigned 2) | |
initInput = (WaitStart, 0, False, repeat 0, 0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment