From 011d88b5441af538c824d6270c8b5ae96ff95763 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 4 Apr 2019 19:40:19 -0400 Subject: [PATCH] PackedArray conversion supports arbitrary endianness --- src/Convert/PackedArray.hs | 56 +++++++++---- src/Language/SystemVerilog/AST/Expr.hs | 20 +++++ test/basic/enum_tb.v | 1 + test/basic/flatten.sv | 104 +++++++++++++++++++++++++ test/basic/flatten.v | 2 + test/basic/flatten_tb.v | 34 ++++++++ test/basic/run.sh | 1 - 7 files changed, 200 insertions(+), 18 deletions(-) create mode 100644 test/basic/enum_tb.v create mode 100644 test/basic/flatten.sv create mode 100644 test/basic/flatten.v create mode 100644 test/basic/flatten_tb.v diff --git a/src/Convert/PackedArray.hs b/src/Convert/PackedArray.hs index 782f592..5033f81 100644 --- a/src/Convert/PackedArray.hs +++ b/src/Convert/PackedArray.hs @@ -22,16 +22,13 @@ - Note: We don't count usages with an index in expressions as such, as those - usages could be equivalently converted to range accesses with some added in - multiplication. - - - - TODO: This assumes that the first range index is the upper bound. We could - - probably get around this with some cleverness in the generate block. I don't - - think it's urgent to have support for "backwards" ranges. -} module Convert.PackedArray (convert) where import Control.Monad.State import Data.List (partition) +import Data.Tuple (swap) import qualified Data.Set as Set import qualified Data.Map.Strict as Map @@ -186,18 +183,20 @@ flattenModuleItem _ other = other -- produces `generate` items for creating an unflattened copy of the given -- flattened, packed array unflattener :: Bool -> Identifier -> (Type, Range) -> [GenItem] -unflattener writeToFlatVariant arr (t, (majorHi, majorLo)) = +unflattener writeToFlatVariant arr (t, major @ (majorHi, majorLo)) = [ GenModuleItem $ MIPackageItem $ Comment $ "sv2v packed-array-flatten unflattener for " ++ arr , GenModuleItem $ MIDecl $ Variable Local t arrUnflat [(majorHi, majorLo)] Nothing , GenModuleItem $ Genvar index , GenModuleItem $ MIDecl $ Variable Local (IntegerAtom TInteger Unspecified) (arrUnflat ++ "_repeater_index") [] Nothing , GenFor (index, majorLo) - (BinOp Le (Ident index) majorHi) - (index, AsgnOp Add, Number "1") + (ccExpr major + (BinOp Le (Ident index) majorHi) + (BinOp Ge (Ident index) majorHi)) + (index, AsgnOp Add, ccExpr major (Number "1") (Number "-1")) (Just $ prefix "unflatten_" ++ arr) [ localparam startBit - (simplify $ BinOp Add majorLo + (simplify $ BinOp Add (ccExpr major majorLo majorHi) (BinOp Mul (Ident index) size)) , GenModuleItem $ (uncurry $ Assign Nothing) $ if not writeToFlatVariant @@ -209,13 +208,23 @@ unflattener writeToFlatVariant arr (t, (majorHi, majorLo)) = startBit = prefix "_tmp_start_" ++ arr arrUnflat = prefix arr index = prefix "_tmp_index_" ++ arr - (minorHi, minorLo) = head $ snd $ typeRanges t - size = rangeSize (minorHi, minorLo) + minor = head $ snd $ typeRanges t + size = rangeSize $ ccRange minor minor (swap minor) localparam :: Identifier -> Expr -> GenItem localparam x v = GenModuleItem $ MIDecl $ Localparam (Implicit Unspecified []) x v - origRange = ( (BinOp Add (Ident startBit) + origRangeAg = ( (BinOp Add (Ident startBit) (BinOp Sub size (Number "1"))) - , Ident startBit ) + , Ident startBit ) + origRange = ccRange major origRangeAg (swap origRangeAg) + +ccExpr :: Range -> Expr -> Expr -> Expr +ccExpr r e1 e2 = simplify $ Mux (uncurry (BinOp Ge) r) e1 e2 + +ccRange :: Range -> Range -> Range -> Range +ccRange r r1 r2 = + ( ccExpr r (fst r1) (fst r2) + , ccExpr r (snd r1) (snd r2) + ) typeIsImplicit :: Type -> Bool typeIsImplicit (Implicit _ _) = True @@ -232,13 +241,26 @@ flattenRanges rs = then rs' else error $ "flattenRanges on too small list: " ++ (show rs) where - (s1, e1) = head rs - (s2, e2) = head $ tail rs + r1 = head rs + r2 = head $ tail rs + rYY = flattenRangesHelp r1 r2 + rYN = flattenRangesHelp r1 (swap r2) + rNY = flattenRangesHelp (swap r1) r2 + rNN = flattenRangesHelp (swap r1) (swap r2) + rY = ccRange r2 rYY rYN + rN = ccRange r2 rNY rNN + rAg = ccRange r1 rY rN + r = ccRange r1 rAg (swap rAg) + rs' = (tail $ tail rs) ++ [r] + +flattenRangesHelp :: Range -> Range -> Range +flattenRangesHelp (s1, e1) (s2, e2) = + (simplify upper, simplify lower) + where size1 = rangeSize (s1, e1) size2 = rangeSize (s2, e2) - upper = BinOp Add (BinOp Mul size1 size2) (BinOp Sub e1 (Number "1")) - r' = (simplify upper, e1) - rs' = (tail $ tail rs) ++ [r'] + lower = BinOp Add e1 (BinOp Mul e2 size2) + upper = BinOp Add (BinOp Mul size1 size2) (BinOp Sub lower (Number "1")) rewriteModuleItem :: Info -> ModuleItem -> ModuleItem rewriteModuleItem info = diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index f0498e3..92bb868 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -90,6 +90,22 @@ showRange (h, l) = printf "[%s:%s]" (show h) (show l) -- basic expression simplfication utility to help us generate nicer code in the -- common case of ranges like `[FOO-1:0]` simplify :: Expr -> Expr +simplify (Mux (BinOp Ge c1 c2) e1 e2) = + case (c1', c2') of + (Number a, Number b) -> + case (readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of + (Just x, Just y) -> + if x >= y + then e1 + else e2 + _ -> nochange + _ -> nochange + where + c1' = simplify c1 + c2' = simplify c2 + e1' = simplify e1 + e2' = simplify e2 + nochange = Mux (BinOp Ge c1' c2') e1' e2' simplify (BinOp op e1 e2) = case (op, e1', e2') of (Add, Number "0", e) -> e @@ -103,6 +119,10 @@ simplify (BinOp op e1 e2) = (Sub, Just x, Just y) -> Number $ show (x - y) (Mul, Just x, Just y) -> Number $ show (x * y) _ -> BinOp op e1' e2' + (Add, BinOp Add e (Number a), Number b) -> + case (readMaybe a :: Maybe Int, readMaybe b :: Maybe Int) of + (Just x, Just y) -> BinOp Add e $ Number $ show (x + y) + _ -> BinOp op e1' e2' _ -> BinOp op e1' e2' where e1' = simplify e1 diff --git a/test/basic/enum_tb.v b/test/basic/enum_tb.v new file mode 100644 index 0000000..d11c69f --- /dev/null +++ b/test/basic/enum_tb.v @@ -0,0 +1 @@ +// intentionally empty diff --git a/test/basic/flatten.sv b/test/basic/flatten.sv new file mode 100644 index 0000000..4b52b8a --- /dev/null +++ b/test/basic/flatten.sv @@ -0,0 +1,104 @@ +`define CASE_A(name, dims) \ +module name(clock, in, out); \ + input wire clock, in; \ + output logic dims out; \ + initial out[0] = 0; \ + initial out[1] = 0; \ + initial out[2] = 0; \ + always @(posedge clock) begin \ + \ + out[2][4] = out[2][3]; \ + out[2][3] = out[2][2]; \ + out[2][2] = out[2][1]; \ + out[2][1] = out[2][0]; \ + out[2][0] = out[1][4]; \ + \ + out[1][4] = out[1][3]; \ + out[1][3] = out[1][2]; \ + out[1][2] = out[1][1]; \ + out[1][1] = out[1][0]; \ + out[1][0] = out[0][4]; \ + \ + out[0][4] = out[0][3]; \ + out[0][3] = out[0][2]; \ + out[0][2] = out[0][1]; \ + out[0][1] = out[0][0]; \ + out[0][0] = in; \ + \ + end \ +endmodule + +`CASE_A(A1, [2:0][4:0]) +`CASE_A(A2, [0:2][0:4]) +`CASE_A(A3, [0:2][4:0]) +`CASE_A(A4, [2:0][0:4]) + +`define CASE_B(name, dims) \ +module name(clock, in, out); \ + input wire clock, in; \ + output logic dims out; \ + initial out[1] = 0; \ + initial out[2] = 0; \ + initial out[3] = 0; \ + always @(posedge clock) begin \ + \ + out[3][5] = out[3][4]; \ + out[3][4] = out[3][3]; \ + out[3][3] = out[3][2]; \ + out[3][2] = out[3][1]; \ + out[3][1] = out[2][5]; \ + \ + out[2][5] = out[2][4]; \ + out[2][4] = out[2][3]; \ + out[2][3] = out[2][2]; \ + out[2][2] = out[2][1]; \ + out[2][1] = out[1][5]; \ + \ + out[1][5] = out[1][4]; \ + out[1][4] = out[1][3]; \ + out[1][3] = out[1][2]; \ + out[1][2] = out[1][1]; \ + out[1][1] = in; \ + \ + end \ +endmodule + +`CASE_B(B1, [3:1][5:1]) +`CASE_B(B2, [1:3][1:5]) +`CASE_B(B3, [1:3][5:1]) +`CASE_B(B4, [3:1][1:5]) + +`define CASE_C(name, dims) \ +module name(clock, in, out); \ + input wire clock, in; \ + output logic dims out; \ + initial out[2] = 0; \ + initial out[3] = 0; \ + initial out[4] = 0; \ + always @(posedge clock) begin \ + \ + out[4][6] = out[4][5]; \ + out[4][5] = out[4][4]; \ + out[4][4] = out[4][3]; \ + out[4][3] = out[4][2]; \ + out[4][2] = out[3][6]; \ + \ + out[3][6] = out[3][5]; \ + out[3][5] = out[3][4]; \ + out[3][4] = out[3][3]; \ + out[3][3] = out[3][2]; \ + out[3][2] = out[2][6]; \ + \ + out[2][6] = out[2][5]; \ + out[2][5] = out[2][4]; \ + out[2][4] = out[2][3]; \ + out[2][3] = out[2][2]; \ + out[2][2] = in; \ + \ + end \ +endmodule + +`CASE_C(C1, [4:2][6:2]) +`CASE_C(C2, [2:4][2:6]) +`CASE_C(C3, [2:4][6:2]) +`CASE_C(C4, [4:2][2:6]) diff --git a/test/basic/flatten.v b/test/basic/flatten.v new file mode 100644 index 0000000..2c7a10a --- /dev/null +++ b/test/basic/flatten.v @@ -0,0 +1,2 @@ +// iverilog supports multi-dimensional packed arrays +`include "flatten.sv" diff --git a/test/basic/flatten_tb.v b/test/basic/flatten_tb.v new file mode 100644 index 0000000..a9da44f --- /dev/null +++ b/test/basic/flatten_tb.v @@ -0,0 +1,34 @@ +`define FOO(tag) \ + wire [14:0] tag``one_out, tag``two_out, tag``thr_out, tag``fou_out; \ + tag``1 tag``one(.clock(clock), .in(in), .out(tag``one_out)); \ + tag``2 tag``two(.clock(clock), .in(in), .out(tag``two_out)); \ + tag``3 tag``thr(.clock(clock), .in(in), .out(tag``thr_out)); \ + tag``4 tag``fou(.clock(clock), .in(in), .out(tag``fou_out)); \ + initial begin \ + $monitor(`"tag", $time, ": %h %15b %15b %15b %15b", in, \ + tag``one_out, tag``two_out, tag``thr_out, tag``fou_out); \ + end + +module top; + reg clock, in; + + initial begin + clock = 1; + forever #1 clock = ~clock; + end + + integer i; + localparam [20:0] pattern = 20'b01101100001010101100; + initial begin + for (i = 0; i < 20; i++) begin + in = pattern[i]; + #2; + end + $finish; + end + + `FOO(A) + `FOO(B) + `FOO(C) + +endmodule diff --git a/test/basic/run.sh b/test/basic/run.sh index 0dc63aa..8f8457f 100755 --- a/test/basic/run.sh +++ b/test/basic/run.sh @@ -1,3 +1,2 @@ #!/bin/sh -NO_SEPARATE_TBS=1 source ../lib/runner.sh