레지스터, 시프트 레지스터, 시프트 레지스터, up-down 카운터

2023. 6. 23. 16:28[Harman] 세미콘(semiconductor) 아카데미-반도체설계/Verilog를 이용한 RTL 시스템 반도체 설계

728x90
  • 레지스터 

베릴로그에 의한 레지스터의 구현 방법

클럭이 있는 순차회로 = 플립플롭과 조합게이트로 구성

플립플롭이 없으면 조합회로만 구현 가능

플립플롭만 구성된 회로의 경우 조합논리게이트 없더라도 순차회로로 간주

플립플롭을 포함하고 있는 회로는 순차 회로라는 명칭 뿐만 아니라 수행하는 기능에 의해 레지스터와 카운터로 분류

 

레지스터 = 플립플롭들로 구성되며 각 플립플롭은 클럭을 공유하고 한 비트의 정보를 저장 가능

n비트 렞니스터는 n개의 플립플롭으로 구성되고 n개의 비트를 가지는 2진 정보를 wjwkd

 

카운터

입력이 가해짐에 따라 상태를 미리 정해진 순서대로 진행시키는 레지스터

카운터의 게이트는 레지스터에서 2진상태를 정해진 순서대로 만들어둔 것

 

래치 

임시저장장소의 한 종류로서 두 개의 안정 상태를 가지고 있으며 플립플롭과 별개의 분류로 분류되는 쌍안정소자

레지스터는 클럭에 의해 값이 변하므로 레지스터 자체를 순차논리회로의 하나로 간주

베릴로그의 레지스터는 클리어, 프리셋, 클럭과 비동기 로드 신호에 의해 제어가 가능

저장요소로서의 래치는 신호레벨로 동작

 

레지스터의 회로 표현

q1 = 비동기 로드를 갖는 레지스터 

q2 = 비동기 프리셋, 클리어를 갖는 레지스터

 

레지스터는 클럭에 의해 값이 변하므로 순차논리회로의 하나

모든 순차논리회로는 하나 이상의 레지스터를 포함

 

비동기 로드 레지스터 = load신호가 클럭에 영향을 받지 않음

`timescale 1ns / 1ps

module regitser(
    input clk, clr, pre, load, data, d,
    output reg q1, q2
    );
    
    always @(posedge clk or posedge load) begin
        if(load)
            q1<=data;
        else 
            q1<=d;
    end
    
    always @(posedge clk or negedge clr or negedge pre) begin
        if(!clr)
            q2 <= 1'b0;
        else if(!pre)
            q2 <= 1'b1;
        else
            q2 <= d;
    end
endmodule
module register_tb;

    reg clk, clr, pre, load, data, d;
    wire q1, q2;
    
    regitser uut (
        .clk(clk),
        .clr(clr),
        .pre(pre),
        .load(load),
        .data(data),
        .d(d),
        .q1(q1),
        .q2(q2)
    );
    
    initial begin
        // Initialize inputs
        clk = 0;
        clr = 1;
        pre = 0;
        load = 0;
        data = 0;
        d = 0;
        
        // Test case 1: Load data into q1
        load = 1;
        data = 1;
        #10; // Wait for 10 time units
        
        // Test case 2: Use d as input to q1
        load = 0;
        d = 0;
        #10;
        
        // Test case 3: Clear q2
        clr = 0;
        pre = 1;
        d = 0;
        #10;
        
        // Test case 4: Set q2 with d
        clr = 1;
        pre = 0;
        d = 1;
        #10;
        
        // Add more test cases if needed
        
        $finish; // End simulation
    end
    
    always begin
        #5; // Toggle clock every 5 time units
        clk = ~clk;
    end

endmodule

레지스터 Simulation

 

 

  • 병렬 - 직렬 변환회로 설계

병렬입력 - 직렬출력

시프트 레지스터 = 저장되어 있는 이진 정보를 단방향 또는 양방향으로 이동시킬 수 있는 레지스터의 종류

시프트 레지스터는 직렬입렬 병렬출력과 병렬입력 직렬출력형태를 포함하여 직렬과 병렬의 입출력 조합이 가능. 여기에는 직병렬 입력을 가지고 직병렬 출력을 지닌 형태도 존재. 

시프트레지스터와 각 플립플롭들은 각각 입력과 출력이 연쇄적으로 연결되어 공통으로 입력되는 클럭이 데이터를 한 비트씩 다음 레지스터로 이동

 

입력이 parallell하게 들어간다.

시프트 레지스터를 응용한 병렬-직렬 변환기 블록도

변환기가 필요한 경우는 asic칩에서 모든 데이터 비트를 출력시키는데 사용할 핀들이 충분히 없을 때 유용

신호 load = 1이면, 입력p_in이 시프트 레지스터에 저장

`timescale 1ns / 1ps

