Support wide operands in queues and dynamic arrays (#2352)

This commit is contained in:
Vassilis Papaefstathiou 2020-05-23 21:58:45 -04:00 committed by Wilson Snyder
parent 9ffad7f0db
commit a7432bdea7
5 changed files with 109 additions and 13 deletions

View File

@ -21,6 +21,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
**** Fix $isunknown with constant Z's.
**** Fix queues and dynamic array wide ops. (#2352) [Vassilis Papaefstathiou]
* Verilator 4.034 2020-05-03

View File

@ -48,6 +48,7 @@ Tim Snyder
Tobias Rosenkranz
Tobias Wölfel
Todd Strader
Vassilis Papaefstathiou
Veripool API Bot
Wilson Snyder
Yossi Nivin

View File

@ -304,13 +304,7 @@ public:
AstAssocArrayDType* adtypep = VN_CAST(nodep->fromp()->dtypep(), AssocArrayDType);
UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type");
if (adtypep->keyDTypep()->isWide()) {
// Container class must take non-C-array (pointer) argument, so convert
putbs("VL_CVT_W_A(");
iterateAndNextNull(nodep->bitp());
puts(", ");
iterateAndNextNull(nodep->fromp());
putbs(".atDefault()"); // Not accessed; only to get the proper type of values
puts(")");
emitCvtWideArray(nodep->bitp(), nodep->fromp());
} else {
iterateAndNextNull(nodep->bitp());
}
@ -351,10 +345,21 @@ public:
bool comma = false;
for (AstNode* subnodep = nodep->pinsp(); subnodep; subnodep = subnodep->nextp()) {
if (comma) puts(", ");
iterate(subnodep);
// handle wide arguments to the queues
if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) {
emitCvtWideArray(subnodep, nodep->fromp());
} else {
iterate(subnodep);
}
comma = true;
}
puts(")");
// if there is a return value that is wide convert to array
if (nodep->dtypep()->isWide()
&& (VN_IS(nodep->fromp()->dtypep(), QueueDType)
|| VN_IS(nodep->fromp()->dtypep(), DynArrayDType))) {
puts(".data()"); // Access returned std::array as C array
}
// Some are statements some are math.
if (nodep->isStatement()) puts(";\n");
UASSERT_OBJ(!nodep->isStatement() || VN_IS(nodep->dtypep(), VoidDType), nodep,
@ -1041,6 +1046,14 @@ public:
puts(")");
}
}
void emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
putbs("VL_CVT_W_A(");
iterate(nodep);
puts(", ");
iterate(fromp);
putbs(".atDefault()"); // Not accessed; only to get the proper type of values
puts(")");
}
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) {
@ -1638,17 +1651,22 @@ class EmitCImp : EmitCStmts {
AstBasicDType* basicp = dtypep->basicp();
// Returns string to do resetting, empty to do nothing (which caller should handle)
if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) {
string cvtarray
= (adtypep->subDTypep()->isWide() ? ".data()"
: ""); // Access std::array as C array
// Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
".atDefault()" + cvtarray);
} else if (AstClassRefDType* adtypep = VN_CAST(dtypep, ClassRefDType)) {
return ""; // Constructor does it
} else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()");
// Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
".atDefault()" + cvtarray);
} else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) {
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, ".atDefault()");
// Access std::array as C array
string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1,
".atDefault()" + cvtarray);
} else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
UASSERT_OBJ(adtypep->msb() >= adtypep->lsb(), varp,
"Should have swapped msb & lsb earlier.");

View File

@ -27,6 +27,15 @@ module t (/*AUTOARG*/
byte_t a[];
byte_t b[];
// wide data array
typedef struct packed {
logic [15:0] header;
logic [223:0] payload;
logic [15:0] checksum;
} pck256_t;
pck256_t p256[];
always @ (posedge clk) begin
cyc <= cyc + 1;
begin
@ -100,6 +109,33 @@ module t (/*AUTOARG*/
`checkh(b[1], 0);
`checkh(b[2], 0);
`checkh(b[4], 0);
// test wide dynamic array
p256 = new [11];
`checkh(p256.size, 11);
`checkh(p256.size(), 11);
p256[1].header = 16'hcafe;
p256[1].payload = {14{16'hbabe}};
p256[1].checksum = 16'hdead;
`checkh(p256[1].header, 16'hcafe);
`checkh(p256[1], {16'hcafe,{14{16'hbabe}},16'hdead});
`checkh(p256[0], '0);
p256[5] = '1;
`checkh(p256[5], {32{8'hff}});
p256[5].header = 16'h2;
`checkh(p256[5], {16'h2,{30{8'hff}}});
p256[2] = ( p256[5].header == 2 ) ? p256[1] : p256[5];
`checkh(p256[2], {16'hcafe,{14{16'hbabe}},16'hdead});
p256.delete();
`checkh(p256.size, 0);
end
$write("*-* All Finished *-*\n");

View File

@ -195,6 +195,45 @@ module t (/*AUTOARG*/
end
// testing a wide queue
begin
typedef struct packed {
bit [7:0] opcode;
bit [23:0] addr;
bit [127:0] data;
} instructionW; // named structure type
instructionW inst_push;
instructionW inst_pop;
instructionW q[$];
`checkh($dimensions(q), 2);
`checkh(q[0].opcode, 0);
`checkh(q[0].addr, 0);
`checkh(q[0].data, 0);
inst_push.opcode = 1;
inst_push.addr = 42;
inst_push.data = {4{32'hdeadbeef}};
q.push_back(inst_push);
`checkh(q[0].opcode, 1);
`checkh(q[0].addr, 42);
`checkh(q[0].data, {4{32'hdeadbeef}});
inst_pop = q.pop_front();
`checkh(inst_pop.opcode, 1);
`checkh(inst_pop.addr, 42);
`checkh(inst_pop.data, {4{32'hdeadbeef}});
`checkh(q.size(), 0);
`checkh(q[0].opcode, 0);
`checkh(q[0].addr, 0);
`checkh(q[0].data, 0);
end
/* Unsup:
begin
int q[4][$];