BaN 0 20 сентября, 2021 Опубликовано 20 сентября, 2021 · Жалоба У меня есть регистр статуса, к которому позже, возможно, нужно будет добавить еще флагов, и поэтому я хочу параметризировать размер этого регистра, чтобы вручную потом не править размер регистра и проще было править последовательность флагов в нем. Для этого я думал использовать enum для объявления флагов регистра и задать ширину регистра по количеству элементов enum: enum { STATUS_1, STATUS_2, STATUS_3 } STATUS_ENUM; logic [STATUS_ENUM.num-1:0] status; Но Quartus ругается на строку с объявлением переменной: Error: Verilog HDL error at : constant expression cannot contain a hierarchical identifier Error: Verilog HDL error at : STATUS_ENUM is not a constant Если нельзя использовать такую конструкцию, то есть какие-нибудь другие варианты реализации задачи? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 20 сентября, 2021 Опубликовано 20 сентября, 2021 · Жалоба Ошибся с кодом, забыл скобки, так работает: logic [STATUS_ENUM.num()-1:0] status; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
R6L-025 1 20 сентября, 2021 Опубликовано 20 сентября, 2021 · Жалоба Ну еще есть старый сишный трюк когда после крайнего полезного элемента перечисления вставляется еще один. Т.к. перечисление стартует с 0, то номер этого последнего элемента будет равен количеству всех элементов. Т.е. [Num0, Num1, CounOfNums]. CounOfNums будет равен 2. Что и нужно Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 20 сентября, 2021 Опубликовано 20 сентября, 2021 · Жалоба Хочу таким же способом параметризировать размер шины адреса: module tst ( // Memory mapped read/write slave interface input logic [$clog2(S_ADDR_ENUM.last())-1:0] avs_s0_address, // avs_s0.address input logic avs_s0_read, // avs_s0.read input logic avs_s0_write, // avs_s0.write output logic [S_DATA_W-1:0] avs_s0_readdata, // avs_s0.readdata input logic [S_DATA_W-1:0] avs_s0_writedata, // avs_s0.writedata input logic [(S_DATA_W/8)-1:0] avs_s0_byteenable // avs_s0.byteenable ); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; parameter S_DATA_W = 32; Но Platform Designer ругается на определение avs_s0_address: Error: Width of port avs_s0_address is invalid: (non-static) - (0) + 1 (must be an integer or parameter name) Info: s0: Ports with parameterized width: {avs_s0_address} Есть ли какие-то способы обойти это ограничение? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба Похоже, что никак это ограничение не обойти средствами Quartus, только если внешней программой парсить значения enum и подставлять в размер шины после изменения файла, но такое не портируемое решение не подходит. Придется руками каждый раз править. Само ограничение: Quote Error: Width of port <port name> is invalid: (non-static) - (0) + 1 (must be an integer or parameter name) Description You may see this error in the Quartus® II software version 12.0 or later when synthesizing your Qsys project that contains ports whose width is defined by complex arithmetic of parameter values. Workaround/Fix Only simple arithmetic of parameter values is supported for port width expressions. and bits2rep() are examples of complex functions that are not supported in hw.tcl. Although previous version of the Quartus II software did not report this error, complex functions have never been supported. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Timmy 1 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба Можно попробовать написать аналог $clog2, через define с операторами ?: внутри, возможно, прокатит за простую арифметику. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба 8 hours ago, BaN said: Хочу таким же способом параметризировать размер шины адреса: module tst ( // Memory mapped read/write slave interface input logic [$clog2(S_ADDR_ENUM.last())-1:0] avs_s0_address, // avs_s0.address input logic avs_s0_read, // avs_s0.read input logic avs_s0_write, // avs_s0.write output logic [S_DATA_W-1:0] avs_s0_readdata, // avs_s0.readdata input logic [S_DATA_W-1:0] avs_s0_writedata, // avs_s0.writedata input logic [(S_DATA_W/8)-1:0] avs_s0_byteenable // avs_s0.byteenable ); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; parameter S_DATA_W = 32; По хорошему, тип должен быть определен до использования, а не после. Да зачем вообще так делать? у вас типовой модуль, шина адреса, шина данных. Нужны уникальные константы, чтобы не назначить одинаковый адрес - ну дык глобальный тип и ссылайтесь на него как на константу, более того, никто не мешает присвоить в типе адрес и компилятор сам будет отслеживать его уникальность. А если вам просто нужна типизация - сделайте глобальный тип и положите его в глобальное простанство определений или в пакет Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 21 сентября, 2021 Опубликовано 21 сентября, 2021 (изменено) · Жалоба 1 hour ago, Timmy said: Можно попробовать написать аналог $clog2, через define с операторами ?: внутри, возможно, прокатит за простую арифметику. Не получится, там арифметика в ширине порта не то, чтобы $clog2 или ?: не поддерживает, даже сдвиг логический не поддерживает, например, (S_DATA_W>>3) вместо (S_DATA_W/8) не работает. Видимо, работают только + - / *. 1 hour ago, des00 said: Да зачем вообще так делать? Мысль у меня была такая: Например, нужно мне будет через какое-то время в этот модуль добавить еще пару регистров, добавлю я их спокойно в enum, чтобы назначились уникальные адреса: enum { S_ADDR_CTRL1, S_ADDR_CTRL2, S_ADDR_CTRL3, S_ADDR_STATUS } S_ADDR_ENUM; Но потом мне нужно будет вручную смотреть, какое там максимальное значение адреса у последнего элемента enum и вручную исправлять ширину шины адреса. А могу и забыть исправить константу и потратить потом лишнее время на исправление этой ошибки. Этого и хотелось избежать, чтобы не нужно было вручную потом править какие-то константы при добавлении новых адресов. Изменено 21 сентября, 2021 пользователем BaN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба 40 minutes ago, BaN said: Например, нужно мне будет через какое-то время в этот модуль добавить еще пару регистров, добавлю я их спокойно в enum, чтобы назначились уникальные адреса: enum { S_ADDR_CTRL1, S_ADDR_CTRL2, S_ADDR_CTRL3, S_ADDR_STATUS } S_ADDR_ENUM; Но потом мне нужно будет вручную смотреть, какое там максимальное значение адреса у последнего элемента enum и вручную исправлять ширину шины адреса. А могу и забыть исправить константу и потратить потом лишнее время на исправление этой ошибки. Этого и хотелось избежать, чтобы не нужно было вручную потом править какие-то константы при добавлении новых адресов. Ну я же вам написал, используйте типизацию в глобальном пространстве имен, в чем проблема typedef enum { pipa_addr, popa_addr, pipa_popa_addr } addr_t; module pipa (input addr_t ipopa, output logic [2 : 0] opopa); assign opopa[0] = (ipopa == pipa_addr); assign opopa[1] = (ipopa == popa_addr); assign opopa[2] = (ipopa == pipa_popa_addr); endmodule А если потом у вас появятся дырки в адресном пространстве, сделаете вот так typedef enum bit [31 : 0] { pipa_addr = 32'h00_00, popa_addr = 32'h00_10, pipa_popa_addr = 32'h10_00 } addr_t; без изменения кода. Главное, в декларации enum в глобальном пространстве, чтобы у вас потом констант с именами равными полям enum не было Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Raven 8 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба 11 hours ago, BaN said: Но Platform Designer ругается на определение avs_s0_address: Есть ли какие-то способы обойти это ограничение? А если попробовать вот так: $bits(S_ADDR_ENUM.num()) ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 21 сентября, 2021 Опубликовано 21 сентября, 2021 (изменено) · Жалоба 1 hour ago, des00 said: output logic [2 : 0] opopa Но ведь проблема та же и останется, нужно будет вручную изменять ширину шины [2:0] при добавлении элементов enum. Или я неправильно понимаю идею? 22 minutes ago, Raven said: А если попробовать вот так: Так тоже не работает, даже если там без всякой математики указать просто enum: module tst ( input logic [S_ADDR_STATUS:0] avs_s0_address, // avs_s0.address ); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; То пишет ту же ошибку, он не резолвит enum. Изменено 21 сентября, 2021 пользователем BaN Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба Приветствую! 26 minutes ago, Raven said: $bits(S_ADDR_ENUM.num()) Получите число бит в числе возвращаемого методом .num() - фактически это будет $bits(int) 12 hours ago, BaN said: Есть ли какие-то способы обойти это ограничение? Можно сначала определить разрядности и другие константы а потом уже объявит порты в старом стиле Verilog. module tst (avs_s0_address, avs_s0_read, ...); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; localparam S_ADDR_ENUM_N = $clog2(S_ADDR_ENUM.num()); // Memory mapped read/write slave interface input logic [S_ADDR_ENUM_N-1:0] avs_s0_address; // avs_s0.address input logic avs_s0_read; // avs_s0.read Либо объявить в теле модуля свою константную функцию которую использовать для задания разрядности портов, типа module tst ( // Memory mapped read/write slave interface input logic [SA_WH()-1:0] avs_s0_address, // avs_s0.address ... ); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; function int SA_WH (); return $clog2(S_ADDR_ENUM.num()); endfunctin Но тут могут быть сложности так как константность функции не всегда можно добиться. IMHO проще и правильнее все же, как и советовал @des00 выше, вынести такие определения во внешний package и использовать их по мере необходимости. Например так package tst_pkg; enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; localparam SA_N = $clog2(S_ADDR_ENUM.num()); endpackage module tst ( // Memory mapped read/write slave interface input logic [tst_pkg::SA_N-1:0] avs_s0_address, // avs_s0.address ... ); Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
BaN 0 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба 7 minutes ago, RobFPGA said: Приветствую! Получите число бит в числе возвращаемого методом .num() - фактически это будет $bits(int) Можно сначала определить разрядности и другие константы а потом уже объявит порты в старом стиле Verilog. module tst (avs_s0_address, avs_s0_read, ...); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; localparam S_ADDR_ENUM_N = $clog2(S_ADDR_ENUM.num()); // Memory mapped read/write slave interface input logic [S_ADDR_ENUM_N-1:0] avs_s0_address; // avs_s0.address input logic avs_s0_read; // avs_s0.read Либо объявить в теле модуля свою константную функцию которую использовать для задания разрядности портов, типа module tst ( // Memory mapped read/write slave interface input logic [SA_WH()-1:0] avs_s0_address, // avs_s0.address ... ); enum { S_ADDR_CTRL, S_ADDR_STATUS } S_ADDR_ENUM; function int SA_WH (); return $clog2(S_ADDR_ENUM.num()); endfunctin Но тут могут быть сложности так как константность функции не всегда можно добиться. IMHO проще и правильнее все же, как и советовал @des00 выше, вынести такие определения во внешний package и использовать их по мере необходимости Удачи! Rob. Попробовал оба варианта - та же проблема. Думаю еще над вариантом подключить свой модуль не в виде компонента в Platform Designer, а в модуле верхнего уровня в проекте и сделать определение typedef enum, чтобы оно было доступно из моего модуля и из модуля верхнего уровня проекта. И уже в модуле верхнего уровня проекта задать параметр ширины шины моего модуля на основе этого enum. Может пройдет такое. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
RobFPGA 27 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба Приветствую! 1 minute ago, BaN said: Попробовал оба варианта - та же проблема Скорее всего метод .num() не считается синтезатором константной функцией, или вообще не поддерживается при синтезе, отсюда и проблемы. Удачи! Rob. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Raven 8 21 сентября, 2021 Опубликовано 21 сентября, 2021 · Жалоба 24 minutes ago, RobFPGA said: Получите число бит в числе возвращаемого методом .num() - фактически это будет $bits(int) Ну, все же не $bits(int). Здесь мы имеем вариант применения $bits(expression) т.е., должно возвращать как раз кол-во битов, достаточное для представления результата выражения в скобках. Но, раз по словам ТС это не работает, проблема опять в особенностях/ограничениях реализации SystemVerilog в конкретном инструменте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться