Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for unpacked structs #4180

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ Verilog Attributes and non-standard features
- The ``nowrshmsk`` attribute on a register prohibits the generation of
shift-and-mask type circuits for writing to bit slices of that register.

- The ``nordshift`` attribute on a net or variable prohibits the generation of
shift type circuits for reading bit slices from that data object.

- The ``onehot`` attribute on wires mark them as one-hot state register. This
is used for example for memory port sharing and set by the fsm_map pass.

Expand Down Expand Up @@ -604,8 +607,8 @@ from SystemVerilog:
- enums are supported (including inside packages)
- but are currently not strongly typed

- packed structs and unions are supported
- arrays of packed structs/unions are currently not supported
- structs and unions are supported
- arrays of structs/unions are currently not supported
- structure literals are currently not supported

- multidimensional arrays are supported
Expand Down
5 changes: 5 additions & 0 deletions frontends/ast/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_reg = false;
is_logic = false;
is_signed = false;
is_unpacked = false;
is_string = false;
is_enum = false;
is_wand = false;
Expand Down Expand Up @@ -340,6 +341,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
fprintf(f, " reg");
if (is_signed)
fprintf(f, " signed");
if (is_unpacked)
fprintf(f, " unpacked");
if (is_unsized)
fprintf(f, " unsized");
if (basic_prep)
Expand All @@ -363,6 +366,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
std::swap(left, right);
fprintf(f, "[%d:%d]", left, right);
}
if (unpacked_dimensions)
fprintf(f, " unpacked_dimensions=%d", unpacked_dimensions);
}
if (is_enum) {
fprintf(f, " type=enum");
Expand Down
2 changes: 1 addition & 1 deletion frontends/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ namespace AST
// node content - most of it is unused in most node types
std::string str;
std::vector<RTLIL::State> bits;
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;
bool is_input, is_output, is_reg, is_logic, is_signed, is_unpacked, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
Expand Down
104 changes: 36 additions & 68 deletions frontends/ast/genrtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1512,8 +1512,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}

// simply return the corresponding RTLIL::SigSpec for an AST_IDENTIFIER node
// for identifiers with dynamic bit ranges (e.g. "foo[bar]" or "foo[bar+3:bar]") a
// shifter cell is created and the output signal of this cell is returned
case AST_IDENTIFIER:
{
RTLIL::Wire *wire = NULL;
Expand Down Expand Up @@ -1592,8 +1590,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)

use_const_chunk:
if (children.size() != 0) {
if (children[0]->type != AST_RANGE)
input_error("Single range expected.\n");
if (children[0]->type != AST_RANGE || !children[0]->range_valid)
input_error("Single static range expected.\n");
int source_width = id2ast->range_left - id2ast->range_right + 1;
int source_offset = id2ast->range_right;
int chunk_left = source_width - 1;
Expand All @@ -1606,70 +1604,34 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk_right = chunk.offset;
}

if (!children[0]->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, 1, -1, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children();
if (member_node)
fake_ast->children[0]->set_attribute(ID::wiretype, member_node->clone());

int fake_ast_width = 0;
bool fake_ast_sign = true;
fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign);
RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign);

if (source_offset != 0) {
shift_val = current_module->Sub(NEW_ID, shift_val, source_offset, fake_ast_sign);
fake_ast->children[1]->is_signed = true;
}
if (id2ast->range_swapped) {
shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast_sign);
fake_ast->children[1]->is_signed = true;
}
if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, ID($shiftx), width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
delete right_at_zero_ast;
delete fake_ast;
return sig;
chunk.width = children[0]->range_left - children[0]->range_right + 1;
chunk.offset += children[0]->range_right - source_offset;
if (id2ast->range_swapped)
chunk.offset = source_width - (chunk.offset + chunk.width);
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
if (chunk.width == 1)
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
str.c_str());
else
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
chunk.width = children[0]->range_left - children[0]->range_right + 1;
chunk.offset += children[0]->range_right - source_offset;
if (id2ast->range_swapped)
chunk.offset = source_width - (chunk.offset + chunk.width);
if (chunk.offset > chunk_left || chunk.offset + chunk.width < chunk_right) {
if (chunk.width == 1)
log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
str.c_str());
else
log_file_warning(filename, location.first_line, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
if (chunk.offset + chunk.width - 1 > chunk_left) {
add_undef_bits_msb = (chunk.offset + chunk.width - 1) - chunk_left;
chunk.width -= add_undef_bits_msb;
}
if (chunk.offset < chunk_right) {
add_undef_bits_lsb = chunk_right - chunk.offset;
chunk.width -= add_undef_bits_lsb;
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
if (chunk.offset + chunk.width - 1 > chunk_left) {
add_undef_bits_msb = (chunk.offset + chunk.width - 1) - chunk_left;
chunk.width -= add_undef_bits_msb;
}
if (chunk.offset < chunk_right) {
add_undef_bits_lsb = chunk_right - chunk.offset;
chunk.width -= add_undef_bits_lsb;
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
log_file_warning(filename, location.first_line, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);
}
}

Expand Down Expand Up @@ -1800,11 +1762,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (0) { case AST_SHIFTX: type_name = ID($shiftx); }
if (0) { case AST_SHIFT: type_name = ID($shift); }
{
int right_width;
bool right_signed;
children[1]->detectSignWidth(right_width, right_signed);
// for ordinary shift operators, the right operand is always treated as an unsigned number,
// while the special cells $shift and $shiftx can shift both to the left (negative) and right (positive)
if (type != AST_SHIFT && type != AST_SHIFTX)
right_signed = false;
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);
// for $shift and $shiftx, the second operand can be negative
RTLIL::SigSpec right = children[1]->genRTLIL(-1, type == AST_SHIFT || type == AST_SHIFTX);
RTLIL::SigSpec right = children[1]->genRTLIL(right_width, right_signed);
int width = width_hint > 0 ? width_hint : left.size();
is_signed = children[0]->is_signed;
return binop2rtlil(this, type_name, width, left, right);
Expand Down
Loading
Loading