diff --git a/src/Convert/TypeOf.hs b/src/Convert/TypeOf.hs index ae265ff..d2e4088 100644 --- a/src/Convert/TypeOf.hs +++ b/src/Convert/TypeOf.hs @@ -12,7 +12,9 @@ module Convert.TypeOf (convert) where import Control.Monad.State +import Data.List (elemIndex) import Data.Maybe (fromMaybe, mapMaybe) +import Data.Int (Int32) import qualified Data.Map.Strict as Map import Convert.Traverse @@ -71,6 +73,11 @@ traverseTypeM (TypeOf expr) = typeof expr traverseTypeM other = return other typeof :: Expr -> State Info Type +typeof (Number n) = + return $ IntegerVector TLogic sg [r] + where + (size, sg) = parseNumber n + r = (Number $ show (size - 1), Number "0") typeof (orig @ (Ident x)) = do res <- gets $ Map.lookup x return $ fromMaybe (TypeOf orig) res @@ -93,9 +100,71 @@ typeof (orig @ (Range e mode r)) = do NonIndexed -> snd r IndexedPlus -> BinOp Sub (uncurry (BinOp Add) r) (Number "1") IndexedMinus -> BinOp Add (uncurry (BinOp Sub) r) (Number "1") -typeof (BinOp Add e Number{}) = typeof e +typeof (orig @ (Cast (Right (Ident x)) _)) = do + typeMap <- get + if Map.member x typeMap + then return $ typeOfSize (Ident x) + else return $ TypeOf orig +typeof (Cast (Right s) _) = return $ typeOfSize s +typeof (UniOp BitNot e ) = typeof e +typeof (BinOp Pow e _) = typeof e +typeof (BinOp ShiftL e _) = typeof e +typeof (BinOp ShiftR e _) = typeof e +typeof (BinOp ShiftAL e _) = typeof e +typeof (BinOp ShiftAR e _) = typeof e +typeof (BinOp Add a b) = return $ largerSizeType a b +typeof (BinOp Sub a b) = return $ largerSizeType a b +typeof (BinOp Mul a b) = return $ largerSizeType a b +typeof (BinOp Div a b) = return $ largerSizeType a b +typeof (BinOp Mod a b) = return $ largerSizeType a b +typeof (BinOp BitAnd a b) = return $ largerSizeType a b +typeof (BinOp BitXor a b) = return $ largerSizeType a b +typeof (BinOp BitXnor a b) = return $ largerSizeType a b +typeof (BinOp BitOr a b) = return $ largerSizeType a b +typeof (Mux _ a b) = return $ largerSizeType a b +typeof (Concat exprs) = return $ typeOfSize $ concatSize exprs +typeof (Repeat reps exprs) = return $ typeOfSize size + where size = BinOp Mul reps (concatSize exprs) typeof other = return $ TypeOf other +-- determines the size and sign of a number literal +parseNumber :: String -> (Int32, Signing) +parseNumber s = + case elemIndex '\'' s of + Nothing -> (32, Signed) + Just 0 -> parseNumber $ '3' : '2' : s + Just idx -> (size, signing) + where + Just size = readNumber $ take idx s + signing = case drop (idx + 1) s of + 's' : _ -> Signed + _ -> Unsigned + +-- produces a type large enough to hold either expression +largerSizeType :: Expr -> Expr -> Type +largerSizeType a b = + typeOfSize larger + where + sizeof = DimsFn FnBits . Right + cond = BinOp Ge (sizeof a) (sizeof b) + larger = Mux cond (sizeof a) (sizeof b) + +-- returns the total size of concatenated list of expressions +concatSize :: [Expr] -> Expr +concatSize exprs = + foldl (BinOp Add) (Number "0") $ + map sizeof exprs + where + sizeof = DimsFn FnBits . Right + +-- produces a generic type of the given size +typeOfSize :: Expr -> Type +typeOfSize size = + IntegerVector TLogic sg [(hi, Number "0")] + where + sg = Unspecified -- suitable for now + hi = BinOp Sub size (Number "1") + -- combines a type with unpacked ranges injectRanges :: Type -> [Range] -> Type injectRanges t [] = t diff --git a/test/basic/typeof.sv b/test/basic/typeof.sv index fb1b39f..a39bbd4 100644 --- a/test/basic/typeof.sv +++ b/test/basic/typeof.sv @@ -11,7 +11,9 @@ module top; initial begin type(f(0)) x = f(0); + type(x) y = ~x; $display("%b", x); + $display("%b", y); $display("%b", $bits(x)); $display("%b", $bits(type(x))); $display("%b", $bits(logic [0:1+$bits(type(x))])); @@ -19,4 +21,43 @@ module top; void'(f(0)); t(1); end + + parameter FLAG = 1; + initial begin + logic [4:1] x = 4'b1011; + type(x ^ 3'b111) y = x ^ 3'b111; + type(x ^ 5'b11111) z = x ^ 5'b11111; + type({8 {x}}) a = {8 {x}}; + type({x, y}) b = {x, y}; + type(FLAG ? x : y) c = FLAG ? x : y; + type(!FLAG ? x : y) d = !FLAG ? x : y; + $display("%b %d %d", x, $left(x), $right(x)); + $display("%b %d %d", y, $left(y), $right(y)); + $display("%b %d %d", z, $left(z), $right(z)); + $display("%b %d %d", a, $left(a), $right(a)); + $display("%b %d %d", b, $left(b), $right(b)); + $display("%b %d %d", c, $left(c), $right(c)); + $display("%b %d %d", d, $left(d), $right(d)); + end + + parameter W = 4; + initial begin + logic [W-1:0] x = 4'hA; + type(FLAG ? x : '1) y = FLAG ? x : '1; + type(!FLAG ? y : '1) z = !FLAG ? y : '1; + $display("%b %d %d", x, $left(x), $right(x)); + $display("%b %d %d", y, $left(y), $right(y)); + $display("%b %d %d", z, $left(z), $right(z)); + end + + initial begin + type(1) w = 1; + type(-1) x = -1; + type(32'hffff_ffff) y = 32'hffff_ffff; + type(32'shffff_ffff) z = 32'shffff_ffff; + $display("%b %d %d %d", w, w, $left(w), $right(w)); + $display("%b %d %d %d", x, x, $left(x), $right(x)); + $display("%b %d %d %d", y, y, $left(y), $right(y)); + $display("%b %d %d %d", z, z, $left(z), $right(z)); + end endmodule diff --git a/test/basic/typeof.v b/test/basic/typeof.v index 74c95f3..fe687d7 100644 --- a/test/basic/typeof.v +++ b/test/basic/typeof.v @@ -12,9 +12,11 @@ module top; endtask initial begin : block - reg x; + reg x, y; x = f(0); + y = ~x; $display("%b", x); + $display("%b", y); $display("%b", 32'd1); $display("%b", 32'd1); $display("%b", 32'd3); @@ -22,4 +24,52 @@ module top; x = f(0); t(1); end + + parameter FLAG = 1; + initial begin : block2 + reg [4:1] x; + reg [3:0] y; + reg [4:0] z; + reg [31:0] a; + reg [7:0] b; + reg [3:0] c, d; + x = 4'b1011; + y = x ^ 3'b111; + z = x ^ 5'b11111; + a = {8 {x}}; + b = {x, y}; + c = FLAG ? x : y; + d = !FLAG ? x : y; + $display("%b %d %d", x, 4, 1); + $display("%b %d %d", y, 3, 0); + $display("%b %d %d", z, 4, 0); + $display("%b %d %d", a, 31, 0); + $display("%b %d %d", b, 7, 0); + $display("%b %d %d", c, 3, 0); + $display("%b %d %d", d, 3, 0); + end + + parameter W = 4; + initial begin : block3 + reg [W-1:0] x, y, z; + x = 4'hA; + y = FLAG ? x : 4'hF; + z = !FLAG ? y : 4'hF; + $display("%b %d %d", x, W-1, 0); + $display("%b %d %d", y, W-1, 0); + $display("%b %d %d", z, W-1, 0); + end + + initial begin : block4 + integer w, x, z; + reg [31:0] y; + w = 1; + x = -1; + y = 32'hffff_ffff; + z = 32'shffff_ffff; + $display("%b %d %d %d", w, w, 31, 0); + $display("%b %d %d %d", x, x, 31, 0); + $display("%b %d %d %d", y, y, 31, 0); + $display("%b %d %d %d", z, z, 31, 0); + end endmodule