module shift_regitser(

    input clk,reset_n,load, 
    input [7:0] p_in, 
    output [7:0] s_out
    );
    reg [7:0] reg1 = 8'h00, s_reg = 8'h00;
    reg [25:0] cnt = 26'h0;
    reg clk100Hz;
    
    always @(posedge clk100Hz) begin
        if(load)
            reg1 <= p_in;
        else begin
            s_reg <= {s_reg[6:0], reg1[7]};
            reg1 <= {reg1[6:0], 1'b0};
        end
    end
    
    always @(posedge clk or negedge reset_n) begin
        if(!reset_n) begin 
            cnt <= 26'b0;
            clk100Hz <= 1'b0; 
        end
        else if(cnt == (26'd50000000 - 1)) begin
             cnt <= 26'd0;
             clk100Hz <= ~clk100Hz;
        end else
             cnt <= cnt +1'b1;    
    end
    assign s_out = s_reg;
endmodule
## Clock signal
set_property -dict { PACKAGE_PIN W5   IOSTANDARD LVCMOS33 } [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]

## Switches
set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports {p_in[0]}]
set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports {p_in[1]}]
set_property -dict { PACKAGE_PIN W16   IOSTANDARD LVCMOS33 } [get_ports {p_in[2]}]
set_property -dict { PACKAGE_PIN W17   IOSTANDARD LVCMOS33 } [get_ports {p_in[3]}]
set_property -dict { PACKAGE_PIN W15   IOSTANDARD LVCMOS33 } [get_ports {p_in[4]}]
set_property -dict { PACKAGE_PIN V15   IOSTANDARD LVCMOS33 } [get_ports {p_in[5]}]
set_property -dict { PACKAGE_PIN W14   IOSTANDARD LVCMOS33 } [get_ports {p_in[6]}]
set_property -dict { PACKAGE_PIN W13   IOSTANDARD LVCMOS33 } [get_ports {p_in[7]}]
set_property -dict { PACKAGE_PIN T1    IOSTANDARD LVCMOS33 } [get_ports {reset_n}]
set_property -dict { PACKAGE_PIN R2    IOSTANDARD LVCMOS33 } [get_ports {load}]

## LEDs
set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports {s_out[0]}]
set_property -dict { PACKAGE_PIN E19   IOSTANDARD LVCMOS33 } [get_ports {s_out[1]}]
set_property -dict { PACKAGE_PIN U19   IOSTANDARD LVCMOS33 } [get_ports {s_out[2]}]
set_property -dict { PACKAGE_PIN V19   IOSTANDARD LVCMOS33 } [get_ports {s_out[3]}]
set_property -dict { PACKAGE_PIN W18   IOSTANDARD LVCMOS33 } [get_ports {s_out[4]}]
set_property -dict { PACKAGE_PIN U15   IOSTANDARD LVCMOS33 } [get_ports {s_out[5]}]
set_property -dict { PACKAGE_PIN U14   IOSTANDARD LVCMOS33 } [get_ports {s_out[6]}]
set_property -dict { PACKAGE_PIN V14   IOSTANDARD LVCMOS33 } [get_ports {s_out[7]}]

 

  • up-down 카운터
`timescale 1ns / 1ps

module updowncnt( clk, reset, updown, cnt_out, updown_out);

input reset, clk, updown;
output [1:0] cnt_out;
output updown_out;

parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
reg [1:0] state = S0;

assign  updown_out = updown;
assign  cnt_out = state;

always @ (posedge clk or negedge reset) begin
    if (~reset)
        state <= S0;
    else begin
        case(state)
        S0 :  if(~updown) state <= S1;
              else        state <= S3;
              
        S1 :  if(~updown) state <= S2;
              else        state <= S0;
        
        S2 :  if(~updown) state <= S3;
              else        state <= S1;
        
        S3 :  if(~updown) state <= S0;
              else        state <= S2;
         endcase
    end
end

endmodule
`timescale 1ns / 1ps

module counter (
    input clkin,
    input reset,
    output reg [1:0] out_counter        // 4x1 Data MUX의 en 역할
);

 
//  reg [1:0] r_counter = 0;  // 선언할 때 초기화
//  assign o_counter = r_counter;

  always @(posedge clkin, negedge reset) 
  begin
    if (~reset) begin
      out_counter <= 0;
    end 
    else begin
      out_counter <= out_counter + 1;
    end
  end

