Kraklog

Day.82 Advanced Verilog #5 본문

[Harman] 하만 반도체 설계/VerilogHDL

Day.82 Advanced Verilog #5

Krakens 2023. 11. 15. 17:05
728x90

클럭 도메인이 안맞을때도 사용가능하지만

이 기능을 사용하지 않고는 뒤에 로직이 하나 더 붙는다.
(동작을 하지 않는 것은 아님)

read enable 신호때 생성을 하게 만들거나

aclr에 asynchornous 를 해주는 세팅을 할 수 있게 하거나 

이것에 대한 순서를 정할 수 있다.

 

module sp_ram_sync_rdwo(
  input             clk   ,
  input             we    ,
  input       [7:0] d     ,
  input       [6:0] addr  ,
  output reg  [7:0] q      
);
  
  reg [7:0] mem [0:127];
  
  always @ (posedge clk) begin
    if(we)
      mem[addr] <= d;
    q <= mem[addr];
  end

endmodule



`define CLK_50Mhz 10

module tb_sp_ram_sync_rdwo();
  reg           clk   ;
  reg           we    ;
  reg     [7:0] d     ;
  reg     [6:0] addr  ;
  wire    [7:0] q     ;

sp_ram_sync_rdwo uSp_ram_sync_rdwo (
  .clk (clk )  ,
  .we  (we  )  ,
  .d   (d   )  ,
  .addr(addr)  ,
  .q   (q   )   
);

initial fork
    clk_gen();
    reset_gen();
    data_gen();
    ctrl_gen();
  join

 
  task clk_gen;
    begin
      clk = 1'b0;
      forever #(`CLK_50Mhz/2) clk=~clk;
    end
  endtask

  task reset_gen();
    begin
      addr=6'b0;
      forever #(`CLK_50Mhz*2) addr=addr+1'b1;
    end
  endtask

  task data_gen;
    begin
      d = 8'hA17;
      forever #(`CLK_50Mhz*5) d = d+1;
    end
  endtask

  task ctrl_gen;
   begin
    we = 1'b0;
    forever #(`CLK_50Mhz*3) we = ~we;
   end 
  endtask

endmodule

module sp_ram_sync_rdwo2(
  input             clk   ,
  input             we    ,
  input       [7:0] d     ,
  input       [6:0] addr  ,
  output reg  [7:0] q      
);
  
  reg [7:0] mem [0:2**8-1];
  
  always @ (posedge clk) begin
    if(we)
      mem[addr] <= d;
    q <= mem[addr];
  end

  //실제로 동작이
  /*
  always @(posedge clk) begin
    if (we)
    mem [addr]  <= d;
    end

    always @(posedge clk) begin
      q <= mem [addr];
    end
  //처럼 동작한다.
  */

  //else가 있다면
 /* always @(posedge clk) 
  begin
    if (we)
      mem[addr] <= d;
    else
     q <= mem[addr];
  end
  이렇게 있으면 we가 1일때 else 전까지만 동작하고 동작하지 않기 때문에 
  else가 없는구문이 맞다.
*/
endmodule

`timescale  1ns/ 1ns
`define CLK_50Mhz 20
`define DBUS_SIZE 8
`define SBUS_SIZE 7 

module tb_sp_ram_sync_rdwo2();
  reg                       clk   ;
  reg                       we    ;
  reg     [`DBUS_SIZE-1:0]  d     ;
  reg     [`SBUS_SIZE-1:0]  addr  ;
  wire    [`DBUS_SIZE-1:0]  q     ;

sp_ram_sync_rdwo2 uSp_ram_sync_rdwo (
  .clk (clk )  ,
  .we  (we  )  ,
  .d   (d   )  ,
  .addr(addr)  ,
  .q   (q   )   
);

initial fork
    clk_gen();
    reset_gen();
    data_gen();
    ctrl_gen();
  join

 
  task clk_gen;
    begin
      clk = 1'b0;
      forever #(`CLK_50Mhz/2) clk=~clk;
    end
  endtask

  task reset_gen();
    begin
    addr = 7'h00;
    repeat(3) @(negedge clk);
    addr = 7'h05;
    @(negedge clk);
    addr = 7'h06;
    @(negedge clk);
    addr = 7'h05;
    @(negedge clk);
    addr = 7'h6;
    @(negedge clk);
    
    end
  endtask

  task data_gen;
    begin
      d=8'hAA;
      repeat(5) @(negedge clk);
      d=8'h55;
      repeat(2) @(negedge clk);
      d=8'hf7;
      
    end
  endtask

  task ctrl_gen;
   begin
   we = 1'b0;
   repeat(5) @(negedge clk);
   we = 1'b1;
   end 
  endtask

