Clock
사람이 오후 5시, 오전 9시와 같은 시간을 기준으로 모임, 약속, 회의와 같은 행위 시간을 잡듯, 컴퓨터의 모든 부품들도 하나의 기준 시간에 따라 돌아가며 단위 부품들이 실행되어야 한다. (이를 '모듈간의 동기화' 라고 한다.)
따라서 각 부품들이 실행될 타이밍을 기술할 시간 단위가 필요하다.
하지만 컴퓨터는 사람이 사용하는 24시간, 60분, 60초의 단위를 그대로 이해할 수 없다.
그래서 컴퓨터 부품들을 위한 전용 시계를 만들어두었는데, 이를 '클럭' 이라고 한다.
클락은 말 그대로 시계처럼 똑딱똑딱하듯 일정한 주기로 0, 1의 신호가 번갈아 나오는 파형이다.
모든 컴퓨터 부품은 이 클럭 주기에 맞춰 움직이기 때문에, 클럭 주기가 높을수록, 컴퓨터 부품이 움직이는 속도도 빨라진다. (그래서 컴퓨터 부품 맞출 때 성능을 높이기 위한 오버클럭 이야기를 하는 것이다.)
클럭도 '파형' 이기 때문에 물리에서 사용하는 파동의 개념을 그대로 사용한다.
1GHz 의 주파수를 가진 CPU는 1초에 1G = 10^9 번 파형이 왔다갔다하는 클럭신호를 갖고 있다.
하나의 파형 기준으로 본다면 주기가 10^-9 = 1 나노초(ns, nano sec)인 파형을 말한다고도 할 수 있다.
만약 클럭의 주기가 2 ns 인 CPU를 샀다면 이 CPU의 주파수는 0.5GHz가 된다.
만약 주파수가 2GHz인 CPU를 샀다면 이 CPU의 주기는 0.5 ns가 된다.
Verilog
베릴로그는 하드웨어의 동작을 기술하는 언어이다.
주어진 그림은 ra1 레지스터에서 메모리 주소를 가져와 데이터를 읽어 rd1으로 가져오고
ra2레지스터에서 메모리 주소를 가져와 해당 위치의 데이터를 읽어 rd2로 가져온다.
그 뒤 wa 주소에 wd 데이터를 쓰는 작업을 하는데, we포트는 write enable의 약자로, 값을 쓸지 말지 결정하는 control 포트이다.
마지막으로 그림에는 안 나와있지만, 위에서 설명한 클락 주기가 들어오는 clk 포트까지 존재한다.
이 그림을 베릴로그로 표현하면 아래와 같다.
module regfile(
input clk,
input we,
input [4:0] ra1, ra2, wa,
input [31:0] wd,
output [31:0] rd1, rd2);
reg [31:0] rf[31:0];
// three ported register file
// read two ports combinationally
// write third port on rising edge of clock
// register 0 hardwired to 0
always @(posedge clk)
if (we) rf[wa] <= wd;
assign rd1 = (ra1 != 0) ? rf[ra1] : 0;
assign rd2 = (ra2 != 0) ? rf[ra2] : 0;
endmodule
우선 베릴로그는 모듈단위로 기능을 기술하기 때문에 module, endmodule 키워드로 시작과 끝을 지정한다.
module 키워드 이후에는 이 모듈의 이름을 마음대로 기술할 수 있다.
위 코드에서는 이 모듈의 이름을 regfile 이라는 이름으로 기술한다.
괄호 안에는 이 모듈을 둘러싸고 있는 모든 포트를 기술해주면 된다.
현재 그림에서는 ra1, ra2, wa, wd, rd1, rd2, we 라는 6개 포트가 존재한다.
input port 로는 clk, we 포트, 5bit 데이터가 들어오는 ra1, ra2, wa 포트, 32bit 데이터가 들어오는 wd 포트가 있다.
ra1, ra2, wa 포트가 5bit 인 이유는, 레지스터가 0부터 31까지 총 32 = 2^5 개가 있기 때문이다.
output port 로는 32bit 데이터가 나가는 rd1, rd2 포트가 있다.
받는 bit 수는 큰 수부터해서 대괄호 안에 범위를 기술한다.
(내 생각에는 몇 비트인지 명시하지 않으면 1bit 데이터를 받는 것 같다. clk, we 모두 1bit 형태의 데이터만 받을 것 같기 때문..)
reg [31:0] rf[31:0];
이 코드는 레지스터를 선언하는 코드이다.
reg는 키워드로 지금 선언하는게 레지스터다 라고 명시하는 역할이다.
MIPS는 총 32개의 레지스터를 갖고 있으므로 [31:0] 으로 32개 레지스터를 선언한다고 명시한다.
그 뒤에는 마치 배열이름 짓듯이 레지스터의 이름을 기술한다.
(레지스터 타입의 32사이즈 배열을 선언하는 느낌으로 이해했다.)
always @(posedge clk)
if (we) rf[wa] <= wd;
이 코드는 쓰기를 수행하는 코드로 아래와 같이 해석된다.
always : 항상 실행한다.
@() : 이 상황이 되면
posedge clk : 클럭이 positive edge 일 때
실행할 내용은
만약 we 가 활성화 되어있다면, rf[wa], 즉, wa 가 가리키는 위치의 레지스터에 wd 값을 쓴다.
클럭이 positive edge 라는 말은 클럭이 0에서 1로 올라가는 형태의 파형이 되는 순간을 의미한다.
그림으로보면 위와 같다.
assign rd1 = (ra1 != 0) ? rf[ra1] : 0;
assign rd2 = (ra2 != 0) ? rf[ra2] : 0;
이 코드는 ra1, ra2 값이 0이 아니라면 해당 레지스터의 값을 rd1, rd2 포트에 저장하고, 아니라면 0을 쓰는 코드이다.
(참고로 0번 레지스터는 값이 항상 0이기 때문에 이렇게 쓴다.)
순차회로와 조합회로
순차회로는 이전 값을 기억하고 이전 값과 현재 값을 조합하여 값을 내보는 회로를 의미한다.
조합회로는 현재 값에 따라 바로바로 값을 내보내는 회로를 의미한다.
위 코드에서 읽기 동작 (assign 키워드) 는 조합회로이다.
ra1 에 담기는 레지스터 번호가 바뀌면 output port rd1, rd2 에 들어가는 값이 그 즉시 바뀐다.
rd1, rd2 는 레지스터 번호에 직접 연결되어 항상 그 값을 갖고 있는 조합회로인 것이다.
반면 쓰기 동작은 postive edge 에서만 일어나고, 이외의 edge 에서는 이전 값을 기억하고 있으므로 순차회로이다.
'CS > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] 6. MIPS Branch Instructions (0) | 2024.04.15 |
---|---|
[컴퓨터 구조] 5. MIPS Data Transfer Instructions (2) (0) | 2024.04.14 |
[컴퓨터 구조] 4. MIPS Data Transfer Instructions (1) (0) | 2024.04.06 |
[컴퓨터 구조] 3. MIPS Arithmetic & Logical Instruction (0) | 2024.04.06 |
[컴퓨터 구조] 1. MIPS Instruction & Register (0) | 2024.03.12 |