Haskellator/src/RTLILParser/Parser.hs
2024-12-06 14:57:32 -05:00

216 lines
5.8 KiB
Haskell

-- this parser largely references:
-- https://yosyshq.readthedocs.io/projects/yosys/en/stable/appendix/rtlil_text.html
module RTLILParser.Parser(a, val) where
import Control.Monad (void)
import Text.Parsec
import Text.Parsec.String (Parser)
import RTLILParser.AST(
AutoIdxStmt(..) ,ParamStmt(..) ,AutogenId(..)
,Constant(..) ,CellStmt(..) ,PublicId(..)
,AttrStmt(..) ,Value(..) ,Id(..)
,CellId(..) ,CellType(..) ,WireId(..)
,SigSpec(..) ,Slice(..) ,ConnStmt(..)
,WireOption(..) ,WireStmt(..) ,Wire(..)
,MemoryOption(..) ,MemoryStmt(..) ,Memory(..)
,MemoryID(..)
)
import Util(binaryStringToInt)
import RTLILParser.Primitives(pEscapedChar)
-- https://github.com/YosysHQ/yosys/blob/111b747d2797238eadf541879848492a9d34909a/frontends/rtlil/rtlil_lexer.l#L88C1-L88C17
nonws :: Parser Char
nonws = noneOf " \t\r\n"
pMaybeWs :: Parser String
pMaybeWs = many (oneOf " \t")
pWs :: Parser String
pWs = many1 (oneOf " \t")
pEol :: Parser String
pEol = many1 (oneOf "\r\n")
pPublicId :: Parser PublicId
pPublicId = PublicId <$> (char '\\' *> many1 nonws)
pAutogenId :: Parser AutogenId
pAutogenId = AutogenId <$> (char '$' *> many1 nonws)
pId :: Parser Id
pId = Public <$> pPublicId
<|> Autogen <$> pAutogenId
pWireId :: Parser WireId
pWireId = WireId <$> pId
decimalDigit :: Parser Char
decimalDigit = oneOf "0123456789"
-- update in the future to support 4 state logic
-- by converting x and z to 0 and warning about it.
pBinaryDigit :: Parser Char
pBinaryDigit = oneOf "01"
pString :: Parser String
pString =
between delimiter delimiter parseString
where
delimiter = char '"'
parseString = many (pEscapedChar <|> noneOf "\\\"")
pValue :: Parser Value
pValue = Value <$> pInteger
<*> (binaryStringToInt <$> many1 pBinaryDigit)
pInteger :: Parser Int
pInteger = do
sign <- optionMaybe (char '-')
digits <- many1 digit
let value = read digits
return $ case sign of
Just _ -> -value
Nothing -> value
pConstant :: Parser Constant
pConstant =
try (ConstantValue <$> pValue)
<|> (ConstantInteger <$> pInteger)
<|> (ConstantString <$> pString)
pAutoIdxStmt :: Parser AutoIdxStmt
pAutoIdxStmt = AutoIdxStmt <$> (string "autoidx" *> pWs *> pInteger <* pEol)
pModuleStmt :: Parser Id
pModuleStmt = string "module" *> pWs *> pId <* pEol
pModuleEndStmt :: Parser ()
pModuleEndStmt = void (string "end")
pParamStmt :: Parser ParamStmt
pParamStmt = ParamStmt
<$> (string "parameter" *> pWs *> pId)
<*> optionMaybe (pWs *> pConstant)
<* pEol
pAttrStmt :: Parser AttrStmt
pAttrStmt = AttrStmt
<$> (string "attribute" *> pWs *> pId)
<*> (pWs *> pConstant)
<* pEol
pCellStmt :: Parser CellStmt
pCellStmt = do
_ <- string "cell"
_ <- pWs
cellId <- CellId <$> pId
_ <- pWs
cellType <- CellType <$> pId
_ <- pEol
return $ CellStmt cellId cellType
-- Parse a single slice
pSlice :: Parser Slice
pSlice =
Slice
<$> (char '[' *> pMaybeWs *> pInteger <* pMaybeWs)
<*> (optionMaybe (char ':' *> pInteger) <* pMaybeWs <* char ']')
pSigSpecConcat :: Parser SigSpec
pSigSpecConcat = do
_ <- char '{' <* pWs
sigspecs <- pSigSpec `sepBy` pWs
_ <- pWs <* char '}'
return $ SigSpecConcat sigspecs
applySlices :: SigSpec -> Parser SigSpec
applySlices base = do
maybeSlice <- optionMaybe pSlice
case maybeSlice of
Nothing -> return base
Just slice -> applySlices (SigSpecSlice base slice)
pSingleSigSpec :: Parser SigSpec
pSingleSigSpec = do
baseSigSpec <- (SigSpecConstant <$> pConstant)
<|>
(SigSpecWireId <$> pWireId)
applySlices baseSigSpec
pSigSpec :: Parser SigSpec
pSigSpec =
try pSigSpecConcat -- Check for concatenation first
<|> pSingleSigSpec -- Otherwise parse a single sigspec
pConnStmt :: Parser ConnStmt
pConnStmt = ConnStmt
<$> (string "connect" *> pWs *> pSigSpec)
<*> (pWs *> pSigSpec)
<* pEol
pWireOption :: Parser WireOption
pWireOption =
try (WireOptionWidth <$> (string "width" *> pWs *> pInteger)) <|>
try (WireOptionOffset <$> (string "offset" *> pWs *> pInteger)) <|>
try (WireOptionInput <$> (string "input" *> pWs *> pInteger)) <|>
try (WireOptionOutput <$> (string "output" *> pWs *> pInteger)) <|>
try (WireOptionInout <$> (string "inout" *> pWs *> pInteger)) <|>
(string "upto" *> return WireOptionUpto) <|>
(string "signed" *> return WireOptionSigned)
pWireStmt :: Parser WireStmt
pWireStmt =
WireStmt
<$ string "wire"
<* pWs
<*> (WireId <$> pId)
<* pWs
<*> many pWireOption
<* pEol
pWire :: Parser Wire
pWire = do
attrs <- many pAttrStmt
wireStmt <- pWireStmt
return $ Wire wireStmt attrs
pMemoryOption :: Parser MemoryOption
pMemoryOption =
try (MemoryOptionWidth <$> (string "width" *> pWs *> pInteger)) <|>
try (MemoryOptionSize <$> (string "size" *> pWs *> pInteger)) <|>
try (MemoryOptionOffset <$> (string "offset" *> pWs *> pInteger))
pMemoryStmt :: Parser MemoryStmt
pMemoryStmt =
MemoryStmt
<$ string "memory"
<* pWs
<*> (MemoryID <$> pId)
<* pWs
<*> many pMemoryOption
<* pEol
pMemory :: Parser Memory
pMemory = do
attrs <- many pAttrStmt
memoryStmt <- pMemoryStmt
return $ Memory memoryStmt attrs
-- would correspond to `123456789[0:9][0:8]`
exampleSigSpecSlice =
SigSpecSlice
(
SigSpecSlice
(SigSpecConstant (ConstantInteger 123456789))
(Slice 0 $ Just 9)
)
(Slice 0 $ Just 8)
-- val = parse pInteger "pInteger" "721"
-- val = parse pModuleStmt "pModuleStmt" "module \\top\n"
val = parse pSigSpec "pSigSpecSlice" "123456789[0:9][0:8]"
a :: Int
a = 3