verilog HDL 기본문법

  • Inverter

  • assign 구문 사용

    • 대부분의 경우 assign을 사용
    • “조건 ? 참일경우 : 거짓일경우” 의 문장을 자주 사용
  • always 구문 사용 always @ (sensitivity_list) begin … end

  • always : 언제나, @ : (sensitivity_list) 신호가 변할 때

  • 논리가 복잡한 경우에 사용

  • 이 경우 if, else if, else 구문 또는 case 구문을 주로 사용

  • @(sensitivity_list) : 감지신호 목록

    • sensitivity_list에 나열된 신호들 중 하나라도 값이 바뀌면 내부 문장이 실행
    • sensitivity_list에는 출력에 영향을 주는 모든 신호가 나열되어야 함
  • assign 구문을 사용한 작성

      wire out;
      assign out = ~in;
    
      wire out;
      assign out = (in == 0)
    
      wire out;
      assign out = ~(in == 1)
    
      wire out;
      assign out = in ? 0 : 1;
    
      wire out;
      assign out = ~in ? 1 : 0;
    
  • always 구문을 사용한 작성

      reg out;
      always @(in)
      out = ~in;
    
      reg out;
      always @(in) begin
      if (in) out = 0;
      else out = 1;
      end
    
      reg out;
      always @(in) begin
      case (in)
          0 : out = 1;
          1 : out = 0;
          default : out = 1'bx;
      endcase
      end
    
  • 인버터 모듈

    • 2개의 입출력 포트(port)

    • 입력신호는 in, 출력 신호는 out

      module inverter (in, out);
      input in;
      output out;
      
      wire out;
      assign out = ~in;
      endmodule
      
  • OR gate(3-input OR gate)

      wire out;
      assign out = in[2] | in[1] | in[0];
    
      wire out;
      assign out = |in[2:0];
    
      wire out;
      assign out = (in[2:0] != 3`b000);
    
      wire out;
      assign out = ~(in[2:0] == 3`b000);
    
  • NOR gate

      wire out;
      assign out = ~(in[2] | in[1] | in[0]);
    
      wire out;
      assign out = ~|in[2:0];
    
      wire out;
      assign out = ~(in[2:0] != 3`b000);
    
      wire out;
      assign out = in[2:0] == 3`b000;
    
  • 반가산기

    • 2개의 입력을 받아 덧셈을 수행하고 sum과 carry를 발생

      module half_adder (a, b, sum, cout);
      input a, b;
      output sum, cout;
      wire sum, cout;
      
      assign sum = a ^ b;
      assign cout = a & b;
      endmodule
      
  • 전가산기

    • 3개의 입력을 받아 sum과 carry를 발생

    • 반가산기 2개와 or 게이트를 사용

      module full_adder (a, b, cin, sum, cout);
      input a, b, cin;
      output sum, cout;
      wire sum, cout;
      
      assign sum = (a ^ b) ^ cin;
      assign cout = ((a ^ b) & cin) | (a & b);
      endmodule
      

Multiplexer(mux)

  • 여러 개의 입력 중 하나만을 선택하여 출력

    • sel == 1 이면 out = a
    • sel == 0 이면 out = b
  • assign을 사용

      wire out;
      assign out = (sel == 1) ? a : b;
    
      wire out;
      assign out = sel ? a : b;
    
  • always를 사용

      reg out;
      always @(sel or a or b)
      out = sel > a : b;
    
      reg out;
      always @(sel or a or b) begin
      if (sel) out = a;
      else out = b;
      end
    
      module mux2to1 (a, b, sel, out);
      input a, b, sel;
      output out;
      reg out;
      always @(sel or a or b) begin
          case (sel)
          1`b1 : out = a;
          1`b0 : out = b;
          endcase
      end
      endmodule
    

-multi-bit mux

    wire [3:0] out;
    assign out[3:0] = sel ? a[3:0] : b[3:0];

    module mux4bit (a, b, sel, out);
    input [3:0] a, b;
    input sel;
    output [3:0] out;

    reg [3:0] out;
    always @(sel or a or b) begin
        case(sel)
        1'b1 : out = a; // a, b, out 이 모두 4비트로
        1'b0 : out = b; // 선언되어 있으므로 비트표시 생략, out[3:0] = a[3:0]
        endcase
    end
    endmodule
  • 가산기(adder)

    • 가산기 작성시 ‘+’ 연산자 사용

    • 합성시에 자동으로 속도에 맞는 가산기가 발생됨

    • 4비트 + 4비트 carry와 4비트의 sum

      wire carry_out;
      wire [3:0] sum;
      assign { carry_out, sum[3:0] } = a[3:0] + b[3:0];
      
  • 가감산기(adder and subtractor)

    • add_nsub == 1 : 가산

    • add_nsub == 0 : 감산

      wire carry_out;
      wire [3:0] sum;
      assign {carry_out, sum[3:0]} = add_nsub > a[3:0] + b[3:0] : a[3:0] + ~b[3:0] + 4'b1;
      
  • 디코더

    • 코드화된 신호를 받아 하나의 출력만을 1 또는 0으로 구동

      wire[3:0] y;
      
      assign y[0] = !a[1] & !a[0];
      assign y[1] = !a[1] & a[0];
      assign y[2] = a[1] & !a[0];
      assign y[3] = a[1] & a[0];
      
      wire[3:0] y;
      
      assign y[0] = a[1:0] == 2'b00;
      assign y[1] = a[1:0] == 2'b01;
      assign y[2] = a[1:0] == 2'b10;
      assign y[3] = a[1:0] == 2'b11;
      
      wire[3:0] y;
      
      assign y = (a == 2'b00) ? 4'b0001 :
                  (a == 2'b01) ? 4'b0010 :
                  (a == 2'b10) ? 4'b0100 :
                                      4'b1000;
      
      reg[3:0] y;
      
      always @(a) begin
      case(a)
          2'b00 : y = 4'b0001;
          2'b01 : y = 4'b0010;
          2'b10 : y = 4'b0100;
          2'b11 : y = 4'b1000;
      endcase
      end
      
  • 인코더

    • 디코더와 반대의 동작으로 개별 신호를 묶어 코드화

      wire b, a, v
      assign b = d3 || (!d3 & d2);
      assign a = d3 || (!d3 & !d2 & d1);
      assign v = !(!d3 & !d2 & !d1 & !d0);
      
  • ROM

    • ROM은 메모리로 분류되지만, 동작관점에서는 조합논리회로임.
  • DFF

      module d_ff (clk, d, q);
      input clk;
      input d;
      output q;
    
      reg q;
      always @(posedge clk)
          q <= d;
    
      endmodule
    
  • DFF with asychronous reset

      reg q;
      always @(posedge clk or negedge rst) begin
      if (!rst) q <= 0;
      else q <= d;
      end
    
  • DFF with enable

      reg q;
      always @(posedge clk or negedge rst) begin
      if(!rst) q <= 0;
      else if (en) q <= d;
      else q <= q; // needless
      end
    
  • DFF with q and qbar outputs

      reg q, q_bar;
      always @(posedge clk) begin
      q <= d;
      q_bar <= ~d;
      end
    
      reg q;
      wire q_bar;
    
      always @(posedge clk)
      q <= d;
      assign q_bar = ~q;