endmodule

without else
with else

else를 적어주면 q에 데이터가 wirte 되질 않는다.

-Old Data가 나오는 셋팅

module sp_ram_sync_rdwo2(
  input             clk   ,
  input             we    ,
  input       [7:0] d     ,
  input       [6:0] addr  ,
  output reg  [7:0] q      
);
  
  reg [7:0] mem [0:2**8-1];
  
  always @ (posedge clk) begin
    if(we)
      mem[addr] = d; //blocking
    q = mem[addr];  //blocking
  end

endmodule

`timescale  1ns/ 1ns
`define CLK_50Mhz 20
`define DBUS_SIZE 8
`define SBUS_SIZE 7 

module tb_sp_ram_sync_rdwo2();
  reg                       clk   ;
  reg                       we    ;
  reg     [`DBUS_SIZE-1:0]  d     ;
  reg     [`SBUS_SIZE-1:0]  addr  ;
  wire    [`DBUS_SIZE-1:0]  q     ;

sp_ram_sync_rdwo2 uSp_ram_sync_rdwo (
  .clk (clk )  ,
  .we  (we  )  ,
  .d   (d   )  ,
  .addr(addr)  ,
  .q   (q   )   
);

initial fork
    clk_gen();
    reset_gen();
    data_gen();
    ctrl_gen();
  join

 
  task clk_gen;
    begin
      clk = 1'b0;
      forever #(`CLK_50Mhz/2) clk=~clk;
    end
  endtask

  task reset_gen();
    begin
    addr = 7'h00;
    repeat(3) @(negedge clk);
    addr = 7'h05;
    @(negedge clk);
    addr = 7'h06;
    @(negedge clk);
    addr = 7'h05;
    @(negedge clk);
    addr = 7'h6;
    @(negedge clk);
    
    end
  endtask

  task data_gen;
    begin
      d=8'hAA;
      repeat(5) @(negedge clk);
      d=8'h55;
      repeat(2) @(negedge clk);
      d=8'hf7;
      
    end
  endtask

  task ctrl_gen;
   begin
   we = 1'b0;
   repeat(5) @(negedge clk);
   we = 1'b1;
   end 
  endtask

endmodule

blocking type
non blocking


blocking - > Immediately

unblocking -> scheduled 

 

f7이 업데이트 되는 속도의 차이가 보인다.

 

 

module dp_dc_ram (
  input       [7:0]   data_a  ,
  input       [7:0]   data_b  ,
  input       [6:0]   addr_a  ,
  input       [6:0]   addr_b  ,
  input               clk_a   ,
  input               clk_b   ,
  input               we_a    ,
  input               we_b    ,
  output  reg [7:0]   q_a     ,
  output  reg [7:0]   q_b      
);

  reg [7:0] mem [0:(2**8)-1];

  always @(posedge clk_a) begin
    if (we_a)
      mem[addr_a] <= data_a;
    q_a <= mem[addr_a];
  end

  always @(posedge clk_b) begin
    if (we_b)
      mem[addr_b] <= data_b;
    q_b <= mem[addr_b];
  end

endmodule


`timescale  1ns/ 1ns
`define CLK_50Mhz 20
`define DBUS_SIZE 8
`define SBUS_SIZE 7 

module tb_dp_dc_ram ();
  reg  [7:0]   data_a  ;
  reg  [7:0]   data_b  ;
  reg  [6:0]   addr_a  ;
  reg  [6:0]   addr_b  ;
  reg          clk_a   ;
  reg          clk_b   ;
  reg          we_a    ;
  reg          we_b    ;
  wire [7:0]   q_a     ;
  wire [7:0]   q_b     ;


dp_dc_ram uDp_dc_ram(
  .data_a(data_a)  ,
  .data_b(data_b)  ,
  .addr_a(addr_a)  ,
  .addr_b(addr_b)  ,
  .clk_a (clk_a )  ,
  .clk_b (clk_b )  ,
  .we_a  (we_a  )  ,
  .we_b  (we_b  )  ,
  .q_a   (q_a   )  ,
  .q_b   (q_b   )   
);

