오늘은 기존에 공부하던 UVM을 위한 System Verilog의 연장선을 배웠습니다.
아래의 그림에서, 오른쪽 부분 Generator, Mailbox, Driver, Interface, DUT에 대해서만 배웠었다면
이번에는 왼쪽 부분인 ScoreBoard, Mailbox, Monitor, Interface, DUT에 대해 배우고 전체 Testbench에 대해서 배웠습니다.
왼쪽부분에 간략히 설명하자면, 오른쪽 부분과 데칼코마니 처럼 비슷합니다. DUT에서 나오는 Output을 Interface의 전선다발로 받게 되고, Monitor가 H/W로 받은 전선 다발을 풀어 S/W의 Tr로 변경해 줍니다.
변경된 Tr은 Mailbox에 들어가고, 이를 감지하는 ScoreBoard가 tr을 받아와 reference model에서 Test 하여 값에 대한 출력을 나타내게 됩니다. 이때, Reference Model이 중요한데, 이는 기존의 H/W dut를 S/W의 방식으로 표현했다고 생각하시면 됩니다.
이에 대한 테스트로 Ram을 설계하고 TestBench를 돌려보겠습니다.
RAM : Single port RAM
RAM 안에 clk, reset + Memory 존재
Memory를 사용하기 위해, Write En, Write Addr, Write Data, Read En, Read Addr, Read Data,
**(Write, Read En은 한개로 묶어 1일 경우 write 동작 수행 + 0일 경우 Read 동작 수행)**
RAM에 대한 Interface를 가볍게 짠 후, Testbench 동작을 수행 할 것입니다.
Testbench입니다. RAM에 대한 interface를 작성하고, Testbench 그림의 오른쪽 부분을 작성합니다. Generator를 통해 RAM에 넣을 Random한 변수를 만들어 냅니다.
Driver는 생성된 Random한 변수를 Mailbox에서 받아 H/W에서 사용할 수 있도록 변환하고, Inteface에 넘기게 됩니다.
Interface를 거쳐 DUT에 input으로 들어가게 됩니다. 그 결과로 DUT에서 output이 출력되고, 똑같이 Interface에 넘겨진 후 Monitor로 들어가게 됩니다. Monitor는 Driver와 반대 동작으로 H/W의 값을 S/W의 Tr로 변환하여 Mailbox에 넣어주게 됩니다. Mailbox에 값이 담기기를 기다리던 Scoreboard가 감지하고 Tr을 입력으로 받습니다. 입력받은 Tr은 S/W의 DUT라 불리는 reference model에 들어가 Test하게 되고 Scoreboard를 통해 출력됩니다.
Environment는 Test를 담당하는 모든것을 통칭합니다. Generator, Mailbox, Driver, Monitor, ScoreBoard 모두를 포함합니다.
그리고 고려해야할 상황이 하나 있습니다. WE의 신호 값이 clk의 상승엣지와 맞물리며 0으로 지속되는 상황이 발생하였습니다. 이를 해결하기 위해 WE의 신호를 살짝 늦추도록 Clock Blocking을 설정해 주었습니다.
Clock Blocking을 @wait(clk) 동작 후, #1을 추가하여 1ns 후에 we를 떨어뜨리거나 clocking 모듈을 활용하여, clk의 상승에지 후에 항상 1ns 기다렸다가 동작을 수행하도록 합니다.
그리하여, 최종적으로 Testbench에 Random한 Addr과 Data를 Random한 WE(1: Wirte, 0: Read) 신호에 따라 값을 출력하는 것을 확인할 수 있습니다.
Random한 Addr, Data를 성공적으로 출력하는 모습
$display와 값 비교를 통해 성공적인 Test를 확인하는 모습
UVM을 위한 Test Bench는 여기서 마치고, RISC - V를 만들기 위한 작업에 돌입하겠습니다.
RISC-V
RV32I : Single - Cycle Architecture
장점 : 매우 Simple
단점 : 매우 느리다
-----> Multi - Cycle Architecture
명령마다 동작 clock 수가 다르다
장점 : Single-Cycle 보다 빠르다
단점 : Single-Cycle 보다 복잡하다
-----> Pipe-Line
장점 : 매우 빠르다
단점 : 매우 복잡하다
RISC - V의 Memory(Register File)
x0 : "0"으로 고정 + pc : Program Counter 존재
CPU 기본 모듈(하버드 구조)
*********************************
Intruction Memory(ROM / FF),
Data Memory(RAM)
Register File
ALU
PC(Program Counter) -> Instruction Memory의 주소를 알려줌
**********************************
CPU(Control Unit , Program Counter, Register + ALU)
Datapath(Program Counter, Register, ALU)
저희는 RISC -V의 RV32I의 Single Cycle, Multi Cycle Architecture에 대해 설계할 것입니다.
하버드 구조의 CPU기본 모듈들을 설계하고 RV32I의 R-Type에 대해 구현할 것 입니다.
기본적으로, 32bit의 Data를 담는 32개의 방으로 이루어진 Register File과 ALU가 존재하고, 이를 제어하기 위한 Control Unit과 32bit 즉 4byte의 메모리에 대한 다음 Address 값을 위한 PC를 Core 부분으로 생각합니다. 그리고 왼쪽에 ROM, 오른쪽에 RAM과 상호작용하며 MCU를 구성하게 됩니다.
어제 0~10까지 누적합을 Register File을 통해 설계하며 제어 신호들을 묶어서 15bit의 신호로 보냈었습니다. 이번에는 32bit의 신호를 보내게 됩니다. 32bit의 신호는 아래와 같습니다.
아래의 그림은 R-Type에 대한 신호들 입니다. 연산에 대한 기능들이 있습니다. rs1과 rs2는 주소 Data로, 5bit의 rs1과 rs2의 주소에 있는 Data를 불러오고 기능에 대한 코드인 [11:7]과 [31:25]의 조합으로 연산에 대한 기능들을 수행하여 목적지 주소인 5bit rd에 값을 넣습니다. 이때 32bit의 신호는 ROM에서 나와 Control Unit, Register File에 들어가며 동작을 실행합니다.
아래는 코드입니다.
R-Type표에 맞춰 Register File 내부로 들어오게 될 32bit의 ROM DATA를 받게 될 rs1/2, rd를 지정하여, 32bit 코드에서 사용할 녀석들(rs1, rs2) 그리고 목적지 녀석(rd)를 연결해야합니다.
DataPath를 작성하며 R-Type표에 맞춰 9개의 ALU Control값을 생성합니다.
그리고 중요한 Control Unit입니다. Control Unit 또한 32bit의 ROM DATA를 받기 때문에 어떠한 연산을 할 것인지에 대해 판별해 주어야합니다. 위에 R-Type 표를 보게 되면 OPCode부분은 모두 동일하고, 연산 값을 모두 rd에 넣는다는 특징이 있습니다. 그리하여 7bit의 opcode가 010011일때 we신호를 1로 두어, 모든 연산 결과를 rd에 write할 수 있도록 하였습니다. 이를 case문으로 잘 활용한다면 I-Type, L-Type, S-Type 등 다양한 Type에 대한 차별점으로 활용할 수 있을 것 같습니다.
opcode가 010011임을 확인하여 신호들이 모두 R-Type임을 확인하고 이를 또 세분화 하는 과정이 필요합니다.
R-Type 표에서 나온 것처럼 ADD, SUB, OR, SLL, SLT 등 9개의 기능이 있는데 이를 구별하기 위해 3bit의 function3(R-Type표 의 [14:12])와 특정 신호에만 [30]의 위치에 1을 띄는 Function7을 결합하여 분간하였습니다.
이를, operator라는 4bit 신호를 만들어, 이 신호를 통해 ALU에 연산 제어 신호를 넣어주도록 설계하였습니다.
DataPath와 ControlUnit을 합친 RV32_Core
RV32에 32bit Data를 전송하여 Type에 맞는 연산을 수행하도록 하는 ROM
아래의 initial begin 구문은 R-Type에 대해 동작을 잘 수행하는지 확인하기 위해 넣었습니다. Testbench를 돌리며 결과를 보여드리겠습니다.
그리고, ROM을 설계하며 assign data = rom[addr[31:2]];를 작성해 놓은 부분이 있습니다. 주소의 하위 2비트를 버린다는 것인데, 명령어는 32bit == 4byte로 저장되기 때문에 4의 배수로 떨어지는 ROM의 index로 활용하기 위함입니다.
RV32_Core와 ROM을 합친 MCU (RAM은 추후에 달 예정입니당)
설계한 내용에 따른 결과 입니다.
아까 ROM에 대해 설명하며 Testbench를 위해 작성한 부분이 있는데, 아래 표로 정리 해 놓았습니다. Simulation 결과를 확인하며 참고하시면 되겠습니다.
아래 Simulation 결과를 확인하면,
제가 지정한 위치에 Addr1의 값인 11과 Addr2의 값인 12와 다양한 ALU연산을 하는 것을 확인할 수 있고, ALU 결과가 ALU Control에서 나오는 신호에 맞춰 특정 register위치들에 저장되는 것을 확인할 수 있습니다.
'[HARMAN] 세미콘 아카데미 > SystemVerilog' 카테고리의 다른 글
[Harman 세미콘 아카데미] Day_48(System Verilog) (0) | 2025.04.11 |
---|---|
[Harman 세미콘 아카데미] Day_47(System Verilog) (0) | 2025.04.10 |
[Harman 세미콘 아카데미] Day_46(System Verilog) (0) | 2025.04.09 |
[Harman 세미콘 아카데미] Day_44(System Verilog) (0) | 2025.04.08 |
[Harman 세미콘 아카데미] Day_43(System Verilog) (0) | 2025.04.07 |