У меня есть проблема, и у меня нет идей, как ее решить. У меня есть класс, который содержит массив с именем data
. Этот динамический массив может иметь параметризованную упакованную ширину - например, 8, 16 или 32 бита.
class MyItem#(int WIDTH=8) extends uvm_sequence_item;
bit[WIDTH-1:0] data[];
endclass
Проблема в том, что когда я хочу создать экземпляр объекта MyItem, мне нужно предоставить ему параметр. Параметр WIDTH, однако, зависит от некоторых других настроек, и для цели примера можно предположить, что он может генерироваться случайным образом в диапазоне от 8,16 до 32.
class MySequence extends uvm_sequence;
rand int width;
constraint c_width {width inside {8, 16, 32}; }
task body();
MyItem#(width) req = MyItem#(width)::type_id::create("item"); // <--- THIS IS NOT ALLOWED
endtask
endclass
Так что мне пришлось придумать способ обойти это. Один из способов - создать дескриптор внутри MyItem для всех значений ширины, а затем использовать тот, который мне нужен. Что-то с эффектом:
class MyItem extends uvm_sequence_item;
bit[ 7:0] data_08[];
bit[15:0] data_16[];
bit[23:0] data_24[];
endclass
Это позволило бы мне использовать ручку в зависимости от размера упаковки. Но это немного глупо, и я бы предпочел избегать этого, поскольку мне приходится постоянно проверять параметр WIDTH и обращаться к данным data_08, data_16 или data_24, которые раздувают код.
Другой вариант - просто использовать параметр MAX_WIDTH и дополнить биты.
class MyItem extends uvm_sequence_item;
bit[MAX_WIDTH:0] data[];
endclass
Но для очень больших массивов это пустая трата памяти и неэффективно.
Последнее решение, которое я придумала, но не работает, - это создание базового класса с именем MyItemBase, и затем Item расширяется. Так что теперь я могу (или, скорее, должен иметь) доступ к данным как просто obj_handle.data
class MyItemBase extends uvm_sequence_item;
bit data[];
endclass
class MyItem#(WIDTH) extends MyItemBase;
bit[WIDTH-1:0] data[];
endclass
Это позволяет мне использовать следующий код в моей последовательности:
rand int width;
constraint c_width {width inside {8, 16, 32}; }
task body();
MyItemBase req
case(width)
8: req = MyItem#(8)::type_id::create("item");
16: req = MyItem#(8)::type_id::create("item");
32: req = MyItem#(8)::type_id::create("item");
default: //
endcase
// Now I should be able to use req.data
req.data = new[32];
foreach(req.data[i]) req.data[i] = $urandom();
foreach(req.data[i]) $display("data[%0d] = %0x", i, data[i]);
endtask
endclass
Как вы уже догадались, это не сработало. Мой массив данных имеет ширину всего лишь один бит, и я предполагаю, что он получает его из базового класса, поэтому полиморфизм не работает для переменных так же, как для функций (если я не пропустил здесь что-то ключевое).
Теперь наличие однобитовой версии данных в классе MyItemBase вызывает ошибки компиляции, если я не приведу к производному типу. Это вызывает некоторую дополнительную сложность, и я чувствую, что перебиваю себе голову над простой проблемой.
Может кто-нибудь дать мне какие-нибудь предложения о том, как это структурировать?
Спасибо