다운/퍼 가실 때 댓글 부탁드려요. 그리고 받으신 자료 유료 레포트 사이트에 올리지 말아주세요.
1. 개 요
가. 기존에 구현한 Single Cycle CPU에 I-type 형식의 instruction을 처리하는 기능을 추가한다.
나. Instruction Decoder에서 R-type과 I-type의 instruction을 해석하여 각 상황에 맞는 controller signal을 설정하고 정상적인 동작상태를 보인다.
2. 알고리즘
가. Instruction Fetch
|
|
1) 클럭에 동기화 되어 PC값이 증가되면서 해당 rom_data에 있는 instruction을 읽어온다
2) pc는 클럭마다 1씩 증가되고 새로운 instruction을 받아오게 된다.(single_cycle 특성)
3) rom_data의 수는
나. Decoder
|
R-type |
I-type |
|
|
|
1) 받아온 instruction 중에서 R-type은 6비트를 I-type은 3비트를 명령어로 사용한다.
2) R-type은 하위 10비트 중 각각 5비트씩은 read_address1, read_address2로 사용하고, I-type은 하위13비트 중 5비트는 read_address1로, 8비트는 immediate 값으로 사용한다.
3) 또한 클록에 동기화되어 write_address는 [9:5]비트의 데이터를 주소로 사용한다.
다. Register & ALU
|
|
1) Decoder에서 해석된 operand(명령어)는 R-type(6비트), I-type(3비트) 모두 adder기능을 수행한다.
2) R-type의 경우 read_address1과 read_address2주소에 해당하는 read_data1과 read_data2를 rom_table에서 꺼내서 ALU 연산(adder)을 통해서 그 결과값을 다시 매 클럭이 posedge일 때마다 read_address1(write_address) 위치에 삽입한다. (ex. a = a + b)
3) I-type의 경우 read_address1의 주소에 해당하는 read_data1을 rom_table에서 꺼내고 immediate값을 바로 ALU 연산(adder)하여 그 결과값을 다시 매 클럭이 posedge일 때마다 read_address1(write_address)로 삽입한다. (ex. a = a + constant(10))
3) R-type에서 read_enable1, read_enable2은 instruction에 write_enable값은 클럭에 동기화되어 1로 할당되고 이는 매 클럭마다 2개의 data를 add 연산하여 레지스터에 쓰는 구조를 갖게됨을 의미한다. I-type의 경우 read_enable2는 0으로 되고 이는 read_address2 대신에 immediate를 사용함을 의미한다.
3. 코 드
|
module cpu(clk, pc, rst, write_data, read_address1, read_address2, read_enable1, read_enable2); input clk, rst; output [7:0] write_data; output [5:0] pc; output [4:0] read_address1, read_address2; output read_enable1, read_enable2; reg [4:0] read_address1, read_address2, write_address; reg [5:0] pc; reg [7:0] read_data1, read_data2; reg [15:0] inst_out; reg read_enable1, read_enable2, write_enable; // rom_table 모듈 시행 m_rom_table rom_table(clk, pc, rst, inst_out); // instruction decoder 모듈 시행 m_inst_decoder inst_decoder(clk, inst_out, read_address1, read_address2, write_address, read_enable1, read_enable2, write_enable); // register 모듈 시행 m_register register(clk, rst, read_enable1, read_enable2, write_enable, read_address1, read_address2, write_address, read_data1, read_data2, write_data); // alu 모듈 시행 func_sel과 result_sel 값은 adder기능을 수행하도록 0과 2'b00을 대입 m_alu alu(read_data1, read_data2, 0, 2'b00, write_data); always@(posedge clk) // 클럭마다 pc값을 1 증가 begin pc = pc + 1'b1; end endmodule module m_rom_table(clk, pc, rst, inst_out); input [5:0] pc; input clk, rst; output [15:0] inst_out; reg [15:0] inst_out; reg [15:0] rom_data[0:63]; always@(posedge clk or negedge rst) begin if(rst == 1'b0) // rst가 0이면 rom_data 테이블 초기화 begin rom_data[0] = 16'b0000010000000001; rom_data[1] = 16'b0000010000000001; rom_data[2] = 16'b0000010000000001; rom_data[3] = 16'b0000010000000001; |
|
rom_data[4] = 16'b0000010000000001; rom_data[5] = 16'b0000010000000001; rom_data[6] = 16'b0000010000000001; rom_data[7] = 16'b0000010000000001; rom_data[8] = 16'b0000010000000001; rom_data[9] = 16'b0000010000000001; rom_data[10] = 16'b0000010000000001; rom_data[11] = 16'b0000010000000001; rom_data[12] = 16'b0000010000000001; rom_data[13] = 16'b0000010000000001; rom_data[14] = 16'b0000010000000001; rom_data[15] = 16'b0000010000000001; rom_data[16] = 16'b0000010000000001; rom_data[17] = 16'b0000010000000001; rom_data[18] = 16'b0000010000000001; rom_data[19] = 16'b0000010000000001; rom_data[20] = 16'b0000010000000001; rom_data[21] = 16'b0000010000000001; rom_data[22] = 16'b0000010000000001; rom_data[23] = 16'b0000010000000001; rom_data[24] = 16'b0000010000000001; rom_data[25] = 16'b0000010000000001; rom_data[26] = 16'b0000010000000001; rom_data[27] = 16'b0000010000000001; rom_data[28] = 16'b0000010000000001; rom_data[29] = 16'b0000010000000001; rom_data[30] = 16'b0000010000000001; rom_data[31] = 16'b0000010000000001; rom_data[32] = 16'b0000010000000001; rom_data[33] = 16'b0000010000000001; rom_data[34] = 16'b0000010000000001; rom_data[35] = 16'b0000010000000001; rom_data[36] = 16'b0000010000000001; rom_data[37] = 16'b0000010000000001; rom_data[38] = 16'b0000010000000001; rom_data[39] = 16'b0000010000000001; rom_data[40] = 16'b0000010000000001; rom_data[41] = 16'b0000010000000001; rom_data[42] = 16'b0000010000000001; rom_data[43] = 16'b0000010000000001; rom_data[44] = 16'b0000010000000001; rom_data[45] = 16'b0000010000000001; rom_data[46] = 16'b0000010000000001; rom_data[47] = 16'b0000010000000001; rom_data[48] = 16'b0000010000000001; rom_data[49] = 16'b0000010000000001; rom_data[50] = 16'b0000010000000001; rom_data[51] = 16'b0000010000000001; rom_data[52] = 16'b0000010000000001; rom_data[53] = 16'b0000010000000001; rom_data[54] = 16'b0000010000000001; rom_data[55] = 16'b0000010000000001; rom_data[56] = 16'b0000010000000001; rom_data[57] = 16'b0000010000000001; rom_data[58] = 16'b0000010000000001; rom_data[59] = 16'b0000010000000001; rom_data[60] = 16'b0000010000000001; rom_data[61] = 16'b0000010000000001; rom_data[62] = 16'b0000010000000001; rom_data[63] = 16'b0000010000000001; end end always@(posedge clk) // 클럭마다 pc에 해당하는 rom_data의 값 inst_out에 읽어옴 begin inst_out = rom_data[pc]; end endmodule |
|
module m_inst_decoder(clk, inst_in, read_address1, read_address2, write_address, read_enable1, read_enable2, write_enable); input clk; input [15:0] inst_in; output [4:0] read_address1, read_address2, write_address; output read_enable1, read_enable2, write_enable; reg [4:0] read_address1, read_address2, write_address; reg read_enable1, read_enable2, write_enable; always@(inst_in) // instruction을 받을 때마다 read_address1,2를 저장 begin if(inst_in[15:10] == 6'b000001) // R-type 명령어일 때 begin read_address1 = inst_in[9:5]; read_address2 = inst_in[4:0]; read_enable1 = 1; read_enable2 = 1; end else if(inst_in[15:13] == 3'b001) // I-type 명령어 일 때 begin read_address1 = inst_in[12:8]; imm_data = inst_in[7:0]; // read_address2 대신 imm_data값 저장 read_enable1 = 1; read_enable2 = 0; end end always@(posedge clk) // 매 클럭마다 5~9비트 데이터를 write_address로 사용 begin if(inst_in[15:10] == 6'b000001) // R-type 명령어일 때 write_address = inst_in[9:5]; else if(inst_in[15:13] == 3'b001) // I-type 명령어일 때 write_address = inst_in[12:8]; write_enable = 1; // 어느 타입이건 매 클럭마다 write함 end endmodule module m_register(clk, rst, read_enable1, read_enable2, write_enable, read_address1, read_address2, write_address, read_data1, read_data2, write_data); input clk, rst, read_enable1, read_enable2, write_enable; input [4:0] read_address1, read_address2, write_address; input [7:0] write_data; output [7:0] read_data1, read_data2; reg [7:0] read_data1, read_data2; reg [7:0] rom_table[0:31]; always@(posedge clk or negedge rst) begin if(rst == 1'b0) // rst가 0이면 rom_table 초기화 begin rom_table[0] = 8'b00000000; rom_table[1] = 8'b00000001; rom_table[2] = 8'b00000010; rom_table[3] = 8'b00000011; rom_table[4] = 8'b00000100; rom_table[5] = 8'b00000101; rom_table[6] = 8'b00000110; rom_table[7] = 8'b00000111; rom_table[8] = 8'b00001000; rom_table[9] = 8'b00001001; rom_table[10] = 8'b00001010; rom_table[11] = 8'b00001011; rom_table[12] = 8'b00001100; |
|
rom_table[13] = 8'b00001101; rom_table[14] = 8'b00001110; rom_table[15] = 8'b00001111; rom_table[16] = 8'b00010000; rom_table[17] = 8'b00010001; rom_table[18] = 8'b00010010; rom_table[19] = 8'b00010011; rom_table[20] = 8'b00010100; rom_table[21] = 8'b00010101; rom_table[22] = 8'b00010110; rom_table[23] = 8'b00010111; rom_table[24] = 8'b00011000; rom_table[25] = 8'b00011001; rom_table[26] = 8'b00011010; rom_table[27] = 8'b00011011; rom_table[28] = 8'b00011100; rom_table[29] = 8'b00011101; rom_table[30] = 8'b00011110; rom_table[31] = 8'b00011111; end else if(write_enable == 1'b1) // write_enable이 1이면 레지스터에 데이터 쓰기 rom_table[write_address] = write_data; end always@(read_address1) begin if(read_enable1 == 1'b1) // read_enable1이 1이면 레지스터에서 데이터 읽음 read_data1 = rom_table[read_address1]; end always@(read_address2) begin if(read_enable2 == 1'b1) // read_enable2가 1이면 레지스터에서 데이터 읽음 read_data2 = rom_table[read_address2]; else // 아니면 imm_data를 바로 read_data2에 저장 read_data2 = imm_data; end endmodule module m_alu(a, b, func_sel, result_sel, result); // 이 이하부터는 ALU 연산 input [7:0] a, b; input func_sel; input [1:0] result_sel; output [7:0] result; reg [7:0] result; reg [7:0] adder_result; reg [7:0] and_result; reg [7:0] or_result; m_adder adder1(a, b, adder_result, func_sel); m_and and1(a, b, and_result); m_or or1(a, b, or_result); always@(result or adder_result or and_result or or_result or result_sel) case(result_sel) 2'b00 : result = adder_result; 2'b01 : begin if(adder_result >= 0) result = 8'b00000000; else result = 8'b00000001; end |
|
2'b10 : result = and_result; 2'b11 : result = or_result; endcase endmodule module m_adder(a, b, adder_result, func_sel); input [7:0] a, b; input func_sel; output [7:0] adder_result; wire [7:0] c; wire [7:0] b1; m_complement com1(b, b1, func_sel); m_half_adder ha(a[0], b1[0], c[0], adder_result[0]); m_full_adder fa1(a[1], b1[1], c[0], c[1], adder_result[1]); m_full_adder fa2(a[2], b1[2], c[1], c[2], adder_result[2]); m_full_adder fa3(a[3], b1[3], c[2], c[3], adder_result[3]); m_full_adder fa4(a[4], b1[4], c[3], c[4], adder_result[4]); m_full_adder fa5(a[5], b1[5], c[4], c[5], adder_result[5]); m_full_adder fa6(a[6], b1[6], c[5], c[6], adder_result[6]); m_full_adder fa7(a[7], b1[7], c[6], c[7], adder_result[7]); endmodule module m_full_adder(a, b, cin, cout, adder_result); input a, b, cin; output cout, adder_result; wire c1, c2, s1; m_half_adder ha1(b, cin, c1, s1); m_half_adder ha2(a, s1, c2, adder_result); assign cout = c1 | c2; endmodule module m_half_adder(a, b, c, adder_result); input a, b; output c, adder_result; assign adder_result = a ^ b; assign c = a & b; endmodule |
|
module m_complement(b, b1, func_sel); input [7:0] b; input func_sel; output [7:0] b1; reg [7:0] tmp; always@(b or tmp or func_sel) case(func_sel) 1'b0 : tmp = b; 1'b1 : tmp = ~b + 1; endcase assign b1 = tmp; endmodule module m_and(a, b, and_result); input [7:0] a, b; output [7:0] and_result; assign and_result = a & b; endmodule module m_or(a, b, or_result); input [7:0] a, b; output [7:0] or_result; assign or_result = a | b; endmodule |
4. 파형 및 분석
|
|
가. 그림 (1)에서 보면 rst를 0으로 초기화 시켜서 rom_data는 rom_data[0]부터 rom_data[4]까지는 R-type 형식의 instruction을 rom_data[5]부터 rom_data[10]까지는 I-type 형식의 instruction을, 그리고 rom_data[11]부터 rom_data[63]까지는 다시 R-type의 instruction으로 만든다. R-type은 6비트의 명령어(adder만 사용)와 5비트의 rs(source), 5비트의 rt(target)을 사용하고, I-type은 3비트의 명령어(adder만 사용)와 5비트의 rs(source), 8비트의 immediate value를 사용한다.
또한, rom_table은 rom_table[0]을 0(8‘b00000000)으로 저장하고 그 후 차례대로 1‘b1씩 증가하여 마지막 rom_table[31]에는 8'b00011111로 초기화시킨다.
I-type은 rom_data[5]에는 immediate value가 3으로, 그 이후엔 2로 초기화되었다.
나. R-type은 rom_table[0]과 rom_table[1]을 더해서 다시 rom_table[0]에 저장하는 형태이므로 그림 (2)와 같이 매 클럭마다 1씩 증가함을 볼 수 있다.
다. I-type은 rom_table[0]과 immediate value를 더하므로, I-type이 시작하는(즉, read_enable2가 0이 되는 부분인) rom_table[5]의 경우에 3의 값으로 초기화 되어있었으므로 그림 (3)과 같이 write_data(rom_table[0])의 값이 3이 증가하며, 그 후에는 그림 (4)와 같이 2씩 증가됨을 볼 수 있다.
라. 그리고 다시 R-type이 시작되는 그림 (5)를 보면 이후부터 다시 wirte_data가 1씩 증가됨을 확인할 수 있다.
※ 참고 문헌
가. HDL Chip Design(Doone Publications / Douglas J Smith 저)
'레포트 자료' 카테고리의 다른 글
| 컴퓨터구조 설계 및 실험 - 16bit CPU (branch, jump 추가) (0) | 2009/02/02 |
|---|---|
| 컴퓨터구조 설계 및 실험 - 16bit CPU (Load / Store instruction 추가) (0) | 2009/02/02 |
| 컴퓨터구조 설계 및 실험 - 16bit CPU (I-type 추가) (0) | 2009/02/02 |
| 컴퓨터구조 설계 및 실험 - 16bit CPU (Instruction Fetch & Decode) (1) | 2009/02/02 |
| 컴퓨터구조 설계 및 실험 - register (0) | 2009/02/02 |
| 컴퓨터구조 설계 및 실험 - ALU (1) | 2009/02/02 |


cpu2(I-type추가).zip



