2017-07-26 3 views
0

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 
+1

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

Répondre

1

Je pense que vous avez fait un bon travail et que vous avez correctement corrigé les variables. Le problème est que sans flops, vous auriez une boucle. à savoir si vous écrivez quelque chose comme ce qui suit, la simulation en boucle et de silicium sera probablement brûler:

always_comb wait_count = wait_count - 1; 

Donc, vous avez besoin de mettre en scène en insérant un flop:

always_ff @(posedge clk) 
    wait_count <= wait_count - 1; 

Ou dans votre cas vous vous avez utilisé un wait_count_next intermédiaire qui est un bon style:

always_ff @(posedge clk) 
    wait_count_next <= wait_count; 
always_comb 
    wait_count = wait_count_next; 

vous pourriez peut-être ou ne pas avoir un problème avec les dernières missions. Quelle version des signaux que vous souhaitez attribuer à tx et ready? le floppé ou pas?

Et oui, vous pouvez diviser ces blocs en plusieurs blocs, mais dans ce cas, il ne semble pas nécessaire.

Et oui, l'autre style serait tout écrire dans un seul flop toujours bloquer. Mais cela réduira la lisibilité, sera plus sujet à vos erreurs et pourrait avoir des problèmes de synthèse.