[SRAM-PIM Core Circuit] Design 256x1 Analog CIM

"256x1 Analog CIM"


1. Introduction

Cell Array Size가 256x1이므로 256개의 Input이 256개의 Weight가 MAC 연산을 통해 1개의 4-bit Digital 값을 출력

· WL_BL (Wordline)
Bit-Cell의 문을 여닫는 Switch 제어 신호
Weight 데이터를 Bit-Cell에 새로 쓰거나 저장된 값을 읽어올 때 이 신호를 High 시켜 Tr On(평소 연산 수행 시 Low로 Tr Off)

· BL/BLB
Bit-Cell에 실제로 밀어 넣을 Weight 데이터가 지나다니는 데이터 Bus
이 셀에 Weight '+1'을 저장하고 싶다면 주변 회로에서 BL=1/BLB=0 전압을 걸어둔 상태로 WL_BL 문을 Open
→ 내부 Node VL=1/VR=0으로 설정(Weight '-1'을 저장하고 싶다면 반대로 BL=0/BLB=1 → VL=0/VR=1)

· VL/VR
SRAM Bit-Cell 내부에서 Weight 데이터가 머무르는 저장 공간
VL/VR은 항상 반대되는 상호 반전 상태 유지
Weight '+1'인 경우(VL=1/VR=0) : VL=1이므로 왼쪽 Tr ON → MWL로 들어온 신호가 Capacitor를 통과해 MBL로 전달
Weight '-1'인 경우(VL=0/VR=1) : VR=1이므로 오른쪽 Tr ON → MWLB로 들어온 신호가 Capacitor를 통과해 MBL로 전달

· MWL/MWLB
오직 MAC 연산을 수행하기 위해 입력 데이터를 전달하는 전용 신호선

2. Operation

① 연산 시작 전, MWL/MWLB를 Vrst(0.5VDR)인 0.4V로 Pre-Charge

② 입력 데이터 구분 (+1/-1)
'+1' 입력 : MWL = VDR로 상승/MWLB = Vss로 하강
'-1' 입력 : MWL = Vss로 하강/MWLB = VDR로 상승

③ Weight 데이터 구분 (+1/-1)
'+1' Weight (MWL Tr On)
· '+1' 입력 : MWL = VDR로 상승 → MBL 전압 상승 (곱셈 결과 +1)
· '-1' 입력 : MWL = Vss로 하강 → MBL 전압 하강 (곱셈 결과 -1)
'-1' Weight (MWLB Tr On)
· '+1' 입력 : MWLB = Vss로 하강 → MBL 전압 하강 (곱셈 결과 -1)
· '-1' 입력 : MWLB = VDR로 상승 → MBL 전압 상승 (곱셈 결과 +1)

④ 곱셈 결과를 누적한 값이 11단계 Flash ADC를 통해 4-bit Digital로 변환

3. Architecture

<8T1C>

<Comparator>
MBL > Vref → out = 1 / MBL < Vref → out = 0
이전에 설계한 Flash ADC 사용 시 MBL과 Vref를 비교기에 동시에 직접 연결하면 비교기가 0/1을 판별하며 강하게 켜지고 꺼질 때 발생하는 Switching Noise가 MBL로 역류하여 영향을 줌
∴ C3SRAM 논문에서 제시한 Comparator 방식을 사용하여 계산 시 연결을 끊어 MBL로 역류하여 영향을 주는 것을 방지

<Edge Detector>
낮은 Bit 자리의 값이 a, 높은 Bit 자리의 값이 b로 인가
a=1, b=0인 경우 out=1 / a=1, b=1인 경우 out=0이 되어 경계값 찾기

<256x1 Analog CIM>
이전에 Flash ADC 설계 시 사용한 방법(진리표를 바탕으로 OR Gate 사용)을 사용하여 결과값 출력 

4. Setting & Result


  <'+1' Weight>                                        <'-1' Weight>   

[('Sum = 0' Input) x ('+1' Weight)]
<('Sum = 0' Input) x ('+1' Weight)>

<Python Code for 'Sum = 0' Input>

<'Sum = 0'일 때의 MBL 전압>
rst0가 Low로 떨어질 때 MBL과 Capacitor 사이의 Switch가 Off 되어 이 순간의 MBL 전압이 Capacitor에 영구적으로 갇힘
→ rst0가 Low인 순간의 전압이 Vref와 비교

<Step of Vref>
'Sum = 0'일 때 MBL 전압이 약 0.385V이므로 이를 중간점으로 잡고 30mV 간격으로 11단계를 나눔

<'Sum = 0'일 때의 MBL 전압과 Vref>

<'Sum = 0'일 때의 result>
Vref4 < MBL < Vref5 → result = 0101(11단계(0000~1010)의 중간 값)

[('Sum = +50' Input) x ('+1' Weight)]
<('Sum = +50' Input) x ('+1' Weight)>

<Python Code for 'Sum = +50' Input>

<'Sum = +50'일 때의 MBL 전압>

<'Sum = +50'일 때의 MBL 전압과 Vref>

<'Sum = +50'일 때의 result>
Vref6 < MBL < Vref7 → result = 0111

[(Random Input) x (Random Weight)]
<(Random Input) x (Random Weight)>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import random
 
ROWS = 256
COLS = 1
V_RST = 0.385     # Sum=0일 때의 기준 전압
V_UNIT = 0.0013   # 셀 하나당 전압 변화량 {(+50 = 0.450V) - (0 = 0.385V)} / 50
 
# ADC 전압 단계
V_STEPS = [0.250.280.310.340.370.400.430.460.490.52]
 
# 데이터 생성 (Input: -1, 0, 1 / Weight: -1, 1)
inputs = [random.choice([-101]) for _ in range(ROWS)]
weights = [[random.choice([-11]) for _ in range(COLS)] for _ in range(ROWS)]
 
# --- [SPICE Stimuli 출력] ---
print("*" * 65)
print("  [1] SPICE STIMULI (DIFFERENTIAL + ZERO INPUT)")
print("*" * 65)
 
print("\n# --- 차동 입력 ---")
for i, inp in enumerate(inputs):
    if inp == 1:
        print(f"vmwl{i:<4} MWL<{i}> 0 pwl(0 0.4 15n 0.4 15.1n 0.8)")
        print(f"vmwlb{i:<3} MWLB<{i}> 0 pwl(0 0.4 15n 0.4 15.1n xvss)")
    elif inp == -1:
        print(f"vmwl{i:<4} MWL<{i}> 0 pwl(0 0.4 15n 0.4 15.1n xvss)")
        print(f"vmwlb{i:<3} MWLB<{i}> 0 pwl(0 0.4 15n 0.4 15.1n 0.8)")
    else# Input 0 case
        print(f"vmwl{i:<4} MWL<{i}> 0 pwl(0 0.4 15n 0.4 15.1n 0.4)")
        print(f"vmwlb{i:<3} MWLB<{i}> 0 pwl(0 0.4 15n 0.4 15.1n 0.4)")
 
print("\n# --- 초기 가중치 (.ic) ---")
for r in range(ROWS):
    for c in range(COLS):
        cell_idx = r * COLS + c
        if weights[r][c] == 1:
            print(f".ic v(VL<{cell_idx}>)=xvdd v(VR<{cell_idx}>)=xvss")
        else:
            print(f".ic v(VL<{cell_idx}>)=xvss v(VR<{cell_idx}>)=xvdd")
 
# --- [Step 기준 결과 예측] ---
print("\n" + "*" * 50)
print("  EXPECTED RESULTS (USER DEFINED STEP CRITERIA)")
print("*" * 50)
 
def classify_adc(v_mbl):
    # <Step Of Vref> 기준에 따른 분류 로직
    for code, threshold in enumerate(V_STEPS):
        if v_mbl < threshold:
            return code
    return 10 # 0.52V 이상일 경우 표의 마지막 값인 1010(Code 10) 출력
 
adc_results = []
for c in range(COLS):
    dot_sum = sum(inputs[r] * weights[r][c] for r in range(ROWS))
    # 물리적 전압 계산: 초기전압 + (누적합 * 단위전압)
    predicted_v = V_RST + (dot_sum * V_UNIT)
    code = classify_adc(predicted_v)
    adc_results.append(code)
    print(f"Sum={dot_sum:>4} | Voltage={predicted_v:.4f}V | Code={code:>2}")
cs
<Python Code for Random Input & Random Weight>
'Sum = 0'일 때 MBL 전압은 0.385V, 'Sum = +50'일 때 MBL 전압은 0.450V
→ 기준 전압 = 0.385V, 전압 변화량 = {(+50 = 0.450V) - (0 = 0.385V)} / 50

<(Random Input) x (Random Weight) 예상 출력 값>

<MBL 전압>

<MBL 전압과 Vref>

<result = 0100>
MBL 전압 값의 차이는 약 550uV로 회로 상 존재하는 Noise로 인한 약간의 오차로 간주

5. Reference

▶ C3SRAM
https://hecess.blogspot.com/2026/01/sram-pim-core-circuit-study-c3sram-paper.html

댓글

이 블로그의 인기 게시물

[Mini-NPU RTL] NN Reference Model

[Mini-NPU RTL] TPU (Study Paper)