initial fork
    clk_gen_a();
    clk_gen_b();
    add_a();
    add_b();
    data_gen_a();
    data_gen_b();
    ctrl_gen_a();
    ctrl_gen_b();
  join

  task clk_gen_a;
    begin
      clk_a = 1'b0;
      forever #(`CLK_50Mhz/2) clk_a=~clk_a;
    end
  endtask



  task add_a;
    begin
    addr_a = 7'h00;
    repeat(3) @(negedge clk_a);
    addr_a = 7'h05;
    @(negedge clk_a);
    addr_a = 7'h06;
    @(negedge clk_a);
    addr_a = 7'h05;
    @(negedge clk_a);
    addr_a = 7'h6;
    end
  endtask

  task data_gen_a;
    begin
      data_a=8'hAA;
      repeat(5) @(negedge clk_a);
      data_a=8'hBB;
      repeat(2) @(negedge clk_a);
      data_a=8'hf7;
    end
  endtask

  task ctrl_gen_a;
   begin
   we_a= 1'b0;
   repeat(5) @(negedge clk_a);
   we_a= 1'b1;

   end 
  endtask

  task clk_gen_b;
    begin
      clk_b = 1'b0;
      #5
      forever #(`CLK_50Mhz/2) clk_b=~clk_b;
    end
  endtask

  task add_b;
    begin
      addr_b = 7'h00;
      repeat(3) @(negedge clk_b);
      addr_b = 7'h01;
      @(negedge clk_b);
      addr_b = 7'h02;
      @(negedge clk_b);
      addr_b = 7'h03;
      @(negedge clk_b);    
      addr_b = 7'h04;
    end
  endtask

  task data_gen_b;
    begin   
      data_b=8'hBB;
      repeat(5) @(negedge clk_b);
      data_b=8'hBC;  
      repeat(2) @(negedge clk_b);  
      data_b=8'hf8;
    end
  endtask 

  task ctrl_gen_b;
   begin
    we_b= 1'b0;
    repeat(5) @(negedge clk_b);
    we_b= 1'b1;
   end 
  endtask

endmodule

 

 

a와 b의 클락 위상을 다르게 대입 할 수 있다.

vlib work
vlog dp_dc_ram.v tb_dp_dc_ram.v
vsim -t ns tb_dp_dc_ram
view wave
add wave -expand -group a -radix binary /tb_dp_dc_ram/clk_a
add wave -expand -group a -radix binary /tb_dp_dc_ram/we_a
add wave -expand -group a -radix hexadecimal /tb_dp_dc_ram/data_a
add wave -expand -group a -radix hexadecimal /tb_dp_dc_ram/addr_a
add wave -expand -group a /tb_dp_dc_ram/uDp_dc_ram/mem
add wave -expand -group a -radix hexadecimal /tb_dp_dc_ram/q_a
add wave -expand -group b -radix binary /tb_dp_dc_ram/clk_b
add wave -expand -group b -radix binary /tb_dp_dc_ram/we_b
add wave -expand -group b -radix hexadecimal /tb_dp_dc_ram/data_b
add wave -expand -group b -radix hexadecimal /tb_dp_dc_ram/addr_b
add wave -expand -group b /tb_dp_dc_ram/uDp_dc_ram/mem
add wave -expand -group b -radix hexadecimal /tb_dp_dc_ram/q_b
run 500ns

 그룹 + 확장까지 되는 tcl.

module dp_dc_ram (
  input       [7:0]   data_a  ,
  input       [7:0]   data_b  ,
  input       [6:0]   addr_a  ,
  input       [6:0]   addr_b  ,
  input               clk_a   ,
  input               clk_b   ,
  input               we_a    ,
  input               we_b    ,
  output  reg [7:0]   q_a     ,
  output  reg [7:0]   q_b      
);

  reg [7:0] mem [0:(2**8)-1];

  always @(posedge clk_a) begin
    if (we_a)
      mem[addr_a] <= data_a;
    q_a <= mem[addr_a];
  end

  always @(posedge clk_b) begin
    if (we_b)
      mem[addr_b] <= data_b;
    q_b <= mem[addr_b];
  end

endmodule



`timescale  1ns/ 1ns
`define CLK_50Mhz 20

module tb_dp_dc_ram ();
  reg  [7:0]   data_a  ;
  reg  [7:0]   data_b  ;
  reg  [6:0]   addr_a  ;
  reg  [6:0]   addr_b  ;
  reg          clk_a   ;
  reg          clk_b   ;
  reg          we_a    ;
  reg          we_b    ;
  wire [7:0]   q_a     ;
  wire [7:0]   q_b     ;


dp_dc_ram uDp_dc_ram(
  .data_a(data_a)  ,
  .data_b(data_b)  ,
  .addr_a(addr_a)  ,
  .addr_b(addr_b)  ,
  .clk_a (clk_a )  ,
  .clk_b (clk_b )  ,
  .we_a  (we_a  )  ,
  .we_b  (we_b  )  ,
  .q_a   (q_a   )  ,
  .q_b   (q_b   )   
);

