If-else 및 case 사용법 

 

// 2to1 mux if 문 구현방법 
//always@(*) 문에 포함한다

module mux2to1 (s, d0, d1, z); 
	input s, d0, d1; 
    output z; 
    reg z; //always 문에서 배정되는 값은 wire가 아니라 reg type을 사용할 것 ! 
    
    always @(*) begin // sensitivity list @(s,d0,d1) 과 동일하지만 @(*)를 쓰자
    	if( s==0) begin // begin-end는  c의 중괄호와 비슷하며, c와 마찬가리고 한 개 명령이면 생략가능
        	z=d0; 
        end
        else begin 
        	z=d1; 
        end 
    end
endmodule

 

 

// 4to1 mux case 문 
// c와 쓰임은 비슷하다 문법이 상이함 

modulemux4to1(s,d0,d1,d2,d3,z);  
	input[1:0]s;  
    inputd0,d1,d2,d3;  
    output z;  reg z;  //output reg z; 도 ok!!!!!!
    
    
    always@(*)begin  
    	case(s)       // case는 보통 mux로 합성된다!!! 
        	0:z=d0;  //2b'00 
            1:z=d1;  //2b'01
            2:z=d2;  //2b'10
            default:z=d3;  //3대신 default 가 있는 것이 좋음 
        endcase
    end  
endmodule

//case 문은 특정 조건에 따라 여러 값을 선택하는 구조를 하드웨어적으로 효율적으로 구현할 수 있다.

 

 

언제 wire assign을 사용하고 언제 reg always를 사용하는 것이 좋을까? ( 조사 ) 

  1. 조합 회로의 경우:
    wire와 assign을 사용해야 합니다.  예를 들어, AND, OR, XOR 연산과 같은 조합 논리를 구현할 때, wire로 선언된 신호에 assign 문을 사용하여 값을 할당합니다.
  2. verilog
    코드 복사
    assign z = a & b; // 조합 논리
  3. 순차 회로의 경우:
    reg와 always를 사용해야 합니다. 클록에 동기화되어 값을 저장하거나 순차적인 동작을 구현할 때 reg와 always를 사용합니다.
  4. verilog
    코드 복사
    always @(posedge clk) begin q <= a; // 순차 회로 end
  5. 상태 머신, 레지스터 등의 순차적 동작:
    순차적으로 동작하는 설계를 할 때, 예를 들어 상태 머신, 카운터, 레지스터 배열 등을 구현할 때는 reg와 always를 사용합니다. 클록 또는 리셋 신호에 따라 상태를 업데이트하고 값을 저장합니다.

결론

  • wire assign: 조합 회로에서 신호의 계산 및 할당이 지속적으로 이루어져야 할 때 사용합니다.
  • reg always: 클록에 동기화된 값의 저장이 필요하거나 순차적인 동작이 필요한 경우 사용합니다.
 

 

 

8.2  structural modeling 

다른 모듈을 서브모듈삼아 더 복잡한 모듈을 설계할 수 있다. 

어떤 모듈을 다른 모듈 안에 인스턴스화 하는 방법 

< module 종류> <인스턴스 이름>(포트이름); 

module top(input a,b,c, output d); 
	wire e; 
    siple mysimplemodule(a,b,c,e); 
    assign d = ~e; //~ 대신 not mynot (d, e) ; 도 가능 but 흔히 쓰이지는 않는다. 
endmodule 


// not .. (z,a) = assign z = ~a; 
// and .. (z,a,b) = assign z = a&b;


//submodule port와의 연결을 명시적으로 언급하는 방법 
module top(input a,b,c, output d); 
	wire e; 
    simple mysimplemodule( .x(a), .y(b), .z(c), .f(e)); 
    assign d = ~e; 
endmodule

 

 

// half adder 로 full adder 구현하기 

module full_adder(output sum, cout, input x, y, z);
    wire s1, c1, c2;
    
    half_adder ha0(s1, c1, x, y);  // 첫 번째 half adder
    half_adder ha1(sum, c2, s1, z); // 두 번째 half adder
    assign cout = c1 | c2; // 캐리 아웃 계산
endmodule

 

 

// 4b 감가산기를 verilog로 설계하기 

module tb_addsub4b;
	reg [3:0] x;
	reg [3:0] y;	
	reg op;
	wire [3:0] s;	
	wire ovf;	
	
	integer i;
	wire [3:0] z_ans;
	wire [3:0] s_ans;
	wire ovf_ans;
	integer cnt = 0;

	initial begin
		x = 0; y = 0;
		for(i = 0; i < 16; i = i + 1, x = x - 1, y = y + 2) begin
			op = (i%2==0) ? 0 : 1;
			#10;
			if( s != s_ans || ovf != ovf_ans ) begin
				$display("x=%04b, y=%04b, op=%01b, expecting sum:%04b, overflow:%01b, but observed %04b and %01b", x, y, op, s_ans, ovf_ans, s, ovf);
				cnt = cnt + 1;
			end				
		end
		
		$display("////Simulation finished with %d errors////", cnt);

		$finish;
	end
	
	assign z_ans = (op) ? ~y : y;
	assign s_ans = x + z_ans + op;
	assign ovf_ans = (~x[3]&~y[3]&~op&s[3])|(x[3]&y[3]&~op&~s[3])|(x[3]&~y[3]&op&~s[3])|(~x[3]&y[3]&op&s[3]);
	
	addsub4b dut(x, y, op, s, ovf);
	
	wire [3:0] yn = dut.yn;
	wire [3:0] z = dut.z;
	wire [3:0] c = dut.c;

endmodule

 

 

C vs Verilog 

c는 순차언어인 반면 벨로그는 병렬 언어 

- c의 명령어는 cpu 명령어로 변환되어 수행 후 명령어로 넘어가만, 벨로그의 statement들은 디지털회로로 변환되어 항상 연산을 하고 있음 (입출력 신호만 바뀜)

- 벨로그에서 모든 모듈 인스턴스, assignment 등은 동시에 지속 수행됨