1. Introduction
micro-architecture: datapath, controller
single-cycle: 한 사이클에 하나의 명령어
pipeline: 실행하는 동안 여러 명령어가 오버랩, 실행이 여러 단계로 쪼개짐
cpu time: #insts * CPI * clock cycle time = #insts * cpi / f
(cpi는 명령어 1개에 필요한 평균 사이클 수)
- combitnaional logic: 아웃풋이 현재 인풋에 의해 바로 튀어나옴
ex) and, add, mux, alu
- sequential logic: 아웃풋은 현재 인풋 + 이전 인풋 같은 것들도 고려하여 결정
-> flip-flop을 상태 정보를 저장하기 위해 사용
register store data in a circuit (by flip-flop)
-> 클락 신호가 언제 값을 업데이트 하는지 결정
- rising edge(0->1), falling edge(1->0)
-> 데이터 인풋이 무엇을 업데이트 하는지 결정 (0 or 1)
-> write 컨트롤이 있다면 얘도 1이여야 업데이트
clk이 rising edge일 때 D 값이 있으면 Q에 복사, 다음 rising edge까지 값 유지
조합 회로는 두 state element(플립플롭) 사이에 위치
여러 조합 회로 중 가장 긴 애가 주파수를 결정
메모리에서 명령어, 데이터를 주고 받는 포트를 분리함
- behavioral modeling: 모듈을 있는 그대로 기술
- structural modeling: 이미 정의해놓은 module들을 가져다씀
microarchitecture는 datapath와 contorl로 구성
- datapath: data가 흘러가는 경로, used to operate or hold data
ex) register file(hold data), ALU(operate), mux, memory
- contorl: datapath element를 제어, datapath가 어떻게 명령어를 실행해야하는지 알려줌
ex) mux select, register enable, ALU control, memory write signals ...
2. Instruction Execution in CPU
1) Fetch: pc를 이용하여 명령어 주소를 제공받고 메모리에서 명령어를 fetch 한다.
2) Decoding: 명령어를 해석하고 operand를 읽는다.
3) Execution: 계산을 위해 ALU를 사용한다.
ex) 산술/논리 연산, 접근하고자 하는 메모리 주소 계산, 분기하고자 하는 주소 계산
Next Fetch: pc <- pc+4
1) Instruction Fetch
외부에서 reset, clock 신호가 생성되어 들어온다. pc는 32비트 레지스터임.
pc를 이용하여 메모리에 접근하여 32비트 명령어를 cpu로 fetch해온다.
pc는 다음 명령어를 가져오기 위해 pc+4를 계산하여 다시 pc로 돌아옴.
module pcreg (
input clk,
input reset,
input [31:0] pcnext,
output reg [31:0] pc); // 입출력 포트 기술,
always 구문에 사용 시 reg 키워드 추가
always @ (posedge clk, posedge reset) // reset or clk이 0->1
begin
if (reset) pc <= 32'h00000000; // reset이 0->1이면 0으로 초기화
else pc <= pcnext; // clk이 0->1이면 pcnext로 초기화
end
endmodule
module myadder (
input [31:0] a,
input [31:0] b,
output [31:0] y);
assign y = a + b; // 간단한 조합회로는 assign으로 기술
endmodule
module mips (
input clk,
input reset,
output [31:0] pc);
wire [31:0] pecnext; // 내부적으로 생성하고 사용
// pcreg 인스턴스화
pcreg mips_pc (.clk (clk),
.reset (reset),
.pc (pc),
.pcnext(pcnext));
// adder 인스턴스화
myadder pcadd4 (.a (pc),
.b (32'b100), // 상수 4
.y (pcnext));
endmodule
// generic memory model in verilog
module mem (input clk, MemWrite,
input [7:2] Address, // word 단위로 읽을거라 하위 2비트는 버림
input [31:0] WriteData,
output [31:0] ReadData);
reg [31:0] RAM[63:0];
// Memory Initialization
initial
begin
$readmemh("memfile.dat",RAM);
end
// Memory Read
assign ReadData = RAM[Address[7:2]]; // 간단한 조합 회로
// Memory Write
always @(posedge clk)
begin
if (MemWrite)
RAM[Address[7:2]] <= WriteData;
end
endmodule
2) Instruction Decoding (32비트 명령어 해석)
control logic은 opcode, fucnt 필드 읽어들임 -> datapath control 제공
operand는 명령어의 register number 또는 immediate field를 32비트로 확장해서 사용
module regfile (input clk,
input RegWrite,
input [4:0] ra1, ra2, wa,
input [31:0] wd,
output [31:0] rd1, rd2);
reg [31:0] rf[31:0]; // 32비트 32개
always @ (posedge clk)
if (RegWrite) rf[wq] <= wd;
assign rd1 = (ra1 != 0) ? rf[ra1] : 0; // ra가 0이면 0, 아니면 rf[ra]
assign rd2 = (ra2 != 0) ? rf[ra2] :0;
endmodule
module sign_zero_ext (input sign_ext,
input [15:0] a,
output reg [31:0] y);
always @(*) // 항상 들여다봄
begin
if (sign_ext) y <= {{16{a[15]}}, a};
else y <= {{16{1'b0}}, a};
end
endmodule
3-1) Instruction Execution #1
- R-type: 산술, 논리 연산 ex) add, sub, and, or
레지스터 파일에서 2개의 피연산자를 가져옴 rs, rt, rd
- I-type: 산술, 논리 연산 ex) addi, andi, ori
피연산자 1개는 레지스터 파일에서, 다른 1개는 상수 필드에서 가져옴
rs(소스1), rt, immediate(소스2)
* destination register의 위치가 다르다 (rd vs rt)
소스1은 동일하고, 소스2는 rt vs immediate, 목적지는 rd vs rt
module mux2 (input [31:0] d0,
input [31:0] d1,
input s, // ALUSrc (1이면 d1, 0이면 d0)
output [31:0] y);
assign y = s ? d1 : d0;
endmodule
// 범용적인 사용
module mux2 #(parameter WIDTH = 8)
(input [WIDTH-1:0] d0, d1;
input s,
output [WIDTH-1:0] y);
assign y = s ? d1 : d0;
endmodule
...
// 인스턴스화
mux2 #32 mymux(
.d0 (writedata),
.d1 (signimm),
.s (alusrc),
.y (result));
...
3-2) Instruction Execution #2
lw, sw 명령어 -> I-type
opcode rs, rt, imm
3-3) Instruction Execution #3
beq, bne <- R-format
opcode rs, rt ,imm # destination = (pc+4) + imm<<2
j <- J-format
opcode jump-target # destination = {(pc+4)[31:28], jump-target, 2'b00}