evalOTerms :: [(Int, TeakOTerm)] -> SimValue -> SimFlow [(Int, SimValue)]
    evalOTerms terms inp = do
        values <- foldM evalTerm [(0, inp)] terms
        return $ reverse values
        where
            getOSliceValue values (i, slice) = getBitfield slice $ fromJust $ lookup i values

            evalTerm :: [(Int, SimValue)] -> (Int, TeakOTerm) -> SimFlow [(Int, SimValue)]
            evalTerm values (i, term) = case term of
                TeakOBuiltin name _ params slices -> do
                    value <- simBuiltinCall (map (getOSliceValue values) slices) (BuiltinCallExpr undefined name
                        (map teakParamToFuncActual params) undefined undefined)
                    return $ (i, value):values
                _ -> return $ (i, evalPureTerm values term) : values

            evalPureTerm _ (TeakOConstant _ value) = SimValue value []
            evalPureTerm values (TeakOAppend count slices) = simAppendValues
                (concat (replicate count widths)) (concat (replicate count inValues))
                where
                    widths = map oSliceWidth slices
                    inValues = map (getOSliceValue values) slices
            evalPureTerm values (TeakOp op slices) = opFunc sliceValues
                where
                    binOp op [SimValue l _, SimValue r _] = SimValue (cropInt width (l `op` r)) []
                    binOp _ _ = error "binOp: bad args"
                    unsignedInEq op [SimValue l _, SimValue r _] = SimValue (boolToBit $ l `op` r) []
                    unsignedInEq _ _ = error "unsignedInEq: bad args"
                    signedInEq op [SimValue l _, SimValue r _] = SimValue
                        (boolToBit $ (recoverSign width l) `op` (recoverSign width r)) []
                    signedInEq _ _ = error "signedInEq: bad args"

                    slice:_ = slices
                    width = oSliceWidth slice
                    sliceValues = map (getOSliceValue values) slices

                    opFunc = case op of
                        TeakOpAdd -> binOp (+)
                        TeakOpSub -> binOp (-)
                        TeakOpAnd -> binOp (.&.)
                        TeakOpOr -> binOp (.|.)
                        TeakOpNot -> \[SimValue l _] -> SimValue (bitNot width l) []
                        TeakOpXor -> binOp xor
                        TeakOpUnsignedGT -> unsignedInEq (>)
                        TeakOpUnsignedGE -> unsignedInEq (>=)
                        TeakOpEqual -> unsignedInEq (==)
                        TeakOpNotEqual -> unsignedInEq (/=)
                        TeakOpSignedGT -> signedInEq (>)
                        TeakOpSignedGE -> signedInEq (>=)
            evalPureTerm values (TeakOMux impss slices@(choiceSlice:_)) = fromMaybe (SimValue 0 []) $
                liftM snd $ find match $ zip impss sliceValues
                where
                    match (imps, _) = any (impIsCoveredByImp choiceWidth (Imp choiceValue 0)) imps
                    (SimValue choiceValue _):sliceValues = map (getOSliceValue values) slices
                    choiceWidth = oSliceWidth choiceSlice
            evalPureTerm _ term = error $ "putEvalTerm: unrecognised term `" ++ show term ++ "'"
