Search code examples
verilogsystem-verilogclockhdl

clock gating verilog code not working correctly


I'm to trying to code a clock gating logic that allows data to pass only at the posedge write_clk_en. the code is compiled correctly in EDA playground but the output is not as intended.So according to code,

@ (posedge write_clk_en)begin
 data_in[3] <= 1'b1;
end

at this instance the write_clk_en is disabled, so data_in[3] NBA should be halted and it waits for next valid posedge (which is the next posedge of write_clk_en here), data_in[3] should be written. But that is not happening, rather the gated clock period is also getting considered and the NBA assignment is occurring even when write_clk_en is gated for 4th pulse.What could be the issue ?.the wave form is shown here.

enter image description here

the sv code :

module tb;

logic [4:0]  data_in;
logic  write_clk;
logic  write_clk_en;
logic write_clk_mod;  
logic [5:0] write_clk_init;

always//write_clk 500M
  begin
        write_clk  =0;
    #10 write_clk = 1;
    #10 write_clk = 0;
  end


initial begin
  $dumpfile("dump.vcd");
  $dumpvars;
  #10000 $finish;
end  

initial begin
data_in=5'b00000;
write_clk_init = 6'b000000;
write_clk_mod=0;
end

initial begin
write_clk_init =6'b110111;
end

initial begin
repeat (3) begin
@(posedge write_clk)begin
if(write_clk_init[0]==1 || write_clk_init[0]==0)
write_clk_mod<=write_clk_init[0];
end
@(posedge write_clk)begin
if(write_clk_init[1]==1 || write_clk_init[1]==0)
write_clk_mod<=write_clk_init[1];
end
@(posedge write_clk)begin
if(write_clk_init[2]==1 || write_clk_init[2]==0)
write_clk_mod<=write_clk_init[2];
end
@(posedge write_clk)begin
if(write_clk_init[3]==1 || write_clk_init[3]==0)
write_clk_mod<=write_clk_init[3];
end
@(posedge write_clk)begin
if(write_clk_init[4]==1 || write_clk_init[4]==0)
write_clk_mod<=write_clk_init[4];
end
@(posedge write_clk)begin
if(write_clk_init[5]==1 || write_clk_init[5]==0)
write_clk_mod<=write_clk_init[5];
end
end
end

  always @ (*) begin 
  write_clk_en  = write_clk & write_clk_mod;
end

initial begin 

@ (posedge write_clk_en)begin
data_in[0] <= 1'b1;
end
@ (posedge write_clk_en)begin
data_in[1] <= 1'b1;
end
@ (posedge write_clk_en)begin
 data_in[2] <= 1'b1;
 end
@ (posedge write_clk_en)begin
 data_in[3] <= 1'b1;
end
@ (posedge write_clk_en)begin
data_in[4] <= 1'b1;
end

end


endmodule

Solution

  • Within initial blocks, change your NBAs to BAs. NBAs should only be used within an always @(posedge clocksignal) block

    Take also into account that in simulations, @(posedge clocksignal) blocks (without the reserved word always) are treated as delays (wait until a rising edge clk event happens, then continue simulation). By the way you have written these blocks in your initial statements, I didn't know for sure if you were aware of their true behaviour. I've rewritten those @(posedge) blocks to make the simulation flow a bit clear.

    I have also merged some of your initial blocks into one. Every initial block you have is started at the same time (simulation time 0). Particulary, write_clk_init is assigned in two different initial blocks.

    This edited code works as expected. It is also available at https://www.edaplayground.com/x/3VYk

    OpenWavwe output

    module tb;
      reg [4:0]  data_in;
      reg  write_clk;
      reg  write_clk_en;
      reg write_clk_mod;  
      reg [5:0] write_clk_init;
    
      initial begin
        $dumpfile("dump.vcd");
        $dumpvars;
        #10000 $finish;
      end  
    
      initial begin
        data_in = 5'b00000;
        write_clk_init = 6'b110111;
        write_clk_mod = 0;
        write_clk = 0;
    
        repeat (3) begin
          @(posedge write_clk);
          if(write_clk_init[0]==1 || write_clk_init[0]==0)
              write_clk_mod = write_clk_init[0];
    
          @(posedge write_clk);
          if(write_clk_init[1]==1 || write_clk_init[1]==0)
              write_clk_mod = write_clk_init[1];
    
          @(posedge write_clk);
          if(write_clk_init[2]==1 || write_clk_init[2]==0)
              write_clk_mod = write_clk_init[2];
    
          @(posedge write_clk);
          if(write_clk_init[3]==1 || write_clk_init[3]==0)
              write_clk_mod = write_clk_init[3];
    
          @(posedge write_clk);
          if(write_clk_init[4]==1 || write_clk_init[4]==0)
              write_clk_mod = write_clk_init[4];
    
          @(posedge write_clk);
          if(write_clk_init[5]==1 || write_clk_init[5]==0)
              write_clk_mod = write_clk_init[5];
        end
      end
    
      always @* begin 
        write_clk_en  = write_clk & write_clk_mod;
      end
    
      initial begin 
        @(posedge write_clk_en);
        data_in[0] = 1'b1;
    
        @(posedge write_clk_en);
        data_in[1] = 1'b1;
    
        @(posedge write_clk_en);
        data_in[2] = 1'b1;
    
        @(posedge write_clk_en);
        data_in[3] = 1'b1;
    
        @(posedge write_clk_en);
        data_in[4] = 1'b1;
      end
    
      always begin
        write_clk = #10 ~write_clk;
      end      
    endmodule