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)
(ccExpr major
(BinOp Le (Ident index) majorHi)
(index, AsgnOp Add, Number "1")
(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 )
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