7/12 동기식 카운터

정유석·2024년 7월 12일

교육 - 베릴로그

목록 보기
7/28
post-thumbnail

조합회로

  • mux, lut(look up table)

순서회로

  • 플립플롭


    f(A,B,C)=Σm(0,1,5,7)
    입력 A,B,C 중에 출력 (0,1,5,7)이 1

    베릴로그는 c언어의 연산자들을 대부분 쓸수있지만 증감 연산자는 쓸수없다


    베릴로그로 만든 파일을 FPGA칩에 Generate Bitstream을 이용해서 보냄

if문같은 경우 {}대신 begin end로 묶는데 실행문이 1문장이면 생략가능하고, if-else문은 ';'은 두개 들어가지만 세트로 1문장으로 친다

if() //begin   //begin end 생략 가능
	if() ~~;
    else ~~;
//end

동기식 카운터

https://www.slideserve.com/iliana-sharpe/counter

T플립플롭으로 사용
A는 클락 때마다 토글
B는 클락 때마다와 A가 1일때 토글

FPGA에는 lut과 D플립플롭만 있음
비바도에 있는 덧셈기 사용
회로도 대로 만들면 T플립플롭만들고 and게이트를 만들어야 하고 그에따른 lut도 따로 사용해야함

업 카운터

상승엣지 업 카운터

