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);
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);
--- /dev/null
+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