mirror of https://github.com/YosysHQ/yosys.git
verilog: fix dynamic dynamic range asgn elab
This commit is contained in:
parent
90bb47d181
commit
15eb66b99d
|
@ -8,6 +8,8 @@ Yosys 0.14 .. Yosys 0.14-dev
|
|||
* Verilog
|
||||
- Fixed evaluation of constant functions with variables or arguments with
|
||||
reversed dimensions
|
||||
- Fixed elaboration of dynamic range assignments where the vector is
|
||||
reversed or is not zero-indexed
|
||||
|
||||
Yosys 0.13 .. Yosys 0.14
|
||||
--------------------------
|
||||
|
|
|
@ -2704,6 +2704,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
current_ast_mod->children.push_back(wire_data);
|
||||
|
||||
int shamt_width_hint = -1;
|
||||
bool shamt_sign_hint = true;
|
||||
shift_expr->detectSignWidth(shamt_width_hint, shamt_sign_hint);
|
||||
|
||||
AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true)));
|
||||
wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);
|
||||
wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false);
|
||||
wire_sel->is_logic = true;
|
||||
wire_sel->is_signed = shamt_sign_hint;
|
||||
while (wire_sel->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
current_ast_mod->children.push_back(wire_sel);
|
||||
|
||||
did_something = true;
|
||||
newNode = new AstNode(AST_BLOCK);
|
||||
|
||||
|
@ -2720,39 +2732,44 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
ref_data->id2ast = wire_data;
|
||||
ref_data->was_checked = true;
|
||||
|
||||
AstNode *ref_sel = new AstNode(AST_IDENTIFIER);
|
||||
ref_sel->str = wire_sel->str;
|
||||
ref_sel->id2ast = wire_sel;
|
||||
ref_sel->was_checked = true;
|
||||
|
||||
AstNode *old_data = lvalue->clone();
|
||||
if (type == AST_ASSIGN_LE)
|
||||
old_data->lookahead = true;
|
||||
|
||||
AstNode *shamt = shift_expr;
|
||||
AstNode *s = new AstNode(AST_ASSIGN_EQ, ref_sel->clone(), shift_expr);
|
||||
newNode->children.push_back(s);
|
||||
|
||||
int shamt_width_hint = 0;
|
||||
bool shamt_sign_hint = true;
|
||||
shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint);
|
||||
AstNode *shamt = ref_sel;
|
||||
|
||||
// convert to signed while preserving the sign and value
|
||||
shamt = new AstNode(AST_CAST_SIZE, mkconst_int(shamt_width_hint + 1, true), shamt);
|
||||
shamt = new AstNode(AST_TO_SIGNED, shamt);
|
||||
|
||||
// offset the shift amount by the lower bound of the dimension
|
||||
int start_bit = children[0]->id2ast->range_right;
|
||||
bool use_shift = shamt_sign_hint;
|
||||
shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true));
|
||||
|
||||
if (start_bit != 0) {
|
||||
shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true));
|
||||
use_shift = true;
|
||||
}
|
||||
// reflect the shift amount if the dimension is swapped
|
||||
if (children[0]->id2ast->range_swapped)
|
||||
shamt = new AstNode(AST_SUB, mkconst_int(source_width - result_width, true), shamt);
|
||||
|
||||
// AST_SHIFT uses negative amounts for shifting left
|
||||
shamt = new AstNode(AST_NEG, shamt);
|
||||
|
||||
AstNode *t;
|
||||
|
||||
t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false);
|
||||
if (use_shift)
|
||||
t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone()));
|
||||
else
|
||||
t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone());
|
||||
t = new AstNode(AST_SHIFT, t, shamt->clone());
|
||||
t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t);
|
||||
newNode->children.push_back(t);
|
||||
|
||||
t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone());
|
||||
if (use_shift)
|
||||
t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt));
|
||||
else
|
||||
t = new AstNode(AST_SHIFT_LEFT, t, shamt);
|
||||
t = new AstNode(AST_SHIFT, t, shamt);
|
||||
t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t);
|
||||
newNode->children.push_back(t);
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
run() {
|
||||
alt=$1
|
||||
span=$2
|
||||
left=$3
|
||||
right=$4
|
||||
echo "a=$alt s=$span l=$left r=$right"
|
||||
|
||||
../../yosys -q \
|
||||
-DALT=$alt \
|
||||
-DSPAN=$span \
|
||||
-DLEFT=$left \
|
||||
-DRIGHT=$right \
|
||||
-p "read_verilog dynamic_range_lhs.v" \
|
||||
-p "proc" \
|
||||
-p "equiv_make gold gate equiv" \
|
||||
-p "equiv_simple" \
|
||||
-p "equiv_status -assert"
|
||||
}
|
||||
|
||||
trap 'echo "ERROR in dynamic_range_lhs.sh span=$span left=$left right=$right" >&2; exit 1' ERR
|
||||
|
||||
for alt in `seq 0 1`; do
|
||||
for span in `seq 1 4`; do
|
||||
for left in `seq -4 4`; do
|
||||
for right in `seq $(expr $left + -3) $(expr $left + 3)`; do
|
||||
run $alt $span $left $right
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
|
@ -0,0 +1,76 @@
|
|||
module gate(
|
||||
output reg [`LEFT:`RIGHT] out_u, out_s,
|
||||
(* nowrshmsk = `ALT *)
|
||||
input wire data,
|
||||
input wire [1:0] sel1, sel2
|
||||
);
|
||||
always @* begin
|
||||
out_u = 0;
|
||||
out_s = 0;
|
||||
case (`SPAN)
|
||||
1: begin
|
||||
out_u[sel1*sel2] = data;
|
||||
out_s[$signed(sel1*sel2)] = data;
|
||||
end
|
||||
2: begin
|
||||
out_u[sel1*sel2+:2] = {data, data};
|
||||
out_s[$signed(sel1*sel2)+:2] = {data, data};
|
||||
end
|
||||
3: begin
|
||||
out_u[sel1*sel2+:3] = {data, data, data};
|
||||
out_s[$signed(sel1*sel2)+:3] = {data, data, data};
|
||||
end
|
||||
4: begin
|
||||
out_u[sel1*sel2+:4] = {data, data, data, data};
|
||||
out_s[$signed(sel1*sel2)+:4] = {data, data, data, data};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
||||
module gold(
|
||||
output reg [`LEFT:`RIGHT] out_u, out_s,
|
||||
input wire data,
|
||||
input wire [1:0] sel1, sel2
|
||||
);
|
||||
task set;
|
||||
input integer a, b;
|
||||
localparam LOW = `LEFT > `RIGHT ? `RIGHT : `LEFT;
|
||||
localparam HIGH = `LEFT > `RIGHT ? `LEFT : `RIGHT;
|
||||
if (LOW <= a && a <= HIGH)
|
||||
out_u[a] = data;
|
||||
if (LOW <= b && b <= HIGH)
|
||||
out_s[b] = data;
|
||||
endtask
|
||||
always @* begin
|
||||
out_u = 0;
|
||||
out_s = 0;
|
||||
case (sel1*sel2)
|
||||
2'b00: set(0, 0);
|
||||
2'b01: set(1, 1);
|
||||
2'b10: set(2, -2);
|
||||
2'b11: set(3, -1);
|
||||
endcase
|
||||
if (`SPAN >= 2)
|
||||
case (sel1*sel2)
|
||||
2'b00: set(1, 1);
|
||||
2'b01: set(2, 2);
|
||||
2'b10: set(3, -1);
|
||||
2'b11: set(4, 0);
|
||||
endcase
|
||||
if (`SPAN >= 3)
|
||||
case (sel1*sel2)
|
||||
2'b00: set(2, 2);
|
||||
2'b01: set(3, 3);
|
||||
2'b10: set(4, 0);
|
||||
2'b11: set(5, 1);
|
||||
endcase
|
||||
if (`SPAN >= 4)
|
||||
case (sel1*sel2)
|
||||
2'b00: set(3, 3);
|
||||
2'b01: set(4, 4);
|
||||
2'b10: set(5, 1);
|
||||
2'b11: set(6, 2);
|
||||
endcase
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue