레지스터 (Registers)
디지털 시스템에서 레지스터(register)는 데이터를 저장하고 처리하는 핵심적인 순차 회로이다. 레지스터는 플립플롭(flip-flop)이라는 기본 저장 소자를 여러 개 모아 구성한 것으로 각 플립플롭은 클록 신호의 엣지(상승 또는 하강)에 따라 1비트의 데이터를 저장한다. 이처럼 n개의 플립플롭이 모이면 n비트 이진 데이터를 저장할 수 있는 레지스터가 된다.
레지스터는 공통의 클록 신호를 사용하여 동작하며, 내부에 조합 논리 회로(combinational gates)가 포함되어 데이터 입출력을 제어할 수 있다. 레지스터에는 비동기 초기화를 위한 Clear_b 신호가 존재할 수 있으며 이는 활성-로우(active-low)로 동작하여 해당 신호가 0이 되면 모든 출력이 즉시 0으로 초기화된다.
한편, 카운터(counter)는 일종의 특수한 레지스터로, 입력 펄스에 따라 일정한 이진 상태 순서를 따라 전이합니다. 상태 전이는 일반적으로 게이트를 통해 제어되며, 카운터는 주로 타이밍, 계수, 주파수 분할 등에 사용된다.
병렬 로드(Parallel Load) 레지스터
병렬 로드 기능이 있는 레지스터는 모든 비트를 동시에 입력값으로 갱신할 수 있도록 설계되어 있다. 이는 Load 제어 신호에 의해 동작하는데 Load = 1일 경우 새로운 데이터가 레지스터에 병렬로 로드되고 Load = 0이면 현재의 데이터를 그대로 유지합니다. 즉, Load가 0일 때는 데이터를 다시 입력으로 순환(recircultation)시켜 상태를 유지하는 구조입니다.
클록 처리 시 유의사항
클록 경로에서 논리 게이트를 사용하는 것은 타이밍 오류(timing issues)를 초래할 수 있으므로 피해야 한다. 대신, 클록은 항상 플립플롭에 직접 연결하고 제어 논리는 데이터 경로(data path)에 위치시키는 것이 바람직하다. 이를 통해 모든 플립플롭이 동시에 동작하게 하여 시스템의 타이밍을 깔끔하고 안정적으로 유지할 수 있다.
Shift Register
시프트 레지스터(Shift Register)는 데이터를 한 비트씩 밀어가며 저장하고 이동시키는 장치다. 여러 개의 D 플립플롭을 일렬로 연결한 형태로 구성되며, 모든 플립플롭은 동일한 클럭을 받아 동시에 동작한다. 이 구조 덕분에, 클럭이 한 번 발생할 때마다 각 비트는 오른쪽으로 한 칸씩 이동한다. 왼쪽 끝에는 새로운 데이터가 들어오고, 오른쪽 끝의 데이터는 출력되거나 사라진다.
예를 들어, 입력값이 순서대로 1, 0, 1, 1이 들어온다고 가정해보자. 처음에 모든 저장값이 0이었다면, 첫 번째 클럭에서는 1이 맨 왼쪽에 저장되고 나머지는 그대로여서 1000이 된다. 두 번째 클럭에서는 이 1이 오른쪽으로 한 칸 밀리고, 새로 들어온 0이 맨 왼쪽에 저장되어 0100이 된다. 이런 방식으로 네 번의 클럭이 지나면 최종적으로 1111이 된다.
이처럼 시프트 레지스터는 복잡한 연산 없이 단순한 비트 이동만으로 데이터를 순차적으로 처리할 수 있기 때문에, 직렬 통신, 간단한 계산기, 또는 타이밍 제어 회로 등에 널리 사용된다. 기본 형태는 오른쪽으로만 이동하는 단방향 구조지만, 양방향 이동이나 병렬 입출력이 가능한 확장형도 존재한다.
아래 회로의 목적은 클럭 신호를 직접 막지 않으면서도, D 플립플롭의 출력이 변하지 않도록 만드는 것이다. 다시 말해, 클럭이 동작해도 값이 유지되게 하여, 마치 클럭이 멈춘 것처럼 보이게 한다.
- 회로는 MUX(멀티플렉서)와 D 플립플롭으로 구성되어 있다.
- Data_gate라는 제어 신호가 데이터 흐름을 결정한다
0 | 외부 데이터(Data)가 플립플롭에 전달되어 클럭마다 새로운 값이 저장된다. |
1 | 플립플롭의 현재 출력값(Q)이 다시 입력으로 되돌아가 저장되기 때문에, 값이 바뀌지 않고 그대로 유지된다. |
시프트 레지스터의 직렬 모드는 데이터를 한 번에 한 비트씩 전송하는 방식으로 모든 비트를 동시에 전송하는 병렬 모드와는 대비된다. 직렬 전송에서는 데이터가 차례차례 이동하며 한 비트씩 목적지로 전달된다.
이 방식의 기본 구성은 두 개의 시프트 레지스터, 즉 A와 B를 사용하는 것이다. A는 데이터를 보내는 출발지(소스) 역할을 하고, B는 이를 받는 목적지(디스티네이션) 역할을 한다. A 레지스터의 직렬 출력(SO, Serial Output)은 B 레지스터의 직렬 입력(SI, Serial Input)에 직접 연결된다. A는 자기 데이터를 보존하기 위해 피드백 경로를 가지며, 반대로 B는 새 데이터를 받으면서 기존에 있던 데이터는 오른쪽으로 밀려나 사라진다. 따라서 B의 이전 데이터를 보존하려면 별도로 저장해 두어야 한다.
이러한 직렬 전송은 보통 Shift Control 신호를 이용해 제어된다. 예를 들어 AND 게이트를 사용하여 클럭이 특정 횟수만 통과하게 만들 수 있다. 이렇게 하면, 예를 들어 4비트 데이터를 전송하고 싶을 때 클럭이 정확히 4번만 동작하도록 보장할 수 있다. 이를 통해 전송 과정의 타이밍을 안정적으로 제어할 수 있으며, 타이밍 다이어그램을 통해 이 과정을 시각적으로 확인할 수 있다.
직렬 전송에서는 데이터를 한 비트씩 순서대로 이동시킨다. 예를 들어, 레지스터 A에 1011, 레지스터 B에 0010이 초기값으로 저장되어 있다고 하자. 이때 A는 데이터를 보내는 소스이고, B는 데이터를 받는 목적지이다. 이 상태에서 4번의 클럭이 발생하면, A의 값은 변화 없이 그대로 유지되고, B의 값은 A로부터 비트를 하나씩 받아 최종적으로 1011이 된다. 즉, A의 데이터를 B가 그대로 복사해 받은 셈이다.
이러한 방식에서는 데이터가 하위 비트(LSB)부터 상위 비트(MSB) 방향으로 이동하며, 클럭이 한 번 발생할 때마다 1비트씩 전송된다. A와 B의 시프트 동작은 클럭 상승 엣지마다 동시에 이루어진다.
직렬 전송은 병렬 전송보다 속도는 느리지만, 하드웨어 연결선이 훨씬 적다는 큰 장점이 있다. 병렬 전송에서는 비트 수만큼 선이 필요하지만, 직렬 전송에서는 한 쌍의 선(입력/출력)만으로도 데이터 전송이 가능하다.
마지막으로, 회로 설계에서 클럭 신호 자체를 논리 게이트(예: AND)로 제어하는 방식은 추천되지 않는다. 대신, 클럭은 항상 동일하게 공급하고, 입력 경로를 제어하여 데이터 흐름을 관리하는 방식이 타이밍 오류 없이 안정적인 설계로 간주된다.
Serial Adder(직렬 덧셈기)는 이진수를 한 비트씩 순차적으로 더하는 회로로, 시프트 레지스터와 풀 애더(Full Adder) 하나만을 사용하여 구현된다. 이 방식은 병렬 덧셈기처럼 여러 비트를 한 번에 더하지 않고, 클럭이 들어올 때마다 가장 오른쪽 비트(LSB)부터 한 비트씩 계산해 나간다.
동작 방식은 다음과 같다. 레지스터 A와 B에는 각각 두 개의 이진수가 저장되어 있고, 각 클럭 사이클마다 A와 B의 하위 비트가 풀 애더로 입력된다. 여기에 이전 연산에서 생긴 캐리(Carry) 값도 함께 더해진다. 이때 나온 합(Sum)은 다시 A에 저장되고, 캐리는 별도의 플립플롭에 보관되어 다음 비트 연산에 사용된다. 클럭이 반복되며 모든 비트를 순차적으로 더하게 되면, 최종적으로 레지스터 A에는 결과값이 저장되고, 필요하다면 마지막 캐리도 출력으로 처리할 수 있다.
이 방식의 가장 큰 장점은 하드웨어가 매우 단순하다는 것이다. 병렬 덧셈기처럼 비트 수만큼 풀 애더를 쓰지 않아도 되기 때문에, 전력 소모가 적고 회로 면적도 작아 VLSI(초고밀도 집적회로) 설계에 적합하다. 대신 연산 속도는 느린 편인데, 이는 비트 수만큼의 클럭 주기가 필요하기 때문이다.
직렬 덧셈기는 시프트 레지스터와 풀 애더 하나만으로 이진수 덧셈을 수행하는 간단한 구조의 회로다. 기본 구성은 다음과 같다. 레지스터 A는 피가산수(Augend)를 저장하며 동시에 결과값 저장소로도 사용된다. 레지스터 B는 가산수(Addend)를 저장하고, 연산 중에 새로운 수를 직렬로 입력받는 역할도 할 수 있다. 풀 애더(Full Adder)는 A와 B의 출력 비트(LSB)와 이전 단계의 캐리(Carry)를 입력받아 한 비트 덧셈을 수행한다. 캐리는 별도의 플립플롭에 저장되어 다음 비트 덧셈에 사용된다.
초기 설정에서는 레지스터 A에 첫 번째 수를, 레지스터 B에 두 번째 수를 각각 저장한다. 그리고 캐리 플립플롭은 초기값 0으로 설정한다. 이후 클럭이 한 번 들어올 때마다 A와 B는 오른쪽으로 한 비트씩 시프트되고, 각자의 최하위 비트가 풀 애더로 들어가 캐리와 함께 더해진다. 그 결과 합(Sum) 비트는 A의 LSB에 저장되고, 새로 생긴 캐리는 캐리 플립플롭에 저장된다. 이 과정을 n비트 수에 대해 n번 반복하면 전체 덧셈이 완료된다.
또한 이 구조는 연산 도중에 레지스터 B에 새로운 수를 계속해서 입력할 수 있기 때문에, A에 여러 개의 수를 차례대로 누적해서 더하는 다중 피연산자 누산(누적) 연산도 가능하다. 이런 특성 덕분에 직렬 덧셈기는 연산량은 많지만 회로를 간단히 유지해야 하는 **저전력, 소형 시스템(VLSI 설계)**에서 매우 유용하게 사용된다.
기존 직렬 덧셈기에서는 캐리(Carry)를 저장하는 데 D 플립플롭을 썼다면,이번 설계에서는 JK 플립플롭을 사용해 캐리를 저장하려는 거야.JK 플립플롭은 다양한 동작을 하나로 처리할 수 있기 때문에,조금 더 유연하고 간단한 논리로 회로를 구성할 수 있어.
JK 플립플롭이란?
- J = 1, K = 1 → 토글 (현재 값 반전)
- J = 1, K = 0 → 세트 (1 저장)
- J = 0, K = 1 → 리셋 (0 저장)
- J = 0, K = 0 → 유지
즉, J와 K의 값에 따라 다음 상태가 정해지기 때문에, 현재 상태(Q)와 원하는 다음 상태를 보고 J, K 값을 계산해야 해.
이때 쓰는 것이 Excitation Table(유도표)야.
Shift Register A | 피가산수(Augend) + 결과 저장소 |
Shift Register B | 가산수(Addend) + 입력 데이터 |
Full Adder (FA) | A, B, 캐리(Carry)를 받아 한 비트 덧셈 수행 |
JK Flip-Flop | Carry 비트를 저장 |
여기서 입력값을 x, y, Q라고 하자:
- x = A 레지스터의 현재 출력 (A0)
- y = B 레지스터의 현재 출력 (B0)
- Q = 캐리 플립플롭의 현재 상태
각 논리식은 다음과 같다:
- JQ = x · y
→ J 입력은 A와 B 모두가 1일 때만 1 - KQ = (x + y)’
→ K 입력은 A나 B가 둘 다 0일 때만 1 - S = x ⊕ y ⊕ Q
→ S는 FA의 출력, A 레지스터에 저장될 덧셈 결과
이 세 식은 JK 플립플롭이 원하는 캐리 출력을 내도록 제어하는 입력 값이야.
어떻게 작동하나?
- 각 클럭이 들어오면 A와 B의 LSB가 풀 애더에 들어가고, 캐리도 함께 더해짐.
- FA의 합(S)은 다시 A의 LSB로 저장
- FA의 캐리는 JK 플립플롭에 저장
- 다음 클럭에서 다시 오른쪽으로 시프트, 새로운 덧셈 수행
예시 없이 간단 흐름 요약
- A와 B는 시프트 레지스터로 각자 1비트씩 이동
- JK 플립플롭은 캐리 값을 저장하는 데 사용
- J, K 입력은 A, B, 캐리 값(x, y, Q)에 따라 논리식으로 계산됨
- 전체 회로는 매우 적은 구성(1 FA, 1 FF, 2 레지스터)으로 효율적인 덧셈기 완성
시프트 레지스터는 데이터를 저장하고 이동시키는 회로로, 이동 방향과 데이터 입력 방식에 따라 여러 가지 유형이 있다. 단방향 시프트 레지스터(Unidirectional Shift Register)는 데이터가 한쪽 방향(보통 오른쪽)으로만 이동하는 구조다. 반면에 양방향 시프트 레지스터(Bidirectional Shift Register)는 데이터가 왼쪽으로도, 오른쪽으로도 이동할 수 있도록 설계되어 있다.
이보다 더 확장된 형태가 바로 범용 시프트 레지스터(Universal Shift Register)다. 이 회로는 단방향·양방향 시프트뿐만 아니라, 외부 데이터를 한 번에 저장할 수 있는 병렬 로드(Parallel Load) 기능까지 갖춘 다기능 레지스터이다. Universal Shift Register는 보통 2비트 선택 신호 (s1, s0)에 따라 동작 모드가 결정된다.
- 00은 Hold 상태로, 클럭이 들어와도 값이 그대로 유지된다.
- 01은 오른쪽 시프트로, 왼쪽에서 입력된 데이터(MSB_in)가 가장 왼쪽 비트(A3)로 들어가며 나머지는 오른쪽으로 밀린다.
- 10은 왼쪽 시프트로, 오른쪽에서 입력된 데이터(LSB_in)가 가장 오른쪽 비트(A0)로 들어가고, 나머지는 왼쪽으로 이동한다.
- 11은 병렬 로드 모드로, 외부 입력값이 모든 비트에 동시에 저장된다.
이러한 범용 시프트 레지스터는 디지털 시스템 간의 데이터 통신에도 자주 활용된다. 예를 들어, 송신기(transmitter)는 n비트 병렬 데이터를 직렬 데이터로 변환하기 위해 시프트 레지스터를 사용하고, 수신기(receiver)는 반대로 직렬 데이터를 병렬 데이터로 복원하기 위해 시프트 레지스터를 사용한다. 덕분에 물리적인 연결 선을 줄이고, 간단한 인터페이스로 긴 거리를 효율적으로 통신할 수 있게 된다.
Ripple Counters