clash-lang / clash-prelude

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

inout ports #165

Closed christiaanb closed 6 years ago

christiaanb commented 6 years ago

In traditional HDLs we can mark an endpoint, or port, of a wire as inout, thereby making this port function as both a source and a drain for the signals flowing over the wire.

Clash has support for 'inout' ports through the implementation of _BiSignal_s. To cleanly map to functions (and thus support software simulation using Haskell), a BiSignal comes in two parts; the in part:

BiSignalIn (ds :: BiSignalDefault) (dom :: Domain) (n :: Nat)

and the out part:

BiSignalOut (ds :: BiSignalDefault) (dom :: Domain) (n :: Nat)

Where:

BiSignalIn is used by Clash to generate the inout ports on a HDL level, while BiSignalOut is only used for simulation purposes and generally discarded by the compiler.

Example

The following describes a system where two circuits, in alternating fashion, read the current value from the /bus/, increment it, and write it on the next cycle.

-- | Alternatively read / increment+write
counter :: (Bool, Int)
        -- ^ Internal flip + previous read
        -> Int
        -- ^ Int from inout
        -> ((Bool, Int), Maybe Int)
counter (write, prevread) i = ((write', prevread'), output)
  where
    output    = if write then Just (succ prevread) else Nothing
    prevread' = if write then prevread else i
    write' = not write

-- | Write on odd cyles
f :: Clock System Source
  -> Reset System Asynchronous
  -> BiSignalIn  Undefined System (BitSize Int)
  -> BiSignalOut Undefined System (BitSize Int)
f clk rst s = writeToBiSignal s (mealy clk rst counter (False, 0) (readFromBiSignal s))

-- | Write on even cyles
g :: Clock System Source
  -> Reset System Asynchronous
  -> BiSignalIn  Undefined System (BitSize Int)
  -> BiSignalOut Undefined System (BitSize Int)
g clk rst s = writeToBiSignal s (mealy clk rst counter (True, 0) (readFromBiSignal s))

-- | Connect the /f/ and /g/ circuits to the same bus
topEntity :: Clock System Source
          -> Reset System Asynchronous
          -> Signal System Int
topEntity clk rst = readFromBiSignal bus'
  where
    bus  = mergeBiSignalOuts $ f clk rst bus' :> g clk rst bus' :> Nil
    bus' = veryUnsafeToBiSignalIn bus