Asigment Verilog y replicación, ¿Qué hace el paréntesis?

0

Estoy tratando de entender el siguiente ejemplo de código de Verilog, hasta ahora puedo decir que si address == 0 entonces realice el & con data_in o si es 1 realiza bit -wise & con data_dir . Lo que ocurre aquí es que no estoy seguro de si esos paréntesis implican condicionales y por qué está utilizando la replicación por 1 para convertir vector a entero si este es el caso. Gracias de antemano.

  ....
module DE1_SoC_QSYS_i2c_sda (
                              // inputs:
                               address,
                               chipselect,
                               clk,
                               reset_n,
                               write_n,
                               writedata,

                              // outputs:
                               bidir_port,
                               readdata
                            )
;

  inout            bidir_port;
  output  [ 31: 0] readdata;
  input   [  1: 0] address;
  input            chipselect;
  input            clk;
  input            reset_n;
  input            write_n;
  input   [ 31: 0] writedata;

  wire             bidir_port;
  wire             clk_en;
  reg              data_dir;
  wire             data_in;
  reg              data_out;
  wire             read_mux_out;
  reg     [ 31: 0] readdata;
  assign clk_en = 1;
  //s1, which is an e_avalon_slave
  assign read_mux_out = ({1 {(address == 0)}} & data_in) |
    ({1 {(address == 1)}} & data_dir);

  always @(posedge clk or negedge reset_n)
    begin
      if (reset_n == 0)
          readdata <= 0;
      else if (clk_en)
          readdata <= {32'b0 | read_mux_out};
    end


  always @(posedge clk or negedge reset_n)
    begin
      if (reset_n == 0)
          data_out <= 0;
      else if (chipselect && ~write_n && (address == 0))
          data_out <= writedata;
    end


  assign bidir_port = data_dir ? data_out : 1'bZ;
  assign data_in = bidir_port;
  always @(posedge clk or negedge reset_n)
    begin
      if (reset_n == 0)
          data_dir <= 0;
      else if (chipselect && ~write_n && (address == 1))
          data_dir <= writedata;
    end



endmodule
  ....
    
pregunta luffyKun

2 respuestas

1

Ok, wow, eso es un poco de código feo.

Básicamente hace lo siguiente:

assign read_mux_out = (address == 0) ? data_in : ((address == 1) ? data_dir : 0);

Esperemos que sea un poco más claro. No es más que un par de multiplexores anidados.

Cuando address es 0, read_mux_out será igual a data_in .
Si address es 1, read_mux_out será igual a data_dir .
De lo contrario, read_mux_out será 0.

Sin embargo, es probable que todavía esté más limpio para redefinir read_mux_out como tipo reg , y usar una simple declaración case :

always @ * begin
    case (address)
        2'd0:   read_mux_out = data_in;
        2'd1:   read_mux_out = data_mux;
        default: read_mux_out = 0;
    endcase
end

Como parte, la única razón que puedo ver para usar la replicación en ese ejemplo es que probablemente es un código generado desde algún generador de núcleo IP que debe generalizarse. Si genera el ancho de datos como un bus de múltiples bits, el número de replicación se cambiará para que coincida con el ancho de los datos.

Sin embargo, realmente no sé por qué hicieron las cosas a un nivel tan bajo al usar un operador ternario simple y claro para leer que funcionaría igual de bien.

    
respondido por el Tom Carpenter
2

{1 {(address == 0)}} es inusualmente porque no hay replicación. Fácilmente podría escribirse como (address == 0) y tener el mismo resultado. Una forma más legible sería:

assign read_mux_out = (address == 0) ? data_in : (address == 1) ? data_dir : 1'b0;

Mi conjetura por qué fue escrito de esta manera:

  • En algún momento en el tiempo (o anticipándose en el futuro) data_in y data_dir fueron (o pueden convertirse) vectores de múltiples bits. En cuyo caso se utiliza para facilitar el escalado. Pero si lo escribiera de esta manera para futuras pruebas, usaría un parámetro
  • El autor mantiene un estilo de codificación. No puedo ver el resto del código, pero quizás haya lugares donde el replicador tenga sentido.

La única razón racional por la que puedo pensar por qué el autor usa operaciones bitwise ( & , | ) de hecho de los operadores condicionales ( ?: ) es si el sintetizador de destino ha optimizado pobremente los operadores condicionales (lo he visto incluso en algunos sintetizadores modernos de gama alta) y es una ruta de datos crítica. Hay maneras definitivamente más limpias de escribir el código.

    
respondido por el Greg

Lea otras preguntas en las etiquetas