Commit 011d88b5 by Zachary Snow

PackedArray conversion supports arbitrary endianness

parent f4744665
......@@ -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 =
......
......@@ -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
......
// intentionally empty
`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])
// iverilog supports multi-dimensional packed arrays
`include "flatten.sv"
`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
#!/bin/sh
NO_SEPARATE_TBS=1
source ../lib/runner.sh
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment