Je suis un begginer de Verilog. J'ai lu plusieurs matériaux sur les styles de codage Verilog recommandés comme this paper et stackoverflow's questions.
Maintenant, j'ai appris d'eux que "deux toujours bloquer le style" est recommandé; séparer un code en deux parties, l'une est un bloc combinatoire qui modifie next
, et l'autre est un bloc séquentiel qui l'affecte à state
reg comme ceci.Comment écrire un code verilog dans un style deux-toujours-bloc avec plusieurs regs d'état?
reg [1:0] state, next;
always @(posedge clk or negedge rst_n)
if (!rst_n)
state <= IDLE;
else
state <= next;
always @(state or go or ws) begin
next = 'bx;
rd = 1'b0;
ds = 1'b0;
case (state)
IDLE : if (go) next = READ;
else next = IDLE;
...
Et voici ma question. Tous les codes d'exemple que j'ai trouvés ont seulement une paire de registres nommés state
et next
.
Cependant, s'il y a plusieurs regs qui préservent certains types d'états, comment dois-je écrire des codes dans ce style state
-et- next
?
Préparer next
regs correspondant à chacun d'eux semble un peu redondant, car tous les regs seront doublés. Par exemple, s'il vous plaît regardez un code émetteur UART de RS232c que j'ai écrit ci-dessous. Il a besoin de wait_count
, state
et send_buf
comme state
regs. Donc, j'ai écrit wait_count_next
correspondant, state_next
et send_buf_next
comme next
pour un bloc combinatoire. Cela semble un peu redondant et gênant pour moi. Y a-t-il d'autres moyens appropriés?
module uart_sender #(
parameter clock = 50_000_000,
parameter baudrate = 9600
) (
input clk,
input go,
input [7:0] data,
output tx,
output ready
);
parameter wait_time = clock/baudrate;
parameter send_ready = 10'b0000000000,
send_start = 10'b0000000001,
send_stop = 10'b1000000000;
reg [31:0] wait_count = wait_time,
wait_count_next = wait_time;
reg [9:0] state = send_ready,
state_next = send_ready;
reg [8:0] send_buf = 9'b111111111,
send_buf_next = 9'b111111111;
always @(posedge clk) begin
state <= state_next;
wait_count <= wait_count_next;
send_buf <= send_buf_next;
end
always @(*) begin
state_next = state;
wait_count_next = wait_count;
send_buf_next = send_buf;
case (state)
send_ready: begin
if (go == 1) begin
state_next = send_start;
wait_count_next = wait_time;
send_buf_next = {data, 1'b0};
end
end
default: begin
if (wait_count == 0) begin
if (state == send_stop)
state_next = send_ready;
else
state_next = {state[8:0], 1'b0};
wait_count_next = wait_time;
send_buf_next = {1'b1, send_buf[8:1]};
end
else begin
wait_count_next = wait_count - 1;
end
end
endcase
end
assign tx = send_buf[0];
assign ready = state == send_ready;
endmodule
L'idée de base de ceci est de diviser la logique en 2 parties combinatoire et séquentielle. Tout d'abord il n'y a pas de réel besoin en seulement 2 blocs. vous pouvez en avoir plus, c'est-à-dire que plusieurs blocs peuvent toujours représenter votre partie logique combinatoire. En outre, il n'y a pas besoin de flop absolument tous les signaux. Si vous construisez une machine d'état, vous avez juste besoin de flopper ses entrées ou sorties. Il n'y a pas besoin de flop d'autres signaux intermédiaires. Certaines conceptions peuvent nécessiter que vous effondriez les entrées ou les sorties du module. Donc, c'est à vous de décider où placer ces flops. – Serge