evalOTerms :: [(Int, TeakOTerm)] -> SimValue -> SimFlow [(Int, SimValue)]
evalOTerms terms inp = do
        values <- foldM evalTerm [(0, inp)] terms
        return $ reverse values
        where
            getOSliceValue values (i, slice) = getBitfield slice $ fromJust $ lookup i values

            evalTerm :: [(Int, SimValue)] -> (Int, TeakOTerm) -> SimFlow [(Int, SimValue)]
            evalTerm values (i, term) = case term of
                TeakOBuiltin name _ params slices -> do
                    value <- simBuiltinCall (map (getOSliceValue values) slices) (BuiltinCallExpr undefined name
                        (map teakParamToFuncActual params) undefined undefined)
                    return $ (i, value):values
                _ -> return $ (i, evalPureTerm values term) : values

            evalPureTerm _ (TeakOConstant _ value) = SimValue value []
            evalPureTerm values (TeakOAppend count slices) = simAppendValues
                (concat (replicate count widths)) (concat (replicate count inValues))
                where
                    widths = map oSliceWidth slices
                    inValues = map (getOSliceValue values) slices
            evalPureTerm values (TeakOp op slices) = opFunc sliceValues
                where
                    binOp op [SimValue l _, SimValue r _] = SimValue (cropInt width (l `op` r)) []
                    binOp _ _ = error "binOp: bad args"
                    unsignedInEq op [SimValue l _, SimValue r _] = SimValue (boolToBit $ l `op` r) []
                    unsignedInEq _ _ = error "unsignedInEq: bad args"
                    signedInEq op [SimValue l _, SimValue r _] = SimValue
                        (boolToBit $ (recoverSign width l) `op` (recoverSign width r)) []
                    signedInEq _ _ = error "signedInEq: bad args"

                    slice:_ = slices
                    width = oSliceWidth slice
                    sliceValues = map (getOSliceValue values) slices

                    opFunc = case op of
                        TeakOpAdd -> binOp (+)
                        TeakOpSub -> binOp (-)
                        TeakOpAnd -> binOp (.&.)
                        TeakOpOr -> binOp (.|.)
                        TeakOpNot -> \[SimValue l _] -> SimValue (bitNot width l) []
                        TeakOpXor -> binOp xor
                        TeakOpUnsignedGT -> unsignedInEq (>)
                        TeakOpUnsignedGE -> unsignedInEq (>=)
                        TeakOpEqual -> unsignedInEq (==)
                        TeakOpNotEqual -> unsignedInEq (/=)
                        TeakOpSignedGT -> signedInEq (>)
                        TeakOpSignedGE -> signedInEq (>=)
            evalPureTerm values (TeakOMux impss slices@(choiceSlice:_)) = fromMaybe (SimValue 0 []) $
                liftM snd $ find match $ zip impss sliceValues
                where
                    match (imps, _) = any (impIsCoveredByImp choiceWidth (Imp choiceValue 0)) imps
                    (SimValue choiceValue _):sliceValues = map (getOSliceValue values) slices
                    choiceWidth = oSliceWidth choiceSlice
            evalPureTerm _ term = error $ "putEvalTerm: unrecognised term `" ++ show term ++ "'"
evalOTerms terms inp = do
        values <- foldM evalTerm [(0, inp)] terms
        return $ reverse values
        where
            getOSliceValue values (i, slice) = getBitfield slice $ fromJust $ lookup i values

            evalTerm :: [(Int, SimValue)] -> (Int, TeakOTerm) -> SimFlow [(Int, SimValue)]
            evalTerm values (i, term) = case term of
                TeakOBuiltin name _ params slices -> do
                    value <- simBuiltinCall (map (getOSliceValue values) slices) (BuiltinCallExpr undefined name
                        (map teakParamToFuncActual params) undefined undefined)
                    return $ (i, value):values
                _ -> return $ (i, evalPureTerm values term) : values

            evalPureTerm _ (TeakOConstant _ value) = SimValue value []
            evalPureTerm values (TeakOAppend count slices) = simAppendValues
                (concat (replicate count widths)) (concat (replicate count inValues))
                where
                    widths = map oSliceWidth slices
                    inValues = map (getOSliceValue values) slices
            evalPureTerm values (TeakOp op slices) = opFunc sliceValues
                where
                    binOp op [SimValue l _, SimValue r _] = SimValue (cropInt width (l `op` r)) []
                    binOp _ _ = error "binOp: bad args"
                    unsignedInEq op [SimValue l _, SimValue r _] = SimValue (boolToBit $ l `op` r) []
                    unsignedInEq _ _ = error "unsignedInEq: bad args"
                    signedInEq op [SimValue l _, SimValue r _] = SimValue
                        (boolToBit $ (recoverSign width l) `op` (recoverSign width r)) []
                    signedInEq _ _ = error "signedInEq: bad args"

                    slice:_ = slices
                    width = oSliceWidth slice
                    sliceValues = map (getOSliceValue values) slices

                    opFunc = case op of
                        TeakOpAdd -> binOp (+)
                        TeakOpSub -> binOp (-)
                        TeakOpAnd -> binOp (.&.)
                        TeakOpOr -> binOp (.|.)
                        TeakOpNot -> \[SimValue l _] -> SimValue (bitNot width l) []
                        TeakOpXor -> binOp xor
                        TeakOpUnsignedGT -> unsignedInEq (>)
                        TeakOpUnsignedGE -> unsignedInEq (>=)
                        TeakOpEqual -> unsignedInEq (==)
                        TeakOpNotEqual -> unsignedInEq (/=)
                        TeakOpSignedGT -> signedInEq (>)
                        TeakOpSignedGE -> signedInEq (>=)
            evalPureTerm values (TeakOMux impss slices@(choiceSlice:_)) = fromMaybe (SimValue 0 []) $
                liftM snd $ find match $ zip impss sliceValues
                where
                    match (imps, _) = any (impIsCoveredByImp choiceWidth (Imp choiceValue 0)) imps
                    (SimValue choiceValue _):sliceValues = map (getOSliceValue values) slices
                    choiceWidth = oSliceWidth choiceSlice
            evalPureTerm _ term = error $ "putEvalTerm: unrecognised term `" ++ show term ++ "'"