initial fork
    clk_gen_a();
    clk_gen_b();
    data_gen_a();
    data_gen_b();
    ctrl_gen_a();
    ctrl_gen_b();
  join

  task clk_gen_a;
    begin
      clk_a = 1'b0;
      forever #(`CLK_50Mhz/2) clk_a=~clk_a;
    end
  endtask

  task data_gen_a;
    begin
      data_a=8'hAA;
      repeat(5) @(negedge clk_a);
      data_a=8'hBB;
      repeat(2) @(negedge clk_a);
      data_a=8'hf7;
    end
  endtask

  task ctrl_gen_a;
   begin
    we_a  = 1'b0;
    addr_a = 7'h00;
    repeat(5) @(negedge clk_a);
    we_a  = 1'b1;
    addr_a = 7'h05;
    @(negedge clk_a);
    addr_a = 7'h06;
    @(negedge clk_a);
    addr_a = 7'h05;
    @(negedge clk_a);
    addr_a = 7'h6;
   end 
  endtask

  task clk_gen_b;
    begin
      clk_b = 1'b0;
      #5
      forever #(`CLK_50Mhz/2) clk_b=~clk_b;
    end
  endtask


  task data_gen_b;
    begin   
      data_b=8'hBB;
      repeat(5) @(negedge clk_b);
      data_b=8'hBC;  
      repeat(2) @(negedge clk_b);  
      data_b=8'hf8;
    end
  endtask 

  task ctrl_gen_b;
   begin
    we_b= 1'b0;
    addr_b = 7'h00;
    repeat(5) @(negedge clk_b);
    we_b= 1'b1;
    addr_b = 7'h01;
    @(negedge clk_b);
    addr_b = 7'h02;
    @(negedge clk_b);
    addr_b = 7'h03;
    @(negedge clk_b);    
    addr_b = 7'h04;
   end 
  endtask

endmodule

 

module ram_init(
  input             clk     ,
  input             we      ,
  input       [7:0] d       ,
  input       [6:0] wr_addr ,
  input       [6:0] rd_addr ,
  output  reg [7:0] q        
);

  reg [7:0] mem [0:2**7-1];

  initial
  $readmemb ("ram.dat",mem);

  always @(posedge clk) begin
    if (we)
      mem[wr_addr] <= d;
    
    q<=mem[rd_addr];
  end

endmodule

`timescale  1ns/ 1ns
`define CLK_50Mhz 20


module tb_ram_init();
  reg         clk     ;
  reg         we      ;
  reg   [7:0] d       ;
  reg   [6:0] wr_addr ;
  reg   [6:0] rd_addr ;
  wire  [7:0] q       ;



ram_init uRam_init(
  .clk    (clk    ) ,
  .we     (we     ) ,
  .d      (d      ) ,
  .wr_addr(wr_addr) ,
  .rd_addr(rd_addr) ,
  .q      (q      )  
);

initial fork
    clk_gen();
    data_gen();
    ctrl_gen();
  join

  task clk_gen;
    begin
      clk = 1'b0;
      forever #(`CLK_50Mhz/2) clk =~clk ;
    end
  endtask

  task data_gen;
    begin
     d = "ram.dat";
    end
  endtask

  task ctrl_gen;
   begin
    we = 1'b0;
    wr_addr = 7'h00;
    rd_addr = 7'h00;
    repeat(3) @(negedge clk);
    we = 1'b1;
    wr_addr = 7'h01;
    rd_addr = 7'h01;
    repeat(2) @(negedge clk);
    wr_addr = 7'h02;
    rd_addr = 7'h02;
    repeat(2) @(negedge clk);
    wr_addr = 7'h03;
    rd_addr = 7'h03;

   end 
  endtask

endmodule


//create ram.dat
00000000
00000101
00001010
00001111
00010100
00011001
00011110
00100011
00101000
//Repeat segment at
//address 20 hex
@20
00000000
00000101
00001010
00001111
00010100
00011001
00011110
00100011
00101000

 

 

728x90

'[Harman] 하만 반도체 설계 > VerilogHDL' 카테고리의 다른 글

Day.84 Advanced Verilog #7  (0) 2023.11.20
Day.83 Advanced Verilog #6  (0) 2023.11.17
Day.81 Advanced Verilog #4  (0) 2023.11.14
Day.80 Advavnced Verilog #3  (0) 2023.11.13
Day.79 Advanced Verilog #2  (0) 2023.11.10