endmodule
`timescale 1ns / 1ps

module clock_divider_paramN #(parameter N = 50_000_000)(
    input  clk,                                                     //보드 내부 클럭 100MHz,이고 분주하면 50MHz-> 50,000,000 (100MHz는 1초당 1억번 -> 분주 시 5000만번)
    input  reset,
    output reg  clk1000Hz                                   //  클럭 주기를 1000Hz로 설정 
);

  reg [25:0] cnt = 0;                                           // 2^26승 이상일 때부터 50000만 이상 이므로 count는 26 bit 할당, 초기값 0 선언

  always @(posedge clk, negedge reset) begin       // 반복문을 positive edge와 negative edge의 값이 변화할 때 항상 반복을 시작
    if (~reset) begin                                           // if reset(활성화 상태)가 아니라면 
      cnt <= 0;                                                  // count는 0이다.

    end else begin                                           // ~reset인 상태가 아닌 이외의 상태일 때,
      if (cnt == (N - 1)) begin                      // count가 4999번째 클럭이라면 그 다음 클럭에서
        cnt <= 0;                                              // count는 0으로 간다.
        clk1000Hz <= ~clk1000Hz;                     // clk 주기를 다시 1000Hz로
      end else begin        
        cnt <=  cnt + 1;                                    // 현재 count에서 1을 더한 값을 cnt에  
      end
    end
  end

endmodule
`timescale 1ns / 1ps

module data_mux4x1(
    input [3:0] ina, inb, inc, ind,     // 4x1 Data mux 입력 4bit 입력 4개
    input [1:0] dmuxsel,               // counter 구조의 output이 data mux의 select로 입력
    output reg [3:0] dmux_out      // data mux의 output이 FND Decoder의 input으로 들어가므로 register로 데이터 저장
    );
    
    always @ (dmuxsel)  // select의 값이 변할 때 항상 다음을 반복
    begin : datamux4x1  
        case(dmuxsel)   // dmuxsel이 입력될 경우
            2'b00 : dmux_out = ina;     //2'b00이 출력일 때 ina이다.
            2'b01 : dmux_out = inb;     //2'b01이 출력일 때 inb이다.
            2'b10 : dmux_out = inc;     //2'b10이 출력일 때 inc이다.
            2'b11 : dmux_out = ind;     //2'b11이 출력일 때 ind이다.
        endcase
    end
endmodule
`timescale 1ns / 1ps

module mux_4x1(

    input  [1:0] s,     // select
    output reg [3:0] y      // 사용중인 보드(basys3)의 FND가 cathode 방식이므로 0일 때, 활성화
);

  always @(s)
  begin : MUX_4x1
    case (s)
      2'b00:   y = 4'b1110;     // 1번째 FND 결정
      2'b01:   y = 4'b1101;     // 2번째 FND 결정
      2'b10:   y = 4'b1011;     // 3번째 FND 결정
      2'b11:   y = 4'b0111;     // 4번째 FND 결정
      default: y = 4'b1111;     // Default 값 FND 결정
    endcase
    end
 
  endmodule
`timescale 1ns / 1ps

module fnddecoder(
    input  [3:0] a,     // input 4 bit

    output  reg [7:0] fnd  // output -> dot 까지 표현을 위해 8 bit 출력  
    );
    


    always @ (a) begin      // a의 값이 변할 때만 다음 구문을 항상 반복한다
        case (a)        // input a가 입력된 경우
            4'h0 : fnd = 8'h40;     // 16진수 0을 출력에 8 bit 16진수 40에 할당
            4'h1 : fnd = 8'h79;     
            4'h2 : fnd = 8'h24;
            4'h3 : fnd = 8'h30;
            4'h4 : fnd = 8'h19;
            4'h5 : fnd = 8'h12;
            4'h6 : fnd = 8'h02;
            4'h7 : fnd = 8'h58;
            4'h8 : fnd = 8'h00;
            4'h9 : fnd = 8'h10;
            4'ha : fnd = 8'h20;
            4'hb : fnd = 8'h03;
            4'hc : fnd = 8'h27;
            4'hd : fnd = 8'h21;
            4'he : fnd = 8'h04;
            4'hf : fnd = 8'h0e;            
            default:  fnd = 8'hff;      // 이외의 조건은 default 값을 따른다
        endcase
    end
endmodule
`timescale 1ns / 1ps

module clock_divider_paramN #(parameter N = 50_000_000)(
    input  clk,                                                     //보드 내부 클럭 100MHz,이고 분주하면 50MHz-> 50,000,000 (100MHz는 1초당 1억번 -> 분주 시 5000만번)
    input  reset,
    output reg  clk1000Hz                                   //  클럭 주기를 1000Hz로 설정 
);

  reg [25:0] cnt = 0;                                           // 2^26승 이상일 때부터 50000만 이상 이므로 count는 26 bit 할당, 초기값 0 선언

  always @(posedge clk, negedge reset) begin       // 반복문을 positive edge와 negative edge의 값이 변화할 때 항상 반복을 시작
    if (~reset) begin                                           // if reset(활성화 상태)가 아니라면 
      cnt <= 0;                                                  // count는 0이다.

    end else begin                                           // ~reset인 상태가 아닌 이외의 상태일 때,
      if (cnt == (N - 1)) begin                      // count가 4999번째 클럭이라면 그 다음 클럭에서
        cnt <= 0;                                              // count는 0으로 간다.
        clk1000Hz <= ~clk1000Hz;                     // clk 주기를 다시 1000Hz로
      end else begin        
        cnt <=  cnt + 1;                                    // 현재 count에서 1을 더한 값을 cnt에  
      end
    end
  end

endmodule
`timescale 1ns / 1ps