module up_counter_p(
    input clk, reset_p, enable,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else if(enable)count = count +1;
    end
endmodule

하강엣지 업 카운터

module up_counter_n(
    input clk, reset_p, enable,
    output reg [3:0] count);
    
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else if(enable)count = count +1;
    end
endmodule

시뮬레이션

상승엣지 업 카운터

리셋으로 초기화 하지 않으면 unkown 상태로, unkown상태에서 1을 더하든 뭘 하든 unkown상태이다

enable값은 1을 줘서 항상 동작할수있게 함
reset_p의 값에 1을 줘서 리셋 초기화

reset_p에 다시 0주고 (리셋 종료)

다운 카운터

상승엣지 다운 카운터

module down_counter_p(
    input clk, reset_p, enable,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else if(enable)count = count - 1;
    end
endmodule

하강엣지 다운 카운터

module down_counter_p(
    input clk, reset_p, enable,
    output reg [3:0] count);
    
    always @(negedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else if(enable)count = count - 1;
    end
endmodule

시뮬레이션

하강엣지 다운 카운터

리셋 한번 하고

리셋 다시0 주고 하강엣지에서 동작

BCD

2진화 10진수
10진수 각 자리수를 2진수로 표현(표현은 되지만 BCD코드로 계산은 하면 안됨)

BCD 업 카운트

enable입력을 만들지 않아도 회로에 자동으로 생성되고 기본 1값으로 설정

module bcd_upcounter_p(
    input clk, reset_p,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else begin
            if(count >= 9)count = 0;
            else count = count +1;
        end
    end
endmodule

시뮬레이션

초기화 한번 한 후에

BCD 다운 카운트

버전1

module bcd_downcounter_p(
    input clk, reset_p,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else begin
            if(count <= 0)count = 9;
            else count = count -1;
        end
    end
endmodule

시뮬레이션1

초기화 한번 한 후에

버전2
리셋값을 9로 설정
처음 시작을 9부터 시작해서 다운 카운트

module bcd_downcounter_p(
    input clk, reset_p,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 9;
        else begin
            if(count <= 0)count = 9;
            else count = count -1;
        end
    end
endmodule

시뮬레이션2

오류를 고려한 수정된 코드

module bcd_downcounter_p(
    input clk, reset_p,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 9;
        else begin
            if(count >= 10 | count == 0)count = 9; //0보다 작을순없어서 '=='가능 하지만 4비트에서 10보다 큰 수가 나올수도있음(하드웨어적인 오류 등에있어서)
            else count = count -1;
        end
    end
endmodule

동기식 업/다운 카운트

module up_downcounter_p(
    input clk, reset_p,
    input up_down,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)count = 0;
        else begin
            if(up_down)begin
                count = count + 1;
            end
            else begin
                count = count -1;
            end
        end
    end
endmodule

동기식 BCD 업/다운 카운트

동기식 BCD 업/다운 카운터
초기화 0으로 한번 한 뒤
up_down이 1이면 업 카운터로 동작, up_down이 0이면 다운 카운터로 동작

module bcd_up_downcounter_p(
    input clk, reset_p,
    input up_down,
    output reg [3:0] count);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p) count = 0;
        else begin
            if(up_down)begin
                count = count + 1;			//실행 순서 주의
                if(count > 9) count = 0;	//위아랫줄이 바뀌었으면 9나0에 1이 더해지고 출력되서 값이 건너 뛰어질 수 있음
            end
            else begin
                count = count -1;
                if(count == 0 | count >= 10) count = 9;
            end
        end
    end
endmodule

시뮬레이션

링 카운터

  • 임의의 시간에 한 개의 플립플롭만 논리 1이 되고 나머지 플립플롭은 논리 0이 되는 카운터
  • 논리 1은 입력 펄스에 따라 그 위치가 한쪽 방향으로 순환
  • 링 카운터는 계수의 목적으로 사용하기보다는 어떤 일련의 동작을 제어하는 데 매우 유용하다

베릴로그는 병렬적으로 동작한다 c언어처럼 순차적으로 동작하는 것을 구현할때 링 카운터 사용이 유용함

module ring_counter(
    input clk, reset_p,
    output reg [3:0] q);
    
    always @(posedge clk, posedge reset_p)begin
        if(reset_p) q=4'b0001;
        else begin
            case(q)		//q의 변화가 감지 되었을 때 동작 //순차적으로 계속 변하게됨
                4'b0001: q = 4'b0010; //q값이 0001이면 0010으로 	
                4'b0010: q = 4'b0100; //q값이 0010이면 0100으로
                4'b0100: q = 4'b1000; //q값이 0100이면 1000으로
                4'b1000: q = 4'b0001; //q값이 1000이면 0001으로
                default: q = 4'b0001; //q값이 그 외의 값이면 0001으로
            endcase
        end
    end
endmodule

시뮬레이션

쉬프트 연산자 사용

module ring_counter(
    input clk, reset_p,
    output reg [3:0] q);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)q=4'b0001;
        else begin
            if(q == 4'b1000)q=4'b0001;
            else q=q<<1;
        end
    end
    
//    always @(posedge clk, posedge reset_p)begin
//        if(reset_p) q=4'b0001;
//        else begin
//            case(q)
//                4'b0001: q = 4'b0010;
//                4'b0010: q = 4'b0100;
//                4'b0100: q = 4'b1000;
//                4'b1000: q = 4'b0001;
//                default: q = 4'b0001;
//            endcase
//        end
//    end
endmodule



쉬프트 회로

쉬프트 연산 없이 배선만으로 만들기
{}결합 연산자를 통해 q=0001에서 001을 떼오고 1'b0을 맨 오른쪽에 붙여서 q=0010만듬, 클럭마다 반복

module ring_counter(
    input clk, reset_p,
    output reg [3:0] q);
    
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)q=4'b0001;
        else begin
            if(q == 4'b1000)q=4'b0001;
            else q[3:0] = {q[2:0], 1'b0};	//q가 4비트짜리라 else q = {q[2:0], 1'b0}도 가능
            //else q=q<<1;
        end
    end
    
//    always @(posedge clk, posedge reset_p)begin
//        if(reset_p) q=4'b0001;
//        else begin
//            case(q)
//                4'b0001: q = 4'b0010;
//                4'b0010: q = 4'b0100;
//                4'b0100: q = 4'b1000;
//                4'b1000: q = 4'b0001;
//                default: q = 4'b0001;
//            endcase
//        end
//    end
endmodule


쉬프트 연산자 사라짐

출력값 0001일때 mux의 신호선과 입력선에들어가서 0010으로 다시 출력

one cycle clock 상승엣지

시스템 클락의 1주기 동안만 High 되어있는 펄스 클락
always 감지 변수에 버튼 클럭 상승 엣지를 만들어서 안넣는 이유는 언제 버튼 상승엣지가 들어올지 몰라서 pdt계산, 타이밍 계산이 안되서 문법적으로는 가능하지만 안 넣어야 한다.

module edge_detector_p(
    input clk, reset_p,
    input cp,
    output p_edge);
    
    reg ff_cur, ff_old;
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur=0;
            ff_old=0;
        end
        else begin
            ff_old = ff_cur;	//어떤게 먼저 실행되느냐에 따라 다름 //순서대로 처리
            ff_cur = cp;		//병렬처리 사진
            //ff_old = ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
endmodule

cp, ff_cur, ff_old의 잘못된 순서

module edge_detector_p(
    input clk, reset_p,
    input cp,
    output p_edge);
    
    reg ff_cur, ff_old;
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur=0;
            ff_old=0;
        end
        else begin
            //ff_old = ff_cur;	//어떤게 먼저 실행되느냐에 따라 다름 //순서대로 처리
            ff_cur = cp;		//병렬처리 사진
            ff_old = ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
endmodule

바꾼 순서

module edge_detector_p(
    input clk, reset_p,
    input cp,
    output p_edge);
    
    reg ff_cur, ff_old;
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur=0;
            ff_old=0;
        end
        else begin
            ff_old = ff_cur;	//어떤게 먼저 실행되느냐에 따라 다름 //순서대로 처리
            ff_cur = cp;		//병렬처리 사진
            //ff_old = ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
endmodule


always문과 assign문은 병렬적으로 처리되며 서로 즉시 영향을 주지만, 델타사이클에의해 대부분은 always문 내의 모든 문장이 처리되면 assign문에 영향을 준다고 생각하면된다.

병렬처리

순서대로 처리

(대입연산자)블럭킹문 (<=연산자)넌블럭킹문
always문에서는 순서대로 실행

module edge_detector_p(
    input clk, reset_p,
    input cp,
    output p_edge);
    
    reg ff_cur, ff_old;
    always @(posedge clk or posedge reset_p)begin
        if(reset_p)begin
            ff_cur<=0;
            ff_old<=0;
        end
        else begin
            
            ff_cur <= cp;
            ff_old <= ff_cur;
        end
    end
    
    assign p_edge = ({ff_cur, ff_old} == 2'b10) ? 1 : 0;
endmodule

결과

cp(버튼)의 신호가 들어왔을때 ff_cur, ff_old의 신호 차이에 의해 한 클락의 P_edge 발생

베릴로그는 기본적으로 병렬 처리 언어이다. 이는 하드웨어의 동시성을 모델링하기 위함.
하지만 예외가 있다

  1. 순차적 실행
  • 단일 always블록이나 initial블록 내부의 문장들은 순차적으로 실행된다.
  1. 블로킹, 비블로킹
  • 블로킹 할당(=)은 순차적으로 실행되지만, 비블로킹 할당(<=)은 병렬 실행을 모델링한다.
profile
개인 기록공간

0개의 댓글