본문 바로가기

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 16일 - 1, PIPO Shift Register)

1. PIPO Shift Register (Parallel Input Parallel Output)

  • 병렬 형태로 데이터를 입력 받아 저장하고, 레지스터에 저장된 데이터를 병렬 형태로 출력받는 구조를 갖는 레지스터
  • 따라서 아래와 같이 게이트 레벨에서 회로를 구성할 수 있지만, 심각한 문제점을 갖는다.

 

4bit Parallel input - Parallel output register (Gate level)

 

  • 문제점으로 지적되는 부분은 "WR 단자 값이 0일 경우, AND Gate으로 인해 Register를 구성하는 D Flip Flop의 입력값, D로 0이 들어가게 되고, 그 결과 Register에 저장되어 있던 데이터가 사라진다." 이다.
  • 따라서 문제점을 해결하기 위해서 " WR 단자 값이 1일 때는 외부로부터 데이터를 입력 받아 레지스터에 저장하고, WR 단자 값이 0일 때는 외부로부터 데이터를 입력 받지 않고, 현 상태를 유지한다. " 처럼 동작하도록 설계하는 것이다.

 

 

 

1.1. WR 값이 0일 때, 레지스터에 저장된 데이터가 사라지는 문제점을 해결해보자.

  • 먼저, D Flip Flop으로 구현한 8bit PIPO Register는 다음과 같은 구조로 표현 할 수 있다.

D Flip Flop 8개를 병렬로 연결한 8bit Register

  • ★★★★★★
    Q) 그럼 어떻게 8bit Register으로 들어오는 데이터들을 Write_enable_p (WR)으로 제어할 수 있는가?
    A)
    MUX를 통해 다음과 회로를 구성하고, MUX의 selector로 Write_enable_p를 연결하면 된다.

write_enable_p 값을 Selector로 설정함으로서 문제점을 해결할 수 있다.

 

  • 문제점에 대해서 다시 정리하자.
    ▶ PIPO Register는 출력 뿐만 아니라 입력쪽에서도 Common data bus를 사용한다.
    ▶Common data bus 를 사용하는 만큼 한 번에 하나의 register만 사용가능하다.
       (사용 가능하다는 의미는 "Common data bus를 통해 read / write를 할 수 있다.)
    ▶따라서 하나의 메모리가 data bus를 사용 중이라면 나머지 메모리들은 data bus를 사용할 수 없다.
    ▶그래서 각각의 메모리가 Common data bus가 연결되는지 여부를 AND Gate로 구현했지만, write_enable_p 값이 0이면 데이터가 지워지는 문제점이 발생한다.

  • 해결책은 다음과 같다.
    ▶2X1 MUX를 입력 단자 부분에 연결한 뒤, 입력 단자에 각각 Common data bus, feedback을 연결한다.
    ▶MUX의 selector를 write_enable_p로 연결한다.
    ▶write_enable_p = 0 이면 현 상태 유지
    ▶write_enable_p = 1이면 common data bus와 연결되어 데이터를 입력 받는다.

 

 

  • 8bit register를 여러 개 모일 경우 아래와 같이 회로를 구성할 수 있다.

8bit register 2개를 모여 16bit register 생성

 

  • 8bit register의 입력 단자에 있는 MUX의 Selector를 모아 하나의 DEMUX로 관리가 가능하다.
  • DEMUX의 selector을 통해 원하는 8bit register와 Common data bus를 연결 시켜 데이터를 Read / Write가 가능해진다.
  • 이러한 관점에서 보았을 때, 결국 DEMUX의 selector는 메모리의 주소 (Address of memory)라 할 수 있다.
  • ex) 4개의 8bit register가 존재한다면 DEMUX의 selector를 통해 다음과 같이 접근이 가능하다.
    00이면 첫 번째 register, 01이면 두 번째 register, 10이면 세 번째 register, 11이면 4번째 register로 접근할 수 있는 것이다.

 

 

 

 

 

 

1.2. PIPO Register를 MUX를 통해 다시 구현하면 다음과 같다.

  • Output Common data bus와 레지스터 연결을 제어하기 위해서 삼항 버퍼를 사용한다.
  • Input Common data bus와 레지스터 연결을 제어하기 위해서 MUX를 사용한다.  
  • 여러 개의 8bit register 중 하나를 선택하여 접근하기 위해서는 DEMUX를 사용한다.

 

 

 

 

 

 

 

2. N bit  PIPO Shift Register (Negative)

< Source >

