data-svd-0.1.0.0: src/Data/SVD/Parse.hs
{-# LANGUAGE Arrows #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE RecordWildCards #-}
module Data.SVD.Parse where
import Safe
import Control.Arrow.ArrowList
import qualified Data.Char as Char
import qualified Data.Maybe
import Data.Tree.NTree.TypeDefs
import Text.XML.HXT.Core
import Data.SVD.Types
-- atTag doesn't uses deep here
atTag :: ArrowXml cat => String -> cat (NTree XNode) XmlTree
atTag tag = getChildren >>> hasName tag
text :: ArrowXml cat => cat (NTree XNode) String
text = getChildren >>> getText
textAtTag :: ArrowXml cat => String -> cat (NTree XNode) String
textAtTag tag = text <<< atTag tag
textAtTagOrEmpty :: ArrowXml cat => String -> cat (NTree XNode) String
textAtTagOrEmpty tag = withDefault (text <<< atTag tag) ""
att :: ArrowXml cat => String -> cat XmlTree String
att = getAttrValue
-- nonempty attr value
attNE :: ArrowXml cat => String -> cat XmlTree String
attNE x = getAttrValue x >>> isA (/= "")
attMaybe :: ArrowXml cat => String -> String -> cat (NTree XNode) (Maybe String)
attMaybe attname tagname =
withDefault
(arr Just <<< attNE attname <<< atTag tagname)
Nothing
filterCrap :: String -> String
filterCrap =
unwords
. words
. filter (\c -> Char.ord c < 127)
. filter ( not . (`elem` ['\n', '\t', '\r']))
-- svd parser
svd :: ArrowXml cat => cat (NTree XNode) Device
svd = atTag "device" >>>
proc x -> do
--name <- text <<< hasName "name" <<< getChildren -< x
deviceName <- textAtTag "name" -< x
deviceVersion <- textAtTag "version" -< x
desc <- textAtTag "description" -< x
addressUnitBits' <- textAtTag "addressUnitBits" -< x
width' <- textAtTag "width" -< x
size' <- textAtTag "size" -< x
resetValue' <- textAtTag "resetValue" -< x
resetMask' <- textAtTag "resetMask" -< x
let deviceAddressUnitBits = read addressUnitBits'
deviceWidth = read width'
deviceSize = read size'
deviceResetValue = read resetValue'
deviceResetMask = read resetMask'
deviceDescription = filterCrap desc
devicePeripherals <- listA parsePeripheral <<< atTag "peripherals" -< x
returnA -< Device{..}
-- loose version of svd that doesn't require device properties
svdPeripherals :: ArrowXml cat => cat (NTree XNode) [Peripheral]
svdPeripherals = atTag "device" >>>
proc x -> do
devicePeripherals <- listA parsePeripheral <<< atTag "peripherals" -< x
returnA -< devicePeripherals
parsePeripheral :: ArrowXml cat => cat (NTree XNode) Peripheral
parsePeripheral = atTag "peripheral" >>>
proc x -> do
-- only these three avail for derived peripherals
periphName <- textAtTag "name" -< x
periphDerivedFrom <- withDefault (arr Just <<< isA (/= "") <<< att "derivedFrom") Nothing -< x
baseAddress' <- textAtTag "baseAddress" -< x
desc <- withDefault (textAtTag "description") "" -< x
periphGroupName <- withDefault (textAtTag "groupName") "" -< x
periphAddressBlock <- withDefault (arr Just <<< parseAddressBlock) Nothing -< x
periphInterrupts <- listA parseInterrupt -< x
periphRegisters <- withDefault (listA parseRegister <<< atTag "registers") mempty -< x
periphClusters <- withDefault (listA parseCluster <<< atTag "registers") mempty -< x
let periphBaseAddress = read baseAddress'
periphDescription = filterCrap desc
returnA -< Peripheral{..}
parseAddressBlock
:: ArrowXml cat
=> cat (NTree XNode) AddressBlock
parseAddressBlock = atTag "addressBlock" >>>
proc x -> do
offset <- textAtTag "offset" -< x
size <- textAtTag "size" -< x
addressBlockUsage <- textAtTag "usage" -< x
let addressBlockOffset = read offset
addressBlockSize = read size
returnA -< AddressBlock{..}
parseInterrupt
:: ArrowXml cat
=> cat (NTree XNode) Interrupt
parseInterrupt = atTag "interrupt" >>>
proc x -> do
name <- textAtTag "name" -< x
desc <- textAtTag "description" -< x
val <- textAtTag "value" -< x
let interruptName = map Char.toUpper name
interruptValue = read val
interruptDescription = filterCrap desc
returnA -< Interrupt{..}
parseCluster
:: ArrowXml cat
=> cat (NTree XNode) Cluster
parseCluster = atTag "cluster" >>>
proc x -> do
clusterName <- textAtTag "name" -< x
clusterDescription <- textAtTag "description" -< x
clusterDimension <- withDefault (arr Just <<< parseDimension) Nothing -< x
offset <- textAtTag "addressOffset" -< x
clusterRegisters <- listA parseRegister -< x
clusterNested <- listA parseCluster -< x
let clusterAddressOffset = read offset
returnA -< Cluster{..}
parseDimension
:: ArrowXml cat
=> cat (NTree XNode) Dimension
parseDimension =
proc x -> do
dim <- textAtTag "dim" -< x
dimIncr <- textAtTag "dimIncrement" -< x
dimIdx <- textAtTag "dimIndex" -< x
let
dimensionSize = read dim
dimensionIncrement = read dimIncr
dimensionIndex = case dimIdx of
i | '-' `elem` i -> case words [ if c == '-' then ' ' else c | c <- i ] of
[from, to] -> DimensionIndex_FromTo (read from) (read to)
_ -> error $ "Don't know how to handle ranged dimIndex: " <> i
i | ',' `elem` i -> DimensionIndex_List $ words [ if c == ',' then ' ' else c | c <- i ]
i | otherwise -> error $ "Don't know how to handle dimIndex: " <> i
returnA -< Dimension{..}
parseRegister
:: ArrowXml cat
=> cat (NTree XNode) Register
parseRegister = atTag "register" >>>
proc x -> do
regName <- textAtTag "name" -< x
regDisplayName <- textAtTagOrEmpty "displayName" -< x
desc <- textAtTagOrEmpty "description" -< x
offset <- textAtTag "addressOffset" -< x
size <- textAtTag "size" -< x
access <- withDefault (textAtTag "access") "read-write" -< x
regResetValue <- withDefault (arr (Just . read) <<< textAtTag "resetValue") Nothing -< x
regFields <- withDefault (listA parseField <<< atTag "fields") [] -< x
regDimension <- withDefault (arr Just <<< parseDimension) Nothing -< x
let regAddressOffset = read offset
regSize = read size
regAccess = toAccessType access
regDescription = filterCrap desc
returnA -< Register{..}
parseField
:: ArrowXml cat
=> cat (NTree XNode) Field
parseField = atTag "field" >>>
proc x -> do
fieldName <- textAtTag "name" -< x
fieldDimension <- withDefault (arr Just <<< parseDimension) Nothing -< x
desc <- textAtTagOrEmpty "description" -< x
bitOffsetMay <- withDefault (arr (Just . read) <<< textAtTag "bitOffset") Nothing -< x
bitWidthMay <- withDefault (arr (Just . read) <<< textAtTag "bitWidth") Nothing -< x
-- bitRange [MSB:LSB]
bitRange <- withDefault (arr (Just . splitRange) <<< textAtTag "bitRange") Nothing -< x
-- XXX: TODO: one more possibility is lsb msb tags format, handle if needed
let errmsg = error "Neither bitRange nor bitOffset + bitWidth defined"
(fieldBitOffset, fieldBitWidth) = case bitRange of
Nothing -> ( Data.Maybe.fromMaybe errmsg bitOffsetMay
, Data.Maybe.fromMaybe errmsg bitWidthMay)
Just (msb, lsb) -> (lsb, msb - lsb + 1)
fieldDescription = filterCrap desc
fieldReserved = False
fieldRegType = Nothing
returnA -< Field{..}
where
splitRange :: String -> (Int, Int)
splitRange r = (readNote "splitRange" $ takeWhile (/=':') raw,
readNote "splitRange" $ drop 1 $ dropWhile (/=':') raw)
where
raw = drop 1 $ init r