module System.RedPitaya.Fpga (
Fpga,
Registry,
Channel(..),
withOpenFpga,
fpgaId,
dna,
setExpDirP,
getExpDirP,
setExpDirN,
getExpDirN,
setExpOutP,
setExpOutN,
getExpInP,
getExpInN,
GpioType(..),
GpioDirection(..),
PinNum,
setExpDir,
GpioValue(..),
setExpOut,
getExpOut,
setLed,
getLed,
resetWriteSM,
triggerNow,
TriggerSource(..),
setOscTrigger,
triggerDelayEnded,
setTreshold,
getTreshold,
setDelayAfterTrigger,
getDelayAfterTrigger,
setOscDecimationRaw,
getOscDecimationRaw,
OscDecimation(..),
setOscDecimation,
getOscWpCurrent,
getOscWpTrigger,
getOscHysteresis,
setOscHysteresis,
enableOscDecimationAvarage,
setEqualFilter,
getEqualFilter,
setAxiLowerAddress,
getAxiLowerAddress,
setAxiUpperAddress,
getAxiUpperAddress,
setAxiDelayAfterTrigger,
getAxiDelayAfterTrigger,
enableAxiMaster,
getAxiWritePtrTrigger,
getAxiWritePtrCurrent,
getOscBuffer,
getAsgOption,
setAsgOption,
setAsgOptionBExtGatRep,
getAsgOptionBExtGatRep,
setAsgAmplitudeScale,
setAsgAmplitudeOffset,
setAsgCounterWrap,
setAsgCounterStartOffset,
setAsgCounterStep,
getAsgCounterReadPtr,
setAsgCounterReadPtr,
getAsgNumReadCycles,
setAsgNumReadCycles,
getAsgNumRepetitions,
setAsgNumRepetitions,
getAsgBurstDelay,
setAsgBurstDelay,
Page,
Offset,
fpgaRead,
fpgaWrite,
fpgaFmap,
pokeFpgaArray,
peekFpgaArray
)
where
import Foreign.C.Types
import Foreign.Ptr
import Foreign.Marshal.Array
import System.Posix.IO
import Data.Int
import Data.Word
import Data.Bits
import Foreign.Storable
import Control.Monad
import Control.Applicative
import Control.Monad.State
fpgaPageSize = 0x100000
fpgaMapSize = 0x100000 * 8
addrAms = 0x40000000
type FpgaPtr = Ptr ()
type FpgaState = FpgaPtr
type Offset = Int
type Page = Int
type Registry = Word32
type StateMonad a = StateT FpgaState IO a
newtype Fpga a = Fpga (StateMonad a)
deriving (Functor,Applicative, Monad,MonadIO, MonadFix, MonadPlus, Alternative)
data Channel = A | B
getStateType :: Fpga a -> StateMonad a
getStateType (Fpga s) = s
fpgaState a = Fpga ( StateT a )
runFpga :: Fpga a -> FpgaState -> IO (a,FpgaState)
runFpga (Fpga s) = runStateT s
store :: FpgaState -> Fpga ()
store v = fpgaState $ \x -> ( return ((),v) )
getState :: Fpga FpgaState
getState = fpgaState $ \x -> ( return (x,x) )
getPtr :: Fpga FpgaPtr
getPtr = getState
withOpenFpga :: Fpga a -> IO a
withOpenFpga act = do
fd <- openFd "/dev/mem" ReadWrite Nothing defaultFileFlags
setFdOption fd SynchronousWrites True
p <- mmap nullPtr fpgaMapSize (c'PROT_READ + c'PROT_WRITE ) c'MAP_SHARED (fromIntegral fd) addrAms
(r,s) <- runFpga act p
munmap p fpgaMapSize
return r
getOffsetPtr :: Page -> Offset -> Fpga (Ptr Registry)
getOffsetPtr page offset =
(\memmap -> plusPtr memmap (page * fpgaPageSize + offset)) <$> getPtr
fpgaRead :: Page -> Offset -> Fpga Registry
fpgaRead page offset = do
p <- getOffsetPtr page offset
liftIO $ peek p
fpgaWrite :: Page -> Offset -> Registry -> Fpga ()
fpgaWrite page offset reg = do
p <- getOffsetPtr page offset
liftIO $ poke p reg
fpgaFmap :: Page -> Offset -> (Registry -> Registry) -> Fpga ()
fpgaFmap page offset f = do
reg <- fpgaRead page offset
fpgaWrite page offset (f reg)
pokeFpgaArray :: Page -> Offset -> [Registry] -> Fpga ()
pokeFpgaArray page offset xs = do
p <- getOffsetPtr page offset
liftIO $ pokeArray p xs
peekFpgaArray :: Page -> Offset -> Int -> Fpga [Registry]
peekFpgaArray page offset len = do
p <- getOffsetPtr page offset
liftIO $ peekArray len p
fpgaId :: Fpga Registry
fpgaId = fpgaRead 0 0
dna :: Fpga Integer
dna = do
dna1 <- fromIntegral <$> fpgaRead 0 4
dna2 <- fromIntegral <$> fpgaRead 0 8
return $ dna1 + (2^32)*dna2
setExpDirP :: Registry -> Fpga ()
setExpDirP = fpgaWrite 0 0x10
getExpDirP :: Fpga Registry
getExpDirP = fpgaRead 0 0x10
setExpDirN :: Registry -> Fpga ()
setExpDirN = fpgaWrite 0 0x14
getExpDirN :: Fpga Registry
getExpDirN = fpgaRead 0 0x14
setExpOutP :: Registry -> Fpga ()
setExpOutP = fpgaWrite 0 0x18
getExpOutP :: Fpga Registry
getExpOutP = fpgaRead 0 0x18
setExpOutN :: Registry -> Fpga ()
setExpOutN = fpgaWrite 0 0x1C
getExpOutN :: Fpga Registry
getExpOutN = fpgaRead 0 0x1C
getExpInP :: Fpga Registry
getExpInP = fpgaRead 0 0x20
getExpInN :: Fpga Registry
getExpInN = fpgaRead 0 0x24
data GpioType =
P |
N
deriving (Show)
class ToBool b where
toBool :: b -> Bool
setBitValue :: (Bits a,ToBool b) => b -> Int -> a -> a
setBitValue b
| toBool b = flip setBit
| otherwise = flip clearBit
data GpioDirection =
Input |
Output
deriving (Show)
instance ToBool GpioDirection where
toBool Input = True
toBool Output = False
type PinNum = Int
setExpDir :: GpioType -> GpioDirection -> PinNum -> Fpga ()
setExpDir N d p = setBitValue d p <$> getExpDirN >>= setExpDirN
setExpDir P d p = setBitValue d p <$> getExpDirP >>= setExpDirP
data GpioValue =
Low |
Hi
deriving (Show)
instance ToBool GpioValue where
toBool Low = False
toBool Hi = True
setExpOut :: GpioType -> GpioValue -> PinNum -> Fpga ()
setExpOut N v p = setBitValue v p <$> getExpOutN >>= setExpOutN
setExpOut P v p = setBitValue v p <$> getExpOutP >>= setExpOutP
toGpioValue :: Bool -> GpioValue
toGpioValue True = Hi
toGpioValue False = Low
getExpOut :: GpioType -> PinNum -> Fpga GpioValue
getExpOut N p = (\x -> toGpioValue ( testBit x p )) <$> getExpOutN
getExpOut P p = (\x -> toGpioValue ( testBit x p )) <$> getExpOutP
setLed :: Registry -> Fpga ()
setLed = fpgaWrite 0 0x30
getLed :: Fpga Registry
getLed = fpgaRead 0 0x30
osciloscpeFpgaPage :: Int
osciloscpeFpgaPage = 1
fpgaWriteOsc = fpgaWrite osciloscpeFpgaPage
fpgaReadOsc = fpgaRead osciloscpeFpgaPage
resetWriteSM :: Fpga ()
resetWriteSM = fpgaWriteOsc 0 2
triggerNow :: Fpga ()
triggerNow = fpgaWriteOsc 0 1
data TriggerSource =
Immediately
| ChAPositiveEdge
| ChANegativeEdge
| ChBPositiveEdge
| ChBNegativeEdge
| ExtPositiveEdge
| ExtNegaitveEdge
| AWGPositiveEdge
| AWGNegativeEdge
deriving (Show)
setOscTrigger :: TriggerSource -> Fpga ()
setOscTrigger Immediately = setOscTriggerHelper 1
setOscTrigger ChAPositiveEdge = setOscTriggerHelper 2
setOscTrigger ChANegativeEdge = setOscTriggerHelper 3
setOscTrigger ChBPositiveEdge = setOscTriggerHelper 4
setOscTrigger ChBNegativeEdge = setOscTriggerHelper 5
setOscTrigger ExtPositiveEdge = setOscTriggerHelper 6
setOscTrigger ExtNegaitveEdge = setOscTriggerHelper 7
setOscTrigger AWGPositiveEdge = setOscTriggerHelper 8
setOscTrigger AWGNegativeEdge = setOscTriggerHelper 9
setOscTriggerHelper :: Registry -> Fpga ()
setOscTriggerHelper = fpgaWriteOsc 0x4
triggerDelayEnded :: Fpga Bool
triggerDelayEnded = (==0) <$> fpgaReadOsc 0x4
setTreshold :: Channel -> Registry -> Fpga ()
setTreshold A = fpgaWriteOsc 0x8
setTreshold B = fpgaWriteOsc 0xc
getTreshold :: Channel -> Fpga Registry
getTreshold A = fpgaReadOsc 0x8
getTreshold B = fpgaReadOsc 0xc
setDelayAfterTrigger :: Registry -> Fpga ()
setDelayAfterTrigger = fpgaWriteOsc 0x10
getDelayAfterTrigger :: Fpga Registry
getDelayAfterTrigger = fpgaReadOsc 0x10
setOscDecimationRaw :: Registry -> Fpga ()
setOscDecimationRaw = fpgaWriteOsc 0x14
getOscDecimationRaw :: Fpga Registry
getOscDecimationRaw = fpgaReadOsc 0x14
data OscDecimation =
OscDec1
| OscDec8
| OscDec64
| OscDec1024
| OscDec8192
| OscDec65536
deriving (Show)
setOscDecimation :: OscDecimation -> Fpga ()
setOscDecimation OscDec1 = setOscDecimationRaw 1
setOscDecimation OscDec8 = setOscDecimationRaw 8
setOscDecimation OscDec64 = setOscDecimationRaw 64
setOscDecimation OscDec1024 = setOscDecimationRaw 1024
setOscDecimation OscDec8192 = setOscDecimationRaw 8192
setOscDecimation OscDec65536 = setOscDecimationRaw 65536
getOscWpCurrent:: Fpga Registry
getOscWpCurrent = fpgaReadOsc 0x18
getOscWpTrigger :: Fpga Registry
getOscWpTrigger = fpgaReadOsc 0x1C
getOscHysteresis :: Channel -> Fpga Registry
getOscHysteresis A = fpgaReadOsc 0x20
getOscHysteresis B = fpgaReadOsc 0x24
setOscHysteresis :: Channel -> Registry -> Fpga ()
setOscHysteresis A = fpgaWriteOsc 0x20
setOscHysteresis B = fpgaWriteOsc 0x24
enableOscDecimationAvarage :: Bool -> Fpga ()
enableOscDecimationAvarage True = fpgaWriteOsc 0x28 1
enableOscDecimationAvarage False = fpgaWriteOsc 0x28 0
setEqualFilter :: Channel -> [Registry] -> Fpga ()
setEqualFilter A = pokeFpgaArray osciloscpeFpgaPage 0x30 . take 4
setEqualFilter B = pokeFpgaArray osciloscpeFpgaPage 0x40 . take 4
getEqualFilter :: Channel -> Fpga [Registry]
getEqualFilter A = peekFpgaArray osciloscpeFpgaPage 0x30 4
getEqualFilter B = peekFpgaArray osciloscpeFpgaPage 0x40 4
setAxiGeneric' :: Offset -> Channel -> Registry -> Fpga ()
setAxiGeneric' offest A = fpgaWriteOsc offest
setAxiGeneric' offest B = fpgaWriteOsc (offest+0x20)
getAxiGeneric' :: Offset -> Channel -> Fpga Registry
getAxiGeneric' offest A = fpgaReadOsc offest
getAxiGeneric' offest B = fpgaReadOsc (offest+0x20)
setAxiLowerAddress :: Channel -> Registry -> Fpga ()
setAxiLowerAddress = setAxiGeneric' 0x50
getAxiLowerAddress :: Channel -> Fpga Registry
getAxiLowerAddress = getAxiGeneric' 0x50
setAxiUpperAddress :: Channel -> Registry -> Fpga ()
setAxiUpperAddress = setAxiGeneric' 0x54
getAxiUpperAddress :: Channel -> Fpga Registry
getAxiUpperAddress = getAxiGeneric' 0x54
getAxiDelayAfterTrigger :: Channel -> Fpga Registry
getAxiDelayAfterTrigger = getAxiGeneric' 0x58
setAxiDelayAfterTrigger :: Channel -> Registry -> Fpga ()
setAxiDelayAfterTrigger = setAxiGeneric' 0x58
enableAxiMaster :: Channel -> Bool -> Fpga ()
enableAxiMaster ch True = setAxiGeneric' 0x5c ch 1
enableAxiMaster ch False = setAxiGeneric' 0x5c ch 0
getAxiWritePtrTrigger :: Channel -> Fpga Registry
getAxiWritePtrTrigger = getAxiGeneric' 0x60
getAxiWritePtrCurrent :: Channel -> Fpga Registry
getAxiWritePtrCurrent = getAxiGeneric' 0x64
getOscBuffer :: Channel -> Offset -> Int -> Fpga [Registry]
getOscBuffer chan off len = peekFpgaArray osciloscpeFpgaPage (off' + (chOff chan)) len'
where
off' = max 0 off
len' = min (0x10000 off) len
chOff A = 0x10000
chOff B = 0x20000
setBits :: (Int,Int) -> Registry -> Registry -> Registry
setBits (fromBit,toBit) value rin = valueShift .|. hole
where
ones = complement 0 :: Registry
maskShift = xor (shiftL ones fromBit) (shiftL ones (toBit+1))
hole = complement maskShift .&. rin
valueShift = ( shiftL value fromBit ) .&. maskShift
getBits :: (Int,Int) -> Registry -> Registry
getBits (fromBit,toBit) value = shiftR andV fromBit
where
ones = complement 0 :: Registry
maskShift = xor (shiftL ones fromBit) (shiftL ones (toBit+1))
andV = maskShift .&. value
type FpgaSet = Registry -> Fpga ()
type FpgaGet = Fpga Registry
asgFpgaPage = 2
fpgaWriteAsg :: Offset -> Registry -> Fpga ()
fpgaWriteAsg = fpgaWrite asgFpgaPage
fpgaReadAsg :: Offset -> Fpga Registry
fpgaReadAsg = fpgaRead asgFpgaPage
fpgaFmapAsg :: Offset -> (Registry -> Registry) -> Fpga ()
fpgaFmapAsg = fpgaFmap asgFpgaPage
fpgaWriteAsgChannel :: Offset -> Channel -> Registry -> Fpga ()
fpgaWriteAsgChannel offset A = fpgaWriteAsg offset
fpgaWriteAsgChannel offset B = fpgaWriteAsg ( offset + 0x20)
fpgaReadAsgChannel :: Offset -> Channel -> Fpga Registry
fpgaReadAsgChannel offset A = fpgaReadAsg offset
fpgaReadAsgChannel offset B = fpgaReadAsg ( offset + 0x20)
fpgaFmapAsgChannel :: Offset -> (Registry -> Registry) -> Channel -> Fpga ()
fpgaFmapAsgChannel offset f A = fpgaFmapAsg offset f
fpgaFmapAsgChannel offset f B = fpgaFmapAsg ( offset + 0x20) f
getAsgOption :: Fpga Registry
getAsgOption = fpgaReadAsg 0x0
setAsgOption :: Registry -> Fpga ()
setAsgOption = fpgaWriteAsg 0x0
setAsgOptionBExtGatRep :: Registry -> Fpga ()
setAsgOptionBExtGatRep reg = fpgaFmapAsg 0 ( setBits (24,24) reg)
getAsgOptionBExtGatRep :: Fpga Registry
getAsgOptionBExtGatRep = getBits (24,24) <$> getAsgOption
setAsgAmplitudeScale :: Channel -> Registry -> Fpga ()
setAsgAmplitudeScale ch reg = fpgaFmapAsgChannel 0x4 ( setBits (16,29) reg ) ch
setAsgAmplitudeOffset :: Channel -> Registry -> Fpga ()
setAsgAmplitudeOffset ch reg = fpgaFmapAsgChannel 0x4 ( setBits (0,13) reg ) ch
setAsgCounterWrap :: Channel -> Registry -> Fpga ()
setAsgCounterWrap = fpgaWriteAsgChannel 0x8
setAsgCounterStartOffset :: Channel -> Registry -> Fpga ()
setAsgCounterStartOffset = fpgaWriteAsgChannel 0xc
setAsgCounterStep :: Channel -> Registry -> Fpga ()
setAsgCounterStep = fpgaWriteAsgChannel 0x10
getAsgCounterReadPtr :: Channel -> Fpga Registry
getAsgCounterReadPtr = fpgaReadAsgChannel 0x14
setAsgCounterReadPtr :: Channel -> Registry -> Fpga ()
setAsgCounterReadPtr = fpgaWriteAsgChannel 0x14
getAsgNumReadCycles :: Channel -> Fpga Registry
getAsgNumReadCycles = fpgaReadAsgChannel 0x18
setAsgNumReadCycles :: Channel -> Registry -> Fpga ()
setAsgNumReadCycles = fpgaWriteAsgChannel 0x18
getAsgNumRepetitions :: Channel -> Fpga Registry
getAsgNumRepetitions = fpgaReadAsgChannel 0x1a
setAsgNumRepetitions :: Channel -> Registry -> Fpga ()
setAsgNumRepetitions = fpgaWriteAsgChannel 0x1a
getAsgBurstDelay :: Channel -> Fpga Registry
getAsgBurstDelay = fpgaReadAsgChannel 0x20
setAsgBurstDelay :: Channel -> Registry -> Fpga ()
setAsgBurstDelay = fpgaWriteAsgChannel 0x20
foreign import ccall "mmap" mmap
:: Ptr () -> CSize -> CInt -> CInt-> CInt-> CInt -> IO (Ptr ())
foreign import ccall "munmap" munmap
:: Ptr () -> CSize -> IO CInt
c'PROT_EXEC = 4
c'PROT_NONE = 0
c'PROT_READ = 1
c'PROT_WRITE = 2
c'MAP_FIXED = 16
c'MAP_PRIVATE = 2
c'MAP_SHARED = 1
c'MAP_FAILED = wordPtrToPtr 4294967295