module top_controller2(
    input clk,          // counter clk
    input reset,        // counter input reset
    input updown,
    
    output [1:0] cnt_out,                
    output updown_out,
    output [3:0] fndsel,    // select에 따라 output FND 결정 (mux_4x1 output)     // nbitAddSub 회로의 출력 hexout1과 hexout2가 inc와 ind의 입력으로 연결 
    output  [7:0] fnd   // FND output (FND Decoder output)
    );
    
        wire [3:0] w_outy4;
        wire w_clkout;
        wire [1:0] w_counter;
        wire [3:0] w_datafnd;
        wire [3:0] w_clk_out;
  
  updowncnt U0(
        .clk(w_clk_out),
        .reset(reset),
        .updown(updown),
        .updown_out(updown_out),
        .cnt_out(cnt_out)
    );
 
    counter U1(
        .clkin(w_clkout),   
        .reset(reset),
        .out_counter(w_counter)
    );
    
    clock_divider_paramN#(.N(50_000))  U2(
        .clk(clk),
        .reset(reset),
        .clk1000Hz(w_clkout)
    );
    
    data_mux4x1 U3(
        .ina(cnt_out),
        .dmuxsel(w_counter),
        .dmux_out(w_datafnd)
    );
    
   mux_4x1 U4(
        .s(w_counter), 
        .y(fndsel)
    );
    
    fnddecoder U5(
        .a(w_datafnd),
        .fnd(fnd)
    );
    
     clock_divider_paramN#(.N(50_000_000))  U6(
        .clk(clk),
        .reset(reset),
        .clk1000Hz(w_clk_out)
    );

endmodule

 

## Clock signal
set_property -dict { PACKAGE_PIN W5   IOSTANDARD LVCMOS33 } [get_ports clk]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk]


## Switches
set_property -dict { PACKAGE_PIN V17   IOSTANDARD LVCMOS33 } [get_ports {reset}]
set_property -dict { PACKAGE_PIN V16   IOSTANDARD LVCMOS33 } [get_ports {updown}]

## LEDs
set_property -dict { PACKAGE_PIN U16   IOSTANDARD LVCMOS33 } [get_ports {updown_out}]
set_property -dict { PACKAGE_PIN E19   IOSTANDARD LVCMOS33 } [get_ports {cnt_out[0]}]
set_property -dict { PACKAGE_PIN U19   IOSTANDARD LVCMOS33 } [get_ports {cnt_out[1]}]

##7 Segment Display
set_property -dict { PACKAGE_PIN W7   IOSTANDARD LVCMOS33 } [get_ports {fnd[0]}]
set_property -dict { PACKAGE_PIN W6   IOSTANDARD LVCMOS33 } [get_ports {fnd[1]}]
set_property -dict { PACKAGE_PIN U8   IOSTANDARD LVCMOS33 } [get_ports {fnd[2]}]
set_property -dict { PACKAGE_PIN V8   IOSTANDARD LVCMOS33 } [get_ports {fnd[3]}]
set_property -dict { PACKAGE_PIN U5   IOSTANDARD LVCMOS33 } [get_ports {fnd[4]}]
set_property -dict { PACKAGE_PIN V5   IOSTANDARD LVCMOS33 } [get_ports {fnd[5]}]
set_property -dict { PACKAGE_PIN U7   IOSTANDARD LVCMOS33 } [get_ports {fnd[6]}]

set_property -dict { PACKAGE_PIN V7   IOSTANDARD LVCMOS33 } [get_ports fnd[7]]

set_property -dict { PACKAGE_PIN U2   IOSTANDARD LVCMOS33 } [get_ports {fndsel[0]}]
set_property -dict { PACKAGE_PIN U4   IOSTANDARD LVCMOS33 } [get_ports {fndsel[1]}]
set_property -dict { PACKAGE_PIN V4   IOSTANDARD LVCMOS33 } [get_ports {fndsel[2]}]
set_property -dict { PACKAGE_PIN W4   IOSTANDARD LVCMOS33 } [get_ports {fndsel[3]}]