module PIPO_N_bit_Register_Negative #(parameter N = 8) (
    input clk, enable, reset_p,
    input write_enable_p,
    input read_enable_p,
    input [N-1 : 0] input_data,
    output [N-1 : 0] output_data);
    
    reg [N-1 : 0] pipo_reg;
    
    always @(negedge clk or posedge reset_p) begin
        if(reset_p) pipo_reg = 0;
        else if(enable) begin
            if(write_enable_p) pipo_reg = input_data;
            else pipo_reg = pipo_reg;
        end
    end
    
    assign output_data = (read_enable_p)? pipo_reg : 'bz;
    
endmodule

 

 

< Test bench >

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/16 20:04:41
// Design Name: 
// Module Name: tb_PIPO_N_bit_Register_n
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_PIPO_N_bit_Register_n();
    // set type of input / output
    reg clk, enable, reset_p;
    reg write_enable_p;
    reg read_enable_p;
    reg [6:0] input_data;
    wire [6:0] output_data;
    
    
    // create instance
    PIPO_N_bit_Register_Negative #(.N(7)) DUT (
    clk, enable, reset_p, write_enable_p, read_enable_p, input_data, output_data);
    
    // data
    parameter data = 7'b1010101;
    
    // initialization of simulation.
    initial begin 
        clk = 0; enable = 1; reset_p = 1; write_enable_p = 0; read_enable_p = 0; input_data = 0;
    end
    
    // set clock pulse
    always #5 clk = ~clk;
    
    // processing of simulation.
    initial begin 
        #5;
        
        // disable reset_p
        reset_p = 0; #5;
        
        // enable write_enable_p &  Input data
        write_enable_p = 1;
        input_data = data; #10;
        
        // disble write_enable_p & enable read_enable_p.
        read_enable_p = 1;
        write_enable_p = 0; #10;
        
        // delay time : 10ns
        #10;
        
        // End of simulation
        $finish;
    end

endmodule

 

 

< Simulation >

 

 

 

 

 

 

 

3. N bit  PIPO Shift Register (Negative, 2개 이상의 데이터를 레지스터에 저장) 

 

< Test Bench >

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/16 20:04:41
// Design Name: 
// Module Name: tb_PIPO_N_bit_Register_n
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_PIPO_N_bit_Register_n();
    // set type of input / output
    reg clk, enable, reset_p;
    reg write_enable_p;
    reg read_enable_p;
    reg [6:0] input_data;
    wire [6:0] output_data;
    
    
    // create instance
    PIPO_N_bit_Register_Negative #(.N(7)) DUT (
    clk, enable, reset_p, write_enable_p, read_enable_p, input_data, output_data);
    
    // data
    parameter data_0 = 7'b1010101;
    parameter data_1 = 7'b0111110;
    parameter data_2 = 7'b0010100;;
    
    // initialization of simulation.
    initial begin 
        clk = 0; enable = 1; reset_p = 1; write_enable_p = 0; read_enable_p = 0; input_data = 0;
    end
    
    // set clock pulse
    always #5 clk = ~clk;
    
    // processing of simulation.
    initial begin 
        #5;
        
        // disable reset_p
        reset_p = 0; #5;
        
        // enable write_enable_p &  Input data
        write_enable_p = 1;
        input_data = data_0; #10;
        
        // disble write_enable_p & enable read_enable_p.
        read_enable_p = 1;
        write_enable_p = 0; #10;
        
        // delay time : 10ns
        read_enable_p = 0;
        #10;
        
         // enable write_enable_p &  Input data
        write_enable_p = 1;
        input_data = data_1; #10;
        
        // disble write_enable_p & enable read_enable_p.
        read_enable_p = 1;
        write_enable_p = 0; #10;
        
        // delay time : 10ns
        read_enable_p = 0;
        #10;
        
         // enable write_enable_p &  Input data
        write_enable_p = 1;
        input_data = data_2; #10;
        
        // disble write_enable_p & enable read_enable_p.
        read_enable_p = 1;
        write_enable_p = 0; #10;
        
        // delay time : 10ns
        read_enable_p = 0;
        #10;
        
        // End of simulation
        $finish;
    end

endmodule

 

 

< Simulation >

  • Clock Pulse이 Negative edge일 때 + write_enable = 1일 때, 레지스터에 데이터 저장 가능
  • read_enable = 1일 때, (Clock Pulse와는 상관 없음) 레지스터에 저장된 데이터를 읽을 수 있다.

 

 

 

 

 

 

4. Output Common Data bus와 Input Common Data bus를 하나의 Common Data bus로  통합할 수 있다.

  • read_enable 과 write_enable 의 값에 의해 레지스터에 Read와 Write 가 결정되기 때문에 하나의 Common Data bus로  통합할 수 있다.
  • 따라서 Output Common Data bus와 Input Common Data bus를 하나의 Common Data bus로 통합하여 해당 Data bus을 통해 레지스터에 Read / Write 작업을 수행하기 때문에 통합된 Common Data bus는 양방향성 특성을 갖는다.