SarBon88 0 3 декабря, 2022 Опубликовано 3 декабря, 2022 · Жалоба Добрый день. Пытаюсь собрать автомат универсального сдвигового регистра на Verilog. Получился вот такой код. Iverilog синтезирует и тестбенч работает корректно, но Quartus ругается на использование переменной Q в двух блоках always. Пробовал ввести дополнительную переменную вместо Q во втором блоке always (для последовательного вывода) и присвоить Q в блоке "логика автомата" ее значение, но, к сожалению, таким образом последовательный вывод перестает работать. Также попробовал еще несколько различных вариантов, но результат все тот же. Подскажите, пожалуйста, в какую сторону смотреть. Спасибо. module Universal_Shift_Register #(parameter WIDTH = 5) // параметр позволяет быстро менять разрядность входного числа (clk, res, D, out_state, Load, M, enable); localparam parall_out = 1, logic_shft_left = 2, logic_shft_right = 3, ring_shft_left = 4, ring_shft_right = 5, serial_out = 6; input [WIDTH:0] D; //Входное число input [2:0] Load; //Выбор действия input res, clk; input [WIDTH:0] M; //Количество сдвигаемых разрядов input enable; reg [WIDTH:0] Q; //Результат reg [2:0] state, next_state; output [WIDTH:0] out_state; always @(posedge clk, negedge res) begin if (!res) state <= parall_out; else state <= next_state; end always @(*) //Логика автомата case (state) parall_out: begin if(Load == 1) begin Q = D; //Параллельный вывод next_state = logic_shft_left; end else next_state = parall_out; end logic_shft_left: begin if(Load == 2) begin Q = D << M; //Логический сдвиг влево на М разрадов next_state = logic_shft_right; end else next_state = logic_shft_left; end logic_shft_right: begin if(Load == 3) begin Q = D >> M; //Логический сдвиг вправо на М разрадов next_state = ring_shft_left; end else next_state = logic_shft_right; end ring_shft_left: begin if(Load == 4) begin Q = {D[WIDTH-2:0], D[WIDTH-1]}; // Кольцевой сдвиг влево next_state = ring_shft_right; end else next_state = ring_shft_left; end ring_shft_right: begin if(Load == 5) begin Q = {D[0], D[WIDTH-1:1]}; // Кольцевой сдвиг вправо next_state = serial_out; end else next_state = ring_shft_right; end serial_out: begin if(Load == 6) // Последовательный вывод begin next_state = parall_out; end else next_state = serial_out; end default : next_state = parall_out; endcase reg [WIDTH:0]qQ; // Логика для последовательного вывода always @ (posedge clk, negedge res) // По приходу тактового импульса, в выходную переменную будет записываться [0] разряд входного числа if (!res) Q <= 0; else if (Load == 6 && enable == 1) // enable служит для разрешения записи входного числа в промежуточную REG переменную qQ qQ <= D; else if (Load == 6 && enable == 0) begin Q <= qQ[0]; // Выводим младший разряд входного числа qQ <= {qQ[0], qQ[WIDTH:1]}; // Сдвигаем входное число вправо для передачи следующего разряда end // Логика для реализации передачи результата assign out_state = Q; endmodule Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
des00 25 3 декабря, 2022 Опубликовано 3 декабря, 2022 · Жалоба Iverilog - не синтезирует, он компилирует в исполняемый симулятором код, ему без разницы физическая реализуемость. А смотреть как обычно, на бумажке разрисовать функциональную схему модуля, расставить триггеры, логику и описать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
stealthisname 7 3 декабря, 2022 Опубликовано 3 декабря, 2022 · Жалоба 2 часа назад, SarBon88 сказал: Подскажите, пожалуйста, в какую сторону смотреть можно начать c описывания и проверки упрощенной версии Вашего модуля например, если дать возможность пользователю блока самому выбирать режим работы с помощью входного порта Load, то без внутреннего состояния State, логика выхода в зависимости от выбранного режима будет предельно простой always @(*) //Логика автомата case (Load) parall_out: Q = D; //Параллельный вывод logic_shft_left: Q = D << M; //Логический сдвиг влево на М разрадов logic_shft_right: Q = D >> M; //Логический сдвиг вправо на М разрадов ring_shft_left: Q = {D[WIDTH-1:0], D[WIDTH]}; // Кольцевой сдвиг влево ring_shft_right: Q = {D[0], D[WIDTH:1]}; // Кольцевой сдвиг вправо serial_out: Q = qQ[0];// Выводим младший разряд входного числа default: Q = D; //Параллельный вывод endcase и не придётся использовать выход Q в описании работы с промежуточной переменной qQ при последовательном выводе // Логика для последовательного вывода always @ (posedge clk, negedge res) // По приходу тактового импульса, в выходную переменную будет записываться [0] разряд входного числа if (!res) qQ <= 0; else if ((Load == serial_out) && (enable == 1)) // enable служит для разрешения записи входного числа в промежуточную REG переменную qQ qQ <= D; else if ((Load == serial_out) && (enable == 0)) begin qQ <= {qQ[0], qQ[WIDTH:1]}; // Сдвигаем входное число вправо для передачи следующего разряда end весь модуль будет выглядеть так module Universal_Shift_Register #(parameter WIDTH = 5) // параметр позволяет быстро менять разрядность входного числа (clk, res, D, Load, M, enable, out_state); localparam parall_out = 1, logic_shft_left = 2, logic_shft_right = 3, ring_shft_left = 4, ring_shft_right = 5, serial_out = 6; input res, clk; input [WIDTH:0] D; //Входное число input [2:0] Load; //Выбор действия input [WIDTH:0] M; //Количество сдвигаемых разрядов input enable; output [WIDTH:0] out_state; reg [WIDTH:0] Q; //Результат reg [WIDTH:0]qQ; //Промежуточная переменная always @(*) //Логика автомата case (Load) parall_out: Q = D; //Параллельный вывод logic_shft_left: Q = D << M; //Логический сдвиг влево на М разрадов logic_shft_right: Q = D >> M; //Логический сдвиг вправо на М разрадов ring_shft_left: Q = {D[WIDTH-1:0], D[WIDTH]}; // Кольцевой сдвиг влево ring_shft_right: Q = {D[0], D[WIDTH:1]}; // Кольцевой сдвиг вправо serial_out: Q = qQ[0];// Выводим младший разряд входного числа default: Q = D; //Параллельный вывод endcase // Логика для последовательного вывода always @ (posedge clk, negedge res) // По приходу тактового импульса, в выходную переменную будет записываться [0] разряд входного числа if (!res) qQ <= 0; else if ((Load == serial_out) && (enable == 1)) // enable служит для разрешения записи входного числа в промежуточную REG переменную qQ qQ <= D; else if ((Load == serial_out) && (enable == 0)) begin qQ <= {qQ[0], qQ[WIDTH:1]}; // Сдвигаем входное число вправо для передачи следующего разряда end // Логика для реализации передачи результата assign out_state = Q; endmodule такая упрощенная версия модуля работает корректно во всех шести режимах для проверки использовался такой тестбенч: Спойлер module Universal_Shift_Register_tb(); reg clk = 0; always#(5) clk = ~clk; reg res = 0; localparam WIDTH = 5; localparam parall_out = 1, logic_shft_left = 2, logic_shft_right = 3, ring_shft_left = 4, ring_shft_right = 5, serial_out = 6; reg [WIDTH:0] D = 0; //Входное число reg [2:0] Load = 0; //Выбор действия reg [WIDTH:0] M = 0; //Количество сдвигаемых разрядов reg enable = 0; wire [WIDTH:0] out_state; initial begin #21; res = 1; // проверяем parall_out @(negedge clk); Load = parall_out; D = 59; @(negedge clk); D = 58; @(negedge clk); D = 57; // проверяем logic_shft_left @(negedge clk); Load = logic_shft_left; M = 0; @(negedge clk); M = 1; @(negedge clk); M = 2; // проверяем logic_shft_right @(negedge clk); Load = logic_shft_right; M = 0; @(negedge clk); M = 1; @(negedge clk); M = 2; // проверяем ring_shft_left @(negedge clk); Load = ring_shft_left; D = 59; @(negedge clk); D = 58; @(negedge clk); D = 57; // проверяем ring_shft_right @(negedge clk); Load = ring_shft_right; D = 59; @(negedge clk); D = 58; @(negedge clk); D = 57; // проверяем ring_shft_right @(negedge clk); Load = serial_out; enable = 1; @(negedge clk); enable = 0; end Universal_Shift_Register #(WIDTH) Universal_Shift_Register_i (clk, res, D, Load, M, enable, out_state); endmodule так как тут нет конфликта с выходом Q, то такая упрощенная версия модуля синтезируется 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SarBon88 0 3 декабря, 2022 Опубликовано 3 декабря, 2022 · Жалоба 4 часа назад, stealthisname сказал: такая упрощенная версия модуля работает корректно во всех шести режимах Добрый день! Спасибо за столь информативный ответ! Да, безусловно, так работать будет, но все же, как я понимаю, это не автомат. Собственно пробовал точно также, как у вас в примере: 6 часов назад, stealthisname сказал: serial_out: Q = qQ[0];// Выводим младший разряд входного числа только в представлении автомата, однако, в состоянии "serial out" вывод был просто 0 и автомат переходил в следующее состояние. Заменил небольшой кусочек в своем коде на этот: serial_out: begin if(Load == 6) // Последовательный вывод begin next_state = serial_out; Q = qQ[0]; end else next_state = parall_out; end И, вроде бы, сейчас все работает адекватно. Еще раз спасибо. Предстоит еще многому учится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 3 декабря, 2022 Опубликовано 3 декабря, 2022 · Жалоба Попробуйте сделать по другому. Автомат, как таковой тут и не нужен... Вам для работы сдвигового регистра нужно сделать набор входов управления, разрешающих делать загрузку, сдвиг, и пр. Для каждого действия - свой вход разрешения... опишите это как регистр, толькл if-else будет больше. и далее вставите как инстанс в проект. А в проекте в нужное время будете подавать нужный сигнал разрешения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться