diff --git a/src/Convert/Inside.hs b/src/Convert/Inside.hs index 410c6f9..6809f40 100644 --- a/src/Convert/Inside.hs +++ b/src/Convert/Inside.hs @@ -3,10 +3,9 @@ - - Conversion for `inside` expressions and cases - - - The expressions are compared to each candidate using the wildcard comparison - - operator. Note that if expression has any Xs or Zs that are not wildcarded in - - the candidate, the results is `1'bx`. As required by the specification, the - - result of each comparison is combined using an OR reduction. + - The expressions are compared to each candidate using `==?`, the wildcard + - comparison. As required by the specification, the result of each comparison + - is combined using an OR reduction. - - `case ... inside` statements are converted to an equivalent if-else cascade. - @@ -41,15 +40,8 @@ convertExpr (Inside expr valueRanges) = where checks = map toCheck valueRanges toCheck :: ExprOrRange -> Expr - toCheck (Left e) = - Mux - (BinOp TNe rxr lxlxrxr) - (Number "1'bx") - (BinOp WEq expr e) - where - lxl = BinOp BitXor expr expr - rxr = BinOp BitXor e e - lxlxrxr = BinOp BitXor lxl rxr + toCheck (Left pattern) = + BinOp WEq expr pattern toCheck (Right (lo, hi)) = BinOp LogAnd (BinOp Le lo expr) diff --git a/src/Convert/Wildcard.hs b/src/Convert/Wildcard.hs index aa93a81..5d9841e 100644 --- a/src/Convert/Wildcard.hs +++ b/src/Convert/Wildcard.hs @@ -4,9 +4,15 @@ - Conversion for `==?` and `!=?` - - `a ==? b` is defined as the bitwise comparison of `a` and `b`, where X and Z - - values in `b` (but not those in `a`) are used as wildcards. We convert `a ==? - - b` to `a ^ b === b ^ b`. This works because any value xor'ed with X or Z - - becomes X. + - values in `b` (but not those in `a`) are used as wildcards. This conversion + - relies on the fact that works because any value xor'ed with X or Z becomes X. + - + - Procedure for `A ==? B`: + - 1. If there is any bit in A that doesn't match a non-wildcarded bit in B, + - then the result is always `1'b0`. + - 2. If there is any X or Z in A that is not wildcarded in B, then the result + - is `1'bx`. + - 3. Otherwise, the result is `1'b1`. - - `!=?` is simply converted as the logical negation of `==?`, which is - converted as described above. @@ -25,9 +31,19 @@ convert = convertExpr :: Expr -> Expr convertExpr (BinOp WEq l r) = - BinOp TEq - (BinOp BitXor r r) - (BinOp BitXor r l) + Mux noteq (Number "1'b0") $ + Mux badxs (Number "1'bx") + (Number "1'b1") + where + lxl = BinOp BitXor l l + rxr = BinOp BitXor r r + -- Step #1: definitive mismatch + noteq = BinOp TNe rxlxl lxrxr + rxlxl = BinOp BitXor r lxl + lxrxr = BinOp BitXor l rxr + -- Step #2: extra X or Z + badxs = BinOp TNe lxlxrxr rxr + lxlxrxr = BinOp BitXor lxl rxr convertExpr (BinOp WNe l r) = UniOp LogNot $ convertExpr $ diff --git a/test/basic/inside_exhaust.sv b/test/basic/inside_exhaust.sv new file mode 100644 index 0000000..669cef0 --- /dev/null +++ b/test/basic/inside_exhaust.sv @@ -0,0 +1,20 @@ +module Suite; + parameter WIDTH = 1; + `include "inside_exhaust.vh" + + function [0:0] test_weq; + input [WIDTH-1:0] x, y; + return x ==? y; + endfunction + + function [0:0] test_inside; + input [WIDTH-1:0] x, y, z; + return x inside {y, z}; + endfunction +endmodule + +module top; + Suite #(1) a(); + Suite #(2) b(); + Suite #(3) c(); +endmodule diff --git a/test/basic/inside_exhaust.v b/test/basic/inside_exhaust.v new file mode 100644 index 0000000..cebc757 --- /dev/null +++ b/test/basic/inside_exhaust.v @@ -0,0 +1,33 @@ +module Suite; + parameter WIDTH = 1; + `include "inside_exhaust.vh" + + function [0:0] test_weq; + input [WIDTH-1:0] x, y; + integer idx; + begin + test_weq = 1'b1; + for (idx = 0; idx < WIDTH; idx = idx + 1) begin + if (y[idx] === 1'bx || y[idx] === 1'bz) + ; + else if (x[idx] === 1'bx || x[idx] === 1'bz) + test_weq = 1'bx; + else if (y[idx] !== x[idx]) begin + test_weq = 1'b0; + idx = WIDTH; + end + end + end + endfunction + + function [0:0] test_inside; + input [WIDTH-1:0] x, y, z; + test_inside = |{test_weq(x, y), test_weq(x, z)}; + endfunction +endmodule + +module top; + Suite #(1) a(); + Suite #(2) b(); + Suite #(3) c(); +endmodule diff --git a/test/basic/inside_exhaust.vh b/test/basic/inside_exhaust.vh new file mode 100644 index 0000000..aa40edb --- /dev/null +++ b/test/basic/inside_exhaust.vh @@ -0,0 +1,44 @@ +function [WIDTH-1:0] incr; + input [WIDTH-1:0] inp; + reg carry; + integer idx; + begin + carry = 1; + idx = 0; + while (carry) begin + carry = 0; + if (inp[idx] === 1'b0) + inp[idx] = 1'b1; + else if (inp[idx] === 1'b1) + inp[idx] = 1'bx; + else if (inp[idx] === 1'bx) + inp[idx] = 1'bz; + else begin + inp[idx] = 1'b0; + idx = idx + 1; + carry = idx < WIDTH; + end + end + incr = inp; + end +endfunction + +reg [WIDTH-1:0] a, b, c; +initial begin : x + integer i, j, k; + a = 0; b = 0; c = 0; + + for (i = 0; i < 4**WIDTH; ++i) begin + for (j = 0; j < 4**WIDTH; ++j) begin + $display("%b ==? %b = 1'b%b", + a, b, test_weq(a, b)); + for (k = 0; k < 4**WIDTH; ++k) begin + $display("%b inside {%b, %b} = 1'b%b", + a, b, c, test_inside(a, b, c)); + c = incr(c); + end + b = incr(b); + end + a = incr(a); + end +end